diff options
Diffstat (limited to 'indra/llcommon')
291 files changed, 35798 insertions, 35775 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index c947184dc8..5f4ed2fffa 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -3,7 +3,6 @@ project(llcommon) include(00-Common) -include(ICU4C) include(LLCommon) include(bugsplat) include(Linking) @@ -283,7 +282,6 @@ target_link_libraries( ll::uriparser ll::oslibraries ll::tracy - ll::icu4c ) target_include_directories(llcommon INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp index 56defc6465..201eeed56b 100644 --- a/indra/llcommon/StackWalker.cpp +++ b/indra/llcommon/StackWalker.cpp @@ -1,5 +1,5 @@ /********************************************************************** - * + * * StackWalker.cpp * http://stackwalker.codeplex.com/ * @@ -13,14 +13,14 @@ * http://www.codeproject.com/threads/StackWalker.asp * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack * (to simplify the usage) - * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL + * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL * (should also be enough) * - Changed to compile correctly with the PSDK of VC7.0 * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: * it uses LPSTR instead of LPCSTR as first paremeter) * - Added declarations to support VC5/6 without using 'dbghelp.h' - * - Added a 'pUserData' member to the ShowCallstack function and the - * PReadProcessMemoryRoutine declaration (to pass some user-defined data, + * - Added a 'pUserData' member to the ShowCallstack function and the + * PReadProcessMemoryRoutine declaration (to pass some user-defined data, * which can be used in the readMemoryFunction-callback) * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default * - Added example for doing an exception-callstack-walking in main.cpp @@ -60,26 +60,26 @@ * Copyright (c) 2005-2013, Jochen Kalmbach * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **********************************************************************/ @@ -234,7 +234,7 @@ DWORD64 // Some missing defines (for VC5/6): #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif +#endif // secure-CRT_functions are only available starting with VC8 @@ -396,7 +396,7 @@ public: m_szSymPath = _strdup(szSymPath); if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); - + DWORD symOptions = this->pSGO(); // SymGetOptions symOptions |= SYMOPT_LOAD_LINES; symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; @@ -512,11 +512,11 @@ struct IMAGEHLP_MODULE64_V2 { tSSO pSSO; // StackWalk64() - typedef BOOL (__stdcall *tSW)( - DWORD MachineType, + typedef BOOL (__stdcall *tSW)( + DWORD MachineType, HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, @@ -1012,7 +1012,7 @@ BOOL StackWalker::LoadModules() // The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction // This has to be done due to a problem with the "hProcess"-parameter in x64... -// Because this class is in no case multi-threading-enabled (because of the limitations +// Because this class is in no case multi-threading-enabled (because of the limitations // of dbghelp.dll) it is "safe" to use a static-variable static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; static LPVOID s_readMemoryFunction_UserData = NULL; @@ -1222,7 +1222,7 @@ BOOL StackWalker::ShowCallstack(bool verbose, HANDLE hThread, const CONTEXT *con csEntry.symTypeString = NULL; break; } - + MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); csEntry.baseOfImage = Module.BaseOfImage; MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); @@ -1243,7 +1243,7 @@ BOOL StackWalker::ShowCallstack(bool verbose, HANDLE hThread, const CONTEXT *con et = firstEntry; bLastEntryCalled = false; this->OnCallstackEntry(et, csEntry); - + if (s.AddrReturn.Offset == 0) { bLastEntryCalled = true; @@ -1358,7 +1358,7 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA(&ver) != FALSE) { - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion); if (m_verbose) @@ -1372,7 +1372,7 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) { - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); if (m_verbose) diff --git a/indra/llcommon/StackWalker.h b/indra/llcommon/StackWalker.h index 4634765d0b..91cd55bbaf 100644 --- a/indra/llcommon/StackWalker.h +++ b/indra/llcommon/StackWalker.h @@ -1,5 +1,5 @@ /********************************************************************** - * + * * StackWalker.h * * @@ -13,33 +13,33 @@ * Copyright (c) 2005-2009, Jochen Kalmbach * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * **********************************************************************/ #if LL_WINDOWS -// #pragma once is supported starting with _MCS_VER 1000, +// #pragma once is supported starting with _MCS_VER 1000, // so we need not to check the version (because we only support _MSC_VER >= 1100)! #pragma once @@ -61,34 +61,34 @@ class StackWalker public: typedef enum StackWalkOptions { - // No addition info will be retrived + // No addition info will be retrived // (only the address is available) RetrieveNone = 0, - + // Try to get the symbol-name RetrieveSymbol = 1, - + // Try to get the line for this symbol RetrieveLine = 2, - + // Try to retrieve the module-infos RetrieveModuleInfo = 4, - + // Also retrieve the version for the DLL/EXE RetrieveFileVersion = 8, - + // Contains all the abouve RetrieveVerbose = 0xF, - + // Generate a "good" symbol-search-path SymBuildPath = 0x10, - + // Also use the public Microsoft-Symbol-Server SymUseSymSrv = 0x20, - + // Contains all the abouve "Sym"-options SymAll = 0x30, - + // Contains all options (default) OptionsAll = 0x3F } StackWalkOptions; @@ -96,8 +96,8 @@ public: StackWalker( bool verbose = true, int options = OptionsAll, // 'int' is by design, to combine the enum-flags - LPCSTR szSymPath = NULL, - DWORD dwProcessId = GetCurrentProcessId(), + LPCSTR szSymPath = NULL, + DWORD dwProcessId = GetCurrentProcessId(), HANDLE hProcess = GetCurrentProcess() ); StackWalker(DWORD dwProcessId, HANDLE hProcess); @@ -116,18 +116,18 @@ public: BOOL ShowCallstack( bool verbose, - HANDLE hThread = GetCurrentThread(), - const CONTEXT *context = NULL, + HANDLE hThread = GetCurrentThread(), + const CONTEXT *context = NULL, PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback ); #if _MSC_VER >= 1300 -// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" +// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" // in older compilers in order to use it... starting with VC7 we can declare it as "protected" protected: #endif - enum { STACKWALK_MAX_NAMELEN = 4096 }; // max name length for found symbols + enum { STACKWALK_MAX_NAMELEN = 4096 }; // max name length for found symbols protected: // Entry for each Callstack-Entry @@ -173,10 +173,10 @@ protected: // The "ugly" assembler-implementation is needed for systems before XP -// If you have a new PSDK and you only compile for XP and later, then you can use +// If you have a new PSDK and you only compile for XP and later, then you can use // the "RtlCaptureContext" -// Currently there is no define which determines the PSDK-Version... -// So we just use the compiler-version (and assumes that the PSDK is +// Currently there is no define which determines the PSDK-Version... +// So we just use the compiler-version (and assumes that the PSDK is // the one which was installed by the VS-IDE) // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... @@ -185,7 +185,7 @@ protected: #if defined(_M_IX86) #ifdef CURRENT_THREAD_VIA_EXCEPTION -// TODO: The following is not a "good" implementation, +// TODO: The following is not a "good" implementation, // because the callstack is only valid in the "__except" block... #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ do { \ diff --git a/indra/llcommon/always_return.h b/indra/llcommon/always_return.h index 6b9f1fdeaf..a206471da5 100644 --- a/indra/llcommon/always_return.h +++ b/indra/llcommon/always_return.h @@ -4,7 +4,7 @@ * @date 2023-01-20 * @brief Call specified callable with arbitrary arguments, but always return * specified type. - * + * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Copyright (c) 2023, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/apply.cpp b/indra/llcommon/apply.cpp index 417e23d3b4..805b1234ac 100644 --- a/indra/llcommon/apply.cpp +++ b/indra/llcommon/apply.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-12-21 * @brief Implementation for apply. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h index cf6161ed50..ec1a39f7b0 100644 --- a/indra/llcommon/apply.h +++ b/indra/llcommon/apply.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-18 * @brief C++14 version of std::apply() - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ @@ -69,7 +69,7 @@ using std::invoke; // Use invoke() to handle pointer-to-method: // derived from https://stackoverflow.com/a/38288251 -template<typename Fn, typename... Args, +template<typename Fn, typename... Args, typename std::enable_if<std::is_member_pointer<typename std::decay<Fn>::type>::value, int>::type = 0 > auto invoke(Fn&& f, Args&&... args) @@ -77,7 +77,7 @@ auto invoke(Fn&& f, Args&&... args) return std::mem_fn(std::forward<Fn>(f))(std::forward<Args>(args)...); } -template<typename Fn, typename... Args, +template<typename Fn, typename... Args, typename std::enable_if<!std::is_member_pointer<typename std::decay<Fn>::type>::value, int>::type = 0 > auto invoke(Fn&& f, Args&&... args) @@ -154,7 +154,7 @@ using std::bind_front; #else // no std::bind_front() -template<typename Fn, typename... Args, +template<typename Fn, typename... Args, typename std::enable_if<!std::is_member_pointer<typename std::decay<Fn>::type>::value, int>::type = 0 > auto bind_front(Fn&& f, Args&&... args) @@ -172,7 +172,7 @@ auto bind_front(Fn&& f, Args&&... args) }; } -template<typename Fn, typename... Args, +template<typename Fn, typename... Args, typename std::enable_if<std::is_member_pointer<typename std::decay<Fn>::type>::value, int>::type = 0 > auto bind_front(Fn&& f, Args&&... args) diff --git a/indra/llcommon/chrono.h b/indra/llcommon/chrono.h index 806e871892..d121b9adf6 100644 --- a/indra/llcommon/chrono.h +++ b/indra/llcommon/chrono.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-05 * @brief supplement <chrono> with utility functions - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/classic_callback.cpp b/indra/llcommon/classic_callback.cpp index 5674e0a44d..b2d0e7b303 100644 --- a/indra/llcommon/classic_callback.cpp +++ b/indra/llcommon/classic_callback.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-09-23 * @brief Implementation for classic_callback. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/commoncontrol.cpp b/indra/llcommon/commoncontrol.cpp index 81e66baf8c..d8bdcd5aa5 100644 --- a/indra/llcommon/commoncontrol.cpp +++ b/indra/llcommon/commoncontrol.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-08 * @brief Implementation for commoncontrol. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/commoncontrol.h b/indra/llcommon/commoncontrol.h index 07d4a45ac5..13aa983a99 100644 --- a/indra/llcommon/commoncontrol.h +++ b/indra/llcommon/commoncontrol.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-08 * @brief Access LLViewerControl LLEventAPI, if process has one. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/ctype_workaround.h b/indra/llcommon/ctype_workaround.h index 552be9fb90..89a47fe3db 100644 --- a/indra/llcommon/ctype_workaround.h +++ b/indra/llcommon/ctype_workaround.h @@ -1,4 +1,4 @@ -/** +/** * @file ctype_workaround.h * @brief The workaround is to create some legacy symbols that point * to the correct symbols, which avoids link errors. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,12 +42,12 @@ __const unsigned short int *__ctype_b; __const __int32_t *__ctype_tolower; __const __int32_t *__ctype_toupper; -// call this function at the beginning of main() +// call this function at the beginning of main() void ctype_workaround() { - __ctype_b = *(__ctype_b_loc()); - __ctype_toupper = *(__ctype_toupper_loc()); - __ctype_tolower = *(__ctype_tolower_loc()); + __ctype_b = *(__ctype_b_loc()); + __ctype_toupper = *(__ctype_toupper_loc()); + __ctype_tolower = *(__ctype_tolower_loc()); } #endif diff --git a/indra/llcommon/fix_macros.h b/indra/llcommon/fix_macros.h index 43c09c54bc..ed6c26a371 100644 --- a/indra/llcommon/fix_macros.h +++ b/indra/llcommon/fix_macros.h @@ -6,7 +6,7 @@ * generic names, preventing any library from using those names. We've * had to fix these in so many places that it's worth making a header * file to handle it. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/function_types.h b/indra/llcommon/function_types.h index 3f42f6d640..7e15895a7e 100644 --- a/indra/llcommon/function_types.h +++ b/indra/llcommon/function_types.h @@ -4,7 +4,7 @@ * @date 2023-01-20 * @brief Extend boost::function_types to examine boost::function and * std::function - * + * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Copyright (c) 2023, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/hbxxh.cpp b/indra/llcommon/hbxxh.cpp index 388269d6c8..41d797a7e3 100644 --- a/indra/llcommon/hbxxh.cpp +++ b/indra/llcommon/hbxxh.cpp @@ -10,16 +10,16 @@ * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/hbxxh.h b/indra/llcommon/hbxxh.h index 9c0e9cf172..142e140cf3 100644 --- a/indra/llcommon/hbxxh.h +++ b/indra/llcommon/hbxxh.h @@ -10,16 +10,16 @@ * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index 9a0c565b06..d24a221671 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -1,25 +1,25 @@ -/** +/** * @file indra_constants.cpp * @brief some useful short term constants for Indra * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,39 +38,39 @@ const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); // Maintenance's group id. const LLUUID MAINTENANCE_GROUP_ID("dc7b21cd-3c89-fcaa-31c8-25f9ffd224cd"); // Grass Images -const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER +const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER -const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER +const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER -const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver -const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver -const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver -const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver -const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver +const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver +const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver +const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver +const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver +const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver const LLUUID IMG_FACE_SELECT ("a85ac674-cb75-4af6-9499-df7c5aaf7a28"); // face selector const LLUUID IMG_DEFAULT_AVATAR ("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); // dataserver -const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver +const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver const LLUUID IMG_WHITE ("5748decc-f629-461c-9a36-a35a221fe21f"); // dataserver -const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver -const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver -const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver -const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver -const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver +const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver +const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver +const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver +const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver +const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver -const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver -const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver +const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver +const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver -const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEWER -const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER -const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER +const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEWER +const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER +const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER -const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER -const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER -const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER -const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER +const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER +const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER +const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER +const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER -const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER +const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER const LLUUID DEFAULT_OBJECT_TEXTURE ("89556747-24cb-43ed-920b-47caed15465f"); // On dataserver const LLUUID DEFAULT_OBJECT_SPECULAR ("87e0e8f7-8729-1ea8-cfc9-8915773009db"); // On dataserver diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index a16cfac2b9..811313e56e 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -1,25 +1,25 @@ -/** +/** * @file indra_constants.h * @brief some useful short term constants for Indra * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,21 +37,21 @@ static const U32 REGION_WIDTH_U32 = 256; const F32 REGION_HEIGHT_METERS = 4096.f; -const F32 DEFAULT_AGENT_DEPTH = 0.45f; -const F32 DEFAULT_AGENT_WIDTH = 0.60f; -const F32 DEFAULT_AGENT_HEIGHT = 1.9f; +const F32 DEFAULT_AGENT_DEPTH = 0.45f; +const F32 DEFAULT_AGENT_WIDTH = 0.60f; +const F32 DEFAULT_AGENT_HEIGHT = 1.9f; enum ETerrainBrushType { - // the valid brush numbers cannot be reordered, because they - // are used in the binary LSL format as arguments to llModifyLand() - E_LANDBRUSH_LEVEL = 0, - E_LANDBRUSH_RAISE = 1, - E_LANDBRUSH_LOWER = 2, - E_LANDBRUSH_SMOOTH = 3, - E_LANDBRUSH_NOISE = 4, - E_LANDBRUSH_REVERT = 5, - E_LANDBRUSH_INVALID = 6 + // the valid brush numbers cannot be reordered, because they + // are used in the binary LSL format as arguments to llModifyLand() + E_LANDBRUSH_LEVEL = 0, + E_LANDBRUSH_RAISE = 1, + E_LANDBRUSH_LOWER = 2, + E_LANDBRUSH_SMOOTH = 3, + E_LANDBRUSH_NOISE = 4, + E_LANDBRUSH_REVERT = 5, + E_LANDBRUSH_INVALID = 6 }; enum EMouseClickType{ @@ -67,101 +67,101 @@ enum EMouseClickType{ // keys // Bit masks for various keyboard modifier keys. -const MASK MASK_NONE = 0x0000; -const MASK MASK_CONTROL = 0x0001; // Mapped to cmd on Macs -const MASK MASK_ALT = 0x0002; -const MASK MASK_SHIFT = 0x0004; +const MASK MASK_NONE = 0x0000; +const MASK MASK_CONTROL = 0x0001; // Mapped to cmd on Macs +const MASK MASK_ALT = 0x0002; +const MASK MASK_SHIFT = 0x0004; const MASK MASK_NORMALKEYS = 0x0007; // A real mask - only get the bits for normal modifier keys -const MASK MASK_MAC_CONTROL = 0x0008; // Un-mapped Ctrl key on Macs, not used on Windows -const MASK MASK_MODIFIERS = MASK_CONTROL|MASK_ALT|MASK_SHIFT|MASK_MAC_CONTROL; +const MASK MASK_MAC_CONTROL = 0x0008; // Un-mapped Ctrl key on Macs, not used on Windows +const MASK MASK_MODIFIERS = MASK_CONTROL|MASK_ALT|MASK_SHIFT|MASK_MAC_CONTROL; // Special keys go into >128 -const KEY KEY_SPECIAL = 0x80; // special keys start here -const KEY KEY_RETURN = 0x81; -const KEY KEY_LEFT = 0x82; -const KEY KEY_RIGHT = 0x83; -const KEY KEY_UP = 0x84; -const KEY KEY_DOWN = 0x85; -const KEY KEY_ESCAPE = 0x86; +const KEY KEY_SPECIAL = 0x80; // special keys start here +const KEY KEY_RETURN = 0x81; +const KEY KEY_LEFT = 0x82; +const KEY KEY_RIGHT = 0x83; +const KEY KEY_UP = 0x84; +const KEY KEY_DOWN = 0x85; +const KEY KEY_ESCAPE = 0x86; const KEY KEY_BACKSPACE =0x87; -const KEY KEY_DELETE = 0x88; -const KEY KEY_SHIFT = 0x89; -const KEY KEY_CONTROL = 0x8A; -const KEY KEY_ALT = 0x8B; -const KEY KEY_HOME = 0x8C; -const KEY KEY_END = 0x8D; +const KEY KEY_DELETE = 0x88; +const KEY KEY_SHIFT = 0x89; +const KEY KEY_CONTROL = 0x8A; +const KEY KEY_ALT = 0x8B; +const KEY KEY_HOME = 0x8C; +const KEY KEY_END = 0x8D; const KEY KEY_PAGE_UP = 0x8E; const KEY KEY_PAGE_DOWN = 0x8F; const KEY KEY_HYPHEN = 0x90; const KEY KEY_EQUALS = 0x91; const KEY KEY_INSERT = 0x92; const KEY KEY_CAPSLOCK = 0x93; -const KEY KEY_TAB = 0x94; -const KEY KEY_ADD = 0x95; +const KEY KEY_TAB = 0x94; +const KEY KEY_ADD = 0x95; const KEY KEY_SUBTRACT =0x96; const KEY KEY_MULTIPLY =0x97; -const KEY KEY_DIVIDE = 0x98; -const KEY KEY_F1 = 0xA1; -const KEY KEY_F2 = 0xA2; -const KEY KEY_F3 = 0xA3; -const KEY KEY_F4 = 0xA4; -const KEY KEY_F5 = 0xA5; -const KEY KEY_F6 = 0xA6; -const KEY KEY_F7 = 0xA7; -const KEY KEY_F8 = 0xA8; -const KEY KEY_F9 = 0xA9; -const KEY KEY_F10 = 0xAA; -const KEY KEY_F11 = 0xAB; -const KEY KEY_F12 = 0xAC; - -const KEY KEY_PAD_UP = 0xC0; -const KEY KEY_PAD_DOWN = 0xC1; -const KEY KEY_PAD_LEFT = 0xC2; -const KEY KEY_PAD_RIGHT = 0xC3; -const KEY KEY_PAD_HOME = 0xC4; -const KEY KEY_PAD_END = 0xC5; -const KEY KEY_PAD_PGUP = 0xC6; -const KEY KEY_PAD_PGDN = 0xC7; -const KEY KEY_PAD_CENTER = 0xC8; // the 5 in the middle -const KEY KEY_PAD_INS = 0xC9; -const KEY KEY_PAD_DEL = 0xCA; -const KEY KEY_PAD_RETURN = 0xCB; -const KEY KEY_PAD_ADD = 0xCC; // not used -const KEY KEY_PAD_SUBTRACT = 0xCD; // not used +const KEY KEY_DIVIDE = 0x98; +const KEY KEY_F1 = 0xA1; +const KEY KEY_F2 = 0xA2; +const KEY KEY_F3 = 0xA3; +const KEY KEY_F4 = 0xA4; +const KEY KEY_F5 = 0xA5; +const KEY KEY_F6 = 0xA6; +const KEY KEY_F7 = 0xA7; +const KEY KEY_F8 = 0xA8; +const KEY KEY_F9 = 0xA9; +const KEY KEY_F10 = 0xAA; +const KEY KEY_F11 = 0xAB; +const KEY KEY_F12 = 0xAC; + +const KEY KEY_PAD_UP = 0xC0; +const KEY KEY_PAD_DOWN = 0xC1; +const KEY KEY_PAD_LEFT = 0xC2; +const KEY KEY_PAD_RIGHT = 0xC3; +const KEY KEY_PAD_HOME = 0xC4; +const KEY KEY_PAD_END = 0xC5; +const KEY KEY_PAD_PGUP = 0xC6; +const KEY KEY_PAD_PGDN = 0xC7; +const KEY KEY_PAD_CENTER = 0xC8; // the 5 in the middle +const KEY KEY_PAD_INS = 0xC9; +const KEY KEY_PAD_DEL = 0xCA; +const KEY KEY_PAD_RETURN = 0xCB; +const KEY KEY_PAD_ADD = 0xCC; // not used +const KEY KEY_PAD_SUBTRACT = 0xCD; // not used const KEY KEY_PAD_MULTIPLY = 0xCE; // not used -const KEY KEY_PAD_DIVIDE = 0xCF; // not used - -const KEY KEY_BUTTON0 = 0xD0; -const KEY KEY_BUTTON1 = 0xD1; -const KEY KEY_BUTTON2 = 0xD2; -const KEY KEY_BUTTON3 = 0xD3; -const KEY KEY_BUTTON4 = 0xD4; -const KEY KEY_BUTTON5 = 0xD5; -const KEY KEY_BUTTON6 = 0xD6; -const KEY KEY_BUTTON7 = 0xD7; -const KEY KEY_BUTTON8 = 0xD8; -const KEY KEY_BUTTON9 = 0xD9; -const KEY KEY_BUTTON10 = 0xDA; -const KEY KEY_BUTTON11 = 0xDB; -const KEY KEY_BUTTON12 = 0xDC; -const KEY KEY_BUTTON13 = 0xDD; -const KEY KEY_BUTTON14 = 0xDE; -const KEY KEY_BUTTON15 = 0xDF; - -const KEY KEY_NONE = 0xFF; // not sent from keyboard. For internal use only. +const KEY KEY_PAD_DIVIDE = 0xCF; // not used + +const KEY KEY_BUTTON0 = 0xD0; +const KEY KEY_BUTTON1 = 0xD1; +const KEY KEY_BUTTON2 = 0xD2; +const KEY KEY_BUTTON3 = 0xD3; +const KEY KEY_BUTTON4 = 0xD4; +const KEY KEY_BUTTON5 = 0xD5; +const KEY KEY_BUTTON6 = 0xD6; +const KEY KEY_BUTTON7 = 0xD7; +const KEY KEY_BUTTON8 = 0xD8; +const KEY KEY_BUTTON9 = 0xD9; +const KEY KEY_BUTTON10 = 0xDA; +const KEY KEY_BUTTON11 = 0xDB; +const KEY KEY_BUTTON12 = 0xDC; +const KEY KEY_BUTTON13 = 0xDD; +const KEY KEY_BUTTON14 = 0xDE; +const KEY KEY_BUTTON15 = 0xDF; + +const KEY KEY_NONE = 0xFF; // not sent from keyboard. For internal use only. const S32 KEY_COUNT = 256; -const F32 DEFAULT_WATER_HEIGHT = 20.0f; +const F32 DEFAULT_WATER_HEIGHT = 20.0f; // Maturity ratings for simulators -const U8 SIM_ACCESS_MIN = 0; // Treated as 'unknown', usually ends up being SIM_ACCESS_PG -const U8 SIM_ACCESS_PG = 13; -const U8 SIM_ACCESS_MATURE = 21; -const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only -const U8 SIM_ACCESS_DOWN = 254; -const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; +const U8 SIM_ACCESS_MIN = 0; // Treated as 'unknown', usually ends up being SIM_ACCESS_PG +const U8 SIM_ACCESS_PG = 13; +const U8 SIM_ACCESS_MATURE = 21; +const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only +const U8 SIM_ACCESS_DOWN = 254; +const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // attachment constants const U8 ATTACHMENT_ADD = 0x80; @@ -258,84 +258,84 @@ const U32 PARCEL_MEDIA_COMMAND_LOOP_SET = 13; const S32 CHAT_CHANNEL_DEBUG = S32_MAX; // agent constants -const U32 CONTROL_AT_POS_INDEX = 0; -const U32 CONTROL_AT_NEG_INDEX = 1; -const U32 CONTROL_LEFT_POS_INDEX = 2; -const U32 CONTROL_LEFT_NEG_INDEX = 3; -const U32 CONTROL_UP_POS_INDEX = 4; -const U32 CONTROL_UP_NEG_INDEX = 5; -const U32 CONTROL_PITCH_POS_INDEX = 6; -const U32 CONTROL_PITCH_NEG_INDEX = 7; -const U32 CONTROL_YAW_POS_INDEX = 8; -const U32 CONTROL_YAW_NEG_INDEX = 9; -const U32 CONTROL_FAST_AT_INDEX = 10; -const U32 CONTROL_FAST_LEFT_INDEX = 11; -const U32 CONTROL_FAST_UP_INDEX = 12; -const U32 CONTROL_FLY_INDEX = 13; -const U32 CONTROL_STOP_INDEX = 14; -const U32 CONTROL_FINISH_ANIM_INDEX = 15; -const U32 CONTROL_STAND_UP_INDEX = 16; -const U32 CONTROL_SIT_ON_GROUND_INDEX = 17; -const U32 CONTROL_MOUSELOOK_INDEX = 18; -const U32 CONTROL_NUDGE_AT_POS_INDEX = 19; -const U32 CONTROL_NUDGE_AT_NEG_INDEX = 20; -const U32 CONTROL_NUDGE_LEFT_POS_INDEX = 21; -const U32 CONTROL_NUDGE_LEFT_NEG_INDEX = 22; -const U32 CONTROL_NUDGE_UP_POS_INDEX = 23; -const U32 CONTROL_NUDGE_UP_NEG_INDEX = 24; -const U32 CONTROL_TURN_LEFT_INDEX = 25; -const U32 CONTROL_TURN_RIGHT_INDEX = 26; -const U32 CONTROL_AWAY_INDEX = 27; -const U32 CONTROL_LBUTTON_DOWN_INDEX = 28; -const U32 CONTROL_LBUTTON_UP_INDEX = 29; -const U32 CONTROL_ML_LBUTTON_DOWN_INDEX = 30; -const U32 CONTROL_ML_LBUTTON_UP_INDEX = 31; -const U32 TOTAL_CONTROLS = 32; - -const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX; // 0x00000001 -const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX; // 0x00000002 -const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX; // 0x00000004 -const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX; // 0x00000008 -const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX; // 0x00000010 -const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX; // 0x00000020 -const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX; // 0x00000040 -const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX; // 0x00000080 -const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX; // 0x00000100 -const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX; // 0x00000200 - -const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX; // 0x00000400 -const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX; // 0x00000800 -const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX; // 0x00001000 - -const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX; // 0x00002000 -const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX; // 0x00004000 -const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX; // 0x00008000 -const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX; // 0x00010000 -const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX; // 0x00020000 -const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX; // 0x00040000 - -const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; // 0x00080000 -const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; // 0x00100000 -const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; // 0x00200000 -const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; // 0x00400000 -const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; // 0x00800000 -const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; // 0x01000000 -const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX; // 0x02000000 -const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX; // 0x04000000 - -const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000 - -const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX; // 0x10000000 -const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX; // 0x20000000 -const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; // 0x40000000 -const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; // 0x80000000 - -// move these up so that we can hide them in "State" for object updates +const U32 CONTROL_AT_POS_INDEX = 0; +const U32 CONTROL_AT_NEG_INDEX = 1; +const U32 CONTROL_LEFT_POS_INDEX = 2; +const U32 CONTROL_LEFT_NEG_INDEX = 3; +const U32 CONTROL_UP_POS_INDEX = 4; +const U32 CONTROL_UP_NEG_INDEX = 5; +const U32 CONTROL_PITCH_POS_INDEX = 6; +const U32 CONTROL_PITCH_NEG_INDEX = 7; +const U32 CONTROL_YAW_POS_INDEX = 8; +const U32 CONTROL_YAW_NEG_INDEX = 9; +const U32 CONTROL_FAST_AT_INDEX = 10; +const U32 CONTROL_FAST_LEFT_INDEX = 11; +const U32 CONTROL_FAST_UP_INDEX = 12; +const U32 CONTROL_FLY_INDEX = 13; +const U32 CONTROL_STOP_INDEX = 14; +const U32 CONTROL_FINISH_ANIM_INDEX = 15; +const U32 CONTROL_STAND_UP_INDEX = 16; +const U32 CONTROL_SIT_ON_GROUND_INDEX = 17; +const U32 CONTROL_MOUSELOOK_INDEX = 18; +const U32 CONTROL_NUDGE_AT_POS_INDEX = 19; +const U32 CONTROL_NUDGE_AT_NEG_INDEX = 20; +const U32 CONTROL_NUDGE_LEFT_POS_INDEX = 21; +const U32 CONTROL_NUDGE_LEFT_NEG_INDEX = 22; +const U32 CONTROL_NUDGE_UP_POS_INDEX = 23; +const U32 CONTROL_NUDGE_UP_NEG_INDEX = 24; +const U32 CONTROL_TURN_LEFT_INDEX = 25; +const U32 CONTROL_TURN_RIGHT_INDEX = 26; +const U32 CONTROL_AWAY_INDEX = 27; +const U32 CONTROL_LBUTTON_DOWN_INDEX = 28; +const U32 CONTROL_LBUTTON_UP_INDEX = 29; +const U32 CONTROL_ML_LBUTTON_DOWN_INDEX = 30; +const U32 CONTROL_ML_LBUTTON_UP_INDEX = 31; +const U32 TOTAL_CONTROLS = 32; + +const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX; // 0x00000001 +const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX; // 0x00000002 +const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX; // 0x00000004 +const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX; // 0x00000008 +const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX; // 0x00000010 +const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX; // 0x00000020 +const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX; // 0x00000040 +const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX; // 0x00000080 +const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX; // 0x00000100 +const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX; // 0x00000200 + +const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX; // 0x00000400 +const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX; // 0x00000800 +const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX; // 0x00001000 + +const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX; // 0x00002000 +const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX; // 0x00004000 +const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX; // 0x00008000 +const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX; // 0x00010000 +const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX; // 0x00020000 +const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX; // 0x00040000 + +const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; // 0x00080000 +const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; // 0x00100000 +const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; // 0x00200000 +const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; // 0x00400000 +const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; // 0x00800000 +const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; // 0x01000000 +const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX; // 0x02000000 +const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX; // 0x04000000 + +const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000 + +const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX; // 0x10000000 +const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX; // 0x20000000 +const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; // 0x40000000 +const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; // 0x80000000 + +// move these up so that we can hide them in "State" for object updates // (for now) -const U32 AGENT_ATTACH_OFFSET = 4; -const U32 AGENT_ATTACH_MASK = 0xf << AGENT_ATTACH_OFFSET; +const U32 AGENT_ATTACH_OFFSET = 4; +const U32 AGENT_ATTACH_MASK = 0xf << AGENT_ATTACH_OFFSET; -// RN: this method swaps the upper and lower nibbles to maintain backward +// RN: this method swaps the upper and lower nibbles to maintain backward // compatibility with old objects that only used the upper nibble #define ATTACHMENT_ID_FROM_STATE(state) ((S32)((((U8)state & AGENT_ATTACH_MASK) >> 4) | (((U8)state & ~AGENT_ATTACH_MASK) << 4))) diff --git a/indra/llcommon/is_approx_equal_fraction.h b/indra/llcommon/is_approx_equal_fraction.h index 4a9b2e2725..79f4f5ebbd 100644 --- a/indra/llcommon/is_approx_equal_fraction.h +++ b/indra/llcommon/is_approx_equal_fraction.h @@ -5,25 +5,25 @@ * @brief lltut.h uses is_approx_equal_fraction(). Moved to this header * file in llcommon so we can use lltut.h for llcommon tests without * making llcommon depend on llmath. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lazyeventapi.cpp b/indra/llcommon/lazyeventapi.cpp index 028af9f33f..91db0ee4a6 100644 --- a/indra/llcommon/lazyeventapi.cpp +++ b/indra/llcommon/lazyeventapi.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-17 * @brief Implementation for lazyeventapi. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/lazyeventapi.h b/indra/llcommon/lazyeventapi.h index e36831270b..0e5df4e6f4 100644 --- a/indra/llcommon/lazyeventapi.h +++ b/indra/llcommon/lazyeventapi.h @@ -4,7 +4,7 @@ * @date 2022-06-16 * @brief Declaring a static module-scope LazyEventAPI registers a specific * LLEventAPI for future on-demand instantiation. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index a228fd22be..a918caa2e8 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -1,25 +1,25 @@ -/** +/** * @file linden_common.h * @brief Includes common headers that are always safe to include * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index da9d98c16c..0ba8b34cb6 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -1,25 +1,25 @@ -/** +/** * @file llalignedarray.h * @brief A static array which obeys alignment restrictions and mimics std::vector accessors. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,94 +33,94 @@ template <class T, U32 alignment> class LLAlignedArray { public: - T* mArray; - U32 mElementCount; - U32 mCapacity; - - LLAlignedArray(); - ~LLAlignedArray(); - - void push_back(const T& elem); - U32 size() const { return mElementCount; } - void resize(U32 size); - T* append(S32 N); - T& operator[](int idx); - const T& operator[](int idx) const; + T* mArray; + U32 mElementCount; + U32 mCapacity; + + LLAlignedArray(); + ~LLAlignedArray(); + + void push_back(const T& elem); + U32 size() const { return mElementCount; } + void resize(U32 size); + T* append(S32 N); + T& operator[](int idx); + const T& operator[](int idx) const; }; template <class T, U32 alignment> LLAlignedArray<T, alignment>::LLAlignedArray() { - llassert(alignment >= 16); - mArray = NULL; - mElementCount = 0; - mCapacity = 0; + llassert(alignment >= 16); + mArray = NULL; + mElementCount = 0; + mCapacity = 0; } template <class T, U32 alignment> LLAlignedArray<T, alignment>::~LLAlignedArray() { - ll_aligned_free<alignment>(mArray); - mArray = NULL; - mElementCount = 0; - mCapacity = 0; + ll_aligned_free<alignment>(mArray); + mArray = NULL; + mElementCount = 0; + mCapacity = 0; } template <class T, U32 alignment> void LLAlignedArray<T, alignment>::push_back(const T& elem) { - T* old_buf = NULL; - if (mCapacity <= mElementCount) - { - mCapacity++; - mCapacity *= 2; - T* new_buf = (T*) ll_aligned_malloc<alignment>(mCapacity*sizeof(T)); - if (mArray) - { - ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount); - } - old_buf = mArray; - mArray = new_buf; - } - - mArray[mElementCount++] = elem; - - //delete old array here to prevent error on a.push_back(a[0]) - ll_aligned_free<alignment>(old_buf); + T* old_buf = NULL; + if (mCapacity <= mElementCount) + { + mCapacity++; + mCapacity *= 2; + T* new_buf = (T*) ll_aligned_malloc<alignment>(mCapacity*sizeof(T)); + if (mArray) + { + ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount); + } + old_buf = mArray; + mArray = new_buf; + } + + mArray[mElementCount++] = elem; + + //delete old array here to prevent error on a.push_back(a[0]) + ll_aligned_free<alignment>(old_buf); } template <class T, U32 alignment> void LLAlignedArray<T, alignment>::resize(U32 size) { - if (mCapacity < size) - { - mCapacity = size+mCapacity*2; - T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc<alignment>(mCapacity*sizeof(T)) : NULL; - if (mArray) - { - ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount); - ll_aligned_free<alignment>(mArray); - } - - /*for (U32 i = mElementCount; i < mCapacity; ++i) - { - new(new_buf+i) T(); - }*/ - mArray = new_buf; - } - - mElementCount = size; + if (mCapacity < size) + { + mCapacity = size+mCapacity*2; + T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc<alignment>(mCapacity*sizeof(T)) : NULL; + if (mArray) + { + ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount); + ll_aligned_free<alignment>(mArray); + } + + /*for (U32 i = mElementCount; i < mCapacity; ++i) + { + new(new_buf+i) T(); + }*/ + mArray = new_buf; + } + + mElementCount = size; } template <class T, U32 alignment> T& LLAlignedArray<T, alignment>::operator[](int idx) { - if(idx >= mElementCount || idx < 0) + if(idx >= mElementCount || idx < 0) { LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; } - return mArray[idx]; + return mArray[idx]; } template <class T, U32 alignment> @@ -130,15 +130,15 @@ const T& LLAlignedArray<T, alignment>::operator[](int idx) const { LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; } - return mArray[idx]; + return mArray[idx]; } template <class T, U32 alignment> T* LLAlignedArray<T, alignment>::append(S32 N) { - U32 sz = size(); - resize(sz+N); - return &((*this)[sz]); + U32 sz = size(); + resize(sz+N); + return &((*this)[sz]); } #endif diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp index ac97fb71dd..abe3779b85 100644 --- a/indra/llcommon/llallocator.cpp +++ b/indra/llcommon/llallocator.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llallocator.cpp * @brief Implementation of the LLAllocator class. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h index d26ad73c5b..aa3eead546 100644 --- a/indra/llcommon/llallocator.h +++ b/indra/llcommon/llallocator.h @@ -1,25 +1,25 @@ -/** +/** * @file llallocator.h * @brief Declaration of the LLAllocator class. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp index c6d9542b42..85e56b4db4 100644 --- a/indra/llcommon/llallocator_heap_profile.cpp +++ b/indra/llcommon/llallocator_heap_profile.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llallocator_heap_profile.cpp * @brief Implementation of the parser for tcmalloc heap profile data. * @author Brad Kittenbrink @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -67,7 +67,7 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) std::string::const_iterator prof_begin = prof_text.begin() + HEAP_PROFILE_MAGIC_STR.length(); - range_t prof_range(prof_begin, prof_text.end()); + range_t prof_range(prof_begin, prof_text.end()); boost::algorithm::split(prof_lines, prof_range, boost::bind(std::equal_to<llwchar>(), '\n', _1)); @@ -107,34 +107,34 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) ++j; while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens - llassert(j != line_elems.end()); + llassert(j != line_elems.end()); if (j != line_elems.end()) - { - ++j; // skip the '@' - - mLines.push_back(line(live_count, live_size, tot_count, tot_size)); - line & current_line = mLines.back(); - - for(; j != line_elems.end(); ++j) - { - if(!j->empty()) - { - U32 marker = boost::lexical_cast<U32>(*j); - current_line.mTrace.push_back(marker); - } - } - } + { + ++j; // skip the '@' + + mLines.push_back(line(live_count, live_size, tot_count, tot_size)); + line & current_line = mLines.back(); + + for(; j != line_elems.end(); ++j) + { + if(!j->empty()) + { + U32 marker = boost::lexical_cast<U32>(*j); + current_line.mTrace.push_back(marker); + } + } + } } // *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it } void LLAllocatorHeapProfile::dump(std::ostream & out) const { - for (const LLAllocatorHeapProfile::line& line : mLines) + for (const LLAllocatorHeapProfile::line& line : mLines) { out << line.mLiveCount << ": " << line.mLiveSize << '[' << line.mTotalCount << ": " << line.mTotalSize << "] @"; - for (const stack_marker marker : line.mTrace) + for (const stack_marker marker : line.mTrace) { out << ' ' << marker; } diff --git a/indra/llcommon/llallocator_heap_profile.h b/indra/llcommon/llallocator_heap_profile.h index 69300b829b..22f284b703 100644 --- a/indra/llcommon/llallocator_heap_profile.h +++ b/indra/llcommon/llallocator_heap_profile.h @@ -1,4 +1,4 @@ -/** +/** * @file llallocator_heap_profile.h * @brief Declaration of the parser for tcmalloc heap profile data. * @author Brad Kittenbrink @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,7 +59,7 @@ public: { } - void parse(std::string const & prof_text); + void parse(std::string const & prof_text); void dump(std::ostream & out) const; diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 90d0c28eb1..9729f68d23 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llapp.cpp * @brief Implementation of the LLApp class. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -70,8 +70,8 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *); #else // Called by breakpad exception handler after the minidump has been generated. bool unix_post_minidump_callback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded); + const char *minidump_id, + void *context, bool succeeded); #endif # if LL_DARWIN @@ -94,7 +94,7 @@ LLApp* LLApp::sApplication = NULL; // Allows the generation of core files for post mortem under gdb // and disables crashlogger -BOOL LLApp::sDisableCrashlogger = FALSE; +BOOL LLApp::sDisableCrashlogger = FALSE; // Local flag for whether or not to do logging in signal handlers. //static @@ -108,222 +108,222 @@ LLAppErrorHandler LLApp::sErrorHandler = NULL; LLApp::LLApp() { - // Set our status to running - setStatus(APP_STATUS_RUNNING); + // Set our status to running + setStatus(APP_STATUS_RUNNING); + + LLCommon::initClass(); - LLCommon::initClass(); + // initialize the options structure. We need to make this an array + // because the structured data will not auto-allocate if we + // reference an invalid location with the [] operator. + mOptions = LLSD::emptyArray(); + LLSD sd; + for(int i = 0; i < PRIORITY_COUNT; ++i) + { + mOptions.append(sd); + } - // initialize the options structure. We need to make this an array - // because the structured data will not auto-allocate if we - // reference an invalid location with the [] operator. - mOptions = LLSD::emptyArray(); - LLSD sd; - for(int i = 0; i < PRIORITY_COUNT; ++i) - { - mOptions.append(sd); - } + // Make sure we clean up APR when we exit + // Don't need to do this if we're cleaning up APR in the destructor + //atexit(ll_cleanup_apr); - // Make sure we clean up APR when we exit - // Don't need to do this if we're cleaning up APR in the destructor - //atexit(ll_cleanup_apr); + // Set the application to this instance. + sApplication = this; - // Set the application to this instance. - sApplication = this; - - // initialize the buffer to write the minidump filename to - // (this is used to avoid allocating memory in the crash handler) - memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); - mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; + // initialize the buffer to write the minidump filename to + // (this is used to avoid allocating memory in the crash handler) + memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); + mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } LLApp::~LLApp() { - // reclaim live file memory - std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); - mLiveFiles.clear(); + // reclaim live file memory + std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); + mLiveFiles.clear(); - setStopped(); + setStopped(); - SUBSYSTEM_CLEANUP_DBG(LLCommon); + SUBSYSTEM_CLEANUP_DBG(LLCommon); } // static LLApp* LLApp::instance() { - return sApplication; + return sApplication; } LLSD LLApp::getOption(const std::string& name) const { - LLSD rv; - LLSD::array_const_iterator iter = mOptions.beginArray(); - LLSD::array_const_iterator end = mOptions.endArray(); - for(; iter != end; ++iter) - { - rv = (*iter)[name]; - if(rv.isDefined()) break; - } - return rv; + LLSD rv; + LLSD::array_const_iterator iter = mOptions.beginArray(); + LLSD::array_const_iterator end = mOptions.endArray(); + for(; iter != end; ++iter) + { + rv = (*iter)[name]; + if(rv.isDefined()) break; + } + return rv; } bool LLApp::parseCommandOptions(int argc, char** argv) { - LLSD commands; - std::string name; - std::string value; - for(int ii = 1; ii < argc; ++ii) - { - if(argv[ii][0] != '-') - { - LL_INFOS() << "Did not find option identifier while parsing token: " - << argv[ii] << LL_ENDL; - return false; - } - int offset = 1; - if(argv[ii][1] == '-') ++offset; - name.assign(&argv[ii][offset]); - if(((ii+1) >= argc) || (argv[ii+1][0] == '-')) - { - // we found another option after this one or we have - // reached the end. simply record that this option was - // found and continue. - int flag = name.compare("logfile"); - if (0 == flag) - { - commands[name] = "log"; - } - else - { - commands[name] = true; - } - - continue; - } - ++ii; - value.assign(argv[ii]); + LLSD commands; + std::string name; + std::string value; + for(int ii = 1; ii < argc; ++ii) + { + if(argv[ii][0] != '-') + { + LL_INFOS() << "Did not find option identifier while parsing token: " + << argv[ii] << LL_ENDL; + return false; + } + int offset = 1; + if(argv[ii][1] == '-') ++offset; + name.assign(&argv[ii][offset]); + if(((ii+1) >= argc) || (argv[ii+1][0] == '-')) + { + // we found another option after this one or we have + // reached the end. simply record that this option was + // found and continue. + int flag = name.compare("logfile"); + if (0 == flag) + { + commands[name] = "log"; + } + else + { + commands[name] = true; + } + + continue; + } + ++ii; + value.assign(argv[ii]); #if LL_WINDOWS - //Windows changed command line parsing. Deal with it. - S32 slen = value.length() - 1; - S32 start = 0; - S32 end = slen; - if (argv[ii][start]=='"')start++; - if (argv[ii][end]=='"')end--; - if (start!=0 || end!=slen) - { - value = value.substr (start,end); - } + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (argv[ii][start]=='"')start++; + if (argv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } #endif - commands[name] = value; - } - setOptionData(PRIORITY_COMMAND_LINE, commands); - return true; + commands[name] = value; + } + setOptionData(PRIORITY_COMMAND_LINE, commands); + return true; } bool LLApp::parseCommandOptions(int argc, wchar_t** wargv) { - LLSD commands; - std::string name; - std::string value; - for(int ii = 1; ii < argc; ++ii) - { - if(wargv[ii][0] != '-') - { - LL_INFOS() << "Did not find option identifier while parsing token: " - << wargv[ii] << LL_ENDL; - return false; - } - int offset = 1; - if(wargv[ii][1] == '-') ++offset; + LLSD commands; + std::string name; + std::string value; + for(int ii = 1; ii < argc; ++ii) + { + if(wargv[ii][0] != '-') + { + LL_INFOS() << "Did not find option identifier while parsing token: " + << wargv[ii] << LL_ENDL; + return false; + } + int offset = 1; + if(wargv[ii][1] == '-') ++offset; #if LL_WINDOWS - name.assign(utf16str_to_utf8str(&wargv[ii][offset])); + name.assign(utf16str_to_utf8str(&wargv[ii][offset])); #else - name.assign(wstring_to_utf8str(&wargv[ii][offset])); + name.assign(wstring_to_utf8str(&wargv[ii][offset])); #endif - if(((ii+1) >= argc) || (wargv[ii+1][0] == '-')) - { - // we found another option after this one or we have - // reached the end. simply record that this option was - // found and continue. - int flag = name.compare("logfile"); - if (0 == flag) - { - commands[name] = "log"; - } - else - { - commands[name] = true; - } - - continue; - } - ++ii; + if(((ii+1) >= argc) || (wargv[ii+1][0] == '-')) + { + // we found another option after this one or we have + // reached the end. simply record that this option was + // found and continue. + int flag = name.compare("logfile"); + if (0 == flag) + { + commands[name] = "log"; + } + else + { + commands[name] = true; + } + + continue; + } + ++ii; #if LL_WINDOWS - value.assign(utf16str_to_utf8str((wargv[ii]))); + value.assign(utf16str_to_utf8str((wargv[ii]))); #else - value.assign(wstring_to_utf8str((wargv[ii]))); + value.assign(wstring_to_utf8str((wargv[ii]))); #endif #if LL_WINDOWS - //Windows changed command line parsing. Deal with it. - S32 slen = value.length() - 1; - S32 start = 0; - S32 end = slen; - if (wargv[ii][start]=='"')start++; - if (wargv[ii][end]=='"')end--; - if (start!=0 || end!=slen) - { - value = value.substr (start,end); - } + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (wargv[ii][start]=='"')start++; + if (wargv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } #endif - commands[name] = value; - } - setOptionData(PRIORITY_COMMAND_LINE, commands); - return true; + commands[name] = value; + } + setOptionData(PRIORITY_COMMAND_LINE, commands); + return true; } void LLApp::manageLiveFile(LLLiveFile* livefile) { - if(!livefile) return; - livefile->checkAndReload(); - livefile->addToEventTimer(); - mLiveFiles.push_back(livefile); + if(!livefile) return; + livefile->checkAndReload(); + livefile->addToEventTimer(); + mLiveFiles.push_back(livefile); } bool LLApp::setOptionData(OptionPriority level, LLSD data) { - if((level < 0) - || (level >= PRIORITY_COUNT) - || (data.type() != LLSD::TypeMap)) - { - return false; - } - mOptions[level] = data; - return true; + if((level < 0) + || (level >= PRIORITY_COUNT) + || (data.type() != LLSD::TypeMap)) + { + return false; + } + mOptions[level] = data; + return true; } LLSD LLApp::getOptionData(OptionPriority level) { - if((level < 0) || (level >= PRIORITY_COUNT)) - { - return LLSD(); - } - return mOptions[level]; + if((level < 0) || (level >= PRIORITY_COUNT)) + { + return LLSD(); + } + return mOptions[level]; } void LLApp::stepFrame() { - LLFrameTimer::updateFrameTime(); - LLFrameTimer::updateFrameCount(); - LLEventTimer::updateClass(); - mRunner.run(); + LLFrameTimer::updateFrameTime(); + LLFrameTimer::updateFrameCount(); + LLEventTimer::updateClass(); + mRunner.run(); } #if LL_WINDOWS @@ -332,31 +332,31 @@ void LLApp::stepFrame() //in-depth article on the issue may be found here: http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesn-work/ void EnableCrashingOnCrashes() { - typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); - typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); - const DWORD EXCEPTION_SWALLOWING = 0x1; - - HMODULE kernel32 = LoadLibraryA("kernel32.dll"); - tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, - "GetProcessUserModeExceptionPolicy"); - tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, - "SetProcessUserModeExceptionPolicy"); - if (pGetPolicy && pSetPolicy) - { - DWORD dwFlags; - if (pGetPolicy(&dwFlags)) - { - // Turn off the filter - pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); - } - } + typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); + typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); + const DWORD EXCEPTION_SWALLOWING = 0x1; + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, + "GetProcessUserModeExceptionPolicy"); + tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, + "SetProcessUserModeExceptionPolicy"); + if (pGetPolicy && pSetPolicy) + { + DWORD dwFlags; + if (pGetPolicy(&dwFlags)) + { + // Turn off the filter + pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + } + } } #endif void LLApp::setupErrorHandling(bool second_instance) { - // Error handling is done by starting up an error handling thread, which just sleeps and - // occasionally checks to see if the app is in an error state, and sees if it needs to be run. + // Error handling is done by starting up an error handling thread, which just sleeps and + // occasionally checks to see if the app is in an error state, and sees if it needs to be run. #if LL_WINDOWS @@ -377,19 +377,19 @@ void LLApp::setupErrorHandling(bool second_instance) void LLApp::setErrorHandler(LLAppErrorHandler handler) { - LLApp::sErrorHandler = handler; + LLApp::sErrorHandler = handler; } // static void LLApp::runErrorHandler() { - if (LLApp::sErrorHandler) - { - LLApp::sErrorHandler(); - } + if (LLApp::sErrorHandler) + { + LLApp::sErrorHandler(); + } - //LL_INFOS() << "App status now STOPPED" << LL_ENDL; - LLApp::setStopped(); + //LL_INFOS() << "App status now STOPPED" << LL_ENDL; + LLApp::setStopped(); } namespace @@ -435,14 +435,14 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - // set app status to ERROR - setStatus(APP_STATUS_ERROR); + // set app status to ERROR + setStatus(APP_STATUS_ERROR); } void LLApp::setDebugFileNames(const std::string &path) { - mStaticDebugFileName = path + "static_debug_info.log"; - mDynamicDebugFileName = path + "dynamic_debug_info.log"; + mStaticDebugFileName = path + "static_debug_info.log"; + mDynamicDebugFileName = path + "dynamic_debug_info.log"; } void LLApp::writeMiniDump() @@ -452,64 +452,64 @@ void LLApp::writeMiniDump() // static void LLApp::setQuitting() { - if (!isExiting()) - { - // If we're already exiting, we don't want to reset our state back to quitting. - LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; - setStatus(APP_STATUS_QUITTING); - } + if (!isExiting()) + { + // If we're already exiting, we don't want to reset our state back to quitting. + LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; + setStatus(APP_STATUS_QUITTING); + } } // static void LLApp::setStopped() { - setStatus(APP_STATUS_STOPPED); + setStatus(APP_STATUS_STOPPED); } // static bool LLApp::isStopped() { - return (APP_STATUS_STOPPED == sStatus.get()); + return (APP_STATUS_STOPPED == sStatus.get()); } // static bool LLApp::isRunning() { - return (APP_STATUS_RUNNING == sStatus.get()); + return (APP_STATUS_RUNNING == sStatus.get()); } // static bool LLApp::isError() { - return (APP_STATUS_ERROR == sStatus.get()); + return (APP_STATUS_ERROR == sStatus.get()); } // static bool LLApp::isQuitting() { - return (APP_STATUS_QUITTING == sStatus.get()); + return (APP_STATUS_QUITTING == sStatus.get()); } // static bool LLApp::isExiting() { - return isQuitting() || isError(); + return isQuitting() || isError(); } void LLApp::disableCrashlogger() { - sDisableCrashlogger = TRUE; + sDisableCrashlogger = TRUE; } // static bool LLApp::isCrashloggerDisabled() { - return (sDisableCrashlogger == TRUE); + return (sDisableCrashlogger == TRUE); } // static @@ -518,336 +518,336 @@ int LLApp::getPid() #if LL_WINDOWS return GetCurrentProcessId(); #else - return getpid(); + return getpid(); #endif } #if LL_WINDOWS LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop) { - // Translate the signals/exceptions into cross-platform stuff - // Windows implementation + // Translate the signals/exceptions into cross-platform stuff + // Windows implementation - // Make sure the user sees something to indicate that the app crashed. - LONG retval; + // Make sure the user sees something to indicate that the app crashed. + LONG retval; - if (LLApp::isError()) - { - LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; - } + if (LLApp::isError()) + { + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; + retval = EXCEPTION_EXECUTE_HANDLER; + return retval; + } - // Flag status to error, so thread_error starts its work - LLApp::setError(); + // Flag status to error, so thread_error starts its work + LLApp::setError(); - // Block in the exception handler until the app has stopped - // This is pretty sketchy, but appears to work just fine - while (!LLApp::isStopped()) - { - ms_sleep(10); - } + // Block in the exception handler until the app has stopped + // This is pretty sketchy, but appears to work just fine + while (!LLApp::isStopped()) + { + ms_sleep(10); + } - // - // Generate a minidump if we can. - // - // TODO: This needs to be ported over form the viewer-specific - // LLWinDebug class + // + // Generate a minidump if we can. + // + // TODO: This needs to be ported over form the viewer-specific + // LLWinDebug class - // - // At this point, we always want to exit the app. There's no graceful - // recovery for an unhandled exception. - // - // Just kill the process. - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; + // + // At this point, we always want to exit the app. There's no graceful + // recovery for an unhandled exception. + // + // Just kill the process. + retval = EXCEPTION_EXECUTE_HANDLER; + return retval; } // Win32 doesn't support signals. This is used instead. -BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) -{ - switch (fdwCtrlType) - { - case CTRL_BREAK_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - case CTRL_CLOSE_EVENT: // From end task or the window close button. - case CTRL_C_EVENT: // from CTRL-C on the keyboard - // Just set our state to quitting, not error - if (LLApp::isQuitting() || LLApp::isError()) - { - // We're already trying to die, just ignore this signal - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; - } - return TRUE; - } - LLApp::setQuitting(); - return TRUE; - - default: - return FALSE; - } -} +BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) + { + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + case CTRL_CLOSE_EVENT: // From end task or the window close button. + case CTRL_C_EVENT: // from CTRL-C on the keyboard + // Just set our state to quitting, not error + if (LLApp::isQuitting() || LLApp::isError()) + { + // We're already trying to die, just ignore this signal + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; + } + return TRUE; + } + LLApp::setQuitting(); + return TRUE; + + default: + return FALSE; + } +} #else //!LL_WINDOWS void setup_signals() { - // - // Set up signal handlers that may result in program termination - // - struct sigaction act; - act.sa_sigaction = default_unix_signal_handler; - sigemptyset( &act.sa_mask ); - act.sa_flags = SA_SIGINFO; + // + // Set up signal handlers that may result in program termination + // + struct sigaction act; + act.sa_sigaction = default_unix_signal_handler; + sigemptyset( &act.sa_mask ); + act.sa_flags = SA_SIGINFO; - // Synchronous signals + // Synchronous signals # ifndef LL_BUGSPLAT - sigaction(SIGABRT, &act, NULL); + sigaction(SIGABRT, &act, NULL); # endif - sigaction(SIGALRM, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGPIPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSYS, &act, NULL); - - sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); - sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); - - // Asynchronous signals that are normally ignored + sigaction(SIGALRM, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGFPE, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGPIPE, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGSYS, &act, NULL); + + sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); + sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); + + // Asynchronous signals that are normally ignored #ifndef LL_IGNORE_SIGCHLD - sigaction(SIGCHLD, &act, NULL); + sigaction(SIGCHLD, &act, NULL); #endif // LL_IGNORE_SIGCHLD - sigaction(SIGUSR2, &act, NULL); + sigaction(SIGUSR2, &act, NULL); - // Asynchronous signals that result in attempted graceful exit - sigaction(SIGHUP, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGINT, &act, NULL); + // Asynchronous signals that result in attempted graceful exit + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGINT, &act, NULL); + + // Asynchronous signals that result in core + sigaction(SIGQUIT, &act, NULL); - // Asynchronous signals that result in core - sigaction(SIGQUIT, &act, NULL); - } void clear_signals() { - struct sigaction act; - act.sa_handler = SIG_DFL; - sigemptyset( &act.sa_mask ); - act.sa_flags = SA_SIGINFO; + struct sigaction act; + act.sa_handler = SIG_DFL; + sigemptyset( &act.sa_mask ); + act.sa_flags = SA_SIGINFO; - // Synchronous signals + // Synchronous signals # ifndef LL_BUGSPLAT - sigaction(SIGABRT, &act, NULL); + sigaction(SIGABRT, &act, NULL); # endif - sigaction(SIGALRM, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGPIPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSYS, &act, NULL); - - sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); - sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); - - // Asynchronous signals that are normally ignored + sigaction(SIGALRM, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGFPE, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGPIPE, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGSYS, &act, NULL); + + sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); + sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); + + // Asynchronous signals that are normally ignored #ifndef LL_IGNORE_SIGCHLD - sigaction(SIGCHLD, &act, NULL); + sigaction(SIGCHLD, &act, NULL); #endif // LL_IGNORE_SIGCHLD - // Asynchronous signals that result in attempted graceful exit - sigaction(SIGHUP, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGINT, &act, NULL); + // Asynchronous signals that result in attempted graceful exit + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGINT, &act, NULL); - // Asynchronous signals that result in core - sigaction(SIGUSR2, &act, NULL); - sigaction(SIGQUIT, &act, NULL); + // Asynchronous signals that result in core + sigaction(SIGUSR2, &act, NULL); + sigaction(SIGQUIT, &act, NULL); } void default_unix_signal_handler(int signum, siginfo_t *info, void *) { - // Unix implementation of synchronous signal handler - // This runs in the thread that threw the signal. - // We do the somewhat sketchy operation of blocking in here until the error handler - // has gracefully stopped the app. + // Unix implementation of synchronous signal handler + // This runs in the thread that threw the signal. + // We do the somewhat sketchy operation of blocking in here until the error handler + // has gracefully stopped the app. - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; - } + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; + } - switch (signum) - { - case SIGCHLD: - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; - } + switch (signum) + { + case SIGCHLD: + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; + } - return; - case SIGABRT: + return; + case SIGABRT: // Note that this handler is not set for SIGABRT when using Bugsplat - // Abort just results in termination of the app, no funky error handling. - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; - } - clear_signals(); - raise(signum); - return; - case SIGINT: - case SIGHUP: - case SIGTERM: - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; - } - // Graceful exit - // Just set our state to quitting, not error - if (LLApp::isQuitting() || LLApp::isError()) - { - // We're already trying to die, just ignore this signal - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; - } - return; - } - LLApp::setQuitting(); - return; - case SIGALRM: - case SIGPIPE: - case SIGUSR2: - default: - if (signum == LL_SMACKDOWN_SIGNAL || - signum == SIGBUS || - signum == SIGILL || - signum == SIGFPE || - signum == SIGSEGV || - signum == SIGQUIT) - { - if (signum == LL_SMACKDOWN_SIGNAL) - { - // Smackdown treated just like any other app termination, for now - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; - } - else - { - // Don't log anything, even errors - this is because this signal could happen anywhere. - LLError::setDefaultLevel(LLError::LEVEL_NONE); - } - - // Change the signal that we reraise to SIGABRT, so we generate a core dump. - signum = SIGABRT; - } - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; - } - if (LLApp::isError()) - { - // Received second fatal signal while handling first, just die right now - // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app. - clear_signals(); - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; - } - raise(signum); - return; - } - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; - } - - if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem - { - clear_signals(); - LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; - raise(signum); - return; - } - - // Flag status to ERROR - LLApp::setError(); - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; - } - clear_signals(); - raise(signum); - return; - } else { - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; - } - } - } + // Abort just results in termination of the app, no funky error handling. + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; + } + clear_signals(); + raise(signum); + return; + case SIGINT: + case SIGHUP: + case SIGTERM: + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; + } + // Graceful exit + // Just set our state to quitting, not error + if (LLApp::isQuitting() || LLApp::isError()) + { + // We're already trying to die, just ignore this signal + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; + } + return; + } + LLApp::setQuitting(); + return; + case SIGALRM: + case SIGPIPE: + case SIGUSR2: + default: + if (signum == LL_SMACKDOWN_SIGNAL || + signum == SIGBUS || + signum == SIGILL || + signum == SIGFPE || + signum == SIGSEGV || + signum == SIGQUIT) + { + if (signum == LL_SMACKDOWN_SIGNAL) + { + // Smackdown treated just like any other app termination, for now + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; + } + else + { + // Don't log anything, even errors - this is because this signal could happen anywhere. + LLError::setDefaultLevel(LLError::LEVEL_NONE); + } + + // Change the signal that we reraise to SIGABRT, so we generate a core dump. + signum = SIGABRT; + } + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; + } + if (LLApp::isError()) + { + // Received second fatal signal while handling first, just die right now + // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app. + clear_signals(); + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; + } + raise(signum); + return; + } + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; + } + + if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem + { + clear_signals(); + LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; + raise(signum); + return; + } + + // Flag status to ERROR + LLApp::setError(); + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; + } + clear_signals(); + raise(signum); + return; + } else { + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; + } + } + } } #if LL_LINUX #endif bool unix_post_minidump_callback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded) -{ - // Copy minidump file path into fixed buffer in the app instance to avoid - // heap allocations in a crash handler. - - // path format: <dump_dir>/<minidump_id>.dmp - auto dirPathLength = strlen(dump_dir); - auto idLength = strlen(minidump_id); - - // The path must not be truncated. - llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); - - char * path = LLApp::instance()->getMiniDumpFilename(); - auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; - strncpy(path, dump_dir, remaining); - remaining -= dirPathLength; - path += dirPathLength; - if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') - { - *path++ = '/'; - --remaining; - } - if (remaining > 0) - { - strncpy(path, minidump_id, remaining); - remaining -= idLength; - path += idLength; - strncpy(path, ".dmp", remaining); - } - - LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; - LLApp::runErrorHandler(); - + const char *minidump_id, + void *context, bool succeeded) +{ + // Copy minidump file path into fixed buffer in the app instance to avoid + // heap allocations in a crash handler. + + // path format: <dump_dir>/<minidump_id>.dmp + auto dirPathLength = strlen(dump_dir); + auto idLength = strlen(minidump_id); + + // The path must not be truncated. + llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); + + char * path = LLApp::instance()->getMiniDumpFilename(); + auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; + strncpy(path, dump_dir, remaining); + remaining -= dirPathLength; + path += dirPathLength; + if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') + { + *path++ = '/'; + --remaining; + } + if (remaining > 0) + { + strncpy(path, minidump_id, remaining); + remaining -= idLength; + path += idLength; + strncpy(path, ".dmp", remaining); + } + + LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; + LLApp::runErrorHandler(); + #ifndef LL_RELEASE_FOR_DOWNLOAD - clear_signals(); - return false; + clear_signals(); + return false; #else - return true; + return true; #endif } #endif // !WINDOWS diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index a892bfeb1e..93bf4dd929 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -1,25 +1,25 @@ -/** +/** * @file llapp.h * @brief Declaration of the LLApp class. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -53,290 +53,290 @@ void clear_signals(); class LL_COMMON_API LLApp { public: - typedef enum e_app_status - { - APP_STATUS_RUNNING, // The application is currently running - the default status - APP_STATUS_QUITTING, // The application is currently quitting - threads should listen for this and clean up - APP_STATUS_STOPPED, // The application is no longer running - tells the error thread it can exit - APP_STATUS_ERROR // The application had a fatal error occur - tells the error thread to run - } EAppStatus; - - - LLApp(); - virtual ~LLApp(); - - /** - * @brief Return the static app instance if one was created. - */ - static LLApp* instance(); - - /** @name Runtime options */ - //@{ - /** - * @brief Enumeration to specify option priorities in highest to - * lowest order. - */ - enum OptionPriority - { - PRIORITY_RUNTIME_OVERRIDE, - PRIORITY_COMMAND_LINE, - PRIORITY_SPECIFIC_CONFIGURATION, - PRIORITY_GENERAL_CONFIGURATION, - PRIORITY_DEFAULT, - PRIORITY_COUNT - }; - - /** - * @brief Get the application option at the highest priority. - * - * If the return value is undefined, the option does not exist. - * @param name The name of the option. - * @return Returns the option data. - */ - LLSD getOption(const std::string& name) const; - - /** - * @brief Parse ASCII command line options and insert them into - * application command line options. - * - * The name inserted into the option will have leading option - * identifiers (a minus or double minus) stripped. All options - * with values will be stored as a string, while all options - * without values will be stored as true. - * @param argc The argc passed into main(). - * @param argv The argv passed into main(). - * @return Returns true if the parse succeeded. - */ - bool parseCommandOptions(int argc, char** argv); - - /** - * @brief Parse Unicode command line options and insert them into - * application command line options. - * - * The name inserted into the option will have leading option - * identifiers (a minus or double minus) stripped. All options - * with values will be stored as a string, while all options - * without values will be stored as true. - * @param argc The argc passed into main(). - * @param wargv The wargv passed into main(). - * @return Returns true if the parse succeeded. - */ - bool parseCommandOptions(int argc, wchar_t** wargv); - - /** - * @brief Keep track of live files automatically. - * - * *TODO: it currently uses the <code>addToEventTimer()</code> API - * instead of the runner. I should probalby use the runner. - * - * *NOTE: DO NOT add the livefile instance to any kind of check loop. - * - * @param livefile A valid instance of an LLLiveFile. This LLApp - * instance will delete the livefile instance. - */ - void manageLiveFile(LLLiveFile* livefile); - - /** - * @brief Set the options at the specified priority. - * - * This function completely replaces the options at the priority - * level with the data specified. This function will make sure - * level and data might be valid before doing the replace. - * @param level The priority level of the data. - * @param data The data to set. - * @return Returns true if the option was set. - */ - bool setOptionData(OptionPriority level, LLSD data); - - /** - * @brief Get the option data at the specified priority. - * - * This method is probably not so useful except when merging - * information. - * @param level The priority level of the data. - * @return Returns The data (if any) at the level priority. - */ - LLSD getOptionData(OptionPriority level); - //@} - - - - // - // Main application logic - // - virtual bool init() = 0; // Override to do application initialization - - // - // cleanup() - // - // It's currently assumed that the cleanup() method will only get - // called from the main thread or the error handling thread, as it will - // likely do thread shutdown, among other things. - // - virtual bool cleanup() = 0; // Override to do application cleanup - - // - // frame() - // - // Pass control to the application for a single frame. Returns 'done' - // flag: if frame() returns false, it expects to be called again. - // - virtual bool frame() = 0; // Override for application body logic - - // - // Crash logging - // - void disableCrashlogger(); // Let the OS handle the crashes - static bool isCrashloggerDisabled(); // Get the here above set value - - // - // Application status - // - static void setQuitting(); // Set status to QUITTING, the app is now shutting down - static void setStopped(); // Set status to STOPPED, the app is done running and should exit - static void setError(); // Set status to ERROR, the error handler should run - static bool isStopped(); - static bool isRunning(); - static bool isQuitting(); - static bool isError(); - static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not) - static int getPid(); - - // - // Sleep for specified time while still running - // - // For use by a coroutine or thread that performs some maintenance on a - // periodic basis. (See also LLEventTimer.) This method supports the - // pattern of an "infinite" loop that sleeps for some time, performs some - // action, then sleeps again. The trouble with literally sleeping a worker - // thread is that it could potentially sleep right through attempted - // application shutdown. This method avoids that by returning false as - // soon as the application status changes away from APP_STATUS_RUNNING - // (isRunning()). - // - // sleep() returns true if it sleeps undisturbed for the entire specified - // duration. The idea is that you can code 'while sleep(duration) ...', - // which will break the loop once shutdown begins. - // - // Since any time-based LLUnit should be implicitly convertible to - // F32Milliseconds, accept that specific type as a proxy. - static bool sleep(F32Milliseconds duration); - // Allow any duration defined in terms of <chrono>. - // One can imagine a wonderfully general bidirectional conversion system - // between any type derived from LLUnits::LLUnit<T, LLUnits::Seconds> and - // any std::chrono::duration -- but that doesn't yet exist. - template <typename Rep, typename Period> - bool sleep(const std::chrono::duration<Rep, Period>& duration) - { - // wait_for_unequal() has the opposite bool return convention - return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING); - } - - /** @name Error handling methods */ - //@{ - /** - * @brief Do our generic platform-specific error-handling setup -- - * signals on unix, structured exceptions on windows. - * - * DO call this method if your app will either spawn children or be - * spawned by a launcher. - * Call just after app object construction. - * (Otherwise your app will crash when getting signals, - * and will not core dump.) - * - * DO NOT call this method if your application has specialized - * error handling code. - */ - void setupErrorHandling(bool mSecondInstance=false); - - void setErrorHandler(LLAppErrorHandler handler); - static void runErrorHandler(); // run shortly after we detect an error - //@} - - // the maximum length of the minidump filename returned by getMiniDumpFilename() - static const U32 MAX_MINDUMP_PATH_LENGTH = 256; - - // change the directory where Breakpad minidump files are written to - void setDebugFileNames(const std::string &path); - - // Return the Google Breakpad minidump filename after a crash. - char *getMiniDumpFilename() { return mMinidumpPath; } - std::string* getStaticDebugFile() { return &mStaticDebugFileName; } - std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } - - // Write out a Google Breakpad minidump file. - void writeMiniDump(); - - - /** - * @brief Get a reference to the application runner - * - * Please use the runner with caution. Since the Runner usage - * pattern is not yet clear, this method just gives access to it - * to add and remove runnables. - * @return Returns the application runner. Do not save the - * pointer past the caller's stack frame. - */ - LLRunner& getRunner() { return mRunner; } + typedef enum e_app_status + { + APP_STATUS_RUNNING, // The application is currently running - the default status + APP_STATUS_QUITTING, // The application is currently quitting - threads should listen for this and clean up + APP_STATUS_STOPPED, // The application is no longer running - tells the error thread it can exit + APP_STATUS_ERROR // The application had a fatal error occur - tells the error thread to run + } EAppStatus; + + + LLApp(); + virtual ~LLApp(); + + /** + * @brief Return the static app instance if one was created. + */ + static LLApp* instance(); + + /** @name Runtime options */ + //@{ + /** + * @brief Enumeration to specify option priorities in highest to + * lowest order. + */ + enum OptionPriority + { + PRIORITY_RUNTIME_OVERRIDE, + PRIORITY_COMMAND_LINE, + PRIORITY_SPECIFIC_CONFIGURATION, + PRIORITY_GENERAL_CONFIGURATION, + PRIORITY_DEFAULT, + PRIORITY_COUNT + }; + + /** + * @brief Get the application option at the highest priority. + * + * If the return value is undefined, the option does not exist. + * @param name The name of the option. + * @return Returns the option data. + */ + LLSD getOption(const std::string& name) const; + + /** + * @brief Parse ASCII command line options and insert them into + * application command line options. + * + * The name inserted into the option will have leading option + * identifiers (a minus or double minus) stripped. All options + * with values will be stored as a string, while all options + * without values will be stored as true. + * @param argc The argc passed into main(). + * @param argv The argv passed into main(). + * @return Returns true if the parse succeeded. + */ + bool parseCommandOptions(int argc, char** argv); + + /** + * @brief Parse Unicode command line options and insert them into + * application command line options. + * + * The name inserted into the option will have leading option + * identifiers (a minus or double minus) stripped. All options + * with values will be stored as a string, while all options + * without values will be stored as true. + * @param argc The argc passed into main(). + * @param wargv The wargv passed into main(). + * @return Returns true if the parse succeeded. + */ + bool parseCommandOptions(int argc, wchar_t** wargv); + + /** + * @brief Keep track of live files automatically. + * + * *TODO: it currently uses the <code>addToEventTimer()</code> API + * instead of the runner. I should probalby use the runner. + * + * *NOTE: DO NOT add the livefile instance to any kind of check loop. + * + * @param livefile A valid instance of an LLLiveFile. This LLApp + * instance will delete the livefile instance. + */ + void manageLiveFile(LLLiveFile* livefile); + + /** + * @brief Set the options at the specified priority. + * + * This function completely replaces the options at the priority + * level with the data specified. This function will make sure + * level and data might be valid before doing the replace. + * @param level The priority level of the data. + * @param data The data to set. + * @return Returns true if the option was set. + */ + bool setOptionData(OptionPriority level, LLSD data); + + /** + * @brief Get the option data at the specified priority. + * + * This method is probably not so useful except when merging + * information. + * @param level The priority level of the data. + * @return Returns The data (if any) at the level priority. + */ + LLSD getOptionData(OptionPriority level); + //@} + + + + // + // Main application logic + // + virtual bool init() = 0; // Override to do application initialization + + // + // cleanup() + // + // It's currently assumed that the cleanup() method will only get + // called from the main thread or the error handling thread, as it will + // likely do thread shutdown, among other things. + // + virtual bool cleanup() = 0; // Override to do application cleanup + + // + // frame() + // + // Pass control to the application for a single frame. Returns 'done' + // flag: if frame() returns false, it expects to be called again. + // + virtual bool frame() = 0; // Override for application body logic + + // + // Crash logging + // + void disableCrashlogger(); // Let the OS handle the crashes + static bool isCrashloggerDisabled(); // Get the here above set value + + // + // Application status + // + static void setQuitting(); // Set status to QUITTING, the app is now shutting down + static void setStopped(); // Set status to STOPPED, the app is done running and should exit + static void setError(); // Set status to ERROR, the error handler should run + static bool isStopped(); + static bool isRunning(); + static bool isQuitting(); + static bool isError(); + static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not) + static int getPid(); + + // + // Sleep for specified time while still running + // + // For use by a coroutine or thread that performs some maintenance on a + // periodic basis. (See also LLEventTimer.) This method supports the + // pattern of an "infinite" loop that sleeps for some time, performs some + // action, then sleeps again. The trouble with literally sleeping a worker + // thread is that it could potentially sleep right through attempted + // application shutdown. This method avoids that by returning false as + // soon as the application status changes away from APP_STATUS_RUNNING + // (isRunning()). + // + // sleep() returns true if it sleeps undisturbed for the entire specified + // duration. The idea is that you can code 'while sleep(duration) ...', + // which will break the loop once shutdown begins. + // + // Since any time-based LLUnit should be implicitly convertible to + // F32Milliseconds, accept that specific type as a proxy. + static bool sleep(F32Milliseconds duration); + // Allow any duration defined in terms of <chrono>. + // One can imagine a wonderfully general bidirectional conversion system + // between any type derived from LLUnits::LLUnit<T, LLUnits::Seconds> and + // any std::chrono::duration -- but that doesn't yet exist. + template <typename Rep, typename Period> + bool sleep(const std::chrono::duration<Rep, Period>& duration) + { + // wait_for_unequal() has the opposite bool return convention + return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING); + } + + /** @name Error handling methods */ + //@{ + /** + * @brief Do our generic platform-specific error-handling setup -- + * signals on unix, structured exceptions on windows. + * + * DO call this method if your app will either spawn children or be + * spawned by a launcher. + * Call just after app object construction. + * (Otherwise your app will crash when getting signals, + * and will not core dump.) + * + * DO NOT call this method if your application has specialized + * error handling code. + */ + void setupErrorHandling(bool mSecondInstance=false); + + void setErrorHandler(LLAppErrorHandler handler); + static void runErrorHandler(); // run shortly after we detect an error + //@} + + // the maximum length of the minidump filename returned by getMiniDumpFilename() + static const U32 MAX_MINDUMP_PATH_LENGTH = 256; + + // change the directory where Breakpad minidump files are written to + void setDebugFileNames(const std::string &path); + + // Return the Google Breakpad minidump filename after a crash. + char *getMiniDumpFilename() { return mMinidumpPath; } + std::string* getStaticDebugFile() { return &mStaticDebugFileName; } + std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } + + // Write out a Google Breakpad minidump file. + void writeMiniDump(); + + + /** + * @brief Get a reference to the application runner + * + * Please use the runner with caution. Since the Runner usage + * pattern is not yet clear, this method just gives access to it + * to add and remove runnables. + * @return Returns the application runner. Do not save the + * pointer past the caller's stack frame. + */ + LLRunner& getRunner() { return mRunner; } #ifdef LL_WINDOWS virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } #endif public: - typedef std::map<std::string, std::string> string_map; - string_map mOptionMap; // Contains all command-line options and arguments in a map + typedef std::map<std::string, std::string> string_map; + string_map mOptionMap; // Contains all command-line options and arguments in a map protected: - static void setStatus(EAppStatus status); // Use this to change the application status. - static LLScalarCond<EAppStatus> sStatus; // Reflects current application status - static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. - std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. + static void setStatus(EAppStatus status); // Use this to change the application status. + static LLScalarCond<EAppStatus> sStatus; // Reflects current application status + static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. + std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. std::string mDumpPath; //output path for google breakpad. Dependency workaround. - /** - * @brief This method is called once a frame to do once a frame tasks. - */ - void stepFrame(); + /** + * @brief This method is called once a frame to do once a frame tasks. + */ + void stepFrame(); private: - // Contains the filename of the minidump file after a crash. - char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; - - std::string mStaticDebugFileName; - std::string mDynamicDebugFileName; + // Contains the filename of the minidump file after a crash. + char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; + + std::string mStaticDebugFileName; + std::string mDynamicDebugFileName; - // *NOTE: On Windows, we need a routine to reset the structured - // exception handler when some evil driver has taken it over for - // their own purposes - typedef int(*signal_handler_func)(int signum); - static LLAppErrorHandler sErrorHandler; + // *NOTE: On Windows, we need a routine to reset the structured + // exception handler when some evil driver has taken it over for + // their own purposes + typedef int(*signal_handler_func)(int signum); + static LLAppErrorHandler sErrorHandler; - // This is the application level runnable scheduler. - LLRunner mRunner; + // This is the application level runnable scheduler. + LLRunner mRunner; - /** @name Runtime option implementation */ - //@{ + /** @name Runtime option implementation */ + //@{ - // The application options. - LLSD mOptions; + // The application options. + LLSD mOptions; - // The live files for this application - std::vector<LLLiveFile*> mLiveFiles; - //@} + // The live files for this application + std::vector<LLLiveFile*> mLiveFiles; + //@} private: - // the static application instance if it was created. - static LLApp* sApplication; + // the static application instance if it was created. + static LLApp* sApplication; #if !LL_WINDOWS - friend void default_unix_signal_handler(int signum, siginfo_t *info, void *); + friend void default_unix_signal_handler(int signum, siginfo_t *info, void *); #endif public: - static BOOL sLogInSignal; + static BOOL sLogInSignal; }; #endif // LL_LLAPP_H diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 575c524219..c907a8c073 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llapr.cpp * @author Phoenix * @date 2004-11-28 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,200 +46,200 @@ int abortfunc(int retcode) void ll_init_apr() { - // Initialize APR and create the global pool - apr_initialize(); - - if (!gAPRPoolp) - { - apr_pool_create_ex(&gAPRPoolp, NULL, abortfunc, NULL); - } + // Initialize APR and create the global pool + apr_initialize(); + + if (!gAPRPoolp) + { + apr_pool_create_ex(&gAPRPoolp, NULL, abortfunc, NULL); + } - if(!LLAPRFile::sAPRFilePoolp) - { - LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ; - } + if(!LLAPRFile::sAPRFilePoolp) + { + LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ; + } - gAPRInitialized = true; + gAPRInitialized = true; } bool ll_apr_is_initialized() { - return gAPRInitialized; + return gAPRInitialized; } void ll_cleanup_apr() { - gAPRInitialized = false; + gAPRInitialized = false; - LL_DEBUGS("APR") << "Cleaning up APR" << LL_ENDL; + LL_DEBUGS("APR") << "Cleaning up APR" << LL_ENDL; - if (gAPRPoolp) - { - apr_pool_destroy(gAPRPoolp); - gAPRPoolp = NULL; - } - if (LLAPRFile::sAPRFilePoolp) - { - delete LLAPRFile::sAPRFilePoolp ; - LLAPRFile::sAPRFilePoolp = NULL ; - } - apr_terminate(); + if (gAPRPoolp) + { + apr_pool_destroy(gAPRPoolp); + gAPRPoolp = NULL; + } + if (LLAPRFile::sAPRFilePoolp) + { + delete LLAPRFile::sAPRFilePoolp ; + LLAPRFile::sAPRFilePoolp = NULL ; + } + apr_terminate(); } // // //LLAPRPool // -LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) - : mParent(parent), - mReleasePoolFlag(releasePoolFlag), - mMaxSize(size), - mPool(NULL) -{ - createAPRPool() ; +LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) + : mParent(parent), + mReleasePoolFlag(releasePoolFlag), + mMaxSize(size), + mPool(NULL) +{ + createAPRPool() ; } -LLAPRPool::~LLAPRPool() +LLAPRPool::~LLAPRPool() { - releaseAPRPool() ; + releaseAPRPool() ; } void LLAPRPool::createAPRPool() { - if(mPool) - { - return ; - } + if(mPool) + { + return ; + } - mStatus = apr_pool_create(&mPool, mParent); - ll_apr_warn_status(mStatus) ; + mStatus = apr_pool_create(&mPool, mParent); + ll_apr_warn_status(mStatus) ; - if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes. - { - apr_allocator_t *allocator = apr_pool_allocator_get(mPool); - if (allocator) - { - apr_allocator_max_free_set(allocator, mMaxSize) ; - } - } + if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes. + { + apr_allocator_t *allocator = apr_pool_allocator_get(mPool); + if (allocator) + { + apr_allocator_max_free_set(allocator, mMaxSize) ; + } + } } void LLAPRPool::releaseAPRPool() { - if(!mPool) - { - return ; - } + if(!mPool) + { + return ; + } - if(!mParent || mReleasePoolFlag) - { - apr_pool_destroy(mPool) ; - mPool = NULL ; - } + if(!mParent || mReleasePoolFlag) + { + apr_pool_destroy(mPool) ; + mPool = NULL ; + } } //virtual -apr_pool_t* LLAPRPool::getAPRPool() -{ - return mPool ; +apr_pool_t* LLAPRPool::getAPRPool() +{ + return mPool ; } -LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) - : LLAPRPool(parent, size, releasePoolFlag), - mNumActiveRef(0), - mNumTotalRef(0) +LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) + : LLAPRPool(parent, size, releasePoolFlag), + mNumActiveRef(0), + mNumTotalRef(0) { - //create mutex - if(!is_local) //not a local apr_pool, that is: shared by multiple threads. - { - mMutexp.reset(new std::mutex()); - } + //create mutex + if(!is_local) //not a local apr_pool, that is: shared by multiple threads. + { + mMutexp.reset(new std::mutex()); + } } LLVolatileAPRPool::~LLVolatileAPRPool() { - //delete mutex + //delete mutex mMutexp.reset(); } // //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). // -//virtual -apr_pool_t* LLVolatileAPRPool::getAPRPool() +//virtual +apr_pool_t* LLVolatileAPRPool::getAPRPool() { - return LLVolatileAPRPool::getVolatileAPRPool() ; + return LLVolatileAPRPool::getVolatileAPRPool() ; } -apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() -{ - LLScopedLock lock(mMutexp.get()) ; +apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() +{ + LLScopedLock lock(mMutexp.get()) ; - mNumTotalRef++ ; - mNumActiveRef++ ; + mNumTotalRef++ ; + mNumActiveRef++ ; - if(!mPool) - { - createAPRPool() ; - } - - return mPool ; + if(!mPool) + { + createAPRPool() ; + } + + return mPool ; } -void LLVolatileAPRPool::clearVolatileAPRPool() +void LLVolatileAPRPool::clearVolatileAPRPool() { LLScopedLock lock(mMutexp.get()); - if(mNumActiveRef > 0) - { - mNumActiveRef--; - if(mNumActiveRef < 1) - { - if(isFull()) - { - mNumTotalRef = 0 ; - - //destroy the apr_pool. - releaseAPRPool() ; - } - else - { - //This does not actually free the memory, - //it just allows the pool to re-use this memory for the next allocation. - apr_pool_clear(mPool) ; - } - } - } - else - { - llassert_always(mNumActiveRef > 0) ; - } - - llassert(mNumTotalRef <= (FULL_VOLATILE_APR_POOL << 2)) ; + if(mNumActiveRef > 0) + { + mNumActiveRef--; + if(mNumActiveRef < 1) + { + if(isFull()) + { + mNumTotalRef = 0 ; + + //destroy the apr_pool. + releaseAPRPool() ; + } + else + { + //This does not actually free the memory, + //it just allows the pool to re-use this memory for the next allocation. + apr_pool_clear(mPool) ; + } + } + } + else + { + llassert_always(mNumActiveRef > 0) ; + } + + llassert(mNumTotalRef <= (FULL_VOLATILE_APR_POOL << 2)) ; } BOOL LLVolatileAPRPool::isFull() { - return mNumTotalRef > FULL_VOLATILE_APR_POOL ; + return mNumTotalRef > FULL_VOLATILE_APR_POOL ; } //--------------------------------------------------------------------- bool _ll_apr_warn_status(apr_status_t status, const char* file, int line) { - if(APR_SUCCESS == status) return false; + if(APR_SUCCESS == status) return false; #if !LL_LINUX - char buf[MAX_STRING]; /* Flawfinder: ignore */ - apr_strerror(status, buf, sizeof(buf)); - LL_WARNS("APR") << "APR: " << file << ":" << line << " " << buf << LL_ENDL; + char buf[MAX_STRING]; /* Flawfinder: ignore */ + apr_strerror(status, buf, sizeof(buf)); + LL_WARNS("APR") << "APR: " << file << ":" << line << " " << buf << LL_ENDL; #endif - return true; + return true; } void _ll_apr_assert_status(apr_status_t status, const char* file, int line) { - llassert(! _ll_apr_warn_status(status, file, line)); + llassert(! _ll_apr_warn_status(status, file, line)); } //--------------------------------------------------------------------- @@ -253,7 +253,7 @@ class LLAPRFilePoolScope public: LLAPRFilePoolScope() : pPool(NULL), mInitialized(false) {} LLAPRFilePoolScope(LLVolatileAPRPool* poolp) : mInitialized(false) - { + { setFilePool(poolp); } ~LLAPRFilePoolScope() @@ -305,154 +305,154 @@ private: // LLAPRFile functions // LLAPRFile::LLAPRFile() - : mFile(NULL), - mCurrentFilePoolp(NULL) + : mFile(NULL), + mCurrentFilePoolp(NULL) { } LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool) - : mFile(NULL), - mCurrentFilePoolp(NULL) + : mFile(NULL), + mCurrentFilePoolp(NULL) { - open(filename, flags, pool); + open(filename, flags, pool); } LLAPRFile::~LLAPRFile() { - close() ; + close() ; } -apr_status_t LLAPRFile::close() +apr_status_t LLAPRFile::close() { - apr_status_t ret = APR_SUCCESS ; - if(mFile) - { - ret = apr_file_close(mFile); - mFile = NULL ; - } + apr_status_t ret = APR_SUCCESS ; + if(mFile) + { + ret = apr_file_close(mFile); + mFile = NULL ; + } - if(mCurrentFilePoolp) - { - mCurrentFilePoolp->clearVolatileAPRPool() ; - mCurrentFilePoolp = NULL ; - } + if(mCurrentFilePoolp) + { + mCurrentFilePoolp->clearVolatileAPRPool() ; + mCurrentFilePoolp = NULL ; + } - return ret ; + return ret ; } apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep) { - apr_status_t s ; - - //check if already open some file - llassert_always(!mFile) ; - llassert_always(!mCurrentFilePoolp) ; - - mCurrentFilePoolp = pool ? pool : sAPRFilePoolp; - apr_pool_t* apr_pool = mCurrentFilePoolp->getVolatileAPRPool(); //paired with clear in close() - s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); - - if (s != APR_SUCCESS || !mFile) - { - mFile = NULL ; - - if (sizep) - { - *sizep = 0; - } - } - else if (sizep) - { - S32 file_size = 0; - apr_off_t offset = 0; - if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS) - { - llassert_always(offset <= 0x7fffffff); - file_size = (S32)offset; - offset = 0; - apr_file_seek(mFile, APR_SET, &offset); - } - *sizep = file_size; - } - - if (!mFile) - { - // It will clean pool - close() ; - } - - return s ; + apr_status_t s ; + + //check if already open some file + llassert_always(!mFile) ; + llassert_always(!mCurrentFilePoolp) ; + + mCurrentFilePoolp = pool ? pool : sAPRFilePoolp; + apr_pool_t* apr_pool = mCurrentFilePoolp->getVolatileAPRPool(); //paired with clear in close() + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); + + if (s != APR_SUCCESS || !mFile) + { + mFile = NULL ; + + if (sizep) + { + *sizep = 0; + } + } + else if (sizep) + { + S32 file_size = 0; + apr_off_t offset = 0; + if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS) + { + llassert_always(offset <= 0x7fffffff); + file_size = (S32)offset; + offset = 0; + apr_file_seek(mFile, APR_SET, &offset); + } + *sizep = file_size; + } + + if (!mFile) + { + // It will clean pool + close() ; + } + + return s ; } //use gAPRPoolp. apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool) { - apr_status_t s; + apr_status_t s; - //check if already open some file - llassert_always(!mFile) ; - llassert_always(!mCurrentFilePoolp) ; - llassert_always(use_global_pool) ; //be aware of using gAPRPoolp. - - s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); - if (s != APR_SUCCESS || !mFile) - { - mFile = NULL ; - close() ; - return s; - } + //check if already open some file + llassert_always(!mFile) ; + llassert_always(!mCurrentFilePoolp) ; + llassert_always(use_global_pool) ; //be aware of using gAPRPoolp. - return s; + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); + if (s != APR_SUCCESS || !mFile) + { + mFile = NULL ; + close() ; + return s; + } + + return s; } // File I/O S32 LLAPRFile::read(void *buf, S32 nbytes) { - if(!mFile) - { - LL_WARNS() << "apr mFile is removed by somebody else. Can not read." << LL_ENDL ; - return 0; - } - - apr_size_t sz = nbytes; - apr_status_t s = apr_file_read(mFile, buf, &sz); - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - return 0; - } - else - { - llassert_always(sz <= 0x7fffffff); - return (S32)sz; - } + if(!mFile) + { + LL_WARNS() << "apr mFile is removed by somebody else. Can not read." << LL_ENDL ; + return 0; + } + + apr_size_t sz = nbytes; + apr_status_t s = apr_file_read(mFile, buf, &sz); + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + return 0; + } + else + { + llassert_always(sz <= 0x7fffffff); + return (S32)sz; + } } S32 LLAPRFile::write(const void *buf, S32 nbytes) { - if(!mFile) - { - LL_WARNS() << "apr mFile is removed by somebody else. Can not write." << LL_ENDL ; - return 0; - } - - apr_size_t sz = nbytes; - apr_status_t s = apr_file_write(mFile, buf, &sz); - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - return 0; - } - else - { - llassert_always(sz <= 0x7fffffff); - return (S32)sz; - } + if(!mFile) + { + LL_WARNS() << "apr mFile is removed by somebody else. Can not write." << LL_ENDL ; + return 0; + } + + apr_size_t sz = nbytes; + apr_status_t s = apr_file_write(mFile, buf, &sz); + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + return 0; + } + else + { + llassert_always(sz <= 0x7fffffff); + return (S32)sz; + } } S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) { - return LLAPRFile::seek(mFile, where, offset) ; + return LLAPRFile::seek(mFile, where, offset) ; } // @@ -461,285 +461,285 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) // //static -apr_status_t LLAPRFile::close(apr_file_t* file_handle) +apr_status_t LLAPRFile::close(apr_file_t* file_handle) { - apr_status_t ret = APR_SUCCESS ; - if(file_handle) - { - ret = apr_file_close(file_handle); - file_handle = NULL ; - } + apr_status_t ret = APR_SUCCESS ; + if(file_handle) + { + ret = apr_file_close(file_handle); + file_handle = NULL ; + } - return ret ; + return ret ; } //static apr_file_t* LLAPRFile::open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags) { - apr_status_t s; - apr_file_t* file_handle ; + apr_status_t s; + apr_file_t* file_handle ; - s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); - if (s != APR_SUCCESS || !file_handle) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL; - file_handle = NULL ; - close(file_handle) ; - return NULL; - } + s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); + if (s != APR_SUCCESS || !file_handle) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL; + file_handle = NULL ; + close(file_handle) ; + return NULL; + } - return file_handle ; + return file_handle ; } //static S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) { - if(!file_handle) - { - return -1 ; - } - - apr_status_t s; - apr_off_t apr_offset; - if (offset >= 0) - { - apr_offset = (apr_off_t)offset; - s = apr_file_seek(file_handle, where, &apr_offset); - } - else - { - apr_offset = 0; - s = apr_file_seek(file_handle, APR_END, &apr_offset); - } - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - return -1; - } - else - { - llassert_always(apr_offset <= 0x7fffffff); - return (S32)apr_offset; - } + if(!file_handle) + { + return -1 ; + } + + apr_status_t s; + apr_off_t apr_offset; + if (offset >= 0) + { + apr_offset = (apr_off_t)offset; + s = apr_file_seek(file_handle, where, &apr_offset); + } + else + { + apr_offset = 0; + s = apr_file_seek(file_handle, APR_END, &apr_offset); + } + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + return -1; + } + else + { + llassert_always(apr_offset <= 0x7fffffff); + return (S32)apr_offset; + } } //static S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { LL_PROFILE_ZONE_SCOPED; - //***************************************** - LLAPRFilePoolScope scope(pool); - apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); - //***************************************** - if (!file_handle) - { - return 0; - } - - llassert(offset >= 0); - - if (offset > 0) - offset = LLAPRFile::seek(file_handle, APR_SET, offset); - - apr_size_t bytes_read; - if (offset < 0) - { - bytes_read = 0; - } - else - { - bytes_read = nbytes ; - apr_status_t s = apr_file_read(file_handle, buf, &bytes_read); - if (s != APR_SUCCESS) - { - LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL; - ll_apr_warn_status(s); - bytes_read = 0; - } - else - { - llassert_always(bytes_read <= 0x7fffffff); - } - } - - //***************************************** - close(file_handle) ; - //***************************************** - return (S32)bytes_read; + //***************************************** + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); + //***************************************** + if (!file_handle) + { + return 0; + } + + llassert(offset >= 0); + + if (offset > 0) + offset = LLAPRFile::seek(file_handle, APR_SET, offset); + + apr_size_t bytes_read; + if (offset < 0) + { + bytes_read = 0; + } + else + { + bytes_read = nbytes ; + apr_status_t s = apr_file_read(file_handle, buf, &bytes_read); + if (s != APR_SUCCESS) + { + LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL; + ll_apr_warn_status(s); + bytes_read = 0; + } + else + { + llassert_always(bytes_read <= 0x7fffffff); + } + } + + //***************************************** + close(file_handle) ; + //***************************************** + return (S32)bytes_read; } //static S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { LL_PROFILE_ZONE_SCOPED; - apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; - if (offset < 0) - { - flags |= APR_APPEND; - offset = 0; - } - - //***************************************** - LLAPRFilePoolScope scope(pool); - apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags); - //***************************************** - if (!file_handle) - { - return 0; - } - - if (offset > 0) - { - offset = LLAPRFile::seek(file_handle, APR_SET, offset); - } - - apr_size_t bytes_written; - if (offset < 0) - { - bytes_written = 0; - } - else - { - bytes_written = nbytes ; - apr_status_t s = apr_file_write(file_handle, buf, &bytes_written); - if (s != APR_SUCCESS) - { - LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL; - ll_apr_warn_status(s); - bytes_written = 0; - } - else - { - llassert_always(bytes_written <= 0x7fffffff); - } - } - - //***************************************** - LLAPRFile::close(file_handle); - //***************************************** - - return (S32)bytes_written; + apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; + if (offset < 0) + { + flags |= APR_APPEND; + offset = 0; + } + + //***************************************** + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags); + //***************************************** + if (!file_handle) + { + return 0; + } + + if (offset > 0) + { + offset = LLAPRFile::seek(file_handle, APR_SET, offset); + } + + apr_size_t bytes_written; + if (offset < 0) + { + bytes_written = 0; + } + else + { + bytes_written = nbytes ; + apr_status_t s = apr_file_write(file_handle, buf, &bytes_written); + if (s != APR_SUCCESS) + { + LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL; + ll_apr_warn_status(s); + bytes_written = 0; + } + else + { + llassert_always(bytes_written <= 0x7fffffff); + } + } + + //***************************************** + LLAPRFile::close(file_handle); + //***************************************** + + return (S32)bytes_written; } //static bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) { - apr_status_t s; + apr_status_t s; - LLAPRFilePoolScope scope(pool); - s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool()); + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool()); - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL; - return false; - } - return true; + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL; + return false; + } + return true; } //static bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool) { - apr_status_t s; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool()); - LLAPRFilePoolScope scope(pool); - s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL; - return false; - } - return true; + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL; + return false; + } + return true; } //static bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) { - apr_file_t* apr_file; - apr_status_t s; + apr_file_t* apr_file; + apr_status_t s; - LLAPRFilePoolScope scope(pool); - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool()); + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool()); - if (s != APR_SUCCESS || !apr_file) - { - return false; - } - else - { - apr_file_close(apr_file) ; - return true; - } + if (s != APR_SUCCESS || !apr_file) + { + return false; + } + else + { + apr_file_close(apr_file) ; + return true; + } } //static S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) { - apr_file_t* apr_file; - apr_finfo_t info; - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS || !apr_file) - { - return 0; - } - else - { - apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); - - apr_file_close(apr_file) ; - - if (s == APR_SUCCESS) - { - return (S32)info.size; - } - else - { - return 0; - } - } + apr_file_t* apr_file; + apr_finfo_t info; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool()); + + if (s != APR_SUCCESS || !apr_file) + { + return 0; + } + else + { + apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); + + apr_file_close(apr_file) ; + + if (s == APR_SUCCESS) + { + return (S32)info.size; + } + else + { + return 0; + } + } } //static bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) { - apr_status_t s; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool()); - LLAPRFilePoolScope scope(pool); - s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL; - return false; - } - return true; + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL; + return false; + } + return true; } //static bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) { - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL; - return false; - } - return true; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool()); + + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL; + return false; + } + return true; } // //end of static components of LLAPRFile diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 565d7cfb63..2f88fdcd59 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -1,4 +1,4 @@ -/** +/** * @file llapr.h * @author Phoenix * @date 2004-11-28 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -57,13 +57,13 @@ void LL_COMMON_API _ll_apr_assert_status(apr_status_t status, const char* file, extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool -/** +/** * @brief initialize the common apr constructs -- apr itself, the * global pool, and a mutex. */ void LL_COMMON_API ll_init_apr(); -/** +/** * @brief Cleanup those common apr constructs. */ void LL_COMMON_API ll_cleanup_apr(); @@ -78,22 +78,22 @@ bool LL_COMMON_API ll_apr_is_initialized(); class LL_COMMON_API LLAPRPool { public: - LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; - virtual ~LLAPRPool() ; + LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; + virtual ~LLAPRPool() ; - virtual apr_pool_t* getAPRPool() ; - apr_status_t getStatus() {return mStatus ; } + virtual apr_pool_t* getAPRPool() ; + apr_status_t getStatus() {return mStatus ; } protected: - void releaseAPRPool() ; - void createAPRPool() ; + void releaseAPRPool() ; + void createAPRPool() ; protected: - apr_pool_t* mPool ; //pointing to an apr_pool - apr_pool_t* mParent ; //parent pool - apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. - apr_status_t mStatus ; //status when creating the pool - BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. + apr_pool_t* mPool ; //pointing to an apr_pool + apr_pool_t* mParent ; //parent pool + apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. + apr_status_t mStatus ; //status when creating the pool + BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. }; // @@ -104,20 +104,20 @@ protected: class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool { public: - LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); - virtual ~LLVolatileAPRPool(); + LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); + virtual ~LLVolatileAPRPool(); - /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). - apr_pool_t* getVolatileAPRPool() ; - void clearVolatileAPRPool() ; + /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). + apr_pool_t* getVolatileAPRPool() ; + void clearVolatileAPRPool() ; + + BOOL isFull() ; - BOOL isFull() ; - private: - S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. - S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. + S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. + S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. - std::unique_ptr<std::mutex> mMutexp; + std::unique_ptr<std::mutex> mMutexp; } ; // File IO convenience functions. @@ -137,7 +137,7 @@ private: //which: 1)only keeps one file open; // 2)closes the open file in the destruction function // 3)informs the apr_pool to clean the memory when the file is closed. -//Note: please close an open file at the earliest convenience. +//Note: please close an open file at the earliest convenience. // especially do not put some time-costly operations between open() and close(). // otherwise it might lock the APRFilePool. //there are two different apr_pools the APRFile can use: @@ -147,53 +147,53 @@ private: class LL_COMMON_API LLAPRFile : boost::noncopyable { - // make this non copyable since a copy closes the file + // make this non copyable since a copy closes the file private: - apr_file_t* mFile ; - LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. + apr_file_t* mFile ; + LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. public: - LLAPRFile() ; - LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL); - ~LLAPRFile() ; - - apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL); - apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp. - apr_status_t close() ; - - // Returns actual offset, -1 if seek fails - S32 seek(apr_seek_where_t where, S32 offset); - apr_status_t eof() { return apr_file_eof(mFile);} - - // Returns bytes read/written, 0 if read/write fails: - S32 read(void* buf, S32 nbytes); - S32 write(const void* buf, S32 nbytes); - - apr_file_t* getFileHandle() {return mFile;} - + LLAPRFile() ; + LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL); + ~LLAPRFile() ; + + apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL); + apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp. + apr_status_t close() ; + + // Returns actual offset, -1 if seek fails + S32 seek(apr_seek_where_t where, S32 offset); + apr_status_t eof() { return apr_file_eof(mFile);} + + // Returns bytes read/written, 0 if read/write fails: + S32 read(void* buf, S32 nbytes); + S32 write(const void* buf, S32 nbytes); + + apr_file_t* getFileHandle() {return mFile;} + // //******************************************************************************************************************************* //static components // public: - static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. + static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. private: - static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags); - static apr_status_t close(apr_file_t* file) ; - static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); + static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags); + static apr_status_t close(apr_file_t* file) ; + static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); public: - // returns false if failure: - static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); - static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); - static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - - // Returns bytes read/written, 0 if read/write fails: - static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); - static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append + // returns false if failure: + static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); + static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); + static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + + // Returns bytes read/written, 0 if read/write fails: + static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); + static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append //******************************************************************************************************************************* }; diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 6492d888c1..3e46bde954 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llassettype.cpp * @brief Implementatino of LLAssetType functionality. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,69 +36,69 @@ ///---------------------------------------------------------------------------- struct AssetEntry : public LLDictionaryEntry { - AssetEntry(const char *desc_name, - const char *type_name, // 8 character limit! - const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one - bool can_link, // can you create a link to this type? - bool can_fetch, // can you fetch this asset by ID? - bool can_know) // can you see this asset's ID? - : - LLDictionaryEntry(desc_name), - mTypeName(type_name), - mHumanName(human_name), - mCanLink(can_link), - mCanFetch(can_fetch), - mCanKnow(can_know) - { - llassert(strlen(mTypeName) <= 8); - } - - const char *mTypeName; - const char *mHumanName; - bool mCanLink; - bool mCanFetch; - bool mCanKnow; + AssetEntry(const char *desc_name, + const char *type_name, // 8 character limit! + const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one + bool can_link, // can you create a link to this type? + bool can_fetch, // can you fetch this asset by ID? + bool can_know) // can you see this asset's ID? + : + LLDictionaryEntry(desc_name), + mTypeName(type_name), + mHumanName(human_name), + mCanLink(can_link), + mCanFetch(can_fetch), + mCanKnow(can_know) + { + llassert(strlen(mTypeName) <= 8); + } + + const char *mTypeName; + const char *mHumanName; + bool mCanLink; + bool mCanFetch; + bool mCanKnow; }; class LLAssetDictionary : public LLSingleton<LLAssetDictionary>, - public LLDictionary<LLAssetType::EType, AssetEntry> + public LLDictionary<LLAssetType::EType, AssetEntry> { - LLSINGLETON(LLAssetDictionary); + LLSINGLETON(LLAssetDictionary); }; LLAssetDictionary::LLAssetDictionary() { - // DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW? - // |--------------------|-----------|-------------------|-----------|-----------|---------| - addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true)); - addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true)); - addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false)); - addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true)); - addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false)); - addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true)); - addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false)); - addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true)); - addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false)); - addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false)); - addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false)); - addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false)); - addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true)); - addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false)); - addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false)); - addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false)); - addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true)); - addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true)); - addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false)); - - addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true)); - addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true)); - addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); - addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false)); - addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false)); - addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true)); - addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true)); - addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false)); - addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); + // DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW? + // |--------------------|-----------|-------------------|-----------|-----------|---------| + addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true)); + addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true)); + addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false)); + addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true)); + addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false)); + addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true)); + addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false)); + addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true)); + addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false)); + addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false)); + addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false)); + addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false)); + addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true)); + addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false)); + addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false)); + addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false)); + addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true)); + addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true)); + addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false)); + + addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true)); + addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true)); + addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); + addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false)); + addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false)); + addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true)); + addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true)); + addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false)); + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); }; @@ -107,140 +107,140 @@ const std::string LLAssetType::BADLOOKUP("llassettype_bad_lookup"); // static LLAssetType::EType LLAssetType::getType(const std::string& desc_name) { - std::string s = desc_name; - LLStringUtil::toUpper(s); - return LLAssetDictionary::getInstance()->lookup(s); + std::string s = desc_name; + LLStringUtil::toUpper(s); + return LLAssetDictionary::getInstance()->lookup(s); } // static const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type) { - const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type); - if (entry) - { - return entry->mName; - } - else - { - return BADLOOKUP; - } + const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type); + if (entry) + { + return entry->mName; + } + else + { + return BADLOOKUP; + } } // static const char *LLAssetType::lookup(LLAssetType::EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mTypeName; - } - else - { - return BADLOOKUP.c_str(); - } + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mTypeName; + } + else + { + return BADLOOKUP.c_str(); + } } // static LLAssetType::EType LLAssetType::lookup(const char* name) { - return lookup(ll_safe_string(name)); + return lookup(ll_safe_string(name)); } // static LLAssetType::EType LLAssetType::lookup(const std::string& type_name) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - for (const LLAssetDictionary::value_type& pair : *dict) - { - const AssetEntry *entry = pair.second; - if (type_name == entry->mTypeName) - { - return pair.first; - } - } - return AT_UNKNOWN; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + for (const LLAssetDictionary::value_type& pair : *dict) + { + const AssetEntry *entry = pair.second; + if (type_name == entry->mTypeName) + { + return pair.first; + } + } + return AT_UNKNOWN; } // static const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mHumanName; - } - else - { - return BADLOOKUP.c_str(); - } + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mHumanName; + } + else + { + return BADLOOKUP.c_str(); + } } // static LLAssetType::EType LLAssetType::lookupHumanReadable(const char* name) { - return lookupHumanReadable(ll_safe_string(name)); + return lookupHumanReadable(ll_safe_string(name)); } // static LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_name) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - for (const LLAssetDictionary::value_type& pair : *dict) - { - const AssetEntry *entry = pair.second; - if (entry->mHumanName && (readable_name == entry->mHumanName)) - { - return pair.first; - } - } - return AT_NONE; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + for (const LLAssetDictionary::value_type& pair : *dict) + { + const AssetEntry *entry = pair.second; + if (entry->mHumanName && (readable_name == entry->mHumanName)) + { + return pair.first; + } + } + return AT_NONE; } // static bool LLAssetType::lookupCanLink(EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mCanLink; - } - return false; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanLink; + } + return false; } // static // Not adding this to dictionary since we probably will only have these two types bool LLAssetType::lookupIsLinkType(EType asset_type) { - if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER) - { - return true; - } - return false; + if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER) + { + return true; + } + return false; } // static bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mCanFetch; - } - return false; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanFetch; + } + return false; } // static bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mCanKnow; - } - return false; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanKnow; + } + return false; } diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index e8df8574f7..1989155550 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -1,25 +1,25 @@ -/** +/** * @file llassettype.h * @brief Declaration of LLAssetType. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,89 +32,89 @@ class LL_COMMON_API LLAssetType { public: - enum EType - { - AT_TEXTURE = 0, - // Used for painting the faces of geometry. - // Stored in typical j2c stream format. + enum EType + { + AT_TEXTURE = 0, + // Used for painting the faces of geometry. + // Stored in typical j2c stream format. - AT_SOUND = 1, - // Used to fill the aural spectrum. + AT_SOUND = 1, + // Used to fill the aural spectrum. - AT_CALLINGCARD = 2, - // Links instant message access to the user on the card. - // : E.G. A card for yourself, for linden support, for - // : the guy you were talking to in the coliseum. + AT_CALLINGCARD = 2, + // Links instant message access to the user on the card. + // : E.G. A card for yourself, for linden support, for + // : the guy you were talking to in the coliseum. - AT_LANDMARK = 3, - // Links to places in the world with location and a screen shot or image saved. - // : E.G. Home, linden headquarters, the coliseum, destinations where - // : we want to increase traffic. + AT_LANDMARK = 3, + // Links to places in the world with location and a screen shot or image saved. + // : E.G. Home, linden headquarters, the coliseum, destinations where + // : we want to increase traffic. - AT_SCRIPT = 4, - // Valid scripts that can be attached to an object. - // : E.G. Open a door, jump into the air. + AT_SCRIPT = 4, + // Valid scripts that can be attached to an object. + // : E.G. Open a door, jump into the air. - AT_CLOTHING = 5, - // A collection of textures and parameters that can be worn by an avatar. + AT_CLOTHING = 5, + // A collection of textures and parameters that can be worn by an avatar. - AT_OBJECT = 6, - // Any combination of textures, sounds, and scripts that are - // associated with a fixed piece of geometry. - // : E.G. A hot tub, a house with working door. + AT_OBJECT = 6, + // Any combination of textures, sounds, and scripts that are + // associated with a fixed piece of geometry. + // : E.G. A hot tub, a house with working door. - AT_NOTECARD = 7, - // Just text. + AT_NOTECARD = 7, + // Just text. - AT_CATEGORY = 8, - // Holds a collection of inventory items. - // It's treated as an item in the inventory and therefore needs a type. + AT_CATEGORY = 8, + // Holds a collection of inventory items. + // It's treated as an item in the inventory and therefore needs a type. - AT_LSL_TEXT = 10, - AT_LSL_BYTECODE = 11, - // The LSL is the scripting language. - // We've split it into a text and bytecode representation. - - AT_TEXTURE_TGA = 12, - // Uncompressed TGA texture. + AT_LSL_TEXT = 10, + AT_LSL_BYTECODE = 11, + // The LSL is the scripting language. + // We've split it into a text and bytecode representation. - AT_BODYPART = 13, - // A collection of textures and parameters that can be worn by an avatar. + AT_TEXTURE_TGA = 12, + // Uncompressed TGA texture. - AT_SOUND_WAV = 17, - // Uncompressed sound. + AT_BODYPART = 13, + // A collection of textures and parameters that can be worn by an avatar. - AT_IMAGE_TGA = 18, - // Uncompressed image, non-square. - // Not appropriate for use as a texture. + AT_SOUND_WAV = 17, + // Uncompressed sound. - AT_IMAGE_JPEG = 19, - // Compressed image, non-square. - // Not appropriate for use as a texture. + AT_IMAGE_TGA = 18, + // Uncompressed image, non-square. + // Not appropriate for use as a texture. - AT_ANIMATION = 20, - // Animation. + AT_IMAGE_JPEG = 19, + // Compressed image, non-square. + // Not appropriate for use as a texture. - AT_GESTURE = 21, - // Gesture, sequence of animations, sounds, chat, wait steps. + AT_ANIMATION = 20, + // Animation. - AT_SIMSTATE = 22, - // Simstate file. + AT_GESTURE = 21, + // Gesture, sequence of animations, sounds, chat, wait steps. - AT_LINK = 24, - // Inventory symbolic link + AT_SIMSTATE = 22, + // Simstate file. + + AT_LINK = 24, + // Inventory symbolic link + + AT_LINK_FOLDER = 25, + // Inventory folder link - AT_LINK_FOLDER = 25, - // Inventory folder link - AT_MARKETPLACE_FOLDER = 26, // Marketplace folder. Same as an AT_CATEGORY but different display methods. - - AT_WIDGET = 40, - // UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...) - - AT_PERSON = 45, - // A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop. + + AT_WIDGET = 40, + // UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...) + + AT_PERSON = 45, + // A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop. AT_MESH = 49, // Mesh data in our proprietary SLM format @@ -129,45 +129,45 @@ public: AT_SETTINGS = 56, // Collection of settings AT_MATERIAL = 57, // Render Material - AT_COUNT = 58, + AT_COUNT = 58, - // +*********************************************************+ - // | TO ADD AN ELEMENT TO THIS ENUM: | - // +*********************************************************+ - // | 1. INSERT BEFORE AT_COUNT | - // | 2. INCREMENT AT_COUNT BY 1 | - // | 3. ADD TO LLAssetType.cpp | - // | 4. ADD TO LLViewerAssetType.cpp | - // | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | - // +*********************************************************+ - AT_UNKNOWN = 255, - AT_NONE = -1 - }; + // +*********************************************************+ + // | TO ADD AN ELEMENT TO THIS ENUM: | + // +*********************************************************+ + // | 1. INSERT BEFORE AT_COUNT | + // | 2. INCREMENT AT_COUNT BY 1 | + // | 3. ADD TO LLAssetType.cpp | + // | 4. ADD TO LLViewerAssetType.cpp | + // | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | + // +*********************************************************+ + AT_UNKNOWN = 255, + AT_NONE = -1 + }; - // machine transation between type and strings - static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate - static EType lookup(const std::string& type_name); - static const char* lookup(EType asset_type); + // machine transation between type and strings + static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate + static EType lookup(const std::string& type_name); + static const char* lookup(EType asset_type); - // translation from a type to a human readable form. - static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate - static EType lookupHumanReadable(const std::string& readable_name); - static const char* lookupHumanReadable(EType asset_type); + // translation from a type to a human readable form. + static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate + static EType lookupHumanReadable(const std::string& readable_name); + static const char* lookupHumanReadable(EType asset_type); - static EType getType(const std::string& desc_name); - static const std::string& getDesc(EType asset_type); + static EType getType(const std::string& desc_name); + static const std::string& getDesc(EType asset_type); - static bool lookupCanLink(EType asset_type); - static bool lookupIsLinkType(EType asset_type); + static bool lookupCanLink(EType asset_type); + static bool lookupIsLinkType(EType asset_type); - static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download - static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer + static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download + static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer static const std::string BADLOOKUP; protected: - LLAssetType() {} - ~LLAssetType() {} + LLAssetType() {} + ~LLAssetType() {} }; #endif // LL_LLASSETTYPE_H diff --git a/indra/llcommon/llatomic.cpp b/indra/llcommon/llatomic.cpp index 93aba1f460..d200bb0406 100644 --- a/indra/llcommon/llatomic.cpp +++ b/indra/llcommon/llatomic.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llatomic.cpp * * $LicenseInfo:firstyear=2018&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2018, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llatomic.h b/indra/llcommon/llatomic.h index 8de773846c..c5304637cc 100644 --- a/indra/llcommon/llatomic.h +++ b/indra/llcommon/llatomic.h @@ -1,25 +1,25 @@ -/** +/** * @file llatomic.h * @brief Base classes for atomic. * * $LicenseInfo:firstyear=2018&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2018, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,7 +40,7 @@ public: operator const Type() { return mData; } - Type CurrentValue() const { return mData; } + Type CurrentValue() const { return mData; } Type operator =(const Type& x) { mData.store(x); return mData; } void operator -=(Type x) { mData -= x; } diff --git a/indra/llcommon/llbase32.cpp b/indra/llcommon/llbase32.cpp index 349567c90b..979114fe86 100644 --- a/indra/llcommon/llbase32.cpp +++ b/indra/llcommon/llbase32.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbase32.cpp * @brief base32 encoding that returns a std::string * @author James Cook @@ -10,21 +10,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -118,9 +118,9 @@ base32_encode(char *dst, size_t size, const void *data, size_t len) | 6 | 1 0 7 6 5 | 3-4 | | 7 | 4 3 2 1 0 | 4 | +-------+-----------+--------+ - + */ - + s[0] = (x[0] >> 3); s[1] = ((x[0] & 0x07) << 2) | (x[1] >> 6); s[2] = (x[1] >> 1) & 0x1f; @@ -167,12 +167,12 @@ base32_decode(char *dst, size_t size, const void *data, size_t len) if (0 == base32_map[0]) { for (i = 0; i < LL_ARRAY_SIZE(base32_map); i++) { const char *x; - + x = memchr(base32_alphabet, ascii_toupper(i), sizeof base32_alphabet); base32_map[i] = x ? (x - base32_alphabet) : (unsigned char) -1; } } - + for (i = 0; i < len && max_pad > 0; i++) { unsigned char c; char s[8]; @@ -219,20 +219,20 @@ base32_decode(char *dst, size_t size, const void *data, size_t len) // static std::string LLBase32::encode(const U8* input, size_t input_size) { - std::string output; - if (input) - { - // Each 5 byte chunk of input is represented by an - // 8 byte chunk of output. - size_t input_chunks = (input_size + 4) / 5; - size_t output_size = input_chunks * 8; - - output.resize(output_size); - - size_t encoded = base32_encode(&output[0], output_size, input, input_size); - - LL_INFOS() << "encoded " << encoded << " into buffer of size " - << output_size << LL_ENDL; - } - return output; + std::string output; + if (input) + { + // Each 5 byte chunk of input is represented by an + // 8 byte chunk of output. + size_t input_chunks = (input_size + 4) / 5; + size_t output_size = input_chunks * 8; + + output.resize(output_size); + + size_t encoded = base32_encode(&output[0], output_size, input, input_size); + + LL_INFOS() << "encoded " << encoded << " into buffer of size " + << output_size << LL_ENDL; + } + return output; } diff --git a/indra/llcommon/llbase32.h b/indra/llcommon/llbase32.h index eeb96d789d..8cfbd7ef53 100644 --- a/indra/llcommon/llbase32.h +++ b/indra/llcommon/llbase32.h @@ -1,4 +1,4 @@ -/** +/** * @file llbase32.h * @brief base32 encoding that returns a std::string * @author James Cook @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,7 +31,7 @@ class LL_COMMON_API LLBase32 { public: - static std::string encode(const U8* input, size_t input_size); + static std::string encode(const U8* input, size_t input_size); }; #endif diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index 433b54f6f8..dbbbec9813 100644 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbase64.cpp * @brief Wrapper for apr base64 encoding that returns a std::string * @author James Cook @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,25 +37,25 @@ // static std::string LLBase64::encode(const U8* input, size_t input_size) { - std::string output; - if (input - && input_size > 0) - { - // Yes, it returns int. - int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(input_size)); - char* b64_buffer = new char[b64_buffer_length]; - - // This is faster than apr_base64_encode() if you know - // you're not on an EBCDIC machine. Also, the output is - // null terminated, even though the documentation doesn't - // specify. See apr_base64.c for details. JC - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - input, - narrow<size_t>(input_size)); - output.assign(b64_buffer); - delete[] b64_buffer; - } - return output; + std::string output; + if (input + && input_size > 0) + { + // Yes, it returns int. + int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(input_size)); + char* b64_buffer = new char[b64_buffer_length]; + + // This is faster than apr_base64_encode() if you know + // you're not on an EBCDIC machine. Also, the output is + // null terminated, even though the documentation doesn't + // specify. See apr_base64.c for details. JC + b64_buffer_length = apr_base64_encode_binary( + b64_buffer, + input, + narrow<size_t>(input_size)); + output.assign(b64_buffer); + delete[] b64_buffer; + } + return output; } diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h index 16d2c217d0..d4e9d97ea4 100644 --- a/indra/llcommon/llbase64.h +++ b/indra/llcommon/llbase64.h @@ -1,4 +1,4 @@ -/** +/** * @file llbase64.h * @brief Wrapper for apr base64 encoding that returns a std::string * @author James Cook @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,7 +31,7 @@ class LL_COMMON_API LLBase64 { public: - static std::string encode(const U8* input, size_t input_size); + static std::string encode(const U8* input, size_t input_size); }; #endif diff --git a/indra/llcommon/llbitpack.cpp b/indra/llcommon/llbitpack.cpp index 622a099945..011b310f40 100644 --- a/indra/llcommon/llbitpack.cpp +++ b/indra/llcommon/llbitpack.cpp @@ -1,25 +1,25 @@ -/** +/** * @file bitpack.cpp * @brief LLBitPack class implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llbitpack.h b/indra/llcommon/llbitpack.h index f99a354cd4..f7eb57a4f0 100644 --- a/indra/llcommon/llbitpack.h +++ b/indra/llcommon/llbitpack.h @@ -1,25 +1,25 @@ -/** +/** * @file llbitpack.h * @brief Convert data to packed bit stream * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,174 +35,174 @@ const U32 MAX_DATA_BITS = 8; class LLBitPack { public: - LLBitPack(U8 *buffer, U32 max_size) : mBuffer(buffer), mBufferSize(0), mLoad(0), mLoadSize(0), mTotalBits(0), mMaxSize(max_size) - { - } - - ~LLBitPack() - { - } - - void resetBitPacking() - { - mLoad = 0; - mLoadSize = 0; - mTotalBits = 0; - mBufferSize = 0; - } - - U32 bitPack(U8 *total_data, U32 total_dsize) - { - U32 dsize; - U8 data; - - while (total_dsize > 0) - { - if (total_dsize > MAX_DATA_BITS) - { - dsize = MAX_DATA_BITS; - total_dsize -= MAX_DATA_BITS; - } - else - { - dsize = total_dsize; - total_dsize = 0; - } - - data = *total_data++; - - data <<= (MAX_DATA_BITS - dsize); - while (dsize > 0) - { - if (mLoadSize == MAX_DATA_BITS) - { - *(mBuffer + mBufferSize++) = mLoad; - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; - } - mLoadSize = 0; - mLoad = 0x00; - } - mLoad <<= 1; - mLoad |= (data >> (MAX_DATA_BITS - 1)); - data <<= 1; - mLoadSize++; - mTotalBits++; - dsize--; - } - } - return mBufferSize; - } - - U32 bitCopy(U8 *total_data, U32 total_dsize) - { - U32 dsize; - U8 data; - - while (total_dsize > 0) - { - if (total_dsize > MAX_DATA_BITS) - { - dsize = MAX_DATA_BITS; - total_dsize -= MAX_DATA_BITS; - } - else - { - dsize = total_dsize; - total_dsize = 0; - } - - data = *total_data++; - - while (dsize > 0) - { - if (mLoadSize == MAX_DATA_BITS) - { - *(mBuffer + mBufferSize++) = mLoad; - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; - } - mLoadSize = 0; - mLoad = 0x00; - } - mLoad <<= 1; - mLoad |= (data >> (MAX_DATA_BITS - 1)); - data <<= 1; - mLoadSize++; - mTotalBits++; - dsize--; - } - } - return mBufferSize; - } - - U32 bitUnpack(U8 *total_retval, U32 total_dsize) - { - U32 dsize; - U8 *retval; - - while (total_dsize > 0) - { - if (total_dsize > MAX_DATA_BITS) - { - dsize = MAX_DATA_BITS; - total_dsize -= MAX_DATA_BITS; - } - else - { - dsize = total_dsize; - total_dsize = 0; - } - - retval = total_retval++; - *retval = 0x00; - while (dsize > 0) - { - if (mLoadSize == 0) - { + LLBitPack(U8 *buffer, U32 max_size) : mBuffer(buffer), mBufferSize(0), mLoad(0), mLoadSize(0), mTotalBits(0), mMaxSize(max_size) + { + } + + ~LLBitPack() + { + } + + void resetBitPacking() + { + mLoad = 0; + mLoadSize = 0; + mTotalBits = 0; + mBufferSize = 0; + } + + U32 bitPack(U8 *total_data, U32 total_dsize) + { + U32 dsize; + U8 data; + + while (total_dsize > 0) + { + if (total_dsize > MAX_DATA_BITS) + { + dsize = MAX_DATA_BITS; + total_dsize -= MAX_DATA_BITS; + } + else + { + dsize = total_dsize; + total_dsize = 0; + } + + data = *total_data++; + + data <<= (MAX_DATA_BITS - dsize); + while (dsize > 0) + { + if (mLoadSize == MAX_DATA_BITS) + { + *(mBuffer + mBufferSize++) = mLoad; + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; + } + mLoadSize = 0; + mLoad = 0x00; + } + mLoad <<= 1; + mLoad |= (data >> (MAX_DATA_BITS - 1)); + data <<= 1; + mLoadSize++; + mTotalBits++; + dsize--; + } + } + return mBufferSize; + } + + U32 bitCopy(U8 *total_data, U32 total_dsize) + { + U32 dsize; + U8 data; + + while (total_dsize > 0) + { + if (total_dsize > MAX_DATA_BITS) + { + dsize = MAX_DATA_BITS; + total_dsize -= MAX_DATA_BITS; + } + else + { + dsize = total_dsize; + total_dsize = 0; + } + + data = *total_data++; + + while (dsize > 0) + { + if (mLoadSize == MAX_DATA_BITS) + { + *(mBuffer + mBufferSize++) = mLoad; + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; + } + mLoadSize = 0; + mLoad = 0x00; + } + mLoad <<= 1; + mLoad |= (data >> (MAX_DATA_BITS - 1)); + data <<= 1; + mLoadSize++; + mTotalBits++; + dsize--; + } + } + return mBufferSize; + } + + U32 bitUnpack(U8 *total_retval, U32 total_dsize) + { + U32 dsize; + U8 *retval; + + while (total_dsize > 0) + { + if (total_dsize > MAX_DATA_BITS) + { + dsize = MAX_DATA_BITS; + total_dsize -= MAX_DATA_BITS; + } + else + { + dsize = total_dsize; + total_dsize = 0; + } + + retval = total_retval++; + *retval = 0x00; + while (dsize > 0) + { + if (mLoadSize == 0) + { #ifdef _DEBUG - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize" << LL_ENDL; - LL_ERRS() << mBufferSize << " > " << mMaxSize << LL_ENDL; - } + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize" << LL_ENDL; + LL_ERRS() << mBufferSize << " > " << mMaxSize << LL_ENDL; + } #endif - mLoad = *(mBuffer + mBufferSize++); - mLoadSize = MAX_DATA_BITS; - } - *retval <<= 1; - *retval |= (mLoad >> (MAX_DATA_BITS - 1)); - mLoadSize--; - mLoad <<= 1; - dsize--; - } - } - return mBufferSize; - } - - U32 flushBitPack() - { - if (mLoadSize) - { - mLoad <<= (MAX_DATA_BITS - mLoadSize); - *(mBuffer + mBufferSize++) = mLoad; - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; - } - mLoadSize = 0; - } - return mBufferSize; - } - - U8 *mBuffer; - U32 mBufferSize; - U8 mLoad; - U32 mLoadSize; - U32 mTotalBits; - U32 mMaxSize; + mLoad = *(mBuffer + mBufferSize++); + mLoadSize = MAX_DATA_BITS; + } + *retval <<= 1; + *retval |= (mLoad >> (MAX_DATA_BITS - 1)); + mLoadSize--; + mLoad <<= 1; + dsize--; + } + } + return mBufferSize; + } + + U32 flushBitPack() + { + if (mLoadSize) + { + mLoad <<= (MAX_DATA_BITS - mLoadSize); + *(mBuffer + mBufferSize++) = mLoad; + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; + } + mLoadSize = 0; + } + return mBufferSize; + } + + U8 *mBuffer; + U32 mBufferSize; + U8 mLoad; + U32 mLoadSize; + U32 mTotalBits; + U32 mMaxSize; }; #endif diff --git a/indra/llcommon/llboost.h b/indra/llcommon/llboost.h index 57d958a51a..980fc9e1c4 100644 --- a/indra/llcommon/llboost.h +++ b/indra/llcommon/llboost.h @@ -1,25 +1,25 @@ -/** +/** * @file llboost.h * @brief helper object & functions for use with boost * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,12 +31,12 @@ // boost_tokenizer typedef /* example usage: - boost_tokenizer tokens(input_string, boost::char_separator<char>(" \t\n")); - for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - std::string tok = *token_iter; - process_token_string( tok ); - } + boost_tokenizer tokens(input_string, boost::char_separator<char>(" \t\n")); + for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + std::string tok = *token_iter; + process_token_string( tok ); + } */ typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer; @@ -44,15 +44,15 @@ typedef boost::tokenizer<boost::char_separator<char> > boost_tokenizer; // returns false if any of the callbacks return false struct boost_boolean_combiner { - typedef bool result_type; - template<typename InputIterator> - bool operator()(InputIterator first, InputIterator last) const - { - bool res = true; - while (first != last) - res &= *first++; - return res; - } + typedef bool result_type; + template<typename InputIterator> + bool operator()(InputIterator first, InputIterator last) const + { + bool res = true; + while (first != last) + res &= *first++; + return res; + } }; #endif // LL_LLBOOST_H diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 9f23ce5317..b5a58e90b3 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcallbacklist.cpp * @brief A simple list of callback functions to call. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,7 +38,7 @@ LLCallbackList gIdleCallbacks; LLCallbackList::LLCallbackList() { - // nothing + // nothing } LLCallbackList::~LLCallbackList() @@ -48,72 +48,72 @@ LLCallbackList::~LLCallbackList() void LLCallbackList::addFunction( callback_t func, void *data) { - if (!func) - { - return; - } - - // only add one callback per func/data pair - // - if (containsFunction(func, data)) - { - return; - } - - callback_pair_t t(func, data); - mCallbackList.push_back(t); + if (!func) + { + return; + } + + // only add one callback per func/data pair + // + if (containsFunction(func, data)) + { + return; + } + + callback_pair_t t(func, data); + mCallbackList.push_back(t); } bool LLCallbackList::containsFunction( callback_t func, void *data) { - callback_pair_t t(func, data); - callback_list_t::iterator iter = find(func,data); - if (iter != mCallbackList.end()) - { - return TRUE; - } - else - { - return FALSE; - } + callback_pair_t t(func, data); + callback_list_t::iterator iter = find(func,data); + if (iter != mCallbackList.end()) + { + return TRUE; + } + else + { + return FALSE; + } } bool LLCallbackList::deleteFunction( callback_t func, void *data) { - callback_list_t::iterator iter = find(func,data); - if (iter != mCallbackList.end()) - { - mCallbackList.erase(iter); - return TRUE; - } - else - { - return FALSE; - } + callback_list_t::iterator iter = find(func,data); + if (iter != mCallbackList.end()) + { + mCallbackList.erase(iter); + return TRUE; + } + else + { + return FALSE; + } } -inline +inline LLCallbackList::callback_list_t::iterator LLCallbackList::find(callback_t func, void *data) { - callback_pair_t t(func, data); - return std::find(mCallbackList.begin(), mCallbackList.end(), t); + callback_pair_t t(func, data); + return std::find(mCallbackList.begin(), mCallbackList.end(), t); } void LLCallbackList::deleteAllFunctions() { - mCallbackList.clear(); + mCallbackList.clear(); } void LLCallbackList::callFunctions() { - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) - { - callback_list_t::iterator curiter = iter++; - curiter->first(curiter->second); - } + for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) + { + callback_list_t::iterator curiter = iter++; + curiter->first(curiter->second); + } } // Shim class to allow arbitrary boost::bind @@ -121,29 +121,29 @@ void LLCallbackList::callFunctions() class OnIdleCallbackOneTime { public: - OnIdleCallbackOneTime(nullary_func_t callable): - mCallable(callable) - { - } - static void onIdle(void *data) - { - gIdleCallbacks.deleteFunction(onIdle, data); - OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data); - self->call(); - delete self; - } - void call() - { - mCallable(); - } + OnIdleCallbackOneTime(nullary_func_t callable): + mCallable(callable) + { + } + static void onIdle(void *data) + { + gIdleCallbacks.deleteFunction(onIdle, data); + OnIdleCallbackOneTime* self = reinterpret_cast<OnIdleCallbackOneTime*>(data); + self->call(); + delete self; + } + void call() + { + mCallable(); + } private: - nullary_func_t mCallable; + nullary_func_t mCallable; }; void doOnIdleOneTime(nullary_func_t callable) { - OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); + OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); } // Shim class to allow generic boost functions to be run as @@ -152,79 +152,79 @@ void doOnIdleOneTime(nullary_func_t callable) class OnIdleCallbackRepeating { public: - OnIdleCallbackRepeating(bool_func_t callable): - mCallable(callable) - { - } - // Will keep getting called until the callable returns true. - static void onIdle(void *data) - { - OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data); - bool done = self->call(); - if (done) - { - gIdleCallbacks.deleteFunction(onIdle, data); - delete self; - } - } - bool call() - { - return mCallable(); - } + OnIdleCallbackRepeating(bool_func_t callable): + mCallable(callable) + { + } + // Will keep getting called until the callable returns true. + static void onIdle(void *data) + { + OnIdleCallbackRepeating* self = reinterpret_cast<OnIdleCallbackRepeating*>(data); + bool done = self->call(); + if (done) + { + gIdleCallbacks.deleteFunction(onIdle, data); + delete self; + } + } + bool call() + { + return mCallable(); + } private: - bool_func_t mCallable; + bool_func_t mCallable; }; void doOnIdleRepeating(bool_func_t callable) { - OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); + OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); } class NullaryFuncEventTimer: public LLEventTimer { public: - NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } + NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): + LLEventTimer(seconds), + mCallable(callable) + { + } private: - BOOL tick() - { - mCallable(); - return TRUE; - } + BOOL tick() + { + mCallable(); + return TRUE; + } - nullary_func_t mCallable; + nullary_func_t mCallable; }; // Call a given callable once after specified interval. void doAfterInterval(nullary_func_t callable, F32 seconds) { - new NullaryFuncEventTimer(callable, seconds); + new NullaryFuncEventTimer(callable, seconds); } class BoolFuncEventTimer: public LLEventTimer { public: - BoolFuncEventTimer(bool_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } + BoolFuncEventTimer(bool_func_t callable, F32 seconds): + LLEventTimer(seconds), + mCallable(callable) + { + } private: - BOOL tick() - { - return mCallable(); - } + BOOL tick() + { + return mCallable(); + } - bool_func_t mCallable; + bool_func_t mCallable; }; // Call a given callable every specified number of seconds, until it returns true. void doPeriodically(bool_func_t callable, F32 seconds) { - new BoolFuncEventTimer(callable, seconds); + new BoolFuncEventTimer(callable, seconds); } diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 89716cd74c..d6c415f7c5 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -1,25 +1,25 @@ -/** +/** * @file llcallbacklist.h * @brief A simple list of callback functions to call. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,29 +34,29 @@ class LLCallbackList { public: - typedef void (*callback_t)(void*); + typedef void (*callback_t)(void*); + + typedef std::pair< callback_t,void* > callback_pair_t; + // NOTE: It is confirmed that we DEPEND on the order provided by using a list :( + // + typedef std::list< callback_pair_t > callback_list_t; - typedef std::pair< callback_t,void* > callback_pair_t; - // NOTE: It is confirmed that we DEPEND on the order provided by using a list :( - // - typedef std::list< callback_pair_t > callback_list_t; - - LLCallbackList(); - ~LLCallbackList(); + LLCallbackList(); + ~LLCallbackList(); - void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) - bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair - bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found - void callFunctions(); // calls all functions - void deleteAllFunctions(); + void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) + bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair + bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found + void callFunctions(); // calls all functions + void deleteAllFunctions(); - static void test(); + static void test(); protected: - inline callback_list_t::iterator find(callback_t func, void *data); + inline callback_list_t::iterator find(callback_t func, void *data); - callback_list_t mCallbackList; + callback_list_t mCallbackList; }; typedef boost::function<void ()> nullary_func_t; diff --git a/indra/llcommon/llcallstack.cpp b/indra/llcommon/llcallstack.cpp index 83d5ae2a63..c0be4f598e 100644 --- a/indra/llcommon/llcallstack.cpp +++ b/indra/llcommon/llcallstack.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcallstack.cpp * @brief run-time extraction of the current callstack * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2016, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -91,7 +91,7 @@ LLCallStack::LLCallStack(S32 skip_count, bool verbose): bool LLCallStack::contains(const std::string& str) { - for (const std::string& src_str : m_strings) + for (const std::string& src_str : m_strings) { if (src_str.find(str) != std::string::npos) { @@ -104,7 +104,7 @@ bool LLCallStack::contains(const std::string& str) std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack) { #ifndef LL_RELEASE_FOR_DOWNLOAD - for (const std::string& str : call_stack.m_strings) + for (const std::string& str : call_stack.m_strings) { s << str; } @@ -121,27 +121,27 @@ LLContextStrings::LLContextStrings() // static LLContextStrings* LLContextStrings::getThreadLocalInstance() { - LLContextStrings *cons = LLThreadLocalSingletonPointer<LLContextStrings>::getInstance(); + LLContextStrings *cons = LLThreadLocalSingletonPointer<LLContextStrings>::getInstance(); if (!cons) { LLThreadLocalSingletonPointer<LLContextStrings>::setInstance(new LLContextStrings); } - return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance(); + return LLThreadLocalSingletonPointer<LLContextStrings>::getInstance(); } // static void LLContextStrings::addContextString(const std::string& str) { - LLContextStrings *cons = getThreadLocalInstance(); + LLContextStrings *cons = getThreadLocalInstance(); //LL_INFOS() << "CTX " << (S32)cons << " ADD " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL; - cons->m_contextStrings[str]++; + cons->m_contextStrings[str]++; } // static void LLContextStrings::removeContextString(const std::string& str) { - LLContextStrings *cons = getThreadLocalInstance(); - cons->m_contextStrings[str]--; + LLContextStrings *cons = getThreadLocalInstance(); + cons->m_contextStrings[str]--; //LL_INFOS() << "CTX " << (S32)cons << " REMOVE " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL; if (cons->m_contextStrings[str] == 0) { @@ -175,7 +175,7 @@ void LLContextStrings::output(std::ostream& os) } } -// static +// static std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status) { LLThreadLocalSingletonPointer<LLContextStrings>::getInstance()->output(s); diff --git a/indra/llcommon/llcallstack.h b/indra/llcommon/llcallstack.h index d5a2b7b157..ad10a9dbf7 100644 --- a/indra/llcommon/llcallstack.h +++ b/indra/llcommon/llcallstack.h @@ -1,25 +1,25 @@ -/** +/** * @file llcallstack.h * @brief run-time extraction of the current callstack * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2016, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llcleanup.cpp b/indra/llcommon/llcleanup.cpp index 1f34c2036a..38b2ccbeff 100644 --- a/indra/llcommon/llcleanup.cpp +++ b/indra/llcommon/llcleanup.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-08-30 * @brief Implementation for llcleanup. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llcleanup.h b/indra/llcommon/llcleanup.h index 0f567ed5f6..b120a5c4fe 100644 --- a/indra/llcommon/llcleanup.h +++ b/indra/llcommon/llcleanup.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2015-05-20 * @brief Mechanism for cleaning up subsystem resources - * + * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Copyright (c) 2015, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llclickaction.h b/indra/llcommon/llclickaction.h index 2f83113af9..daa4e88f80 100644 --- a/indra/llcommon/llclickaction.h +++ b/indra/llcommon/llclickaction.h @@ -1,4 +1,4 @@ -/** +/** * @file llclickaction.h * @author James Cook * @brief Constants for single-click actions on objects @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 6e988260a9..14bdeb5c60 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llcommon.cpp * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -122,32 +122,32 @@ static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL; //static void LLCommon::initClass() { - if (!sAprInitialized) - { - ll_init_apr(); - sAprInitialized = TRUE; - } - LLTimer::initClass(); - LLThreadSafeRefCount::initThreadSafeRefCount(); - assert_main_thread(); // Make sure we record the main thread - if (!sMasterThreadRecorder) - { - sMasterThreadRecorder = new LLTrace::ThreadRecorder(); - LLTrace::set_master_thread_recorder(sMasterThreadRecorder); - } + if (!sAprInitialized) + { + ll_init_apr(); + sAprInitialized = TRUE; + } + LLTimer::initClass(); + LLThreadSafeRefCount::initThreadSafeRefCount(); + assert_main_thread(); // Make sure we record the main thread + if (!sMasterThreadRecorder) + { + sMasterThreadRecorder = new LLTrace::ThreadRecorder(); + LLTrace::set_master_thread_recorder(sMasterThreadRecorder); + } } //static void LLCommon::cleanupClass() { - delete sMasterThreadRecorder; - sMasterThreadRecorder = NULL; - LLTrace::set_master_thread_recorder(NULL); - LLThreadSafeRefCount::cleanupThreadSafeRefCount(); - SUBSYSTEM_CLEANUP_DBG(LLTimer); - if (sAprInitialized) - { - ll_cleanup_apr(); - sAprInitialized = FALSE; - } + delete sMasterThreadRecorder; + sMasterThreadRecorder = NULL; + LLTrace::set_master_thread_recorder(NULL); + LLThreadSafeRefCount::cleanupThreadSafeRefCount(); + SUBSYSTEM_CLEANUP_DBG(LLTimer); + if (sAprInitialized) + { + ll_cleanup_apr(); + sAprInitialized = FALSE; + } } diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h index ca9cad5d05..129e71f703 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -1,24 +1,24 @@ -/** +/** * @file llcommon.h * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,10 +33,10 @@ class LL_COMMON_API LLCommon { public: - static void initClass(); - static void cleanupClass(); + static void initClass(); + static void cleanupClass(); private: - static BOOL sAprInitialized; + static BOOL sAprInitialized; }; #endif diff --git a/indra/llcommon/llcommonutils.cpp b/indra/llcommon/llcommonutils.cpp index d82554c202..a38879c89f 100644 --- a/indra/llcommon/llcommonutils.cpp +++ b/indra/llcommon/llcommonutils.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,29 +28,29 @@ #include "llcommonutils.h" void LLCommonUtils::computeDifference( - const uuid_vec_t& vnew, - const uuid_vec_t& vcur, - uuid_vec_t& vadded, - uuid_vec_t& vremoved) + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved) { - uuid_vec_t vnew_copy(vnew); - uuid_vec_t vcur_copy(vcur); + uuid_vec_t vnew_copy(vnew); + uuid_vec_t vcur_copy(vcur); - std::sort(vnew_copy.begin(), vnew_copy.end()); - std::sort(vcur_copy.begin(), vcur_copy.end()); + std::sort(vnew_copy.begin(), vnew_copy.end()); + std::sort(vcur_copy.begin(), vcur_copy.end()); - size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size()); - vadded.resize(maxsize); - vremoved.resize(maxsize); + size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); - uuid_vec_t::iterator it; - // what was removed - it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin()); - vremoved.erase(it, vremoved.end()); + uuid_vec_t::iterator it; + // what was removed + it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); - // what was added - it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin()); - vadded.erase(it, vadded.end()); + // what was added + it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin()); + vadded.erase(it, vadded.end()); } // EOF diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h index 20ada27830..5f6fd41aa3 100644 --- a/indra/llcommon/llcommonutils.h +++ b/indra/llcommon/llcommonutils.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,21 +31,21 @@ namespace LLCommonUtils { - /** - * Computes difference between 'vnew' and 'vcur' vectors. - * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded' - * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved' - * - * @param vnew[in] - incoming IDs - * @param vcur[in] - current IDs - * @param vadded[out] - difference between incoming and current IDS - added IDs - * @param vremoved[out] - difference between incoming and current IDS - removed IDs - */ - LL_COMMON_API void computeDifference( - const uuid_vec_t& vnew, - const uuid_vec_t& vcur, - uuid_vec_t& vadded, - uuid_vec_t& vremoved); + /** + * Computes difference between 'vnew' and 'vcur' vectors. + * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded' + * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved' + * + * @param vnew[in] - incoming IDs + * @param vcur[in] - current IDs + * @param vadded[out] - difference between incoming and current IDS - added IDs + * @param vremoved[out] - difference between incoming and current IDS - removed IDs + */ + LL_COMMON_API void computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved); }; #endif //LL_LLCOMMONUTILS_H diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h index da6e6affe1..2df1719941 100644 --- a/indra/llcommon/llcond.h +++ b/indra/llcommon/llcond.h @@ -5,7 +5,7 @@ * @brief LLCond is a wrapper around condition_variable to encapsulate the * obligatory condition_variable usage pattern. We also provide * simplified versions LLScalarCond, LLBoolCond and LLOneShotCond. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c13900f74a..aa8eca7d90 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-03 * @brief Implementation for llcoros. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -123,7 +123,7 @@ LLCoros::LLCoros(): // Previously we used // boost::context::guarded_stack_allocator::default_stacksize(); // empirically this is insufficient. - mStackSize(900*1024), + mStackSize(1024*1024), // mCurrent does NOT own the current CoroData instance -- it simply // points to it. So initialize it with a no-op deleter. mCurrent{ [](CoroData*){} } diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index fd878f20ad..71c1c1c443 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-02 * @brief Manage running boost::coroutine instances - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -158,7 +158,7 @@ public: * LLCoros::launch()). */ static std::string getName(); - + /** * rethrow() is called by the thread's main fiber to propagate an * exception from any coroutine into the main fiber, where it can engage diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index 626bb1e564..34aa7b46e8 100644 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcrc.cpp * @brief implementation of the crc class. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -142,77 +142,77 @@ LLCRC::LLCRC() : mCurrent(0xffffffff) U32 LLCRC::getCRC() const { - return ~mCurrent; + return ~mCurrent; } void LLCRC::update(U8 next_byte) { - mCurrent = UPDC32(next_byte, mCurrent); + mCurrent = UPDC32(next_byte, mCurrent); } void LLCRC::update(const U8* buffer, size_t buffer_size) { - for (size_t i = 0; i < buffer_size; i++) - { - mCurrent = UPDC32(buffer[i], mCurrent); - } + for (size_t i = 0; i < buffer_size; i++) + { + mCurrent = UPDC32(buffer[i], mCurrent); + } } void LLCRC::update(const std::string& filename) { - if (filename.empty()) - { - LL_ERRS() << "No filename specified" << LL_ENDL; - return; - } - - FILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - - if (fp) - { - fseek(fp, 0, SEEK_END); - long size = ftell(fp); - - fseek(fp, 0, SEEK_SET); - - if (size > 0) - { - U8* data = new U8[size]; - size_t nread; - - nread = fread(data, 1, size, fp); - fclose(fp); - - if (nread < (size_t) size) - { - LL_WARNS() << "Short read on " << filename << LL_ENDL; - } - - update(data, nread); - delete[] data; - } - else - { - fclose(fp); - } - } + if (filename.empty()) + { + LL_ERRS() << "No filename specified" << LL_ENDL; + return; + } + + FILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ + + if (fp) + { + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + + fseek(fp, 0, SEEK_SET); + + if (size > 0) + { + U8* data = new U8[size]; + size_t nread; + + nread = fread(data, 1, size, fp); + fclose(fp); + + if (nread < (size_t) size) + { + LL_WARNS() << "Short read on " << filename << LL_ENDL; + } + + update(data, nread); + delete[] data; + } + else + { + fclose(fp); + } + } } #ifdef _DEBUG BOOL LLCRC::testHarness() { - const S32 TEST_BUFFER_SIZE = 16; - const char TEST_BUFFER[TEST_BUFFER_SIZE] = "hello &#$)$&Nd0"; /* Flawfinder: ignore */ - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER, TEST_BUFFER_SIZE - 1); - char* rh = (char*)TEST_BUFFER; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - return(c1.getCRC() == c2.getCRC()); + const S32 TEST_BUFFER_SIZE = 16; + const char TEST_BUFFER[TEST_BUFFER_SIZE] = "hello &#$)$&Nd0"; /* Flawfinder: ignore */ + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER, TEST_BUFFER_SIZE - 1); + char* rh = (char*)TEST_BUFFER; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + return(c1.getCRC() == c2.getCRC()); } #endif diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h index 3f41b28ffa..3b48b778ff 100644 --- a/indra/llcommon/llcrc.h +++ b/indra/llcommon/llcrc.h @@ -1,25 +1,25 @@ -/** +/** * @file llcrc.h * @brief LLCRC class header file. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,20 +47,20 @@ class LL_COMMON_API LLCRC { protected: - U32 mCurrent; - + U32 mCurrent; + public: - LLCRC(); + LLCRC(); - U32 getCRC() const; - void update(U8 next_byte); - void update(const U8* buffer, size_t buffer_size); - void update(const std::string& filename); + U32 getCRC() const; + void update(U8 next_byte); + void update(const U8* buffer, size_t buffer_size); + void update(const std::string& filename); #ifdef _DEBUG - // This function runs tests to make sure the crc is - // working. Returns TRUE if it is. - static BOOL testHarness(); + // This function runs tests to make sure the crc is + // working. Returns TRUE if it is. + static BOOL testHarness(); #endif }; diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp index 54be855f67..bb5f2b647a 100644 --- a/indra/llcommon/llcriticaldamp.cpp +++ b/indra/llcommon/llcriticaldamp.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcriticaldamp.cpp * @brief Implementation of the critical damping functionality. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,20 +39,20 @@ F32 LLSmoothInterpolation::sTimeDelta; // helper functors struct LLSmoothInterpolation::CompareTimeConstants { - bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const - { - return a < b.mTimeScale; - } + bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a < b.mTimeScale; + } - bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const - { - return a.mTimeScale < b; // bottom of a is higher than bottom of b - } + bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const + { + return a.mTimeScale < b; // bottom of a is higher than bottom of b + } - bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const - { - return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b - } + bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b + } }; //----------------------------------------------------------------------------- @@ -60,7 +60,7 @@ struct LLSmoothInterpolation::CompareTimeConstants //----------------------------------------------------------------------------- LLSmoothInterpolation::LLSmoothInterpolation() { - sTimeDelta = 0.f; + sTimeDelta = 0.f; } // static @@ -69,46 +69,46 @@ LLSmoothInterpolation::LLSmoothInterpolation() //----------------------------------------------------------------------------- void LLSmoothInterpolation::updateInterpolants() { - sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32(); + sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32(); - for (S32 i = 0; i < sInterpolants.size(); i++) - { - Interpolant& interp = sInterpolants[i]; - interp.mInterpolant = calcInterpolant(interp.mTimeScale); - } -} + for (S32 i = 0; i < sInterpolants.size(); i++) + { + Interpolant& interp = sInterpolants[i]; + interp.mInterpolant = calcInterpolant(interp.mTimeScale); + } +} //----------------------------------------------------------------------------- // getInterpolant() //----------------------------------------------------------------------------- F32 LLSmoothInterpolation::getInterpolant(F32SecondsImplicit time_constant, bool use_cache) { - if (time_constant == 0.f) - { - return 1.f; - } + if (time_constant == 0.f) + { + return 1.f; + } - if (use_cache) - { - interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants()); - if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant) - { - return find_it->mInterpolant; - } - else - { - Interpolant interp; - interp.mTimeScale = time_constant.value(); - interp.mInterpolant = calcInterpolant(time_constant.value()); - sInterpolants.insert(find_it, interp); - return interp.mInterpolant; - } - } - else - { - return calcInterpolant(time_constant.value()); + if (use_cache) + { + interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants()); + if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant) + { + return find_it->mInterpolant; + } + else + { + Interpolant interp; + interp.mTimeScale = time_constant.value(); + interp.mInterpolant = calcInterpolant(time_constant.value()); + sInterpolants.insert(find_it, interp); + return interp.mInterpolant; + } + } + else + { + return calcInterpolant(time_constant.value()); - } + } } //----------------------------------------------------------------------------- @@ -116,6 +116,6 @@ F32 LLSmoothInterpolation::getInterpolant(F32SecondsImplicit time_constant, bool //----------------------------------------------------------------------------- F32 LLSmoothInterpolation::calcInterpolant(F32 time_constant) { - return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f); + return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f); } diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index 1fb6a1af29..2c37d276c4 100644 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -1,26 +1,26 @@ -/** +/** * @file llcriticaldamp.h * @brief A lightweight class that calculates critical damping constants once - * per frame. + * per frame. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,39 +33,39 @@ #include "llframetimer.h" #include "llunits.h" -class LL_COMMON_API LLSmoothInterpolation +class LL_COMMON_API LLSmoothInterpolation { public: - LLSmoothInterpolation(); + LLSmoothInterpolation(); - // MANIPULATORS - static void updateInterpolants(); + // MANIPULATORS + static void updateInterpolants(); - // ACCESSORS - static F32 getInterpolant(F32SecondsImplicit time_constant, bool use_cache = true); + // ACCESSORS + static F32 getInterpolant(F32SecondsImplicit time_constant, bool use_cache = true); - template<typename T> - static T lerp(T a, T b, F32SecondsImplicit time_constant, bool use_cache = true) - { - F32 interpolant = getInterpolant(time_constant, use_cache); - return ((a * (1.f - interpolant)) - + (b * interpolant)); - } + template<typename T> + static T lerp(T a, T b, F32SecondsImplicit time_constant, bool use_cache = true) + { + F32 interpolant = getInterpolant(time_constant, use_cache); + return ((a * (1.f - interpolant)) + + (b * interpolant)); + } protected: - static F32 calcInterpolant(F32 time_constant); + static F32 calcInterpolant(F32 time_constant); - struct CompareTimeConstants; - static LLFrameTimer sInternalTimer; // frame timer for calculating deltas + struct CompareTimeConstants; + static LLFrameTimer sInternalTimer; // frame timer for calculating deltas - struct Interpolant - { - F32 mTimeScale; - F32 mInterpolant; - }; - typedef std::vector<Interpolant> interpolant_vec_t; - static interpolant_vec_t sInterpolants; - static F32 sTimeDelta; + struct Interpolant + { + F32 mTimeScale; + F32 mInterpolant; + }; + typedef std::vector<Interpolant> interpolant_vec_t; + static interpolant_vec_t sInterpolants; + static F32 sTimeDelta; }; typedef LLSmoothInterpolation LLCriticalDamp; diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 2ddcf40895..c63c7012d1 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lldate.cpp * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,36 +44,36 @@ static const F64 DATE_EPOCH = 0.0; static const F64 LL_APR_USEC_PER_SEC = 1000000.0; - // should be APR_USEC_PER_SEC, but that relies on INT64_C which - // isn't defined in glib under our build set up for some reason + // should be APR_USEC_PER_SEC, but that relies on INT64_C which + // isn't defined in glib under our build set up for some reason LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH) {} LLDate::LLDate(const LLDate& date) : - mSecondsSinceEpoch(date.mSecondsSinceEpoch) + mSecondsSinceEpoch(date.mSecondsSinceEpoch) {} LLDate::LLDate(F64SecondsImplicit seconds_since_epoch) : - mSecondsSinceEpoch(seconds_since_epoch.value()) + mSecondsSinceEpoch(seconds_since_epoch.value()) {} LLDate::LLDate(const std::string& iso8601_date) { - if(!fromString(iso8601_date)) - { - LL_WARNS() << "date " << iso8601_date << " failed to parse; " - << "ZEROING IT OUT" << LL_ENDL; - mSecondsSinceEpoch = DATE_EPOCH; - } + if(!fromString(iso8601_date)) + { + LL_WARNS() << "date " << iso8601_date << " failed to parse; " + << "ZEROING IT OUT" << LL_ENDL; + mSecondsSinceEpoch = DATE_EPOCH; + } } std::string LLDate::asString() const { - std::ostringstream stream; - toStream(stream); - return stream.str(); + std::ostringstream stream; + toStream(stream); + return stream.str(); } //@ brief Converts time in seconds since EPOCH @@ -83,236 +83,236 @@ std::string LLDate::asString() const // is one of the standards used and the prefered format std::string LLDate::asRFC1123() const { - return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); + return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } std::string LLDate::toHTTPDateString (std::string fmt) const { LL_PROFILE_ZONE_SCOPED; - - time_t locSeconds = (time_t) mSecondsSinceEpoch; - struct tm * gmt = gmtime (&locSeconds); - return toHTTPDateString(gmt, fmt); + + time_t locSeconds = (time_t) mSecondsSinceEpoch; + struct tm * gmt = gmtime (&locSeconds); + return toHTTPDateString(gmt, fmt); } std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) { LL_PROFILE_ZONE_SCOPED; - // avoid calling setlocale() unnecessarily - it's expensive. - static std::string prev_locale = ""; - std::string this_locale = LLStringUtil::getLocale(); - if (this_locale != prev_locale) - { - setlocale(LC_TIME, this_locale.c_str()); - prev_locale = this_locale; - } - - // use strftime() as it appears to be faster than std::time_put - char buffer[128]; - strftime(buffer, 128, fmt.c_str(), gmt); - std::string res(buffer); + // avoid calling setlocale() unnecessarily - it's expensive. + static std::string prev_locale = ""; + std::string this_locale = LLStringUtil::getLocale(); + if (this_locale != prev_locale) + { + setlocale(LC_TIME, this_locale.c_str()); + prev_locale = this_locale; + } + + // use strftime() as it appears to be faster than std::time_put + char buffer[128]; + strftime(buffer, 128, fmt.c_str(), gmt); + std::string res(buffer); #if LL_WINDOWS - // Convert from locale-dependant charset to UTF-8 (EXT-8524). - res = ll_convert_string_to_utf8_string(res); + // Convert from locale-dependant charset to UTF-8 (EXT-8524). + res = ll_convert_string_to_utf8_string(res); #endif - return res; + return res; } void LLDate::toStream(std::ostream& s) const { - apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); - - apr_time_exp_t exp_time; - if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) - { - s << "1970-01-01T00:00:00Z"; - return; - } - - s << std::dec << std::setfill('0'); + apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + + apr_time_exp_t exp_time; + if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) + { + s << "1970-01-01T00:00:00Z"; + return; + } + + s << std::dec << std::setfill('0'); #if( LL_WINDOWS || __GNUC__ > 2) - s << std::right; + s << std::right; #else - s.setf(ios::right); + s.setf(ios::right); #endif - s << std::setw(4) << (exp_time.tm_year + 1900) - << '-' << std::setw(2) << (exp_time.tm_mon + 1) - << '-' << std::setw(2) << (exp_time.tm_mday) - << 'T' << std::setw(2) << (exp_time.tm_hour) - << ':' << std::setw(2) << (exp_time.tm_min) - << ':' << std::setw(2) << (exp_time.tm_sec); - if (exp_time.tm_usec > 0) - { - s << '.' << std::setw(2) - << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); - } - s << 'Z' - << std::setfill(' '); + s << std::setw(4) << (exp_time.tm_year + 1900) + << '-' << std::setw(2) << (exp_time.tm_mon + 1) + << '-' << std::setw(2) << (exp_time.tm_mday) + << 'T' << std::setw(2) << (exp_time.tm_hour) + << ':' << std::setw(2) << (exp_time.tm_min) + << ':' << std::setw(2) << (exp_time.tm_sec); + if (exp_time.tm_usec > 0) + { + s << '.' << std::setw(2) + << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); + } + s << 'Z' + << std::setfill(' '); } bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const { - apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); - - apr_time_exp_t exp_time; - if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) - { - return false; - } + apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + + apr_time_exp_t exp_time; + if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) + { + return false; + } - if (year) - *year = exp_time.tm_year + 1900; + if (year) + *year = exp_time.tm_year + 1900; - if (month) - *month = exp_time.tm_mon + 1; + if (month) + *month = exp_time.tm_mon + 1; - if (day) - *day = exp_time.tm_mday; + if (day) + *day = exp_time.tm_mday; - if (hour) - *hour = exp_time.tm_hour; + if (hour) + *hour = exp_time.tm_hour; - if (min) - *min = exp_time.tm_min; + if (min) + *min = exp_time.tm_min; - if (sec) - *sec = exp_time.tm_sec; + if (sec) + *sec = exp_time.tm_sec; - return true; + return true; } bool LLDate::fromString(const std::string& iso8601_date) { - std::istringstream stream(iso8601_date); - return fromStream(stream); + std::istringstream stream(iso8601_date); + return fromStream(stream); } bool LLDate::fromStream(std::istream& s) { - struct apr_time_exp_t exp_time; - apr_int32_t tm_part; - int c; - - s >> tm_part; - exp_time.tm_year = tm_part - 1900; - c = s.get(); // skip the hypen - if (c != '-') { return false; } - s >> tm_part; - exp_time.tm_mon = tm_part - 1; - c = s.get(); // skip the hypen - if (c != '-') { return false; } - s >> tm_part; - exp_time.tm_mday = tm_part; - - c = s.get(); // skip the T - if (c != 'T') { return false; } - - s >> tm_part; - exp_time.tm_hour = tm_part; - c = s.get(); // skip the : - if (c != ':') { return false; } - s >> tm_part; - exp_time.tm_min = tm_part; - c = s.get(); // skip the : - if (c != ':') { return false; } - s >> tm_part; - exp_time.tm_sec = tm_part; - - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { - return false; - } - - F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC; - - // check for fractional - c = s.peek(); - if(c == '.') - { - F64 fractional = 0.0; - s >> fractional; - seconds_since_epoch += fractional; - } - - c = s.peek(); // check for offset - if (c == '+' || c == '-') - { - S32 offset_sign = (c == '+') ? 1 : -1; - S32 offset_hours = 0; - S32 offset_minutes = 0; - S32 offset_in_seconds = 0; - - s >> offset_hours; - - c = s.get(); // skip the colon a get the minutes if there are any - if (c == ':') - { - s >> offset_minutes; - } - - offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60; - seconds_since_epoch -= offset_in_seconds; - } - else if (c != 'Z') { return false; } // skip the Z - - mSecondsSinceEpoch = seconds_since_epoch; - return true; + struct apr_time_exp_t exp_time; + apr_int32_t tm_part; + int c; + + s >> tm_part; + exp_time.tm_year = tm_part - 1900; + c = s.get(); // skip the hypen + if (c != '-') { return false; } + s >> tm_part; + exp_time.tm_mon = tm_part - 1; + c = s.get(); // skip the hypen + if (c != '-') { return false; } + s >> tm_part; + exp_time.tm_mday = tm_part; + + c = s.get(); // skip the T + if (c != 'T') { return false; } + + s >> tm_part; + exp_time.tm_hour = tm_part; + c = s.get(); // skip the : + if (c != ':') { return false; } + s >> tm_part; + exp_time.tm_min = tm_part; + c = s.get(); // skip the : + if (c != ':') { return false; } + s >> tm_part; + exp_time.tm_sec = tm_part; + + // zero out the unused fields + exp_time.tm_usec = 0; + exp_time.tm_wday = 0; + exp_time.tm_yday = 0; + exp_time.tm_isdst = 0; + exp_time.tm_gmtoff = 0; + + // generate a time_t from that + apr_time_t time; + if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) + { + return false; + } + + F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC; + + // check for fractional + c = s.peek(); + if(c == '.') + { + F64 fractional = 0.0; + s >> fractional; + seconds_since_epoch += fractional; + } + + c = s.peek(); // check for offset + if (c == '+' || c == '-') + { + S32 offset_sign = (c == '+') ? 1 : -1; + S32 offset_hours = 0; + S32 offset_minutes = 0; + S32 offset_in_seconds = 0; + + s >> offset_hours; + + c = s.get(); // skip the colon a get the minutes if there are any + if (c == ':') + { + s >> offset_minutes; + } + + offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60; + seconds_since_epoch -= offset_in_seconds; + } + else if (c != 'Z') { return false; } // skip the Z + + mSecondsSinceEpoch = seconds_since_epoch; + return true; } bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec) { - struct apr_time_exp_t exp_time; - - exp_time.tm_year = year - 1900; - exp_time.tm_mon = month - 1; - exp_time.tm_mday = day; - exp_time.tm_hour = hour; - exp_time.tm_min = min; - exp_time.tm_sec = sec; - - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { - return false; - } - - mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC; - - return true; + struct apr_time_exp_t exp_time; + + exp_time.tm_year = year - 1900; + exp_time.tm_mon = month - 1; + exp_time.tm_mday = day; + exp_time.tm_hour = hour; + exp_time.tm_min = min; + exp_time.tm_sec = sec; + + // zero out the unused fields + exp_time.tm_usec = 0; + exp_time.tm_wday = 0; + exp_time.tm_yday = 0; + exp_time.tm_isdst = 0; + exp_time.tm_gmtoff = 0; + + // generate a time_t from that + apr_time_t time; + if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) + { + return false; + } + + mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC; + + return true; } F64 LLDate::secondsSinceEpoch() const { - return mSecondsSinceEpoch; + return mSecondsSinceEpoch; } void LLDate::secondsSinceEpoch(F64 seconds) { - mSecondsSinceEpoch = seconds; + mSecondsSinceEpoch = seconds; } /* static */ LLDate LLDate::now() { - // time() returns seconds, we want fractions of a second, which LLTimer provides --RN - return LLDate(LLTimer::getTotalSeconds()); + // time() returns seconds, we want fractions of a second, which LLTimer provides --RN + return LLDate(LLTimer::getTotalSeconds()); } bool LLDate::operator<(const LLDate& rhs) const @@ -322,13 +322,13 @@ bool LLDate::operator<(const LLDate& rhs) const std::ostream& operator<<(std::ostream& s, const LLDate& date) { - date.toStream(s); - return s; + date.toStream(s); + return s; } std::istream& operator>>(std::istream& s, LLDate& date) { - date.fromStream(s); - return s; + date.fromStream(s); + return s; } diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index be2cd2d051..81f2dd0d1c 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -1,4 +1,4 @@ -/** +/** * @file lldate.h * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ #include "stdtypes.h" #include "llunits.h" -/** +/** * @class LLDate * @brief This class represents a particular point in time in UTC. * @@ -44,110 +44,110 @@ class LL_COMMON_API LLDate { public: - /** - * @brief Construct a date equal to epoch. - */ - LLDate(); - - /** - * @brief Construct a date equal to the source date. - */ - LLDate(const LLDate& date); - - /** - * @brief Construct a date from a seconds since epoch value. - * - * @param seconds_since_epoch The number of seconds since UTC epoch. - */ - LLDate(F64SecondsImplicit seconds_since_epoch); - - /** - * @brief Construct a date from a string representation - * - * The date is constructed in the <code>fromString()</code> - * method. See that method for details of supported formats. - * If that method fails to parse the date, the date is set to epoch. - * @param iso8601_date An iso-8601 compatible representation of the date. - */ - LLDate(const std::string& iso8601_date); - - /** - * @brief Return the date as in ISO-8601 string. - * - * @return A string representation of the date. - */ - std::string asString() const; - std::string asRFC1123() const; - void toStream(std::ostream&) const; - bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const; - std::string toHTTPDateString (std::string fmt) const; - static std::string toHTTPDateString (tm * gmt, std::string fmt); - /** - * @brief Set the date from an ISO-8601 string. - * - * The parser only supports strings conforming to - * YYYYF-MM-DDTHH:MM:SS.FFZ where Y is year, M is month, D is day, - * H is hour, M is minute, S is second, F is sub-second, and all - * other characters are literal. - * If this method fails to parse the date, the previous date is - * retained. - * @param iso8601_date An iso-8601 compatible representation of the date. - * @return Returns true if the string was successfully parsed. - */ - bool fromString(const std::string& iso8601_date); - bool fromStream(std::istream&); - bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0); - - /** - * @brief Return the date in seconds since epoch. - * - * @return The number of seconds since epoch UTC. - */ - F64 secondsSinceEpoch() const; - - /** - * @brief Set the date in seconds since epoch. - * - * @param seconds The number of seconds since epoch UTC. - */ - void secondsSinceEpoch(F64 seconds); - + /** + * @brief Construct a date equal to epoch. + */ + LLDate(); + + /** + * @brief Construct a date equal to the source date. + */ + LLDate(const LLDate& date); + + /** + * @brief Construct a date from a seconds since epoch value. + * + * @param seconds_since_epoch The number of seconds since UTC epoch. + */ + LLDate(F64SecondsImplicit seconds_since_epoch); + + /** + * @brief Construct a date from a string representation + * + * The date is constructed in the <code>fromString()</code> + * method. See that method for details of supported formats. + * If that method fails to parse the date, the date is set to epoch. + * @param iso8601_date An iso-8601 compatible representation of the date. + */ + LLDate(const std::string& iso8601_date); + + /** + * @brief Return the date as in ISO-8601 string. + * + * @return A string representation of the date. + */ + std::string asString() const; + std::string asRFC1123() const; + void toStream(std::ostream&) const; + bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const; + std::string toHTTPDateString (std::string fmt) const; + static std::string toHTTPDateString (tm * gmt, std::string fmt); + /** + * @brief Set the date from an ISO-8601 string. + * + * The parser only supports strings conforming to + * YYYYF-MM-DDTHH:MM:SS.FFZ where Y is year, M is month, D is day, + * H is hour, M is minute, S is second, F is sub-second, and all + * other characters are literal. + * If this method fails to parse the date, the previous date is + * retained. + * @param iso8601_date An iso-8601 compatible representation of the date. + * @return Returns true if the string was successfully parsed. + */ + bool fromString(const std::string& iso8601_date); + bool fromStream(std::istream&); + bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0); + + /** + * @brief Return the date in seconds since epoch. + * + * @return The number of seconds since epoch UTC. + */ + F64 secondsSinceEpoch() const; + + /** + * @brief Set the date in seconds since epoch. + * + * @param seconds The number of seconds since epoch UTC. + */ + void secondsSinceEpoch(F64 seconds); + /** * @brief Create an LLDate object set to the current time. - * - * @return The number of seconds since epoch UTC. - */ + * + * @return The number of seconds since epoch UTC. + */ static LLDate now(); - /** - * @brief Compare dates using operator< so we can order them using STL. - * - * @param rhs -- the right hand side of the comparison operator - */ - bool operator<(const LLDate& rhs) const; - - /** - * @brief Remaining comparison operators in terms of operator< + /** + * @brief Compare dates using operator< so we can order them using STL. + * + * @param rhs -- the right hand side of the comparison operator + */ + bool operator<(const LLDate& rhs) const; + + /** + * @brief Remaining comparison operators in terms of operator< * This conforms to the expectation of STL. - * - * @param rhs -- the right hand side of the comparison operator - */ + * + * @param rhs -- the right hand side of the comparison operator + */ bool operator>(const LLDate& rhs) const { return rhs < *this; } bool operator<=(const LLDate& rhs) const { return !(rhs < *this); } bool operator>=(const LLDate& rhs) const { return !(*this < rhs); } bool operator!=(const LLDate& rhs) const { return (*this < rhs) || (rhs < *this); } bool operator==(const LLDate& rhs) const { return !(*this != rhs); } - /** - * @brief Compare to epoch UTC. - */ + /** + * @brief Compare to epoch UTC. + */ + + bool isNull() const { return mSecondsSinceEpoch == 0.0; } + bool notNull() const { return mSecondsSinceEpoch != 0.0; } - bool isNull() const { return mSecondsSinceEpoch == 0.0; } - bool notNull() const { return mSecondsSinceEpoch != 0.0; } - private: - F64 mSecondsSinceEpoch; + F64 mSecondsSinceEpoch; }; // Helper function to stream out a date diff --git a/indra/llcommon/lldeadmantimer.cpp b/indra/llcommon/lldeadmantimer.cpp index 830443b956..f9c14d7c24 100644 --- a/indra/llcommon/lldeadmantimer.cpp +++ b/indra/llcommon/lldeadmantimer.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lldeadmantimer.cpp * @brief Simple deadman-switch timer. * @author monty@lindenlab.com @@ -43,146 +43,146 @@ // true true Not allowed // LLDeadmanTimer::LLDeadmanTimer(F64 horizon, bool inc_cpu) - : mHorizon(time_type(llmax(horizon, F64(0.0)) * get_timer_info().mClockFrequency)), - mActive(false), // If true, a timer is running. - mDone(false), // If true, timer has completed and can be read (once) - mStarted(U64L(0)), - mExpires(U64L(0)), - mStopped(U64L(0)), - mCount(U64L(0)), - mIncCPU(inc_cpu), - mUStartCPU(LLProcInfo::time_type(U64L(0))), - mUEndCPU(LLProcInfo::time_type(U64L(0))), - mSStartCPU(LLProcInfo::time_type(U64L(0))), - mSEndCPU(LLProcInfo::time_type(U64L(0))) + : mHorizon(time_type(llmax(horizon, F64(0.0)) * get_timer_info().mClockFrequency)), + mActive(false), // If true, a timer is running. + mDone(false), // If true, timer has completed and can be read (once) + mStarted(U64L(0)), + mExpires(U64L(0)), + mStopped(U64L(0)), + mCount(U64L(0)), + mIncCPU(inc_cpu), + mUStartCPU(LLProcInfo::time_type(U64L(0))), + mUEndCPU(LLProcInfo::time_type(U64L(0))), + mSStartCPU(LLProcInfo::time_type(U64L(0))), + mSEndCPU(LLProcInfo::time_type(U64L(0))) {} // static LLDeadmanTimer::time_type LLDeadmanTimer::getNow() { - return LLTimer::getCurrentClockCount(); + return LLTimer::getCurrentClockCount(); } void LLDeadmanTimer::start(time_type now) { - // *TODO: If active, let's complete an existing timer and save - // the result to the side. I think this will be useful later. - // For now, wipe out anything in progress, start fresh. - - if (! now) - { - now = LLTimer::getCurrentClockCount(); - } - mActive = true; - mDone = false; - mStarted = now; - mExpires = now + mHorizon; - mStopped = now; - mCount = U64L(0); - if (mIncCPU) - { - LLProcInfo::getCPUUsage(mUStartCPU, mSStartCPU); - } + // *TODO: If active, let's complete an existing timer and save + // the result to the side. I think this will be useful later. + // For now, wipe out anything in progress, start fresh. + + if (! now) + { + now = LLTimer::getCurrentClockCount(); + } + mActive = true; + mDone = false; + mStarted = now; + mExpires = now + mHorizon; + mStopped = now; + mCount = U64L(0); + if (mIncCPU) + { + LLProcInfo::getCPUUsage(mUStartCPU, mSStartCPU); + } } void LLDeadmanTimer::stop(time_type now) { - if (! mActive) - { - return; - } - - if (! now) - { - now = getNow(); - } - mStopped = now; - mActive = false; - mDone = true; - if (mIncCPU) - { - LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); - } + if (! mActive) + { + return; + } + + if (! now) + { + now = getNow(); + } + mStopped = now; + mActive = false; + mDone = true; + if (mIncCPU) + { + LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); + } } bool LLDeadmanTimer::isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, - U64 & user_cpu, U64 & sys_cpu) + U64 & user_cpu, U64 & sys_cpu) { - const bool status(isExpired(now, started, stopped, count)); - if (status) - { - user_cpu = U64(mUEndCPU - mUStartCPU); - sys_cpu = U64(mSEndCPU - mSStartCPU); - } - return status; + const bool status(isExpired(now, started, stopped, count)); + if (status) + { + user_cpu = U64(mUEndCPU - mUStartCPU); + sys_cpu = U64(mSEndCPU - mSStartCPU); + } + return status; } - + bool LLDeadmanTimer::isExpired(time_type now, F64 & started, F64 & stopped, U64 & count) { - if (mActive && ! mDone) - { - if (! now) - { - now = getNow(); - } - - if (now >= mExpires) - { - // mStopped from ringBell() is the value we want - mActive = false; - mDone = true; - } - } - - if (! mDone) - { - return false; - } - - started = mStarted * get_timer_info().mClockFrequencyInv; - stopped = mStopped * get_timer_info().mClockFrequencyInv; - count = mCount; - mDone = false; - - return true; + if (mActive && ! mDone) + { + if (! now) + { + now = getNow(); + } + + if (now >= mExpires) + { + // mStopped from ringBell() is the value we want + mActive = false; + mDone = true; + } + } + + if (! mDone) + { + return false; + } + + started = mStarted * get_timer_info().mClockFrequencyInv; + stopped = mStopped * get_timer_info().mClockFrequencyInv; + count = mCount; + mDone = false; + + return true; } - + void LLDeadmanTimer::ringBell(time_type now, unsigned int count) { - if (! mActive) - { - return; - } - - if (! now) - { - now = getNow(); - } - - if (now >= mExpires) - { - // Timer has expired, this event will be dropped - mActive = false; - mDone = true; - } - else - { - // Timer renewed, keep going - mStopped = now; - mExpires = now + mHorizon; - mCount += count; - if (mIncCPU) - { - LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); - } - } - - return; + if (! mActive) + { + return; + } + + if (! now) + { + now = getNow(); + } + + if (now >= mExpires) + { + // Timer has expired, this event will be dropped + mActive = false; + mDone = true; + } + else + { + // Timer renewed, keep going + mStopped = now; + mExpires = now + mHorizon; + mCount += count; + if (mIncCPU) + { + LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); + } + } + + return; } diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h index 980976e176..3f10420d41 100644 --- a/indra/llcommon/lldeadmantimer.h +++ b/indra/llcommon/lldeadmantimer.h @@ -1,4 +1,4 @@ -/** +/** * @file lldeadmantimer.h * @brief Interface to a simple event timer with a deadman's switch * @author monty@lindenlab.com @@ -25,8 +25,8 @@ * $/LicenseInfo$ */ -#ifndef LL_DEADMANTIMER_H -#define LL_DEADMANTIMER_H +#ifndef LL_DEADMANTIMER_H +#define LL_DEADMANTIMER_H #include "linden_common.h" @@ -78,137 +78,137 @@ class LL_COMMON_API LLDeadmanTimer { public: - /// Public types - - /// Low-level time type chosen for compatibility with - /// LLTimer::getCurrentClockCount() which is the basis - /// of time operations in this class. This is likely - /// to change in a future version in a move to TSC-based - /// timing. - typedef U64 time_type; - + /// Public types + + /// Low-level time type chosen for compatibility with + /// LLTimer::getCurrentClockCount() which is the basis + /// of time operations in this class. This is likely + /// to change in a future version in a move to TSC-based + /// timing. + typedef U64 time_type; + public: - /// Construct and initialize an LLDeadmanTimer - /// - /// @param horizon Time, in seconds, after the last @see ringBell() - /// call at which point the timer will consider itself - /// expired. - /// - /// @param inc_cpu If true, gather system and user cpu stats while - /// running the timer. This does require more syscalls - /// during updates. If false, cpu usage data isn't - /// collected and will be zero if queried. - LLDeadmanTimer(F64 horizon, bool inc_cpu); - - ~LLDeadmanTimer() - {} - + /// Construct and initialize an LLDeadmanTimer + /// + /// @param horizon Time, in seconds, after the last @see ringBell() + /// call at which point the timer will consider itself + /// expired. + /// + /// @param inc_cpu If true, gather system and user cpu stats while + /// running the timer. This does require more syscalls + /// during updates. If false, cpu usage data isn't + /// collected and will be zero if queried. + LLDeadmanTimer(F64 horizon, bool inc_cpu); + + ~LLDeadmanTimer() + {} + private: - LLDeadmanTimer(const LLDeadmanTimer &); // Not defined - void operator=(const LLDeadmanTimer &); // Not defined + LLDeadmanTimer(const LLDeadmanTimer &); // Not defined + void operator=(const LLDeadmanTimer &); // Not defined public: - /// Get the current time. Zero-basis for this time - /// representation is not defined and is different on - /// different platforms. Do not attempt to compute - /// negative times relative to the first value returned, - /// there may not be enough 'front porch' on the range - /// to prevent wraparound. - /// - /// Note: Implementation is expected to change in a - /// future release as well. - /// - static time_type getNow(); - - /// Begin timing. If the timer is already active, it is reset - /// and timing begins now. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - void start(time_type now); - - /// End timing. Actively declare the end of the event independent - /// of the deadman's switch operation. @see isExpired() will return - /// true and appropriate values will be returned. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - void stop(time_type now); - - /// Declare that something interesting happened. This has two - /// effects on an unexpired-timer. 1) The expiration time - /// is extended for 'horizon' seconds after the 'now' value. - /// 2) An internal counter associated with the event is incremented - /// by the @ref count parameter. This count is returned via the - /// @see isExpired() method. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - /// @param count Count of events to be associated with - /// this bell ringing. - /// - void ringBell(time_type now, unsigned int count); - - /// Checks the status of the timer. If the timer has expired, - /// also returns various timer-related stats. Unlike ringBell(), - /// does not extend the horizon, it only checks for expiration. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - /// @param started If expired, the starting time of the event is - /// returned to the caller via this reference. - /// - /// @param stopped If expired, the ending time of the event is - /// returned to the caller via this reference. - /// Ending time will be that provided in the - /// stop() method or the last ringBell() call - /// leading to expiration, whichever (stop() call - /// or notice of expiration) happened first. - /// - /// @param count If expired, the number of ringBell() calls - /// made prior to expiration. - /// - /// @param user_cpu Amount of CPU spent in user mode by the process - /// during the event. Value in microseconds and will - /// read zero if not enabled by the constructor. - /// - /// @param sys_cpu Amount of CPU spent in system mode by the process. - /// - /// @return true if the timer has expired, false otherwise. - /// If true, it also returns the started, - /// stopped and count values otherwise these are - /// left unchanged. - /// - bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, - U64 & user_cpu, U64 & sys_cpu); - - /// Identical to the six-arugment form except it does without the - /// CPU time return if the caller isn't interested in it. - bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count); + /// Get the current time. Zero-basis for this time + /// representation is not defined and is different on + /// different platforms. Do not attempt to compute + /// negative times relative to the first value returned, + /// there may not be enough 'front porch' on the range + /// to prevent wraparound. + /// + /// Note: Implementation is expected to change in a + /// future release as well. + /// + static time_type getNow(); + + /// Begin timing. If the timer is already active, it is reset + /// and timing begins now. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + void start(time_type now); + + /// End timing. Actively declare the end of the event independent + /// of the deadman's switch operation. @see isExpired() will return + /// true and appropriate values will be returned. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + void stop(time_type now); + + /// Declare that something interesting happened. This has two + /// effects on an unexpired-timer. 1) The expiration time + /// is extended for 'horizon' seconds after the 'now' value. + /// 2) An internal counter associated with the event is incremented + /// by the @ref count parameter. This count is returned via the + /// @see isExpired() method. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + /// @param count Count of events to be associated with + /// this bell ringing. + /// + void ringBell(time_type now, unsigned int count); + + /// Checks the status of the timer. If the timer has expired, + /// also returns various timer-related stats. Unlike ringBell(), + /// does not extend the horizon, it only checks for expiration. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + /// @param started If expired, the starting time of the event is + /// returned to the caller via this reference. + /// + /// @param stopped If expired, the ending time of the event is + /// returned to the caller via this reference. + /// Ending time will be that provided in the + /// stop() method or the last ringBell() call + /// leading to expiration, whichever (stop() call + /// or notice of expiration) happened first. + /// + /// @param count If expired, the number of ringBell() calls + /// made prior to expiration. + /// + /// @param user_cpu Amount of CPU spent in user mode by the process + /// during the event. Value in microseconds and will + /// read zero if not enabled by the constructor. + /// + /// @param sys_cpu Amount of CPU spent in system mode by the process. + /// + /// @return true if the timer has expired, false otherwise. + /// If true, it also returns the started, + /// stopped and count values otherwise these are + /// left unchanged. + /// + bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, + U64 & user_cpu, U64 & sys_cpu); + + /// Identical to the six-arugment form except it does without the + /// CPU time return if the caller isn't interested in it. + bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count); protected: - time_type mHorizon; - bool mActive; - bool mDone; - time_type mStarted; - time_type mExpires; - time_type mStopped; - time_type mCount; - - const bool mIncCPU; // Include CPU metrics in timer - LLProcInfo::time_type mUStartCPU; - LLProcInfo::time_type mUEndCPU; - LLProcInfo::time_type mSStartCPU; - LLProcInfo::time_type mSEndCPU; + time_type mHorizon; + bool mActive; + bool mDone; + time_type mStarted; + time_type mExpires; + time_type mStopped; + time_type mCount; + + const bool mIncCPU; // Include CPU metrics in timer + LLProcInfo::time_type mUStartCPU; + LLProcInfo::time_type mUEndCPU; + LLProcInfo::time_type mSStartCPU; + LLProcInfo::time_type mSEndCPU; }; - -#endif // LL_DEADMANTIMER_H + +#endif // LL_DEADMANTIMER_H diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index 4e25001fff..0ba756d472 100644 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -1,25 +1,25 @@ -/** +/** * @file lldefs.h * @brief Various generic constant definitions. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,73 +31,73 @@ #include <type_traits> // Often used array indices -const U32 VX = 0; -const U32 VY = 1; -const U32 VZ = 2; -const U32 VW = 3; -const U32 VS = 3; - -const U32 VRED = 0; -const U32 VGREEN = 1; -const U32 VBLUE = 2; -const U32 VALPHA = 3; - -const U32 INVALID_DIRECTION = 0xFFFFFFFF; -const U32 EAST = 0; -const U32 NORTH = 1; -const U32 WEST = 2; -const U32 SOUTH = 3; - -const U32 NORTHEAST = 4; -const U32 NORTHWEST = 5; -const U32 SOUTHWEST = 6; -const U32 SOUTHEAST = 7; -const U32 MIDDLE = 8; - -const U8 EAST_MASK = 0x1<<EAST; -const U8 NORTH_MASK = 0x1<<NORTH; -const U8 WEST_MASK = 0x1<<WEST; -const U8 SOUTH_MASK = 0x1<<SOUTH; - -const U8 NORTHEAST_MASK = NORTH_MASK | EAST_MASK; -const U8 NORTHWEST_MASK = NORTH_MASK | WEST_MASK; -const U8 SOUTHWEST_MASK = SOUTH_MASK | WEST_MASK; -const U8 SOUTHEAST_MASK = SOUTH_MASK | EAST_MASK; +const U32 VX = 0; +const U32 VY = 1; +const U32 VZ = 2; +const U32 VW = 3; +const U32 VS = 3; + +const U32 VRED = 0; +const U32 VGREEN = 1; +const U32 VBLUE = 2; +const U32 VALPHA = 3; + +const U32 INVALID_DIRECTION = 0xFFFFFFFF; +const U32 EAST = 0; +const U32 NORTH = 1; +const U32 WEST = 2; +const U32 SOUTH = 3; + +const U32 NORTHEAST = 4; +const U32 NORTHWEST = 5; +const U32 SOUTHWEST = 6; +const U32 SOUTHEAST = 7; +const U32 MIDDLE = 8; + +const U8 EAST_MASK = 0x1<<EAST; +const U8 NORTH_MASK = 0x1<<NORTH; +const U8 WEST_MASK = 0x1<<WEST; +const U8 SOUTH_MASK = 0x1<<SOUTH; + +const U8 NORTHEAST_MASK = NORTH_MASK | EAST_MASK; +const U8 NORTHWEST_MASK = NORTH_MASK | WEST_MASK; +const U8 SOUTHWEST_MASK = SOUTH_MASK | WEST_MASK; +const U8 SOUTHEAST_MASK = SOUTH_MASK | EAST_MASK; const U32 gDirOpposite[8] = {2, 3, 0, 1, 6, 7, 4, 5}; const U32 gDirAdjacent[8][2] = { - {4, 7}, - {4, 5}, - {5, 6}, - {6, 7}, - {0, 1}, - {1, 2}, - {2, 3}, - {0, 3} - }; + {4, 7}, + {4, 5}, + {5, 6}, + {6, 7}, + {0, 1}, + {1, 2}, + {2, 3}, + {0, 3} + }; // Magnitude along the x and y axis const S32 gDirAxes[8][2] = { - { 1, 0}, // east - { 0, 1}, // north - {-1, 0}, // west - { 0,-1}, // south - { 1, 1}, // ne - {-1, 1}, // nw - {-1,-1}, // sw - { 1,-1}, // se - }; - -const S32 gDirMasks[8] = { - EAST_MASK, - NORTH_MASK, - WEST_MASK, - SOUTH_MASK, - NORTHEAST_MASK, - NORTHWEST_MASK, - SOUTHWEST_MASK, - SOUTHEAST_MASK - }; + { 1, 0}, // east + { 0, 1}, // north + {-1, 0}, // west + { 0,-1}, // south + { 1, 1}, // ne + {-1, 1}, // nw + {-1,-1}, // sw + { 1,-1}, // se + }; + +const S32 gDirMasks[8] = { + EAST_MASK, + NORTH_MASK, + WEST_MASK, + SOUTH_MASK, + NORTHEAST_MASK, + NORTHWEST_MASK, + SOUTHWEST_MASK, + SOUTHEAST_MASK + }; // Sides of a box... // . Z __.Y @@ -109,21 +109,21 @@ const S32 gDirMasks[8] = { // / | /| -3- / | 5 = TOP_SIDE = +z // +------------------+ | 6 = BOTTOM_SIDE = -z // | | | / | | -// | |/| | / | |/| -// | 2 | | *-------|-1--------> X -// |/| | -4- |/| | +// | |/| | / | |/| +// | 2 | | *-------|-1--------> X +// |/| | -4- |/| | // | +----|---------|---+ // | / / | / // | / -6- | / -// |/ / |/ +// |/ / |/ // +------------------+ -const U32 NO_SIDE = 0; -const U32 FRONT_SIDE = 1; -const U32 BACK_SIDE = 2; -const U32 LEFT_SIDE = 3; -const U32 RIGHT_SIDE = 4; -const U32 TOP_SIDE = 5; -const U32 BOTTOM_SIDE = 6; +const U32 NO_SIDE = 0; +const U32 FRONT_SIDE = 1; +const U32 BACK_SIDE = 2; +const U32 LEFT_SIDE = 3; +const U32 RIGHT_SIDE = 4; +const U32 TOP_SIDE = 5; +const U32 BOTTOM_SIDE = 6; const U8 LL_SOUND_FLAG_NONE = 0x0; const U8 LL_SOUND_FLAG_LOOP = 1<<0; @@ -141,17 +141,17 @@ const U8 LL_SOUND_FLAG_SYNC_MASK = LL_SOUND_FLAG_SYNC_MASTER | LL_SOUND_FLAG_SYN // DO NOT CHANGE. // -------------- // -const U32 LL_MAX_PATH = 1024; // buffer size of maximum path + filename string length +const U32 LL_MAX_PATH = 1024; // buffer size of maximum path + filename string length // For strings we send in messages -const U32 STD_STRING_BUF_SIZE = 255; // Buffer size -const U32 STD_STRING_STR_LEN = 254; // Length of the string (not including \0) +const U32 STD_STRING_BUF_SIZE = 255; // Buffer size +const U32 STD_STRING_STR_LEN = 254; // Length of the string (not including \0) // *NOTE: This value is used as hard-coded numbers in scanf() variants. // DO NOT CHANGE. -const U32 MAX_STRING = STD_STRING_BUF_SIZE; // Buffer size +const U32 MAX_STRING = STD_STRING_BUF_SIZE; // Buffer size -const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luck +const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luck // C++ is our friend. . . use template functions to make life easier! @@ -176,7 +176,7 @@ inline auto llmax(T data) return data; } -template <typename T0, typename T1, typename... Ts> +template <typename T0, typename T1, typename... Ts> inline auto llmax(T0 d0, T1 d1, Ts... rest) { auto maxrest = llmax(d1, rest...); @@ -190,44 +190,44 @@ inline auto llmin(T data) return data; } -template <typename T0, typename T1, typename... Ts> +template <typename T0, typename T1, typename... Ts> inline auto llmin(T0 d0, T1 d1, Ts... rest) { auto minrest = llmin(d1, rest...); return (d0 < minrest) ? d0 : minrest; } -template <typename A, typename MIN, typename MAX> +template <typename A, typename MIN, typename MAX> inline A llclamp(A a, MIN minval, MAX maxval) { - A aminval{ static_cast<A>(minval) }, amaxval{ static_cast<A>(maxval) }; - if ( a < aminval ) - { - return aminval; - } - else if ( a > amaxval ) - { - return amaxval; - } - return a; + A aminval{ static_cast<A>(minval) }, amaxval{ static_cast<A>(maxval) }; + if ( a < aminval ) + { + return aminval; + } + else if ( a > amaxval ) + { + return amaxval; + } + return a; } -template <class LLDATATYPE> +template <class LLDATATYPE> inline LLDATATYPE llclampf(LLDATATYPE a) { - return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(1)); + return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(1)); } -template <class LLDATATYPE> +template <class LLDATATYPE> inline LLDATATYPE llclampb(LLDATATYPE a) { - return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(255)); + return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(255)); } -template <class LLDATATYPE> +template <class LLDATATYPE> inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs) { - std::swap(lhs, rhs); + std::swap(lhs, rhs); } #endif // LL_LLDEFS_H diff --git a/indra/llcommon/lldependencies.cpp b/indra/llcommon/lldependencies.cpp index db546c5c3b..dec0748374 100644 --- a/indra/llcommon/lldependencies.cpp +++ b/indra/llcommon/lldependencies.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-17 * @brief Implementation for lldependencies. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h index 950af4a4ad..47b6fedc7d 100644 --- a/indra/llcommon/lldependencies.h +++ b/indra/llcommon/lldependencies.h @@ -8,21 +8,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -177,7 +177,7 @@ struct LLDependenciesEmpty * values such as NULL or 0 rather than having to write * LLDependenciesEmpty(). */ - LLDependenciesEmpty(void*) {} + LLDependenciesEmpty(void*) {} }; /** @@ -209,7 +209,7 @@ class LLDependencies: public LLDependenciesBase before(before_) {} NODE node; - dep_set after, before; + dep_set after, before; }; typedef std::map<KEY, DepNode> DepNodeMap; typedef typename DepNodeMap::value_type DepNodeMapEntry; @@ -239,7 +239,7 @@ public: * NODE& reference. * * @note - * Actual dependency analysis is deferred to the sort() method, so + * Actual dependency analysis is deferred to the sort() method, so * you can add an arbitrary number of nodes without incurring analysis * overhead for each. The flip side of this is that add()ing nodes that * define a cycle leaves this object in a state in which sort() will @@ -598,7 +598,7 @@ public: return sorted_range(begin, end); } - using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const; + using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const; /// Override base-class describe() with actual implementation virtual std::ostream& describe(std::ostream& out, bool full=true) const diff --git a/indra/llcommon/lldepthstack.h b/indra/llcommon/lldepthstack.h index b65840d342..66a7a4ce15 100644 --- a/indra/llcommon/lldepthstack.h +++ b/indra/llcommon/lldepthstack.h @@ -1,25 +1,25 @@ -/** +/** * @file lldepthstack.h * @brief Declaration of the LLDepthStack class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,65 +32,65 @@ template <class DATA_TYPE> class LLDepthStack { private: - std::deque<DATA_TYPE*> mStack; - U32 mCurrentDepth; - U32 mMaxDepth; + std::deque<DATA_TYPE*> mStack; + U32 mCurrentDepth; + U32 mMaxDepth; public: - LLDepthStack() - : mCurrentDepth(0), mMaxDepth(0) - {} + LLDepthStack() + : mCurrentDepth(0), mMaxDepth(0) + {} + + void setDepth(U32 depth) + { + mMaxDepth = depth; + } + + U32 getDepth(void) const + { + return mCurrentDepth; + } - void setDepth(U32 depth) - { - mMaxDepth = depth; - } + void push(DATA_TYPE *data) + { + if (mCurrentDepth < mMaxDepth) + { + mStack.push_back(data); + mCurrentDepth++; + } + else + { + // the last item falls off stack and is deleted + if (!mStack.empty()) + { + mStack.pop_front(); + } + mStack.push_back(data); + } + } - U32 getDepth(void) const - { - return mCurrentDepth; - } + DATA_TYPE *pop() + { + DATA_TYPE *tempp = NULL; + if (!mStack.empty()) + { + tempp = mStack.back(); + mStack.pop_back(); + mCurrentDepth--; + } + return tempp; + } - void push(DATA_TYPE *data) - { - if (mCurrentDepth < mMaxDepth) - { - mStack.push_back(data); - mCurrentDepth++; - } - else - { - // the last item falls off stack and is deleted - if (!mStack.empty()) - { - mStack.pop_front(); - } - mStack.push_back(data); - } - } - - DATA_TYPE *pop() - { - DATA_TYPE *tempp = NULL; - if (!mStack.empty()) - { - tempp = mStack.back(); - mStack.pop_back(); - mCurrentDepth--; - } - return tempp; - } - - DATA_TYPE *check() - { - return mStack.empty() ? NULL : mStack.back(); - } + DATA_TYPE *check() + { + return mStack.empty() ? NULL : mStack.back(); + } - void removeAllNodes() - { - mCurrentDepth = 0; - mStack.clear(); - } + void removeAllNodes() + { + mCurrentDepth = 0; + mStack.clear(); + } }; #endif diff --git a/indra/llcommon/lldictionary.cpp b/indra/llcommon/lldictionary.cpp index e16c35ed6a..1970aa58f2 100644 --- a/indra/llcommon/lldictionary.cpp +++ b/indra/llcommon/lldictionary.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldictionary.cpp * @brief Lldictionary class header file * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,16 +32,16 @@ // Define in .cpp file to prevent header include of llstring.h LLDictionaryEntry::LLDictionaryEntry(const std::string &name) -: mName(name) +: mName(name) { - mNameCapitalized = mName; - LLStringUtil::replaceChar(mNameCapitalized, '-', ' '); - LLStringUtil::replaceChar(mNameCapitalized, '_', ' '); - for (U32 i=0; i < mNameCapitalized.size(); i++) - { - if (i == 0 || mNameCapitalized[i-1] == ' ') // don't change ordering of this statement or crash - { - mNameCapitalized[i] = toupper(mNameCapitalized[i]); - } - } + mNameCapitalized = mName; + LLStringUtil::replaceChar(mNameCapitalized, '-', ' '); + LLStringUtil::replaceChar(mNameCapitalized, '_', ' '); + for (U32 i=0; i < mNameCapitalized.size(); i++) + { + if (i == 0 || mNameCapitalized[i-1] == ' ') // don't change ordering of this statement or crash + { + mNameCapitalized[i] = toupper(mNameCapitalized[i]); + } + } } diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h index 18664e340e..9c399057ae 100644 --- a/indra/llcommon/lldictionary.h +++ b/indra/llcommon/lldictionary.h @@ -1,25 +1,25 @@ -/** +/** * @file lldictionary.h * @brief Lldictionary class header file * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,64 +34,64 @@ struct LL_COMMON_API LLDictionaryEntry { - LLDictionaryEntry(const std::string &name); - virtual ~LLDictionaryEntry() {} - const std::string mName; - std::string mNameCapitalized; + LLDictionaryEntry(const std::string &name); + virtual ~LLDictionaryEntry() {} + const std::string mName; + std::string mNameCapitalized; }; template <class Index, class Entry> class LLDictionary : public std::map<Index, Entry *> { public: - typedef std::map<Index, Entry *> map_t; - typedef typename map_t::iterator iterator_t; - typedef typename map_t::const_iterator const_iterator_t; - - LLDictionary() {} - virtual ~LLDictionary() - { - for (iterator_t iter = map_t::begin(); iter != map_t::end(); ++iter) - delete (iter->second); - } + typedef std::map<Index, Entry *> map_t; + typedef typename map_t::iterator iterator_t; + typedef typename map_t::const_iterator const_iterator_t; + + LLDictionary() {} + virtual ~LLDictionary() + { + for (iterator_t iter = map_t::begin(); iter != map_t::end(); ++iter) + delete (iter->second); + } - const Entry *lookup(Index index) const - { - const_iterator_t dictionary_iter = map_t::find(index); - if (dictionary_iter == map_t::end()) return NULL; - return dictionary_iter->second; - } - const Index lookup(const std::string &name) const - { - for (const_iterator_t dictionary_iter = map_t::begin(); - dictionary_iter != map_t::end(); - dictionary_iter++) - { - const Entry *entry = dictionary_iter->second; - if (entry->mName == name) - { - return dictionary_iter->first; - } - } - return notFound(); - } + const Entry *lookup(Index index) const + { + const_iterator_t dictionary_iter = map_t::find(index); + if (dictionary_iter == map_t::end()) return NULL; + return dictionary_iter->second; + } + const Index lookup(const std::string &name) const + { + for (const_iterator_t dictionary_iter = map_t::begin(); + dictionary_iter != map_t::end(); + dictionary_iter++) + { + const Entry *entry = dictionary_iter->second; + if (entry->mName == name) + { + return dictionary_iter->first; + } + } + return notFound(); + } protected: - virtual Index notFound() const - { - // default is to assert - // don't assert -- makes it impossible to work on mesh-development and viewer-development simultaneously - // -- davep 2010.10.29 - //llassert(false); - return Index(-1); - } - void addEntry(Index index, Entry *entry) - { - if (!this->emplace(index, entry).second) - { - LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL; - } - } + virtual Index notFound() const + { + // default is to assert + // don't assert -- makes it impossible to work on mesh-development and viewer-development simultaneously + // -- davep 2010.10.29 + //llassert(false); + return Index(-1); + } + void addEntry(Index index, Entry *entry) + { + if (!this->emplace(index, entry).second) + { + LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL; + } + } }; #endif // LL_LLDICTIONARY_H diff --git a/indra/llcommon/lldoubledispatch.h b/indra/llcommon/lldoubledispatch.h index ce6731e864..c8c566205a 100644 --- a/indra/llcommon/lldoubledispatch.h +++ b/indra/llcommon/lldoubledispatch.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-11-11 * @brief function calls virtual on more than one parameter - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,7 +41,7 @@ * subset of that problem: function calls which accept two parameters, and * select which particular function to call depending on the dynamic type of * both. - * + * * Scott Meyers, in More Effective C++ (Item 31), talks about some of the perils * and pitfalls lurking down this pathway. He discusses and dismisses the * straightforward approaches of using single-dispatch virtual functions twice, @@ -50,17 +50,17 @@ * look up the actual types of both parameters (he uses the classes' string names, * via typeid(param).name()) to obtain a pointer to a free (non-member) function * that will accept this pair of parameters. - * + * * He does point out that his approach doesn't handle inheritance. If you have a * registry entry for SpaceShip, and you have in hand a MilitaryShip (subclass of * SpaceShip) and an Asteroid, you'd like to call the function appropriate for * SpaceShips and Asteroids -- but alas, his lookup fails because the class name * for your MilitaryShip subclass isn't in the registry. - * + * * This class extends his idea to build a registry whose entries can examine the * dynamic type of the parameter in a more flexible way -- using dynamic_cast<> * -- thereby supporting inheritance relationships. - * + * * Of course we must allow for the ambiguity this permits. We choose to use a * sequence container rather than a map, and require that the client code * specify the order in which dispatch-table entries should be searched. The @@ -69,7 +69,7 @@ * you catch ErrorBaseClass before you catch ErrorSubclass, then any * ErrorSubclass exceptions thrown by the protected code will always match * ErrorBaseClass, and you will never reach your catch(ErrorSubclass) clause. - * + * * So, in a similar way, if you have a specific routine to process * MilitaryShip and Asteroid, you'd better place that in the table @em before * your more general routine that processes SpaceShip and Asteroid, or else @@ -279,7 +279,7 @@ private: /// Look up the first matching entry. EntryPtr lookup(const ParamBaseType& param1, const ParamBaseType& param2) const { - typename DispatchTable::const_iterator found = find(param1, param2); + typename DispatchTable::const_iterator found = find(param1, param2); if (found != mDispatch.end()) { // Dereferencing the list iterator gets us an EntryPtr diff --git a/indra/llcommon/llendianswizzle.h b/indra/llcommon/llendianswizzle.h index 4c08074a9c..d56eb7be2e 100644 --- a/indra/llcommon/llendianswizzle.h +++ b/indra/llcommon/llendianswizzle.h @@ -1,25 +1,25 @@ -/** +/** * @file llendianswizzle.h * @brief Functions for in-place bit swizzling * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,63 +28,63 @@ #define LL_LLENDIANSWIZZLE_H /* This function is intended to be used for in-place swizzling, particularly after fread() of - binary values from a file. Such as: - - numRead = fread(scale.mV, sizeof(float), 3, fp); - llendianswizzle(scale.mV, sizeof(float), 3); - - It assumes that the values in the file are LITTLE endian, so it's a no-op on a little endian machine. - - It keys off of typesize to do the correct swizzle, so make sure that typesize is the size of the native type. - - 64-bit types are not yet handled. + binary values from a file. Such as: + + numRead = fread(scale.mV, sizeof(float), 3, fp); + llendianswizzle(scale.mV, sizeof(float), 3); + + It assumes that the values in the file are LITTLE endian, so it's a no-op on a little endian machine. + + It keys off of typesize to do the correct swizzle, so make sure that typesize is the size of the native type. + + 64-bit types are not yet handled. */ #ifdef LL_LITTLE_ENDIAN - // little endian is native for most things. - inline void llendianswizzle(void *,int,int) - { - // Nothing to do - } + // little endian is native for most things. + inline void llendianswizzle(void *,int,int) + { + // Nothing to do + } #endif #ifdef LL_BIG_ENDIAN - // big endian requires a bit of work. - inline void llendianswizzle(void *p,int typesize, int count) - { - int i; - switch(typesize) - { - case 2: - { - U16 temp; - for(i=count ;i!=0 ;i--) - { - temp = ((U16*)p)[0]; - ((U16*)p)[0] = ((temp >> 8) & 0x000000FF) | ((temp << 8) & 0x0000FF00); - p = (void*)(((U16*)p) + 1); - } - } - break; - - case 4: - { - U32 temp; - for(i=count; i!=0; i--) - { - temp = ((U32*)p)[0]; - ((U32*)p)[0] = - ((temp >> 24) & 0x000000FF) | - ((temp >> 8) & 0x0000FF00) | - ((temp << 8) & 0x00FF0000) | - ((temp << 24) & 0xFF000000); - p = (void*)(((U32*)p) + 1); - } - } - break; - } - - } + // big endian requires a bit of work. + inline void llendianswizzle(void *p,int typesize, int count) + { + int i; + switch(typesize) + { + case 2: + { + U16 temp; + for(i=count ;i!=0 ;i--) + { + temp = ((U16*)p)[0]; + ((U16*)p)[0] = ((temp >> 8) & 0x000000FF) | ((temp << 8) & 0x0000FF00); + p = (void*)(((U16*)p) + 1); + } + } + break; + + case 4: + { + U32 temp; + for(i=count; i!=0; i--) + { + temp = ((U32*)p)[0]; + ((U32*)p)[0] = + ((temp >> 24) & 0x000000FF) | + ((temp >> 8) & 0x0000FF00) | + ((temp << 8) & 0x00FF0000) | + ((temp << 24) & 0xFF000000); + p = (void*)(((U32*)p) + 1); + } + } + break; + } + + } #endif // Use this when working with a single integral value you want swizzled diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 0f48ce16b2..e4843a88eb 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llerror.cpp * @date December 2006 * @brief error message system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -65,91 +65,91 @@ namespace { #if LL_WINDOWS - void debugger_print(const std::string& s) - { - // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C - // which works just fine under the windows debugger, but can cause users who - // have enabled SEHOP exception chain validation to crash due to interactions - // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 - // - if (IsDebuggerPresent()) - { - // Need UTF16 for Unicode OutputDebugString - // - if (s.size()) - { - OutputDebugString(utf8str_to_utf16str(s).c_str()); - OutputDebugString(TEXT("\n")); - } - } - } + void debugger_print(const std::string& s) + { + // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C + // which works just fine under the windows debugger, but can cause users who + // have enabled SEHOP exception chain validation to crash due to interactions + // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 + // + if (IsDebuggerPresent()) + { + // Need UTF16 for Unicode OutputDebugString + // + if (s.size()) + { + OutputDebugString(utf8str_to_utf16str(s).c_str()); + OutputDebugString(TEXT("\n")); + } + } + } #else - class RecordToSyslog : public LLError::Recorder - { - public: - RecordToSyslog(const std::string& identity) - : mIdentity(identity) - { - openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0); - // we need to set the string from a local copy of the string - // since apparanetly openlog expects the const char* to remain - // valid even after it returns (presumably until closelog) - } - - ~RecordToSyslog() - { - closelog(); - } + class RecordToSyslog : public LLError::Recorder + { + public: + RecordToSyslog(const std::string& identity) + : mIdentity(identity) + { + openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0); + // we need to set the string from a local copy of the string + // since apparanetly openlog expects the const char* to remain + // valid even after it returns (presumably until closelog) + } + + ~RecordToSyslog() + { + closelog(); + } virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x01; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - int syslogPriority = LOG_CRIT; - switch (level) { - case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; - case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break; - case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break; - case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break; - default: syslogPriority = LOG_CRIT; - } - - syslog(syslogPriority, "%s", message.c_str()); - } - private: - std::string mIdentity; - }; + int syslogPriority = LOG_CRIT; + switch (level) { + case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; + case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break; + case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break; + case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break; + default: syslogPriority = LOG_CRIT; + } + + syslog(syslogPriority, "%s", message.c_str()); + } + private: + std::string mIdentity; + }; #endif - class RecordToFile : public LLError::Recorder - { - public: - RecordToFile(const std::string& filename): - mName(filename) - { - mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); - if (!mFile) - { - LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; - } - else - { - if (!LLError::getAlwaysFlush()) - { - mFile.sync_with_stdio(false); - } - } - } - - ~RecordToFile() - { - mFile.close(); - } + class RecordToFile : public LLError::Recorder + { + public: + RecordToFile(const std::string& filename): + mName(filename) + { + mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); + if (!mFile) + { + LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; + } + else + { + if (!LLError::getAlwaysFlush()) + { + mFile.sync_with_stdio(false); + } + } + } + + ~RecordToFile() + { + mFile.close(); + } virtual bool enabled() override { @@ -159,7 +159,7 @@ namespace { return LLError::getEnabledLogTypesMask() & 0x02; #endif } - + bool okay() const { return mFile.good(); } std::string getFilename() const { return mName; } @@ -178,25 +178,25 @@ namespace { } } - private: - const std::string mName; - llofstream mFile; - }; - - - class RecordToStderr : public LLError::Recorder - { - public: - RecordToStderr(bool timestamp) : mUseANSI(checkANSI()) - { + private: + const std::string mName; + llofstream mFile; + }; + + + class RecordToStderr : public LLError::Recorder + { + public: + RecordToStderr(bool timestamp) : mUseANSI(checkANSI()) + { this->showMultiline(true); - } - + } + virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x04; } - + LL_FORCE_INLINE std::string createBoldANSI() { std::string ansi_code; @@ -231,12 +231,12 @@ namespace { return ansi_code; } - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING // The default colors for error, warn and debug are now a bit more pastel - // and easier to read on the default (black) terminal background but you + // and easier to read on the default (black) terminal background but you // now have the option to set the color of each via an environment variables: // LL_ANSI_ERROR_COLOR_CODE (default is red) // LL_ANSI_WARN_COLOR_CODE (default is blue) @@ -256,75 +256,75 @@ namespace { static std::string s_ansi_warn = createANSI(s_ansi_warn_code); // default is blue static std::string s_ansi_debug = createANSI(s_ansi_debug_code); // default is magenta - if (mUseANSI) - { + if (mUseANSI) + { writeANSI((level == LLError::LEVEL_ERROR) ? s_ansi_error : (level == LLError::LEVEL_WARN) ? s_ansi_warn : s_ansi_debug, message); - } + } else { LL_PROFILE_ZONE_NAMED("fprintf"); fprintf(stderr, "%s\n", message.c_str()); } - } - - private: - bool mUseANSI; + } + + private: + bool mUseANSI; LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) - { + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING static std::string s_ansi_bold = createBoldANSI(); // bold text static std::string s_ansi_reset = createResetANSI(); // reset - // ANSI color code escape sequence, message, and reset in one fprintf call + // ANSI color code escape sequence, message, and reset in one fprintf call // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. - fprintf(stderr, "%s%s\n%s", ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); - } - - static bool checkANSI(void) - { - // Check whether it's okay to use ANSI; if stderr is - // a tty then we assume yes. Can be turned off with - // the LL_NO_ANSI_COLOR env var. - return (0 != isatty(2)) && - (NULL == getenv("LL_NO_ANSI_COLOR")); - } - }; - - class RecordToFixedBuffer : public LLError::Recorder - { - public: - RecordToFixedBuffer(LLLineBuffer* buffer) + fprintf(stderr, "%s%s\n%s", ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); + } + + static bool checkANSI(void) + { + // Check whether it's okay to use ANSI; if stderr is + // a tty then we assume yes. Can be turned off with + // the LL_NO_ANSI_COLOR env var. + return (0 != isatty(2)) && + (NULL == getenv("LL_NO_ANSI_COLOR")); + } + }; + + class RecordToFixedBuffer : public LLError::Recorder + { + public: + RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { this->showMultiline(true); this->showTags(false); this->showLocation(false); } - + virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x08; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - mBuffer->addLine(message); - } - - private: - LLLineBuffer* mBuffer; - }; + mBuffer->addLine(message); + } + + private: + LLLineBuffer* mBuffer; + }; #if LL_WINDOWS - class RecordToWinDebug: public LLError::Recorder - { - public: - RecordToWinDebug() - { + class RecordToWinDebug: public LLError::Recorder + { + public: + RecordToWinDebug() + { this->showMultiline(true); this->showTags(false); this->showLocation(false); @@ -334,154 +334,154 @@ namespace { { return LLError::getEnabledLogTypesMask() & 0x10; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - debugger_print(message); - } - }; + debugger_print(message); + } + }; #endif } namespace { - std::string className(const std::type_info& type) - { - return LLError::Log::demangle(type.name()); - } + std::string className(const std::type_info& type) + { + return LLError::Log::demangle(type.name()); + } } // anonymous namespace LLError { - std::string Log::demangle(const char* mangled) - { + std::string Log::demangle(const char* mangled) + { #ifdef __GNUC__ - // GCC: type_info::name() returns a mangled class name,st demangle - // passing nullptr, 0 forces allocation of a unique buffer we can free - // fixing MAINT-8724 on OSX 10.14 - int status = -1; - char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status); - std::string result(name ? name : mangled); - free(name); - return result; + // GCC: type_info::name() returns a mangled class name,st demangle + // passing nullptr, 0 forces allocation of a unique buffer we can free + // fixing MAINT-8724 on OSX 10.14 + int status = -1; + char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status); + std::string result(name ? name : mangled); + free(name); + return result; #elif LL_WINDOWS - // Visual Studio: type_info::name() includes the text "class " at the start - std::string name = mangled; - for (const auto& prefix : std::vector<std::string>{ "class ", "struct " }) - { - if (0 == name.compare(0, prefix.length(), prefix)) - { - return name.substr(prefix.length()); - } - } - // huh, that's odd, we should see one or the other prefix -- but don't - // try to log unless logging is already initialized - // in Python, " or ".join(vector) -- but in C++, a PITB - LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" - << name << "'" << LL_ENDL; - return name; + // Visual Studio: type_info::name() includes the text "class " at the start + std::string name = mangled; + for (const auto& prefix : std::vector<std::string>{ "class ", "struct " }) + { + if (0 == name.compare(0, prefix.length(), prefix)) + { + return name.substr(prefix.length()); + } + } + // huh, that's odd, we should see one or the other prefix -- but don't + // try to log unless logging is already initialized + // in Python, " or ".join(vector) -- but in C++, a PITB + LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" + << name << "'" << LL_ENDL; + return name; #else // neither GCC nor Visual Studio - return mangled; + return mangled; #endif - } + } } // LLError namespace { - std::string functionName(const std::string& preprocessor_name) - { + std::string functionName(const std::string& preprocessor_name) + { #if LL_WINDOWS - // DevStudio: the __FUNCTION__ macro string includes - // the type and/or namespace prefixes + // DevStudio: the __FUNCTION__ macro string includes + // the type and/or namespace prefixes - std::string::size_type p = preprocessor_name.rfind(':'); - if (p == std::string::npos) - { - return preprocessor_name; - } - return preprocessor_name.substr(p + 1); + std::string::size_type p = preprocessor_name.rfind(':'); + if (p == std::string::npos) + { + return preprocessor_name; + } + return preprocessor_name.substr(p + 1); #else - return preprocessor_name; + return preprocessor_name; #endif - } - - - class LogControlFile : public LLLiveFile - { - LOG_CLASS(LogControlFile); - - public: - static LogControlFile& fromDirectory(const std::string& user_dir, const std::string& app_dir); - - virtual bool loadFile(); - - private: - LogControlFile(const std::string &filename) - : LLLiveFile(filename) - { } - }; - - LogControlFile& LogControlFile::fromDirectory(const std::string& user_dir, const std::string& app_dir) - { + } + + + class LogControlFile : public LLLiveFile + { + LOG_CLASS(LogControlFile); + + public: + static LogControlFile& fromDirectory(const std::string& user_dir, const std::string& app_dir); + + virtual bool loadFile(); + + private: + LogControlFile(const std::string &filename) + : LLLiveFile(filename) + { } + }; + + LogControlFile& LogControlFile::fromDirectory(const std::string& user_dir, const std::string& app_dir) + { // NB: We have no abstraction in llcommon for the "proper" // delimiter but it turns out that "/" works on all three platforms - - std::string file = user_dir + "/logcontrol-dev.xml"; - - llstat stat_info; - if (LLFile::stat(file, &stat_info)) { - // NB: stat returns non-zero if it can't read the file, for example - // if it doesn't exist. LLFile has no better abstraction for - // testing for file existence. - - file = app_dir + "/logcontrol.xml"; - } - return * new LogControlFile(file); - // NB: This instance is never freed - } - - bool LogControlFile::loadFile() - { - LLSD configuration; - - { - llifstream file(filename().c_str()); - if (!file.is_open()) - { - LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL; - return false; - } - - if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL; - return false; - } - - if (! configuration || !configuration.isMap()) - { - LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" - " content; not changing configuration" - << LL_ENDL; - return false; - } - } - - LLError::configure(configuration); - LL_INFOS("LogControlFile") << "logging reconfigured from " << filename() << LL_ENDL; - return true; - } - - - typedef std::map<std::string, LLError::ELevel> LevelMap; - typedef std::vector<LLError::RecorderPtr> Recorders; - typedef std::vector<LLError::CallSite*> CallSiteVector; + + std::string file = user_dir + "/logcontrol-dev.xml"; + + llstat stat_info; + if (LLFile::stat(file, &stat_info)) { + // NB: stat returns non-zero if it can't read the file, for example + // if it doesn't exist. LLFile has no better abstraction for + // testing for file existence. + + file = app_dir + "/logcontrol.xml"; + } + return * new LogControlFile(file); + // NB: This instance is never freed + } + + bool LogControlFile::loadFile() + { + LLSD configuration; + + { + llifstream file(filename().c_str()); + if (!file.is_open()) + { + LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL; + return false; + } + + if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE) + { + LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL; + return false; + } + + if (! configuration || !configuration.isMap()) + { + LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" + " content; not changing configuration" + << LL_ENDL; + return false; + } + } + + LLError::configure(configuration); + LL_INFOS("LogControlFile") << "logging reconfigured from " << filename() << LL_ENDL; + return true; + } + + + typedef std::map<std::string, LLError::ELevel> LevelMap; + typedef std::vector<LLError::RecorderPtr> Recorders; + typedef std::vector<LLError::CallSite*> CallSiteVector; class SettingsConfig : public LLRefCount { @@ -492,9 +492,9 @@ namespace LLError::ELevel mDefaultLevel; - bool mLogAlwaysFlush; + bool mLogAlwaysFlush; - U32 mEnabledLogTypesMask; + U32 mEnabledLogTypesMask; LevelMap mFunctionLevelMap; LevelMap mClassLevelMap; @@ -539,34 +539,34 @@ namespace mRecorders.clear(); } - class Globals - { + class Globals + { public: static Globals* getInstance(); protected: - Globals(); - public: - std::string mFatalMessage; + Globals(); + public: + std::string mFatalMessage; - void addCallSite(LLError::CallSite&); - void invalidateCallSites(); + void addCallSite(LLError::CallSite&); + void invalidateCallSites(); SettingsConfigPtr getSettingsConfig(); void resetSettingsConfig(); LLError::SettingsStoragePtr saveAndResetSettingsConfig(); void restore(LLError::SettingsStoragePtr pSettingsStorage); - private: - CallSiteVector callSites; + private: + CallSiteVector callSites; SettingsConfigPtr mSettingsConfig; - }; + }; - Globals::Globals() - : - callSites(), + Globals::Globals() + : + callSites(), mSettingsConfig(new SettingsConfig()) - { - } + { + } Globals* Globals::getInstance() @@ -579,20 +579,20 @@ namespace return &inst; } - void Globals::addCallSite(LLError::CallSite& site) - { - callSites.push_back(&site); - } - - void Globals::invalidateCallSites() - { - for (LLError::CallSite* site : callSites) - { + void Globals::addCallSite(LLError::CallSite& site) + { + callSites.push_back(&site); + } + + void Globals::invalidateCallSites() + { + for (LLError::CallSite* site : callSites) + { site->invalidate(); - } - - callSites.clear(); - } + } + + callSites.clear(); + } SettingsConfigPtr Globals::getSettingsConfig() { @@ -622,77 +622,77 @@ namespace namespace LLError { - CallSite::CallSite(ELevel level, - const char* file, - int line, - const std::type_info& class_info, - const char* function, - bool printOnce, - const char** tags, - size_t tag_count) - : mLevel(level), - mFile(file), - mLine(line), - mClassInfo(class_info), - mFunction(function), - mCached(false), - mShouldLog(false), - mPrintOnce(printOnce), - mTags(new const char* [tag_count]), - mTagCount(tag_count) - { - switch (mLevel) - { + CallSite::CallSite(ELevel level, + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool printOnce, + const char** tags, + size_t tag_count) + : mLevel(level), + mFile(file), + mLine(line), + mClassInfo(class_info), + mFunction(function), + mCached(false), + mShouldLog(false), + mPrintOnce(printOnce), + mTags(new const char* [tag_count]), + mTagCount(tag_count) + { + switch (mLevel) + { case LEVEL_DEBUG: mLevelString = "DEBUG"; break; case LEVEL_INFO: mLevelString = "INFO"; break; case LEVEL_WARN: mLevelString = "WARNING"; break; case LEVEL_ERROR: mLevelString = "ERROR"; break; default: mLevelString = "XXX"; break; - }; + }; - mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine); + mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine); #if LL_WINDOWS - // DevStudio: __FUNCTION__ already includes the full class name + // DevStudio: __FUNCTION__ already includes the full class name #else #if LL_LINUX - // gross, but typeid comparison seems to always fail here with gcc4.1 - if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) #else - if (mClassInfo != typeid(NoClassInfo)) + if (mClassInfo != typeid(NoClassInfo)) #endif // LL_LINUX - { - mFunctionString = className(mClassInfo) + "::"; - } + { + mFunctionString = className(mClassInfo) + "::"; + } #endif - mFunctionString += std::string(mFunction); + mFunctionString += std::string(mFunction); - for (int i = 0; i < tag_count; i++) - { + for (int i = 0; i < tag_count; i++) + { if (strchr(tags[i], ' ')) { LL_ERRS() << "Space is not allowed in a log tag at " << mLocationString << LL_ENDL; } - mTags[i] = tags[i]; - } + mTags[i] = tags[i]; + } mTagString.append("#"); // always construct a tag sequence; will be just a single # if no tag - for (size_t i = 0; i < mTagCount; i++) - { - mTagString.append(mTags[i]); + for (size_t i = 0; i < mTagCount; i++) + { + mTagString.append(mTags[i]); mTagString.append("#"); - } - } - - CallSite::~CallSite() - { - delete []mTags; - } - - void CallSite::invalidate() - { - mCached = false; - } + } + } + + CallSite::~CallSite() + { + delete []mTags; + } + + void CallSite::invalidate() + { + mCached = false; + } } namespace @@ -729,202 +729,202 @@ namespace #endif } - bool stderrLogWantsTime() - { + bool stderrLogWantsTime() + { #if LL_WINDOWS - return false; + return false; #else - return true; + return true; #endif - } - - - void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) - { - Globals::getInstance()->resetSettingsConfig(); - - LLError::setDefaultLevel(LLError::LEVEL_INFO); - LLError::setAlwaysFlush(true); - LLError::setEnabledLogTypesMask(0xFFFFFFFF); - LLError::setTimeFunction(LLError::utcTime); - - // log_to_stderr is only false in the unit and integration tests to keep builds quieter - if (log_to_stderr && shouldLogToStderr()) - { - LLError::logToStderr(); - } + } + + + void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) + { + Globals::getInstance()->resetSettingsConfig(); + + LLError::setDefaultLevel(LLError::LEVEL_INFO); + LLError::setAlwaysFlush(true); + LLError::setEnabledLogTypesMask(0xFFFFFFFF); + LLError::setTimeFunction(LLError::utcTime); + + // log_to_stderr is only false in the unit and integration tests to keep builds quieter + if (log_to_stderr && shouldLogToStderr()) + { + LLError::logToStderr(); + } #if LL_WINDOWS - LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); - LLError::addRecorder(recordToWinDebug); + LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); + LLError::addRecorder(recordToWinDebug); #endif - LogControlFile& e = LogControlFile::fromDirectory(user_dir, app_dir); - - // NOTE: We want to explicitly load the file before we add it to the event timer - // that checks for changes to the file. Else, we're not actually loading the file yet, - // and most of the initialization happens without any attention being paid to the - // log control file. Not to mention that when it finally gets checked later, - // all log statements that have been evaluated already become dirty and need to be - // evaluated for printing again. So, make sure to call checkAndReload() - // before addToEventTimer(). - e.checkAndReload(); - e.addToEventTimer(); - } + LogControlFile& e = LogControlFile::fromDirectory(user_dir, app_dir); + + // NOTE: We want to explicitly load the file before we add it to the event timer + // that checks for changes to the file. Else, we're not actually loading the file yet, + // and most of the initialization happens without any attention being paid to the + // log control file. Not to mention that when it finally gets checked later, + // all log statements that have been evaluated already become dirty and need to be + // evaluated for printing again. So, make sure to call checkAndReload() + // before addToEventTimer(). + e.checkAndReload(); + e.addToEventTimer(); + } } namespace LLError { - void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr) - { - commonInit(user_dir, app_dir, log_to_stderr); - } - - void setFatalFunction(const FatalFunction& f) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mCrashFunction = f; - } - - FatalFunction getFatalFunction() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mCrashFunction; - } - - std::string getFatalMessage() - { - return Globals::getInstance()->mFatalMessage; - } - - void setTimeFunction(TimeFunction f) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mTimeFunction = f; - } - - void setDefaultLevel(ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mDefaultLevel = level; - } - - ELevel getDefaultLevel() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mDefaultLevel; - } - - void setAlwaysFlush(bool flush) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mLogAlwaysFlush = flush; - } - - bool getAlwaysFlush() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mLogAlwaysFlush; - } - - void setEnabledLogTypesMask(U32 mask) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mEnabledLogTypesMask = mask; - } - - U32 getEnabledLogTypesMask() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mEnabledLogTypesMask; - } - - void setFunctionLevel(const std::string& function_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mFunctionLevelMap[function_name] = level; - } - - void setClassLevel(const std::string& class_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mClassLevelMap[class_name] = level; - } - - void setFileLevel(const std::string& file_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mFileLevelMap[file_name] = level; - } - - void setTagLevel(const std::string& tag_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mTagLevelMap[tag_name] = level; - } - - LLError::ELevel decodeLevel(std::string name) - { - static LevelMap level_names; - if (level_names.empty()) - { - level_names["ALL"] = LLError::LEVEL_ALL; - level_names["DEBUG"] = LLError::LEVEL_DEBUG; - level_names["INFO"] = LLError::LEVEL_INFO; - level_names["WARN"] = LLError::LEVEL_WARN; - level_names["ERROR"] = LLError::LEVEL_ERROR; - level_names["NONE"] = LLError::LEVEL_NONE; - } - - std::transform(name.begin(), name.end(), name.begin(), toupper); - - LevelMap::const_iterator i = level_names.find(name); - if (i == level_names.end()) - { - LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; - return LLError::LEVEL_INFO; - } - - return i->second; - } + void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr) + { + commonInit(user_dir, app_dir, log_to_stderr); + } + + void setFatalFunction(const FatalFunction& f) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mCrashFunction = f; + } + + FatalFunction getFatalFunction() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mCrashFunction; + } + + std::string getFatalMessage() + { + return Globals::getInstance()->mFatalMessage; + } + + void setTimeFunction(TimeFunction f) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mTimeFunction = f; + } + + void setDefaultLevel(ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mDefaultLevel = level; + } + + ELevel getDefaultLevel() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mDefaultLevel; + } + + void setAlwaysFlush(bool flush) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mLogAlwaysFlush = flush; + } + + bool getAlwaysFlush() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mLogAlwaysFlush; + } + + void setEnabledLogTypesMask(U32 mask) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mEnabledLogTypesMask = mask; + } + + U32 getEnabledLogTypesMask() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mEnabledLogTypesMask; + } + + void setFunctionLevel(const std::string& function_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mFunctionLevelMap[function_name] = level; + } + + void setClassLevel(const std::string& class_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mClassLevelMap[class_name] = level; + } + + void setFileLevel(const std::string& file_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mFileLevelMap[file_name] = level; + } + + void setTagLevel(const std::string& tag_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mTagLevelMap[tag_name] = level; + } + + LLError::ELevel decodeLevel(std::string name) + { + static LevelMap level_names; + if (level_names.empty()) + { + level_names["ALL"] = LLError::LEVEL_ALL; + level_names["DEBUG"] = LLError::LEVEL_DEBUG; + level_names["INFO"] = LLError::LEVEL_INFO; + level_names["WARN"] = LLError::LEVEL_WARN; + level_names["ERROR"] = LLError::LEVEL_ERROR; + level_names["NONE"] = LLError::LEVEL_NONE; + } + + std::transform(name.begin(), name.end(), name.begin(), toupper); + + LevelMap::const_iterator i = level_names.find(name); + if (i == level_names.end()) + { + LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; + return LLError::LEVEL_INFO; + } + + return i->second; + } } namespace { - void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) - { - LLSD::array_const_iterator i, end; - for (i = list.beginArray(), end = list.endArray(); i != end; ++i) - { - map[*i] = level; - } - } + void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) + { + LLSD::array_const_iterator i, end; + for (i = list.beginArray(), end = list.endArray(); i != end; ++i) + { + map[*i] = level; + } + } } namespace LLError { - void configure(const LLSD& config) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - - s->mFunctionLevelMap.clear(); - s->mClassLevelMap.clear(); - s->mFileLevelMap.clear(); - s->mTagLevelMap.clear(); - s->mUniqueLogMessages.clear(); - - setDefaultLevel(decodeLevel(config["default-level"])); + void configure(const LLSD& config) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + + s->mFunctionLevelMap.clear(); + s->mClassLevelMap.clear(); + s->mFileLevelMap.clear(); + s->mTagLevelMap.clear(); + s->mUniqueLogMessages.clear(); + + setDefaultLevel(decodeLevel(config["default-level"])); if (config.has("log-always-flush")) { setAlwaysFlush(config["log-always-flush"]); @@ -933,7 +933,7 @@ namespace LLError { setEnabledLogTypesMask(config["enabled-log-types-mask"].asInteger()); } - + if (config.has("settings") && config["settings"].isArray()) { LLSD sets = config["settings"]; @@ -952,66 +952,66 @@ namespace LLError } } } - } + } } namespace LLError { - Recorder::Recorder() - : mWantsTime(true) + Recorder::Recorder() + : mWantsTime(true) , mWantsTags(true) , mWantsLevel(true) , mWantsLocation(true) , mWantsFunctionName(true) , mWantsMultiline(false) - { - } - - Recorder::~Recorder() - { - } - - bool Recorder::wantsTime() - { - return mWantsTime; - } - - // virtual - bool Recorder::wantsTags() - { - return mWantsTags; - } - - // virtual - bool Recorder::wantsLevel() - { - return mWantsLevel; - } - - // virtual - bool Recorder::wantsLocation() - { - return mWantsLocation; - } - - // virtual - bool Recorder::wantsFunctionName() - { - return mWantsFunctionName; - } - - // virtual - bool Recorder::wantsMultiline() - { - return mWantsMultiline; - } + { + } + + Recorder::~Recorder() + { + } + + bool Recorder::wantsTime() + { + return mWantsTime; + } + + // virtual + bool Recorder::wantsTags() + { + return mWantsTags; + } + + // virtual + bool Recorder::wantsLevel() + { + return mWantsLevel; + } + + // virtual + bool Recorder::wantsLocation() + { + return mWantsLocation; + } + + // virtual + bool Recorder::wantsFunctionName() + { + return mWantsFunctionName; + } + + // virtual + bool Recorder::wantsMultiline() + { + return mWantsMultiline; + } void Recorder::showTime(bool show) { mWantsTime = show; } - + void Recorder::showTags(bool show) { mWantsTags = show; @@ -1037,28 +1037,28 @@ namespace LLError mWantsMultiline = show; } - void addRecorder(RecorderPtr recorder) - { - if (!recorder) - { - return; - } - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); - s->mRecorders.push_back(recorder); - } - - void removeRecorder(RecorderPtr recorder) - { - if (!recorder) - { - return; - } - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); - s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), - s->mRecorders.end()); - } + void addRecorder(RecorderPtr recorder) + { + if (!recorder) + { + return; + } + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + s->mRecorders.push_back(recorder); + } + + void removeRecorder(RecorderPtr recorder) + { + if (!recorder) + { + return; + } + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), + s->mRecorders.end()); + } // Find an entry in SettingsConfig::mRecorders whose RecorderPtr points to // a Recorder subclass of type RECORDER. Return, not a RecorderPtr (which @@ -1127,26 +1127,26 @@ namespace LLError namespace LLError { - void logToFile(const std::string& file_name) - { - // remove any previous Recorder filling this role - removeRecorder<RecordToFile>(); - - if (!file_name.empty()) - { - std::shared_ptr<RecordToFile> recordToFile(new RecordToFile(file_name)); - if (recordToFile->okay()) - { - addRecorder(recordToFile); - } - } - } - - std::string logFileName() - { - auto found = findRecorder<RecordToFile>(); - return found? found->getFilename() : std::string(); - } + void logToFile(const std::string& file_name) + { + // remove any previous Recorder filling this role + removeRecorder<RecordToFile>(); + + if (!file_name.empty()) + { + std::shared_ptr<RecordToFile> recordToFile(new RecordToFile(file_name)); + if (recordToFile->okay()) + { + addRecorder(recordToFile); + } + } + } + + std::string logFileName() + { + auto found = findRecorder<RecordToFile>(); + return found? found->getFilename() : std::string(); + } void logToStderr() { @@ -1157,17 +1157,17 @@ namespace LLError } } - void logToFixedBuffer(LLLineBuffer* fixedBuffer) - { - // remove any previous Recorder filling this role - removeRecorder<RecordToFixedBuffer>(); + void logToFixedBuffer(LLLineBuffer* fixedBuffer) + { + // remove any previous Recorder filling this role + removeRecorder<RecordToFixedBuffer>(); - if (fixedBuffer) - { - RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); - addRecorder(recordToFixedBuffer); - } - } + if (fixedBuffer) + { + RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); + addRecorder(recordToFixedBuffer); + } + } } namespace @@ -1213,40 +1213,40 @@ namespace return out.str(); } - void writeToRecorders(const LLError::CallSite& site, const std::string& message) - { + void writeToRecorders(const LLError::CallSite& site, const std::string& message) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLError::ELevel level = site.mLevel; - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLError::ELevel level = site.mLevel; + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); std::string escaped_message; LLMutexLock lock(&s->mRecorderMutex); - for (LLError::RecorderPtr& r : s->mRecorders) - { + for (LLError::RecorderPtr& r : s->mRecorders) + { if (!r->enabled()) { continue; } - - std::ostringstream message_stream; - if (r->wantsTime() && s->mTimeFunction != NULL) - { - message_stream << s->mTimeFunction(); - } + std::ostringstream message_stream; + + if (r->wantsTime() && s->mTimeFunction != NULL) + { + message_stream << s->mTimeFunction(); + } message_stream << " "; - - if (r->wantsLevel()) + + if (r->wantsLevel()) { - message_stream << site.mLevelString; + message_stream << site.mLevelString; } message_stream << " "; - - if (r->wantsTags()) - { - message_stream << site.mTagString; - } + + if (r->wantsTags()) + { + message_stream << site.mTagString; + } message_stream << " "; if (r->wantsLocation() || level == LLError::LEVEL_ERROR) @@ -1255,10 +1255,10 @@ namespace } message_stream << " "; - if (r->wantsFunctionName()) - { - message_stream << site.mFunctionString; - } + if (r->wantsFunctionName()) + { + message_stream << site.mFunctionString; + } message_stream << " : "; if (r->wantsMultiline()) @@ -1274,250 +1274,250 @@ namespace message_stream << escaped_message; } - r->recordMessage(level, message_stream.str()); - } - } + r->recordMessage(level, message_stream.str()); + } + } } namespace { - // We need a couple different mutexes, but we want to use the same mechanism - // for both. Make getMutex() a template function with different instances - // for different MutexDiscriminator values. - enum MutexDiscriminator - { - LOG_MUTEX, - STACKS_MUTEX - }; - // Some logging calls happen very early in processing -- so early that our - // module-static variables aren't yet initialized. getMutex() wraps a - // function-static LLMutex so that early calls can still have a valid - // LLMutex instance. - template <MutexDiscriminator MTX> - LLMutex* getMutex() - { - // guaranteed to be initialized the first time control reaches here - static LLMutex sMutex; - return &sMutex; - } - - bool checkLevelMap(const LevelMap& map, const std::string& key, - LLError::ELevel& level) - { - bool stop_checking; - LevelMap::const_iterator i = map.find(key); - if (i == map.end()) - { - return stop_checking = false; - } - - level = i->second; - return stop_checking = true; - } - - bool checkLevelMap( const LevelMap& map, - const char *const * keys, - size_t count, - LLError::ELevel& level) - { - bool found_level = false; - - LLError::ELevel tag_level = LLError::LEVEL_NONE; - - for (size_t i = 0; i < count; i++) - { - LevelMap::const_iterator it = map.find(keys[i]); - if (it != map.end()) - { - found_level = true; - tag_level = llmin(tag_level, it->second); - } - } - - if (found_level) - { - level = tag_level; - } - return found_level; - } + // We need a couple different mutexes, but we want to use the same mechanism + // for both. Make getMutex() a template function with different instances + // for different MutexDiscriminator values. + enum MutexDiscriminator + { + LOG_MUTEX, + STACKS_MUTEX + }; + // Some logging calls happen very early in processing -- so early that our + // module-static variables aren't yet initialized. getMutex() wraps a + // function-static LLMutex so that early calls can still have a valid + // LLMutex instance. + template <MutexDiscriminator MTX> + LLMutex* getMutex() + { + // guaranteed to be initialized the first time control reaches here + static LLMutex sMutex; + return &sMutex; + } + + bool checkLevelMap(const LevelMap& map, const std::string& key, + LLError::ELevel& level) + { + bool stop_checking; + LevelMap::const_iterator i = map.find(key); + if (i == map.end()) + { + return stop_checking = false; + } + + level = i->second; + return stop_checking = true; + } + + bool checkLevelMap( const LevelMap& map, + const char *const * keys, + size_t count, + LLError::ELevel& level) + { + bool found_level = false; + + LLError::ELevel tag_level = LLError::LEVEL_NONE; + + for (size_t i = 0; i < count; i++) + { + LevelMap::const_iterator it = map.find(keys[i]); + if (it != map.end()) + { + found_level = true; + tag_level = llmin(tag_level, it->second); + } + } + + if (found_level) + { + level = tag_level; + } + return found_level; + } } namespace LLError { - bool Log::shouldLog(CallSite& site) - { + bool Log::shouldLog(CallSite& site) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5); - if (!lock.isLocked()) - { - return false; - } - - Globals *g = Globals::getInstance(); - SettingsConfigPtr s = g->getSettingsConfig(); - - s->mShouldLogCallCounter++; - - const std::string& class_name = className(site.mClassInfo); - std::string function_name = functionName(site.mFunction); + LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5); + if (!lock.isLocked()) + { + return false; + } + + Globals *g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); + + s->mShouldLogCallCounter++; + + const std::string& class_name = className(site.mClassInfo); + std::string function_name = functionName(site.mFunction); #if LL_LINUX - // gross, but typeid comparison seems to always fail here with gcc4.1 - if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) #else - if (site.mClassInfo != typeid(NoClassInfo)) + if (site.mClassInfo != typeid(NoClassInfo)) #endif // LL_LINUX - { - function_name = class_name + "::" + function_name; - } - - ELevel compareLevel = s->mDefaultLevel; - - // The most specific match found will be used as the log level, - // since the computation short circuits. - // So, in increasing order of importance: - // Default < Tags < File < Class < Function - checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) - || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) - || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) - || (site.mTagCount > 0 - ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) - : false); - - site.mCached = true; - g->addCallSite(site); - return site.mShouldLog = site.mLevel >= compareLevel; - } - - - void Log::flush(const std::ostringstream& out, const CallSite& site) - { + { + function_name = class_name + "::" + function_name; + } + + ELevel compareLevel = s->mDefaultLevel; + + // The most specific match found will be used as the log level, + // since the computation short circuits. + // So, in increasing order of importance: + // Default < Tags < File < Class < Function + checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) + || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) + || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) + || (site.mTagCount > 0 + ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) + : false); + + site.mCached = true; + g->addCallSite(site); + return site.mShouldLog = site.mLevel >= compareLevel; + } + + + void Log::flush(const std::ostringstream& out, const CallSite& site) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5); - if (!lock.isLocked()) - { - return; - } - - Globals* g = Globals::getInstance(); - SettingsConfigPtr s = g->getSettingsConfig(); - - std::string message = out.str(); - - if (site.mPrintOnce) - { - std::ostringstream message_stream; - - std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message); - if (messageIter != s->mUniqueLogMessages.end()) - { - messageIter->second++; - unsigned int num_messages = messageIter->second; - if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) - { - message_stream << "ONCE (" << num_messages << "th time seen): "; - } - else - { - return; - } - } - else - { - message_stream << "ONCE: "; - s->mUniqueLogMessages[message] = 1; - } - message_stream << message; - message = message_stream.str(); - } - - writeToRecorders(site, message); - - if (site.mLevel == LEVEL_ERROR) - { - g->mFatalMessage = message; + LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5); + if (!lock.isLocked()) + { + return; + } + + Globals* g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); + + std::string message = out.str(); + + if (site.mPrintOnce) + { + std::ostringstream message_stream; + + std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message); + if (messageIter != s->mUniqueLogMessages.end()) + { + messageIter->second++; + unsigned int num_messages = messageIter->second; + if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) + { + message_stream << "ONCE (" << num_messages << "th time seen): "; + } + else + { + return; + } + } + else + { + message_stream << "ONCE: "; + s->mUniqueLogMessages[message] = 1; + } + message_stream << message; + message = message_stream.str(); + } + + writeToRecorders(site, message); + + if (site.mLevel == LEVEL_ERROR) + { + g->mFatalMessage = message; if (s->mCrashFunction) { s->mCrashFunction(message); } - } - } + } + } } namespace LLError { - SettingsStoragePtr saveAndResetSettings() - { - return Globals::getInstance()->saveAndResetSettingsConfig(); - } - - void restoreSettings(SettingsStoragePtr pSettingsStorage) - { - return Globals::getInstance()->restore(pSettingsStorage); - } - - std::string removePrefix(std::string& s, const std::string& p) - { - std::string::size_type where = s.find(p); - if (where == std::string::npos) - { - return s; - } - - return std::string(s, where + p.size()); - } - - void replaceChar(std::string& s, char old, char replacement) - { - std::string::size_type i = 0; - std::string::size_type len = s.length(); - for ( ; i < len; i++ ) - { - if (s[i] == old) - { - s[i] = replacement; - } - } - } - - std::string abbreviateFile(const std::string& filePath) - { - std::string f = filePath; + SettingsStoragePtr saveAndResetSettings() + { + return Globals::getInstance()->saveAndResetSettingsConfig(); + } + + void restoreSettings(SettingsStoragePtr pSettingsStorage) + { + return Globals::getInstance()->restore(pSettingsStorage); + } + + std::string removePrefix(std::string& s, const std::string& p) + { + std::string::size_type where = s.find(p); + if (where == std::string::npos) + { + return s; + } + + return std::string(s, where + p.size()); + } + + void replaceChar(std::string& s, char old, char replacement) + { + std::string::size_type i = 0; + std::string::size_type len = s.length(); + for ( ; i < len; i++ ) + { + if (s[i] == old) + { + s[i] = replacement; + } + } + } + + std::string abbreviateFile(const std::string& filePath) + { + std::string f = filePath; #if LL_WINDOWS - replaceChar(f, '\\', '/'); + replaceChar(f, '\\', '/'); #endif - static std::string indra_prefix = "indra/"; - f = removePrefix(f, indra_prefix); + static std::string indra_prefix = "indra/"; + f = removePrefix(f, indra_prefix); #if LL_DARWIN - static std::string newview_prefix = "newview/../"; - f = removePrefix(f, newview_prefix); + static std::string newview_prefix = "newview/../"; + f = removePrefix(f, newview_prefix); #endif - return f; - } - - int shouldLogCallCount() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mShouldLogCallCounter; - } - - std::string utcTime() - { - time_t now = time(NULL); - const size_t BUF_SIZE = 64; - char time_str[BUF_SIZE]; /* Flawfinder: ignore */ - - auto chars = strftime(time_str, BUF_SIZE, - "%Y-%m-%dT%H:%M:%SZ", - gmtime(&now)); - - return chars ? time_str : "time error"; - } + return f; + } + + int shouldLogCallCount() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mShouldLogCallCounter; + } + + std::string utcTime() + { + time_t now = time(NULL); + const size_t BUF_SIZE = 64; + char time_str[BUF_SIZE]; /* Flawfinder: ignore */ + + auto chars = strftime(time_str, BUF_SIZE, + "%Y-%m-%dT%H:%M:%SZ", + gmtime(&now)); + + return chars ? time_str : "time error"; + } } namespace LLError -{ +{ LLCallStacks::StringVector LLCallStacks::sBuffer ; //static @@ -1576,7 +1576,7 @@ namespace LLError LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; for (StringVector::const_reverse_iterator ri(sBuffer.rbegin()), re(sBuffer.rend()); ri != re; ++ri) - { + { LL_INFOS() << (*ri) << LL_ENDL; } LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 6f6b349cf5..6176ce0d1d 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -1,4 +1,4 @@ -/** +/** * @file llerror.h * @date December 2006 * @brief error message system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -79,16 +79,16 @@ const int LL_ERR_NOERR = 0; #define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")" << LL_ENDL -#define llassert_always(func) llassert_always_msg(func, #func) +#define llassert_always(func) llassert_always_msg(func, #func) #ifdef SHOW_ASSERT -#define llassert(func) llassert_always_msg(func, #func) -#define llassert_msg(func, msg) llassert_always_msg(func, msg) -#define llverify(func) llassert_always_msg(func, #func) +#define llassert(func) llassert_always_msg(func, #func) +#define llassert_msg(func, msg) llassert_always_msg(func, msg) +#define llverify(func) llassert_always_msg(func, #func) #else #define llassert(func) #define llassert_msg(func, msg) -#define llverify(func) do {if (func) {}} while(0) +#define llverify(func) do {if (func) {}} while(0) #endif #ifdef LL_WINDOWS @@ -102,59 +102,59 @@ const int LL_ERR_NOERR = 0; /** Error Logging Facility - Information for most users: - - Code can log messages with constructions like this: - - LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id - << " denied due to timeout" << LL_ENDL; - - Messages can be logged to one of four increasing levels of concern, - using one of four "streams": - - LL_DEBUGS("StringTag") - debug messages that are normally suppressed - LL_INFOS("StringTag") - informational messages that are normal shown - LL_WARNS("StringTag") - warning messages that signal a problem - LL_ERRS("StringTag") - error messages that are major, unrecoverable failures - - The later (LL_ERRS("StringTag")) automatically crashes the process after the message - is logged. - - Note that these "streams" are actually #define magic. Rules for use: - * they cannot be used as normal streams, only to start a message - * messages written to them MUST be terminated with LL_ENDL - * between the opening and closing, the << operator is indeed - writing onto a std::ostream, so all conversions and stream - formating are available - - These messages are automatically logged with function name, and (if enabled) - file and line of the message. (Note: Existing messages that already include - the function name don't get name printed twice.) - - If you have a class, adding LOG_CLASS line to the declaration will cause - all messages emitted from member functions (normal and static) to be tagged - with the proper class name as well as the function name: - - class LLFoo - { - LOG_CLASS(LLFoo); - public: - ... - }; - - void LLFoo::doSomething(int i) - { - if (i > 100) - { - LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; - } - ... - } - - will result in messages like: - - WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283 - + Information for most users: + + Code can log messages with constructions like this: + + LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id + << " denied due to timeout" << LL_ENDL; + + Messages can be logged to one of four increasing levels of concern, + using one of four "streams": + + LL_DEBUGS("StringTag") - debug messages that are normally suppressed + LL_INFOS("StringTag") - informational messages that are normal shown + LL_WARNS("StringTag") - warning messages that signal a problem + LL_ERRS("StringTag") - error messages that are major, unrecoverable failures + + The later (LL_ERRS("StringTag")) automatically crashes the process after the message + is logged. + + Note that these "streams" are actually #define magic. Rules for use: + * they cannot be used as normal streams, only to start a message + * messages written to them MUST be terminated with LL_ENDL + * between the opening and closing, the << operator is indeed + writing onto a std::ostream, so all conversions and stream + formating are available + + These messages are automatically logged with function name, and (if enabled) + file and line of the message. (Note: Existing messages that already include + the function name don't get name printed twice.) + + If you have a class, adding LOG_CLASS line to the declaration will cause + all messages emitted from member functions (normal and static) to be tagged + with the proper class name as well as the function name: + + class LLFoo + { + LOG_CLASS(LLFoo); + public: + ... + }; + + void LLFoo::doSomething(int i) + { + if (i > 100) + { + LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; + } + ... + } + + will result in messages like: + + WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283 + the syntax is: <timestamp> SPACE <level> SPACE <tags> SPACE <location> SPACE <function> SPACE COLON SPACE <message> @@ -164,121 +164,121 @@ const int LL_ERR_NOERR = 0; The tags must be a single word (may not contain a space); if more than one tag is specified, they are all surrounded by '#' ( #FooTag#BarTag# ). - Which messages are logged and which are suppressed can be controlled at run - time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml + Which messages are logged and which are suppressed can be controlled at run + time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml A copy of that file named logcontrol-dev.xml can be made in the users personal settings directory; that will override the installed default file. See the logcontrol.xml file or http://wiki.secondlife.com/wiki/Logging_System_Overview for configuration details. - - Lastly, logging is now very efficient in both compiled code and execution - when skipped. There is no need to wrap messages, even debugging ones, in - #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds, - even release. Which means you can use them to help debug even when deployed - to a real grid. + + Lastly, logging is now very efficient in both compiled code and execution + when skipped. There is no need to wrap messages, even debugging ones, in + #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds, + even release. Which means you can use them to help debug even when deployed + to a real grid. */ namespace LLError { - enum ELevel - { - LEVEL_ALL = 0, - // used to indicate that all messages should be logged - - LEVEL_DEBUG = 0, - LEVEL_INFO = 1, - LEVEL_WARN = 2, - LEVEL_ERROR = 3, // used to be called FATAL - - LEVEL_NONE = 4 - // not really a level - // used to indicate that no messages should be logged - }; - // If you change ELevel, please update llvlog() macro below. - - /* Macro support - The classes CallSite and Log are used by the logging macros below. - They are not intended for general use. - */ - - struct CallSite; - - class LL_COMMON_API Log - { - public: - static bool shouldLog(CallSite&); - static void flush(const std::ostringstream&, const CallSite&); - static std::string demangle(const char* mangled); - /// classname<TYPE>() - template <typename T> - static std::string classname() { return demangle(typeid(T).name()); } - /// classname(some_pointer) - template <typename T> - static std::string classname(T* const ptr) { return ptr? demangle(typeid(*ptr).name()) : "nullptr"; } - /// classname(some_reference) - template <typename T> - static std::string classname(const T& obj) { return demangle(typeid(obj).name()); } - }; - - struct LL_COMMON_API CallSite - { - // Represents a specific place in the code where a message is logged - // This is public because it is used by the macros below. It is not - // intended for public use. - CallSite(ELevel level, - const char* file, - int line, - const std::type_info& class_info, - const char* function, - bool print_once, - const char** tags, - size_t tag_count); - - ~CallSite(); + enum ELevel + { + LEVEL_ALL = 0, + // used to indicate that all messages should be logged + + LEVEL_DEBUG = 0, + LEVEL_INFO = 1, + LEVEL_WARN = 2, + LEVEL_ERROR = 3, // used to be called FATAL + + LEVEL_NONE = 4 + // not really a level + // used to indicate that no messages should be logged + }; + // If you change ELevel, please update llvlog() macro below. + + /* Macro support + The classes CallSite and Log are used by the logging macros below. + They are not intended for general use. + */ + + struct CallSite; + + class LL_COMMON_API Log + { + public: + static bool shouldLog(CallSite&); + static void flush(const std::ostringstream&, const CallSite&); + static std::string demangle(const char* mangled); + /// classname<TYPE>() + template <typename T> + static std::string classname() { return demangle(typeid(T).name()); } + /// classname(some_pointer) + template <typename T> + static std::string classname(T* const ptr) { return ptr? demangle(typeid(*ptr).name()) : "nullptr"; } + /// classname(some_reference) + template <typename T> + static std::string classname(const T& obj) { return demangle(typeid(obj).name()); } + }; + + struct LL_COMMON_API CallSite + { + // Represents a specific place in the code where a message is logged + // This is public because it is used by the macros below. It is not + // intended for public use. + CallSite(ELevel level, + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool print_once, + const char** tags, + size_t tag_count); + + ~CallSite(); #ifdef LL_LIBRARY_INCLUDE - bool shouldLog(); + bool shouldLog(); #else // LL_LIBRARY_INCLUDE - bool shouldLog() - { - return mCached - ? mShouldLog - : Log::shouldLog(*this); - } - // this member function needs to be in-line for efficiency + bool shouldLog() + { + return mCached + ? mShouldLog + : Log::shouldLog(*this); + } + // this member function needs to be in-line for efficiency #endif // LL_LIBRARY_INCLUDE - - void invalidate(); - - // these describe the call site and never change - const ELevel mLevel; - const char* const mFile; - const int mLine; - const std::type_info& mClassInfo; - const char* const mFunction; - const char** mTags; - size_t mTagCount; - const bool mPrintOnce; - const char* mLevelString; - std::string mLocationString, - mFunctionString, - mTagString; - bool mCached, - mShouldLog; - - friend class Log; - }; - - - class End { }; - inline std::ostream& operator<<(std::ostream& s, const End&) - { return s; } - // used to indicate the end of a message - - class LL_COMMON_API NoClassInfo { }; - // used to indicate no class info known for logging + + void invalidate(); + + // these describe the call site and never change + const ELevel mLevel; + const char* const mFile; + const int mLine; + const std::type_info& mClassInfo; + const char* const mFunction; + const char** mTags; + size_t mTagCount; + const bool mPrintOnce; + const char* mLevelString; + std::string mLocationString, + mFunctionString, + mTagString; + bool mCached, + mShouldLog; + + friend class Log; + }; + + + class End { }; + inline std::ostream& operator<<(std::ostream& s, const End&) + { return s; } + // used to indicate the end of a message + + class LL_COMMON_API NoClassInfo { }; + // used to indicate no class info known for logging //LLCallStacks keeps track of call stacks and output the call stacks to log file // - //Note: to be simple, efficient and necessary to keep track of correct call stacks, + //Note: to be simple, efficient and necessary to keep track of correct call stacks, //LLCallStacks is designed not to be thread-safe. //so try not to use it in multiple parallel threads at same time. //Used in a single thread at a time is fine. @@ -287,8 +287,8 @@ namespace LLError private: typedef std::vector<std::string> StringVector; static StringVector sBuffer ; - - public: + + public: static void push(const char* function, const int line) ; static void insert(std::ostream& out, const char* function, const int line) ; static void print() ; @@ -326,34 +326,34 @@ namespace LLError }; } -//this is cheaper than llcallstacks if no need to output other variables to call stacks. +//this is cheaper than llcallstacks if no need to output other variables to call stacks. #define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__) #define llcallstacks \ - { \ - std::ostringstream _out; \ - LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \ - _out + { \ + std::ostringstream _out; \ + LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \ + _out #define llcallstacksendl \ - LLError::End(); \ - LLError::LLCallStacks::end(_out) ; \ - } + LLError::End(); \ + LLError::LLCallStacks::end(_out) ; \ + } #define LL_CLEAR_CALLSTACKS() LLError::LLCallStacks::clear() -#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() +#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() /* - Class type information for logging + Class type information for logging */ -#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG - // Declares class to tag logged messages with. - // See top of file for example of how to use this - +#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG + // Declares class to tag logged messages with. + // See top of file for example of how to use this + typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; - // Outside a class declaration, or in class without LOG_CLASS(), this - // typedef causes the messages to not be associated with any class. + // Outside a class declaration, or in class without LOG_CLASS(), this + // typedef causes the messages to not be associated with any class. ///////////////////////////////// // Error Logging Macros @@ -376,34 +376,34 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; #define lllog(level, once, ...) \ do { \ LL_PROFILE_ZONE_NAMED("lllog"); \ - const char* tags[] = {"", ##__VA_ARGS__}; \ - static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \ - lllog_test_() + const char* tags[] = {"", ##__VA_ARGS__}; \ + static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \ + lllog_test_() #define lllog_test_() \ - if (LL_UNLIKELY(_site.shouldLog())) \ - { \ - std::ostringstream _out; \ - _out + if (LL_UNLIKELY(_site.shouldLog())) \ + { \ + std::ostringstream _out; \ + _out #define lllog_site_args_(level, once, tags) \ - level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \ - __FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1 + level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \ + __FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1 //Use this construct if you need to do computation in the middle of a //message: -// -// LL_INFOS("AgentGesture") << "the agent " << agend_id; -// switch (f) -// { -// case FOP_SHRUGS: LL_CONT << "shrugs"; break; -// case FOP_TAPS: LL_CONT << "points at " << who; break; -// case FOP_SAYS: LL_CONT << "says " << message; break; -// } -// LL_CONT << " for " << t << " seconds" << LL_ENDL; -// +// +// LL_INFOS("AgentGesture") << "the agent " << agend_id; +// switch (f) +// { +// case FOP_SHRUGS: LL_CONT << "shrugs"; break; +// case FOP_TAPS: LL_CONT << "points at " << who; break; +// case FOP_SAYS: LL_CONT << "says " << message; break; +// } +// LL_CONT << " for " << t << " seconds" << LL_ENDL; +// //Such computation is done iff the message will be logged. -#define LL_CONT _out +#define LL_CONT _out #define LL_NEWLINE '\n' @@ -426,24 +426,24 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // NEW Macros for debugging, allow the passing of a string tag // Pass comma separated list of tags (currently only supports up to 0, 1, or 2) -#define LL_DEBUGS(...) lllog(LLError::LEVEL_DEBUG, false, ##__VA_ARGS__) -#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, ##__VA_ARGS__) -#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__) -#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__) +#define LL_DEBUGS(...) lllog(LLError::LEVEL_DEBUG, false, ##__VA_ARGS__) +#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, ##__VA_ARGS__) +#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__) +#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__) // alternative to llassert_always that prints explanatory message // note ## token paste operator hack used above will only work in gcc following // a comma and is completely unnecessary in VS since the comma is automatically // suppressed // https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html // https://docs.microsoft.com/en-us/cpp/preprocessor/variadic-macros?view=vs-2015 -#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(__VA_ARGS__) << "(" #exp ")" -#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(__VA_ARGS__) << "(" #exp ")" +#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(__VA_ARGS__) << "(" #exp ")" +#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(__VA_ARGS__) << "(" #exp ")" // Only print the log message once (good for warnings or infos that would otherwise // spam the log file over and over, such as tighter loops). -#define LL_DEBUGS_ONCE(...) lllog(LLError::LEVEL_DEBUG, true, ##__VA_ARGS__) -#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__) -#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) +#define LL_DEBUGS_ONCE(...) lllog(LLError::LEVEL_DEBUG, true, ##__VA_ARGS__) +#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__) +#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) // Use this if you need to pass LLError::ELevel as a variable. #define LL_VLOGS(level, ...) llvlog(level, false, ##__VA_ARGS__) @@ -459,33 +459,33 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // instance for the passed level value. // Compare implementation to lllog() above. #define llvlog(level, once, ...) \ - do { \ - const char* tags[] = {"", ##__VA_ARGS__}; \ - /* Need a static CallSite instance per expected ELevel value. */ \ - /* Since we intend to index this array with the ELevel, */ \ - /* _sites[0] should be ELevel(0), and so on -- avoid using */ \ - /* ELevel symbolic names when initializing -- except for */ \ - /* the last entry, which handles anything beyond the end. */ \ - /* (Commented ELevel value names are from 2016-09-01.) */ \ - /* Passing an ELevel past the end of this array is itself */ \ - /* a fatal error, so ensure the last is LEVEL_ERROR. */ \ - static LLError::CallSite _sites[] = \ - { \ - /* LEVEL_DEBUG */ \ - LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \ - /* LEVEL_INFO */ \ - LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \ - /* LEVEL_WARN */ \ - LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \ - /* LEVEL_ERROR */ \ - LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \ - }; \ - /* Clamp the passed 'level' to at most last entry */ \ - std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \ - (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \ - /* selected CallSite *must* be named _site for LL_ENDL */ \ - LLError::CallSite& _site(_sites[which]); \ - lllog_test_() + do { \ + const char* tags[] = {"", ##__VA_ARGS__}; \ + /* Need a static CallSite instance per expected ELevel value. */ \ + /* Since we intend to index this array with the ELevel, */ \ + /* _sites[0] should be ELevel(0), and so on -- avoid using */ \ + /* ELevel symbolic names when initializing -- except for */ \ + /* the last entry, which handles anything beyond the end. */ \ + /* (Commented ELevel value names are from 2016-09-01.) */ \ + /* Passing an ELevel past the end of this array is itself */ \ + /* a fatal error, so ensure the last is LEVEL_ERROR. */ \ + static LLError::CallSite _sites[] = \ + { \ + /* LEVEL_DEBUG */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \ + /* LEVEL_INFO */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \ + /* LEVEL_WARN */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \ + /* LEVEL_ERROR */ \ + LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \ + }; \ + /* Clamp the passed 'level' to at most last entry */ \ + std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \ + (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \ + /* selected CallSite *must* be named _site for LL_ENDL */ \ + LLError::CallSite& _site(_sites[which]); \ + lllog_test_() /* // Check at run-time whether logging is enabled, without generating output. @@ -510,7 +510,7 @@ LL_ENDL; LL_DEBUGS("SomeTag") performs the locking and map-searching ONCE, then caches the result in a static variable. -*/ +*/ // used by LLERROR_CRASH void crashdriver(void (*)(int*)); diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 77b187a80f..bf5a6df556 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -38,143 +38,143 @@ class LLSD; /* - This is the part of the LLError namespace that manages the messages - produced by the logging. The logging support is defined in llerror.h. - Most files do not need to include this. + This is the part of the LLError namespace that manages the messages + produced by the logging. The logging support is defined in llerror.h. + Most files do not need to include this. - These implementations are in llerror.cpp. + These implementations are in llerror.cpp. */ // Line buffer interface class LLLineBuffer { public: - LLLineBuffer() {}; - virtual ~LLLineBuffer() {}; + LLLineBuffer() {}; + virtual ~LLLineBuffer() {}; - virtual void clear() = 0; // Clear the buffer, and reset it. + virtual void clear() = 0; // Clear the buffer, and reset it. - virtual void addLine(const std::string& utf8line) = 0; + virtual void addLine(const std::string& utf8line) = 0; }; namespace LLError { - LL_COMMON_API void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true); - // resets all logging settings to defaults needed by applicaitons - // logs to stderr and windows debug log - // sets up log configuration from the file logcontrol.xml in dir + LL_COMMON_API void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true); + // resets all logging settings to defaults needed by applicaitons + // logs to stderr and windows debug log + // sets up log configuration from the file logcontrol.xml in dir - /* - Settings that control what is logged. - Setting a level means log messages at that level or above. - */ + /* + Settings that control what is logged. + Setting a level means log messages at that level or above. + */ - LL_COMMON_API void setPrintLocation(bool); - LL_COMMON_API void setDefaultLevel(LLError::ELevel); - LL_COMMON_API ELevel getDefaultLevel(); - LL_COMMON_API void setAlwaysFlush(bool flush); + LL_COMMON_API void setPrintLocation(bool); + LL_COMMON_API void setDefaultLevel(LLError::ELevel); + LL_COMMON_API ELevel getDefaultLevel(); + LL_COMMON_API void setAlwaysFlush(bool flush); LL_COMMON_API bool getAlwaysFlush(); - LL_COMMON_API void setEnabledLogTypesMask(U32 mask); - LL_COMMON_API U32 getEnabledLogTypesMask(); - LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel); - LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel); - LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel); - LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel); - - LL_COMMON_API LLError::ELevel decodeLevel(std::string name); - LL_COMMON_API void configure(const LLSD&); - // the LLSD can configure all of the settings - // usually read automatically from the live errorlog.xml file - - - /* - Control functions. - */ - - typedef boost::function<void(const std::string&)> FatalFunction; - - LL_COMMON_API void setFatalFunction(const FatalFunction&); - // The fatal function will be called after an message of LEVEL_ERROR - // is logged. Note: supressing a LEVEL_ERROR message from being logged - // (by, for example, setting a class level to LEVEL_NONE), will keep - // that message from causing the fatal function to be invoked. - // The passed FatalFunction will be the LAST log function called - // before LL_ERRS crashes its caller. A FatalFunction can throw an - // exception, or call exit(), to bypass the crash. It MUST disrupt the - // flow of control because no caller expects LL_ERRS to return. - - LL_COMMON_API FatalFunction getFatalFunction(); - // Retrieve the previously-set FatalFunction - - LL_COMMON_API std::string getFatalMessage(); - // Retrieve the message last passed to FatalFunction, if any - - /// temporarily override the FatalFunction for the duration of a - /// particular scope, e.g. for unit tests - class LL_COMMON_API OverrideFatalFunction - { - public: - OverrideFatalFunction(const FatalFunction& func): - mPrev(getFatalFunction()) - { - setFatalFunction(func); - } - ~OverrideFatalFunction() - { - setFatalFunction(mPrev); - } - - private: - FatalFunction mPrev; - }; - - typedef std::string (*TimeFunction)(); - LL_COMMON_API std::string utcTime(); - - LL_COMMON_API void setTimeFunction(TimeFunction); - // The function is use to return the current time, formatted for - // display by those error recorders that want the time included. - - - - class LL_COMMON_API Recorder - { - // An object that handles the actual output or error messages. - public: - Recorder(); - virtual ~Recorder(); - - virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; - // use the level for better display, not for filtering - - virtual bool enabled() { return true; } - - bool wantsTime(); - bool wantsTags(); - bool wantsLevel(); - bool wantsLocation(); - bool wantsFunctionName(); - bool wantsMultiline(); - - void showTime(bool show); - void showTags(bool show); - void showLevel(bool show); - void showLocation(bool show); - void showFunctionName(bool show); - void showMultiline(bool show); - - protected: - bool mWantsTime; - bool mWantsTags; - bool mWantsLevel; - bool mWantsLocation; - bool mWantsFunctionName; - bool mWantsMultiline; - }; - - typedef std::shared_ptr<Recorder> RecorderPtr; + LL_COMMON_API void setEnabledLogTypesMask(U32 mask); + LL_COMMON_API U32 getEnabledLogTypesMask(); + LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel); + LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel); + LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel); + LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel); + + LL_COMMON_API LLError::ELevel decodeLevel(std::string name); + LL_COMMON_API void configure(const LLSD&); + // the LLSD can configure all of the settings + // usually read automatically from the live errorlog.xml file + + + /* + Control functions. + */ + + typedef boost::function<void(const std::string&)> FatalFunction; + + LL_COMMON_API void setFatalFunction(const FatalFunction&); + // The fatal function will be called after an message of LEVEL_ERROR + // is logged. Note: supressing a LEVEL_ERROR message from being logged + // (by, for example, setting a class level to LEVEL_NONE), will keep + // that message from causing the fatal function to be invoked. + // The passed FatalFunction will be the LAST log function called + // before LL_ERRS crashes its caller. A FatalFunction can throw an + // exception, or call exit(), to bypass the crash. It MUST disrupt the + // flow of control because no caller expects LL_ERRS to return. + + LL_COMMON_API FatalFunction getFatalFunction(); + // Retrieve the previously-set FatalFunction + + LL_COMMON_API std::string getFatalMessage(); + // Retrieve the message last passed to FatalFunction, if any + + /// temporarily override the FatalFunction for the duration of a + /// particular scope, e.g. for unit tests + class LL_COMMON_API OverrideFatalFunction + { + public: + OverrideFatalFunction(const FatalFunction& func): + mPrev(getFatalFunction()) + { + setFatalFunction(func); + } + ~OverrideFatalFunction() + { + setFatalFunction(mPrev); + } + + private: + FatalFunction mPrev; + }; + + typedef std::string (*TimeFunction)(); + LL_COMMON_API std::string utcTime(); + + LL_COMMON_API void setTimeFunction(TimeFunction); + // The function is use to return the current time, formatted for + // display by those error recorders that want the time included. + + + + class LL_COMMON_API Recorder + { + // An object that handles the actual output or error messages. + public: + Recorder(); + virtual ~Recorder(); + + virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; + // use the level for better display, not for filtering + + virtual bool enabled() { return true; } + + bool wantsTime(); + bool wantsTags(); + bool wantsLevel(); + bool wantsLocation(); + bool wantsFunctionName(); + bool wantsMultiline(); + + void showTime(bool show); + void showTags(bool show); + void showLevel(bool show); + void showLocation(bool show); + void showFunctionName(bool show); + void showMultiline(bool show); + + protected: + bool mWantsTime; + bool mWantsTags; + bool mWantsLevel; + bool mWantsLocation; + bool mWantsFunctionName; + bool mWantsMultiline; + }; + + typedef std::shared_ptr<Recorder> RecorderPtr; /** * Instantiate GenericRecorder with a callable(level, message) to get @@ -197,48 +197,48 @@ namespace LLError CALLABLE mCallable; }; - /** - * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership - * while still ensuring that the allocated memory is eventually freed - */ - LL_COMMON_API void addRecorder(RecorderPtr); - LL_COMMON_API void removeRecorder(RecorderPtr); - // each error message is passed to each recorder via recordMessage() - /** - * Call addGenericRecorder() with a callable(level, message) to get - * control on every log message without having to code an explicit - * Recorder subclass. Save the returned RecorderPtr if you later want to - * call removeRecorder(). - */ - template <typename CALLABLE> - RecorderPtr addGenericRecorder(const CALLABLE& callable) - { - RecorderPtr ptr{ new GenericRecorder<CALLABLE>(callable) }; - addRecorder(ptr); - return ptr; - } - - LL_COMMON_API void logToFile(const std::string& filename); - LL_COMMON_API void logToStderr(); - LL_COMMON_API void logToFixedBuffer(LLLineBuffer*); - // Utilities to add recorders for logging to a file or a fixed buffer - // A second call to the same function will remove the logger added - // with the first. - // Passing the empty string or NULL to just removes any prior. - LL_COMMON_API std::string logFileName(); - // returns name of current logging file, empty string if none - - - /* - Utilities for use by the unit tests of LLError itself. - */ - - typedef LLPointer<LLRefCount> SettingsStoragePtr; - LL_COMMON_API SettingsStoragePtr saveAndResetSettings(); - LL_COMMON_API void restoreSettings(SettingsStoragePtr pSettingsStorage); - - LL_COMMON_API std::string abbreviateFile(const std::string& filePath); - LL_COMMON_API int shouldLogCallCount(); + /** + * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership + * while still ensuring that the allocated memory is eventually freed + */ + LL_COMMON_API void addRecorder(RecorderPtr); + LL_COMMON_API void removeRecorder(RecorderPtr); + // each error message is passed to each recorder via recordMessage() + /** + * Call addGenericRecorder() with a callable(level, message) to get + * control on every log message without having to code an explicit + * Recorder subclass. Save the returned RecorderPtr if you later want to + * call removeRecorder(). + */ + template <typename CALLABLE> + RecorderPtr addGenericRecorder(const CALLABLE& callable) + { + RecorderPtr ptr{ new GenericRecorder<CALLABLE>(callable) }; + addRecorder(ptr); + return ptr; + } + + LL_COMMON_API void logToFile(const std::string& filename); + LL_COMMON_API void logToStderr(); + LL_COMMON_API void logToFixedBuffer(LLLineBuffer*); + // Utilities to add recorders for logging to a file or a fixed buffer + // A second call to the same function will remove the logger added + // with the first. + // Passing the empty string or NULL to just removes any prior. + LL_COMMON_API std::string logFileName(); + // returns name of current logging file, empty string if none + + + /* + Utilities for use by the unit tests of LLError itself. + */ + + typedef LLPointer<LLRefCount> SettingsStoragePtr; + LL_COMMON_API SettingsStoragePtr saveAndResetSettings(); + LL_COMMON_API void restoreSettings(SettingsStoragePtr pSettingsStorage); + + LL_COMMON_API std::string abbreviateFile(const std::string& filePath); + LL_COMMON_API int shouldLogCallCount(); }; #endif // LL_LLERRORCONTROL_H diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 31dd207008..693e1501d5 100644 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -1,4 +1,4 @@ -/** +/** * @file llerrorlegacy.h * @date January 2007 * @brief old things from the older error system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llevent.cpp b/indra/llcommon/llevent.cpp index 501d06e3cd..305ab8144a 100644 --- a/indra/llcommon/llevent.cpp +++ b/indra/llcommon/llevent.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llevent.cpp * @brief LLEvent and LLEventListener base classes. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,13 +42,13 @@ LLEvent::~LLEvent() // virtual bool LLEvent::accept(LLEventListener* listener) { - return true; + return true; } // virtual const std::string& LLEvent::desc() { - return mDesc; + return mDesc; } /************************************************ @@ -56,50 +56,50 @@ const std::string& LLEvent::desc() ************************************************/ LLObservable::LLObservable() - : mDispatcher(new LLEventDispatcher()) + : mDispatcher(new LLEventDispatcher()) { } // virtual LLObservable::~LLObservable() { - if (mDispatcher.notNull()) - { - mDispatcher->disengage(this); - mDispatcher = NULL; - } + if (mDispatcher.notNull()) + { + mDispatcher->disengage(this); + mDispatcher = NULL; + } } // virtual bool LLObservable::setDispatcher(LLPointer<LLEventDispatcher> dispatcher) { - if (mDispatcher.notNull()) - { - mDispatcher->disengage(this); - mDispatcher = NULL; - } - if (dispatcher.notNull() || dispatcher->engage(this)) - { - mDispatcher = dispatcher; - return true; - } - return false; + if (mDispatcher.notNull()) + { + mDispatcher->disengage(this); + mDispatcher = NULL; + } + if (dispatcher.notNull() || dispatcher->engage(this)) + { + mDispatcher = dispatcher; + return true; + } + return false; } // Returns the current dispatcher pointer. // virtual LLEventDispatcher* LLObservable::getDispatcher() { - return mDispatcher; + return mDispatcher; } // Notifies the dispatcher of an event being fired. void LLObservable::fireEvent(LLPointer<LLEvent> event, LLSD filter) { - if (mDispatcher.notNull()) - { - mDispatcher->fireEvent(event, filter); - } + if (mDispatcher.notNull()) + { + mDispatcher->fireEvent(event, filter); + } } /************************************************ @@ -109,134 +109,134 @@ void LLObservable::fireEvent(LLPointer<LLEvent> event, LLSD filter) class LLEventDispatcher::Impl { public: - virtual ~Impl() { } - virtual bool engage(LLObservable* observable) { return true; } - virtual void disengage(LLObservable* observable) { } - - virtual void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata) = 0; - virtual void removeListener(LLEventListener *listener) = 0; - virtual std::vector<LLListenerEntry> getListeners() const = 0; - virtual bool fireEvent(LLPointer<LLEvent> event, LLSD filter) = 0; + virtual ~Impl() { } + virtual bool engage(LLObservable* observable) { return true; } + virtual void disengage(LLObservable* observable) { } + + virtual void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata) = 0; + virtual void removeListener(LLEventListener *listener) = 0; + virtual std::vector<LLListenerEntry> getListeners() const = 0; + virtual bool fireEvent(LLPointer<LLEvent> event, LLSD filter) = 0; }; bool LLEventDispatcher::engage(LLObservable* observable) { - return impl->engage(observable); + return impl->engage(observable); } void LLEventDispatcher::disengage(LLObservable* observable) { - impl->disengage(observable); + impl->disengage(observable); } void LLEventDispatcher::addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata) { - impl->addListener(listener, filter, userdata); + impl->addListener(listener, filter, userdata); } void LLEventDispatcher::removeListener(LLEventListener *listener) { - impl->removeListener(listener); + impl->removeListener(listener); } std::vector<LLListenerEntry> LLEventDispatcher::getListeners() const { - return impl->getListeners(); + return impl->getListeners(); } bool LLEventDispatcher::fireEvent(LLPointer<LLEvent> event, LLSD filter) { - return impl->fireEvent(event, filter); + return impl->fireEvent(event, filter); } class LLSimpleDispatcher : public LLEventDispatcher::Impl { public: - LLSimpleDispatcher(LLEventDispatcher *parent) : mParent(parent) { } - virtual ~LLSimpleDispatcher(); - virtual void addListener(LLEventListener* listener, LLSD filter, const LLSD& userdata); - virtual void removeListener(LLEventListener* listener); - virtual std::vector<LLListenerEntry> getListeners() const; - virtual bool fireEvent(LLPointer<LLEvent> event, LLSD filter); + LLSimpleDispatcher(LLEventDispatcher *parent) : mParent(parent) { } + virtual ~LLSimpleDispatcher(); + virtual void addListener(LLEventListener* listener, LLSD filter, const LLSD& userdata); + virtual void removeListener(LLEventListener* listener); + virtual std::vector<LLListenerEntry> getListeners() const; + virtual bool fireEvent(LLPointer<LLEvent> event, LLSD filter); protected: - std::vector<LLListenerEntry> mListeners; - LLEventDispatcher *mParent; + std::vector<LLListenerEntry> mListeners; + LLEventDispatcher *mParent; }; LLSimpleDispatcher::~LLSimpleDispatcher() { - while (mListeners.size() > 0) - { - removeListener(mListeners.begin()->listener); - } + while (mListeners.size() > 0) + { + removeListener(mListeners.begin()->listener); + } } void LLSimpleDispatcher::addListener(LLEventListener* listener, LLSD filter, const LLSD& userdata) { - if (listener == NULL) return; - removeListener(listener); - LLListenerEntry new_entry; - new_entry.listener = listener; - new_entry.filter = filter; - new_entry.userdata = userdata; - mListeners.push_back(new_entry); - listener->handleAttach(mParent); + if (listener == NULL) return; + removeListener(listener); + LLListenerEntry new_entry; + new_entry.listener = listener; + new_entry.filter = filter; + new_entry.userdata = userdata; + mListeners.push_back(new_entry); + listener->handleAttach(mParent); } void LLSimpleDispatcher::removeListener(LLEventListener* listener) { - std::vector<LLListenerEntry>::iterator itor = mListeners.begin(); - std::vector<LLListenerEntry>::iterator end = mListeners.end(); - for (; itor != end; ++itor) - { - if ((*itor).listener == listener) - { - mListeners.erase(itor); - break; - } - } - listener->handleDetach(mParent); + std::vector<LLListenerEntry>::iterator itor = mListeners.begin(); + std::vector<LLListenerEntry>::iterator end = mListeners.end(); + for (; itor != end; ++itor) + { + if ((*itor).listener == listener) + { + mListeners.erase(itor); + break; + } + } + listener->handleDetach(mParent); } std::vector<LLListenerEntry> LLSimpleDispatcher::getListeners() const { - std::vector<LLListenerEntry> ret; - for (const LLListenerEntry& entry : mListeners) - { - ret.push_back(entry); - } - - return ret; + std::vector<LLListenerEntry> ret; + for (const LLListenerEntry& entry : mListeners) + { + ret.push_back(entry); + } + + return ret; } // virtual bool LLSimpleDispatcher::fireEvent(LLPointer<LLEvent> event, LLSD filter) { - std::string filter_string = filter.asString(); - for (LLListenerEntry& entry : mListeners) - { - if (filter_string == "" || entry.filter.asString() == filter_string) - { - (entry.listener)->handleEvent(event, entry.userdata); - } - } - return true; + std::string filter_string = filter.asString(); + for (LLListenerEntry& entry : mListeners) + { + if (filter_string == "" || entry.filter.asString() == filter_string) + { + (entry.listener)->handleEvent(event, entry.userdata); + } + } + return true; } LLEventDispatcher::LLEventDispatcher() { - impl = new LLSimpleDispatcher(this); + impl = new LLSimpleDispatcher(this); } LLEventDispatcher::~LLEventDispatcher() { - if (impl) - { - delete impl; - impl = NULL; - } + if (impl) + { + delete impl; + impl = NULL; + } } /************************************************ @@ -249,52 +249,52 @@ LLEventListener::~LLEventListener() LLSimpleListener::~LLSimpleListener() { - clearDispatchers(); + clearDispatchers(); } void LLSimpleListener::clearDispatchers() { - // Remove myself from all listening dispatchers - std::vector<LLEventDispatcher *>::iterator itor; - while (mDispatchers.size() > 0) - { - itor = mDispatchers.begin(); - LLEventDispatcher *dispatcher = *itor; - dispatcher->removeListener(this); - itor = mDispatchers.begin(); - if (itor != mDispatchers.end() && (*itor) == dispatcher) - { - // Somehow, the dispatcher was not removed. Remove it forcibly - mDispatchers.erase(itor); - } - } + // Remove myself from all listening dispatchers + std::vector<LLEventDispatcher *>::iterator itor; + while (mDispatchers.size() > 0) + { + itor = mDispatchers.begin(); + LLEventDispatcher *dispatcher = *itor; + dispatcher->removeListener(this); + itor = mDispatchers.begin(); + if (itor != mDispatchers.end() && (*itor) == dispatcher) + { + // Somehow, the dispatcher was not removed. Remove it forcibly + mDispatchers.erase(itor); + } + } } bool LLSimpleListener::handleAttach(LLEventDispatcher *dispatcher) { - // Add dispatcher if it doesn't already exist - for (LLEventDispatcher* disp : mDispatchers) - { - if (disp == dispatcher) return true; - } - mDispatchers.push_back(dispatcher); - return true; + // Add dispatcher if it doesn't already exist + for (LLEventDispatcher* disp : mDispatchers) + { + if (disp == dispatcher) return true; + } + mDispatchers.push_back(dispatcher); + return true; } bool LLSimpleListener::handleDetach(LLEventDispatcher *dispatcher) { - // Remove dispatcher from list - std::vector<LLEventDispatcher *>::iterator itor; - for (itor = mDispatchers.begin(); itor != mDispatchers.end(); ) - { - if ((*itor) == dispatcher) - { - itor = mDispatchers.erase(itor); - } - else - { - ++itor; - } - } - return true; + // Remove dispatcher from list + std::vector<LLEventDispatcher *>::iterator itor; + for (itor = mDispatchers.begin(); itor != mDispatchers.end(); ) + { + if ((*itor) == dispatcher) + { + itor = mDispatchers.erase(itor); + } + else + { + ++itor; + } + } + return true; } diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h index 28ce7de102..4933f8d607 100644 --- a/indra/llcommon/llevent.h +++ b/indra/llcommon/llevent.h @@ -1,4 +1,4 @@ -/** +/** * @file llevent.h * @author Tom Yedwab * @brief LLEvent and LLEventListener base classes. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,58 +44,58 @@ class LLObservable; class LL_COMMON_API LLEvent : public LLThreadSafeRefCount { protected: - virtual ~LLEvent(); - + virtual ~LLEvent(); + public: - LLEvent(LLObservable* source, const std::string& desc = "") : mSource(source), mDesc(desc) { } - - LLObservable* getSource() { return mSource; } - virtual LLSD getValue() { return LLSD(); } - // Determines whether this particular listener - // should be notified of this event. - // If this function returns true, handleEvent is - // called on the listener with this event as the - // argument. - // Defaults to handling all events. Override this - // if associated with an Observable with many different listeners - virtual bool accept(LLEventListener* listener); - - // return a string describing the event - virtual const std::string& desc(); + LLEvent(LLObservable* source, const std::string& desc = "") : mSource(source), mDesc(desc) { } + + LLObservable* getSource() { return mSource; } + virtual LLSD getValue() { return LLSD(); } + // Determines whether this particular listener + // should be notified of this event. + // If this function returns true, handleEvent is + // called on the listener with this event as the + // argument. + // Defaults to handling all events. Override this + // if associated with an Observable with many different listeners + virtual bool accept(LLEventListener* listener); + + // return a string describing the event + virtual const std::string& desc(); private: - LLObservable* mSource; - std::string mDesc; + LLObservable* mSource; + std::string mDesc; }; // Abstract listener. All listeners derive from LLEventListener class LL_COMMON_API LLEventListener : public LLThreadSafeRefCount { protected: - virtual ~LLEventListener(); - + virtual ~LLEventListener(); + public: - // Processes the event. - // TODO: Make the return value less ambiguous? - virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) = 0; + // Processes the event. + // TODO: Make the return value less ambiguous? + virtual bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata) = 0; - // Called when an dispatcher starts/stops listening - virtual bool handleAttach(LLEventDispatcher *dispatcher) = 0; - virtual bool handleDetach(LLEventDispatcher *dispatcher) = 0; + // Called when an dispatcher starts/stops listening + virtual bool handleAttach(LLEventDispatcher *dispatcher) = 0; + virtual bool handleDetach(LLEventDispatcher *dispatcher) = 0; }; // A listener which tracks references to it and cleans up when it's deallocated class LL_COMMON_API LLSimpleListener : public LLEventListener { public: - void clearDispatchers(); - virtual bool handleAttach(LLEventDispatcher *dispatcher); - virtual bool handleDetach(LLEventDispatcher *dispatcher); + void clearDispatchers(); + virtual bool handleAttach(LLEventDispatcher *dispatcher); + virtual bool handleDetach(LLEventDispatcher *dispatcher); protected: - ~LLSimpleListener(); - std::vector<LLEventDispatcher *> mDispatchers; + ~LLSimpleListener(); + std::vector<LLEventDispatcher *> mDispatchers; }; class LLObservable; // defined below @@ -103,9 +103,9 @@ class LLObservable; // defined below // A structure which stores a Listener and its metadata struct LLListenerEntry { - LLEventListener* listener; - LLSD filter; - LLSD userdata; + LLEventListener* listener; + LLSD filter; + LLSD userdata; }; // Base class for a dispatcher - an object which listens @@ -114,40 +114,40 @@ struct LLListenerEntry class LL_COMMON_API LLEventDispatcher : public LLThreadSafeRefCount { protected: - virtual ~LLEventDispatcher(); - + virtual ~LLEventDispatcher(); + public: - // The default constructor creates a default simple dispatcher implementation. - // The simple implementation has an array of listeners and fires every event to - // all of them. - LLEventDispatcher(); - - // This dispatcher is being attached to an observable object. - // If we return false, the attach fails. - bool engage(LLObservable* observable); + // The default constructor creates a default simple dispatcher implementation. + // The simple implementation has an array of listeners and fires every event to + // all of them. + LLEventDispatcher(); + + // This dispatcher is being attached to an observable object. + // If we return false, the attach fails. + bool engage(LLObservable* observable); - // This dispatcher is being detached from an observable object. - void disengage(LLObservable* observable); + // This dispatcher is being detached from an observable object. + void disengage(LLObservable* observable); - // Adds a listener to this dispatcher, with a given user data - // that will be passed to the listener when an event is fired. - // Duplicate pointers are removed on addtion. - void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata); + // Adds a listener to this dispatcher, with a given user data + // that will be passed to the listener when an event is fired. + // Duplicate pointers are removed on addtion. + void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata); - // Removes a listener from this dispatcher - void removeListener(LLEventListener *listener); + // Removes a listener from this dispatcher + void removeListener(LLEventListener *listener); - // Gets a list of interested listeners - std::vector<LLListenerEntry> getListeners() const; + // Gets a list of interested listeners + std::vector<LLListenerEntry> getListeners() const; - // Handle an event that has just been fired by communicating it - // to listeners, passing it across a network, etc. - bool fireEvent(LLPointer<LLEvent> event, LLSD filter); + // Handle an event that has just been fired by communicating it + // to listeners, passing it across a network, etc. + bool fireEvent(LLPointer<LLEvent> event, LLSD filter); public: - class Impl; + class Impl; private: - Impl* impl; + Impl* impl; }; // Interface for observable data (data that fires events) @@ -157,38 +157,38 @@ private: class LL_COMMON_API LLObservable { public: - // Initialize with the default Dispatcher - LLObservable(); - virtual ~LLObservable(); - - // Replaces the existing dispatcher pointer to the new one, - // informing the dispatcher of the change. - virtual bool setDispatcher(LLPointer<LLEventDispatcher> dispatcher); - - // Returns the current dispatcher pointer. - virtual LLEventDispatcher* getDispatcher(); - - void addListener(LLEventListener *listener, LLSD filter = "", const LLSD& userdata = "") - { - if (mDispatcher.notNull()) mDispatcher->addListener(listener, filter, userdata); - } - void removeListener(LLEventListener *listener) - { - if (mDispatcher.notNull()) mDispatcher->removeListener(listener); - } - // Notifies the dispatcher of an event being fired. - void fireEvent(LLPointer<LLEvent> event, LLSD filter = LLSD()); + // Initialize with the default Dispatcher + LLObservable(); + virtual ~LLObservable(); + + // Replaces the existing dispatcher pointer to the new one, + // informing the dispatcher of the change. + virtual bool setDispatcher(LLPointer<LLEventDispatcher> dispatcher); + + // Returns the current dispatcher pointer. + virtual LLEventDispatcher* getDispatcher(); + + void addListener(LLEventListener *listener, LLSD filter = "", const LLSD& userdata = "") + { + if (mDispatcher.notNull()) mDispatcher->addListener(listener, filter, userdata); + } + void removeListener(LLEventListener *listener) + { + if (mDispatcher.notNull()) mDispatcher->removeListener(listener); + } + // Notifies the dispatcher of an event being fired. + void fireEvent(LLPointer<LLEvent> event, LLSD filter = LLSD()); protected: - LLPointer<LLEventDispatcher> mDispatcher; + LLPointer<LLEventDispatcher> mDispatcher; }; class LLValueChangedEvent : public LLEvent { public: - LLValueChangedEvent(LLObservable* source, LLSD value) : LLEvent(source, "value_changed"), mValue(value) { } - LLSD getValue() { return mValue; } - LLSD mValue; + LLValueChangedEvent(LLObservable* source, LLSD value) : LLEvent(source, "value_changed"), mValue(value) { } + LLSD getValue() { return mValue; } + LLSD mValue; }; } // LLOldEvents diff --git a/indra/llcommon/lleventapi.cpp b/indra/llcommon/lleventapi.cpp index 3d46ef1034..8b724256b8 100644 --- a/indra/llcommon/lleventapi.cpp +++ b/indra/llcommon/lleventapi.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-11-10 * @brief Implementation for lleventapi. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventapi.h b/indra/llcommon/lleventapi.h index 25f6becd8b..3ae820db51 100644 --- a/indra/llcommon/lleventapi.h +++ b/indra/llcommon/lleventapi.h @@ -5,25 +5,25 @@ * @brief LLEventAPI is the base class for every class that wraps a C++ API * in an event API * (see https://wiki.lindenlab.com/wiki/Incremental_Viewer_Automation/Event_API). - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 067b5e6fbc..e1fc4764f6 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-29 * @brief Implementation for lleventcoro. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index c0fe8b094f..492563bb98 100644 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-29 * @brief Utilities to interface between coroutines and events. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -152,7 +152,7 @@ LLSD postAndSuspendWithTimeout(const LLSD& event, F32 timeout, const LLSD& timeoutResult); /// Suspend the coroutine until an event is fired on the identified pump -/// or the timeout duration has elapsed. If the timeout duration +/// or the timeout duration has elapsed. If the timeout duration /// elapses the specified LLSD is returned. inline LLSD suspendUntilEventOnWithTimeout(const LLEventPumpOrPumpName& suspendPumpOrName, diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp index da96de18f7..9dd6864cff 100644 --- a/indra/llcommon/lleventdispatcher.cpp +++ b/indra/llcommon/lleventdispatcher.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-18 * @brief Implementation for lleventdispatcher. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -755,7 +755,7 @@ std::string LLEventDispatcher::getState() const bool LLEventDispatcher::setState(SetState&, const std::string& state) const { - // If SetState is instantiated at multiple levels of function call, ignore + // If SetState is instantiated at multiple levels of function call, ignore // the lower-level call because the outer call presumably provides more // context. if (mState.get()) diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index a82bc7a69b..4c3c0f3414 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -6,25 +6,25 @@ * useful when you have a single LLEventPump listener on which you can * request different operations, vs. instantiating a different * LLEventPump for each such operation. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -201,7 +201,7 @@ public: template <typename R, class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG)) @@ -213,7 +213,7 @@ public: template <typename R, class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG) const) @@ -226,7 +226,7 @@ public: template <class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG)) @@ -238,7 +238,7 @@ public: template <class CLASS, typename ARG, typename = typename std::enable_if< ! std::is_same<typename std::decay<ARG>::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG) const) @@ -247,7 +247,7 @@ public: } // non-const binary (or more) method - template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG0, ARG1, ARGS...)) @@ -256,7 +256,7 @@ public: } // const binary (or more) method - template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <typename R, class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG0, ARG1, ARGS...) const) @@ -265,7 +265,7 @@ public: } // non-const binary (or more) method returning void - template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG0, ARG1, ARGS...)) @@ -274,7 +274,7 @@ public: } // const binary (or more) method returning void - template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> + template <class CLASS, typename ARG0, typename ARG1, typename... ARGS> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG0, ARG1, ARGS...) const) @@ -371,7 +371,7 @@ public: const InstanceGetter& getter, const LLSD& params, const LLSD& defaults=LLSD()); - //@} + //@} /// Unregister a callable bool remove(const std::string& name); diff --git a/indra/llcommon/lleventemitter.h b/indra/llcommon/lleventemitter.h index cd82fc56f9..14160e1e76 100644 --- a/indra/llcommon/lleventemitter.h +++ b/indra/llcommon/lleventemitter.h @@ -1,25 +1,25 @@ -/** +/** * @file lleventemitter.h * @brief General event emitter class * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,65 +38,65 @@ #include "stdtypes.h" /////////////////////////////////////////////////////////////////////////////// -// templatized emitter class +// templatized emitter class template < class T > class eventEmitter { - public: - typedef typename T::EventType EventType; - typedef std::list< T* > ObserverContainer; - typedef void ( T::*observerMethod )( const EventType& ); + public: + typedef typename T::EventType EventType; + typedef std::list< T* > ObserverContainer; + typedef void ( T::*observerMethod )( const EventType& ); - protected: - ObserverContainer observers; + protected: + ObserverContainer observers; - public: - eventEmitter () { }; + public: + eventEmitter () { }; - ~eventEmitter () { }; + ~eventEmitter () { }; - /////////////////////////////////////////////////////////////////////////////// - // - BOOL addObserver ( T* observerIn ) - { - if ( ! observerIn ) - return FALSE; + /////////////////////////////////////////////////////////////////////////////// + // + BOOL addObserver ( T* observerIn ) + { + if ( ! observerIn ) + return FALSE; - // check if observer already exists - if ( std::find ( observers.begin (), observers.end (), observerIn ) != observers.end () ) - return FALSE; + // check if observer already exists + if ( std::find ( observers.begin (), observers.end (), observerIn ) != observers.end () ) + return FALSE; - // save it - observers.push_back ( observerIn ); + // save it + observers.push_back ( observerIn ); - return true; - }; + return true; + }; - /////////////////////////////////////////////////////////////////////////////// - // - BOOL remObserver ( T* observerIn ) - { - if ( ! observerIn ) - return FALSE; + /////////////////////////////////////////////////////////////////////////////// + // + BOOL remObserver ( T* observerIn ) + { + if ( ! observerIn ) + return FALSE; - observers.remove ( observerIn ); + observers.remove ( observerIn ); - return TRUE; - }; + return TRUE; + }; - /////////////////////////////////////////////////////////////////////////////// - // - void update ( observerMethod method, const EventType& msgIn ) - { - typename std::list< T* >::iterator iter = observers.begin (); + /////////////////////////////////////////////////////////////////////////////// + // + void update ( observerMethod method, const EventType& msgIn ) + { + typename std::list< T* >::iterator iter = observers.begin (); - while ( iter != observers.end () ) - { - ( ( *iter )->*method ) ( msgIn ); + while ( iter != observers.end () ) + { + ( ( *iter )->*method ) ( msgIn ); - ++iter; - }; - }; + ++iter; + }; + }; }; #endif // lleventemitter_h diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index 4cded7f88e..604ee8a42d 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-05 * @brief Implementation for lleventfilter. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 1fb41e0297..5c45144fad 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-05 * @brief Define LLEventFilter: LLEventStream subclass with conditions - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -149,11 +149,11 @@ public: /** * Like actionAfter(), but where the desired Action is a particular event * for all listeners. Pass the timeout time and the desired @a event data. - * + * * Suppose the timeout should only be satisfied by a particular event, but * the ultimate listener must see all other incoming events as well, plus * the timeout @a event if any: - * + * * @code * some LLEventMatching LLEventMatching * event ---> for particular ---> LLEventTimeout ---> for timeout @@ -161,7 +161,7 @@ public: * \ \ ultimate * `-----------------------------------------------------> listener * @endcode - * + * * Since a given listener can listen on more than one LLEventPump, we can * set things up so it sees the set union of events from LLEventTimeout * and the original event source. However, as LLEventTimeout passes @@ -197,8 +197,8 @@ private: /** * Production implementation of LLEventTimoutBase. - * - * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) + * + * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) * constructor to ensure that the upstream event pump is not an LLEventMaildrop * or any other kind of store and forward pump which may have events outstanding. * Using this constructor will cause the upstream event pump to fire any pending @@ -207,7 +207,7 @@ private: * from the event pump and attached using the listen method. * See llcoro::suspendUntilEventOnWithTimeout() for an example. */ - + class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase { public: diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 70931f3a65..5b4e69659d 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-12 * @brief Implementation for llevents. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -423,8 +423,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL float nodePosition = 1.0; - // if the supplied name is empty we are not interested in the ordering mechanism - // and can bypass attempting to find the optimal location to insert the new + // if the supplied name is empty we are not interested in the ordering mechanism + // and can bypass attempting to find the optimal location to insert the new // listener. We'll just tack it on to the end. if (!name.empty()) // should be the same as testing against ANONYMOUS { @@ -569,12 +569,12 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL // Now that newNode has a value that places it appropriately in mSignal, // connect it. LLBoundListener bound = mSignal->connect(nodePosition, listener); - + if (!name.empty()) { // note that we are not tracking anonymous listeners here either. - // This means that it is the caller's responsibility to either assign - // to a TempBoundListerer (scoped_connection) or manually disconnect - // when done. + // This means that it is the caller's responsibility to either assign + // to a TempBoundListerer (scoped_connection) or manually disconnect + // when done. mConnections[name] = bound; } return bound; @@ -641,9 +641,9 @@ bool LLEventMailDrop::post(const LLSD& event) { // forward the call to our base class bool posted = LLEventStream::post(event); - + if (!posted) - { // if the event was not handled we will save it for later so that it can + { // if the event was not handled we will save it for later so that it can // be posted to any future listeners when they attach. mEventHistory.push_back(event); } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index bebcfacdcb..9a0a6863f0 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -6,25 +6,25 @@ * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System, * originally introduced in llnotifications.h. It has nothing * whatsoever to do with the older system in llevent.h. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,13 +39,13 @@ #include <deque> #include <functional> #if LL_WINDOWS - #pragma warning (push) - #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch - #pragma warning (disable : 4264) + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) #endif #include <boost/signals2.hpp> #if LL_WINDOWS - #pragma warning (pop) + #pragma warning (pop) #endif #include <boost/bind.hpp> @@ -310,9 +310,9 @@ public: /** * Find the named LLEventPump instance. If it exists post the message to it. * If the pump does not exist, do nothing. - * + * * returns the result of the LLEventPump::post. If no pump exists returns false. - * + * * This is syntactically similar to LLEventPumps::instance().post(name, message), * however if the pump does not already exist it will not be created. */ @@ -541,10 +541,10 @@ public: * instantiate your listener, then passing the same name on each listen() * call, allows us to optimize away the second and subsequent dependency * sorts. - * - * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire - * dependency and ordering calculation. In this case, it is critical that - * the result be assigned to a LLTempBoundListener or the listener is + * + * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire + * dependency and ordering calculation. In this case, it is critical that + * the result be assigned to a LLTempBoundListener or the listener is * manually disconnected when no longer needed since there will be no * way to later find and disconnect this listener manually. */ @@ -607,7 +607,7 @@ protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, const NameList& after, const NameList& before); - + /// implement the dispatching std::shared_ptr<LLStandardSignal> mSignal; @@ -660,21 +660,21 @@ public: * by all listeners, until some listener consumes it. The caveat is that each * event *must* eventually reach a listener that will consume it, else the * queue will grow to arbitrary length. - * + * * @NOTE: When using an LLEventMailDrop with an LLEventTimeout or * LLEventFilter attaching the filter downstream, using Timeout's constructor will - * cause the MailDrop to discharge any of its stored events. The timeout should - * instead be connected upstream using its listen() method. + * cause the MailDrop to discharge any of its stored events. The timeout should + * instead be connected upstream using its listen() method. */ class LL_COMMON_API LLEventMailDrop : public LLEventStream { public: LLEventMailDrop(const std::string& name, bool tweak = false) : LLEventStream(name, tweak) {} virtual ~LLEventMailDrop() {} - + /// Post an event to all listeners virtual bool post(const LLSD& event) override; - + /// Remove any history stored in the mail drop. void discard(); diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index f575a7b6bf..33fafffefd 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lleventtimer.cpp - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,20 +33,20 @@ ////////////////////////////////////////////////////////////////////////////// // -// LLEventTimer Implementation +// LLEventTimer Implementation // ////////////////////////////////////////////////////////////////////////////// LLEventTimer::LLEventTimer(F32 period) : mEventTimer() { - mPeriod = period; + mPeriod = period; } LLEventTimer::LLEventTimer(const LLDate& time) : mEventTimer() { - mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); + mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); } @@ -55,19 +55,19 @@ LLEventTimer::~LLEventTimer() } //static -void LLEventTimer::updateClass() +void LLEventTimer::updateClass() { - for (auto& timer : instance_snapshot()) - { - F32 et = timer.mEventTimer.getElapsedTimeF32(); - if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { - timer.mEventTimer.reset(); - if ( timer.tick() ) - { - delete &timer; - } - } - } + for (auto& timer : instance_snapshot()) + { + F32 et = timer.mEventTimer.getElapsedTimeF32(); + if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { + timer.mEventTimer.reset(); + if ( timer.tick() ) + { + delete &timer; + } + } + } } diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index dbbfe0c6e6..ed6f10d5e1 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -1,30 +1,30 @@ -/** +/** * @file lleventtimer.h - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_EVENTTIMER_H +#ifndef LL_EVENTTIMER_H #define LL_EVENTTIMER_H #include "stdtypes.h" @@ -37,42 +37,42 @@ class LL_COMMON_API LLEventTimer : public LLInstanceTracker<LLEventTimer> { public: - LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds - LLEventTimer(const LLDate& time); - virtual ~LLEventTimer(); + LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds + LLEventTimer(const LLDate& time); + virtual ~LLEventTimer(); - //function to be called at the supplied frequency - // Normally return FALSE; TRUE will delete the timer after the function returns. - virtual BOOL tick() = 0; + //function to be called at the supplied frequency + // Normally return FALSE; TRUE will delete the timer after the function returns. + virtual BOOL tick() = 0; - static void updateClass(); + static void updateClass(); - /// Schedule recurring calls to generic callable every period seconds. - /// Returns a pointer; if you delete it, cancels the recurring calls. - template <typename CALLABLE> - static LLEventTimer* run_every(F32 period, const CALLABLE& callable); + /// Schedule recurring calls to generic callable every period seconds. + /// Returns a pointer; if you delete it, cancels the recurring calls. + template <typename CALLABLE> + static LLEventTimer* run_every(F32 period, const CALLABLE& callable); - /// Schedule a future call to generic callable. Returns a pointer. - /// CAUTION: The object referenced by that pointer WILL BE DELETED once - /// the callback has been called! LLEventTimer::getInstance(pointer) (NOT - /// pointer->getInstance(pointer)!) can be used to test whether the - /// pointer is still valid. If it is, deleting it will cancel the - /// callback. - template <typename CALLABLE> - static LLEventTimer* run_at(const LLDate& time, const CALLABLE& callable); + /// Schedule a future call to generic callable. Returns a pointer. + /// CAUTION: The object referenced by that pointer WILL BE DELETED once + /// the callback has been called! LLEventTimer::getInstance(pointer) (NOT + /// pointer->getInstance(pointer)!) can be used to test whether the + /// pointer is still valid. If it is, deleting it will cancel the + /// callback. + template <typename CALLABLE> + static LLEventTimer* run_at(const LLDate& time, const CALLABLE& callable); - /// Like run_at(), but after a time delta rather than at a timestamp. - /// Same CAUTION. - template <typename CALLABLE> - static LLEventTimer* run_after(F32 interval, const CALLABLE& callable); + /// Like run_at(), but after a time delta rather than at a timestamp. + /// Same CAUTION. + template <typename CALLABLE> + static LLEventTimer* run_after(F32 interval, const CALLABLE& callable); protected: - LLTimer mEventTimer; - F32 mPeriod; + LLTimer mEventTimer; + F32 mPeriod; private: - template <typename CALLABLE> - class Generic; + template <typename CALLABLE> + class Generic; }; template <typename CALLABLE> diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index 0787bde57f..c0154a569f 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-08-12 * @brief Implementation for llexception. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ @@ -99,8 +99,8 @@ static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) { const auto stack = to_string(boost::stacktrace::stacktrace()); - LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code - << "\n Stack trace: \n" + LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code + << "\n Stack trace: \n" << stack << LL_ENDL; if (code == STATUS_MSC_EXCEPTION) diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 375bea4a57..68e609444e 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-06-29 * @brief Types needed for generic exception handling - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 2612d0f07c..722743f453 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfasttimer.cpp * @brief Implementation of the fast timer. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,8 +49,8 @@ #include "lltimer.h" #elif LL_DARWIN #include <sys/time.h> -#include "lltimer.h" // get_clock_count() -#else +#include "lltimer.h" // get_clock_count() +#else #error "architecture not supported" #endif @@ -60,7 +60,7 @@ namespace LLTrace ////////////////////////////////////////////////////////////////////////////// // statics -bool BlockTimer::sLog = false; +bool BlockTimer::sLog = false; std::string BlockTimer::sLogName = ""; bool BlockTimer::sMetricLog = false; @@ -70,83 +70,83 @@ U64 BlockTimer::sClockResolution = 1000000000; // Nanosecond resolution U64 BlockTimer::sClockResolution = 1000000; // Microsecond resolution #endif -static LLMutex* sLogLock = NULL; +static LLMutex* sLogLock = NULL; static std::queue<LLSD> sLogQueue; -block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id) -{ - return block_timer_tree_df_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); +block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id) +{ + return block_timer_tree_df_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } -block_timer_tree_df_iterator_t end_block_timer_tree_df() -{ - return block_timer_tree_df_iterator_t(); +block_timer_tree_df_iterator_t end_block_timer_tree_df() +{ + return block_timer_tree_df_iterator_t(); } -block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id) -{ - return block_timer_tree_df_post_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); +block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id) +{ + return block_timer_tree_df_post_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } -block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post() -{ - return block_timer_tree_df_post_iterator_t(); +block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post() +{ + return block_timer_tree_df_post_iterator_t(); } block_timer_tree_bf_iterator_t begin_block_timer_tree_bf(BlockTimerStatHandle& id) -{ - return block_timer_tree_bf_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); +{ + return block_timer_tree_bf_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } block_timer_tree_bf_iterator_t end_block_timer_tree_bf() - { - return block_timer_tree_bf_iterator_t(); - } - -block_timer_tree_df_iterator_t begin_timer_tree(BlockTimerStatHandle& id) - { - return block_timer_tree_df_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); - } - -block_timer_tree_df_iterator_t end_timer_tree() - { - return block_timer_tree_df_iterator_t(); + { + return block_timer_tree_bf_iterator_t(); + } + +block_timer_tree_df_iterator_t begin_timer_tree(BlockTimerStatHandle& id) + { + return block_timer_tree_df_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); + } + +block_timer_tree_df_iterator_t end_timer_tree() + { + return block_timer_tree_df_iterator_t(); } // sort child timers by name struct SortTimerByName - { - bool operator()(const BlockTimerStatHandle* i1, const BlockTimerStatHandle* i2) - { - return i1->getName() < i2->getName(); - } + { + bool operator()(const BlockTimerStatHandle* i1, const BlockTimerStatHandle* i2) + { + return i1->getName() < i2->getName(); + } }; static BlockTimerStatHandle sRootTimer("root", NULL); BlockTimerStatHandle& BlockTimer::getRootTimeBlock() { - return sRootTimer; - } + return sRootTimer; + } void BlockTimer::pushLog(LLSD log) { - LLMutexLock lock(sLogLock); + LLMutexLock lock(sLogLock); - sLogQueue.push(log); + sLogQueue.push(log); } void BlockTimer::setLogLock(LLMutex* lock) { - sLogLock = lock; + sLogLock = lock; } @@ -154,40 +154,40 @@ void BlockTimer::setLogLock(LLMutex* lock) #if (LL_DARWIN || LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) U64 BlockTimer::countsPerSecond() { - return sClockResolution; + return sClockResolution; } #else // windows or x86-mac or x86-linux U64 BlockTimer::countsPerSecond() { #if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS - //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz - static LLUnit<U64, LLUnits::Hertz> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency(); - return sCPUClockFrequency.value(); + //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz + static LLUnit<U64, LLUnits::Hertz> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency(); + return sCPUClockFrequency.value(); #else - // If we're not using RDTSC, each fasttimer tick is just a performance counter tick. - // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency()) - // since that would change displayed MHz stats for CPUs - static bool firstcall = true; - static U64 sCPUClockFrequency; - if (firstcall) - { - QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency); - firstcall = false; - } - return sCPUClockFrequency.value(); + // If we're not using RDTSC, each fasttimer tick is just a performance counter tick. + // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency()) + // since that would change displayed MHz stats for CPUs + static bool firstcall = true; + static U64 sCPUClockFrequency; + if (firstcall) + { + QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency); + firstcall = false; + } + return sCPUClockFrequency.value(); #endif } #endif BlockTimerStatHandle::BlockTimerStatHandle(const char* name, const char* description) -: StatType<TimeBlockAccumulator>(name, description) +: StatType<TimeBlockAccumulator>(name, description) {} TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const { - TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex()); - llassert(nodep); - return *nodep; + TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex()); + llassert(nodep); + return *nodep; } @@ -223,71 +223,71 @@ void BlockTimer::bootstrapTimerTree() void BlockTimer::incrementalUpdateTimerTree() { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock()); - it != end_block_timer_tree_df_post(); - ++it) - { - BlockTimerStatHandle* timerp = *it; - - // sort timers by time last called, so call graph makes sense - TimeBlockTreeNode& tree_node = timerp->getTreeNode(); - if (tree_node.mNeedsSorting) + for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock()); + it != end_block_timer_tree_df_post(); + ++it) + { + BlockTimerStatHandle* timerp = *it; + + // sort timers by time last called, so call graph makes sense + TimeBlockTreeNode& tree_node = timerp->getTreeNode(); + if (tree_node.mNeedsSorting) { - std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName()); + std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName()); } - // skip root timer - if (timerp != &BlockTimer::getRootTimeBlock()) + // skip root timer + if (timerp != &BlockTimer::getRootTimeBlock()) { - TimeBlockAccumulator& accumulator = timerp->getCurrentAccumulator(); + TimeBlockAccumulator& accumulator = timerp->getCurrentAccumulator(); - if (accumulator.mMoveUpTree) + if (accumulator.mMoveUpTree) { - // since ancestors have already been visited, re-parenting won't affect tree traversal - //step up tree, bringing our descendants with us - LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << - " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL; - timerp->setParent(timerp->getParent()->getParent()); - accumulator.mParent = timerp->getParent(); - accumulator.mMoveUpTree = false; - - // don't bubble up any ancestors until descendants are done bubbling up - // as ancestors may call this timer only on certain paths, so we want to resolve - // child-most block locations before their parents - it.skipAncestors(); - } - } - } + // since ancestors have already been visited, re-parenting won't affect tree traversal + //step up tree, bringing our descendants with us + LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << + " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL; + timerp->setParent(timerp->getParent()->getParent()); + accumulator.mParent = timerp->getParent(); + accumulator.mMoveUpTree = false; + + // don't bubble up any ancestors until descendants are done bubbling up + // as ancestors may call this timer only on certain paths, so we want to resolve + // child-most block locations before their parents + it.skipAncestors(); + } + } + } } void BlockTimer::updateTimes() { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // walk up stack of active timers and accumulate current time while leaving timing structures active - BlockTimerStackRecord* stack_record = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); - if (!stack_record) return; - - U64 cur_time = getCPUClockCount64(); - BlockTimer* cur_timer = stack_record->mActiveTimer; - TimeBlockAccumulator* accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); - - while(cur_timer - && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self - { - U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; - cur_timer->mStartTime = cur_time; - - accumulator->mTotalTimeCounter += cumulative_time_delta; - accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime; - stack_record->mChildTime = 0; - - stack_record = &cur_timer->mParentTimerData; - accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); - cur_timer = stack_record->mActiveTimer; - - stack_record->mChildTime += cumulative_time_delta; - } + // walk up stack of active timers and accumulate current time while leaving timing structures active + BlockTimerStackRecord* stack_record = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + if (!stack_record) return; + + U64 cur_time = getCPUClockCount64(); + BlockTimer* cur_timer = stack_record->mActiveTimer; + TimeBlockAccumulator* accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); + + while(cur_timer + && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self + { + U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; + cur_timer->mStartTime = cur_time; + + accumulator->mTotalTimeCounter += cumulative_time_delta; + accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime; + stack_record->mChildTime = 0; + + stack_record = &cur_timer->mParentTimerData; + accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); + cur_timer = stack_record->mActiveTimer; + + stack_record->mChildTime += cumulative_time_delta; + } } static LLTrace::BlockTimerStatHandle FTM_PROCESS_TIMES("Process FastTimer Times"); @@ -297,192 +297,192 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_TIMES("Process FastTimer Times" void BlockTimer::processTimes() { #if LL_TRACE_ENABLED - LL_RECORD_BLOCK_TIME(FTM_PROCESS_TIMES); - get_clock_count(); // good place to calculate clock frequency + LL_RECORD_BLOCK_TIME(FTM_PROCESS_TIMES); + get_clock_count(); // good place to calculate clock frequency - // set up initial tree - bootstrapTimerTree(); + // set up initial tree + bootstrapTimerTree(); - incrementalUpdateTimerTree(); + incrementalUpdateTimerTree(); - updateTimes(); + updateTimes(); - // reset for next frame - for (auto& base : BlockTimerStatHandle::instance_snapshot()) - { - // because of indirect derivation from LLInstanceTracker, have to downcast - BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); - TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); + // reset for next frame + for (auto& base : BlockTimerStatHandle::instance_snapshot()) + { + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); - accumulator.mLastCaller = NULL; - accumulator.mMoveUpTree = false; - } + accumulator.mLastCaller = NULL; + accumulator.mMoveUpTree = false; + } #endif } std::vector<BlockTimerStatHandle*>::iterator BlockTimerStatHandle::beginChildren() - { - return getTreeNode().mChildren.begin(); - } + { + return getTreeNode().mChildren.begin(); + } std::vector<BlockTimerStatHandle*>::iterator BlockTimerStatHandle::endChildren() - { - return getTreeNode().mChildren.end(); + { + return getTreeNode().mChildren.end(); } std::vector<BlockTimerStatHandle*>& BlockTimerStatHandle::getChildren() { - return getTreeNode().mChildren; - } + return getTreeNode().mChildren; + } bool BlockTimerStatHandle::hasChildren() { - return ! getTreeNode().mChildren.empty(); + return ! getTreeNode().mChildren.empty(); } // static void BlockTimer::logStats() { - // get ready for next frame - if (sLog) - { //output current frame counts to performance log - - static S32 call_count = 0; - if (call_count % 100 == 0) - { - LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL; - LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL; - LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL; - LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL; - LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64() / (F64HertzImplicit)LLProcessorInfo().getCPUFrequency()) << LL_ENDL; - } - call_count++; - - F64Seconds total_time(0); - LLSD sd; - - { - for (auto& base : BlockTimerStatHandle::instance_snapshot()) - { - // because of indirect derivation from LLInstanceTracker, have to downcast - BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); - LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); - sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value()); - sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount())); - - // computing total time here because getting the root timer's getCountHistory - // doesn't work correctly on the first frame - total_time += frame_recording.getLastRecording().getSum(timer); - } - } - - sd["Total"]["Time"] = (LLSD::Real) total_time.value(); - sd["Total"]["Calls"] = (LLSD::Integer) 1; - - { - LLMutexLock lock(sLogLock); - sLogQueue.push(sd); - } - } + // get ready for next frame + if (sLog) + { //output current frame counts to performance log + + static S32 call_count = 0; + if (call_count % 100 == 0) + { + LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL; + LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL; + LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL; + LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL; + LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64() / (F64HertzImplicit)LLProcessorInfo().getCPUFrequency()) << LL_ENDL; + } + call_count++; + + F64Seconds total_time(0); + LLSD sd; + + { + for (auto& base : BlockTimerStatHandle::instance_snapshot()) + { + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value()); + sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount())); + + // computing total time here because getting the root timer's getCountHistory + // doesn't work correctly on the first frame + total_time += frame_recording.getLastRecording().getSum(timer); + } + } + + sd["Total"]["Time"] = (LLSD::Real) total_time.value(); + sd["Total"]["Calls"] = (LLSD::Integer) 1; + + { + LLMutexLock lock(sLogLock); + sLogQueue.push(sd); + } + } } //static void BlockTimer::dumpCurTimes() { - LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); - LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); - - // walk over timers in depth order and output timings - for(block_timer_tree_df_iterator_t it = begin_timer_tree(BlockTimer::getRootTimeBlock()); - it != end_timer_tree(); - ++it) - { - BlockTimerStatHandle* timerp = (*it); - F64Seconds total_time = last_frame_recording.getSum(*timerp); - U32 num_calls = last_frame_recording.getSum(timerp->callCount()); - - // Don't bother with really brief times, keep output concise - if (total_time < F32Milliseconds(0.1f)) continue; - - std::ostringstream out_str; - BlockTimerStatHandle* parent_timerp = timerp; - while(parent_timerp && parent_timerp != parent_timerp->getParent()) - { - out_str << "\t"; - parent_timerp = parent_timerp->getParent(); - } - - out_str << timerp->getName() << " " - << std::setprecision(3) << total_time.valueInUnits<LLUnits::Milliseconds>() << " ms, " - << num_calls << " calls"; - - LL_INFOS() << out_str.str() << LL_ENDL; + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); + + // walk over timers in depth order and output timings + for(block_timer_tree_df_iterator_t it = begin_timer_tree(BlockTimer::getRootTimeBlock()); + it != end_timer_tree(); + ++it) + { + BlockTimerStatHandle* timerp = (*it); + F64Seconds total_time = last_frame_recording.getSum(*timerp); + U32 num_calls = last_frame_recording.getSum(timerp->callCount()); + + // Don't bother with really brief times, keep output concise + if (total_time < F32Milliseconds(0.1f)) continue; + + std::ostringstream out_str; + BlockTimerStatHandle* parent_timerp = timerp; + while(parent_timerp && parent_timerp != parent_timerp->getParent()) + { + out_str << "\t"; + parent_timerp = parent_timerp->getParent(); + } + + out_str << timerp->getName() << " " + << std::setprecision(3) << total_time.valueInUnits<LLUnits::Milliseconds>() << " ms, " + << num_calls << " calls"; + + LL_INFOS() << out_str.str() << LL_ENDL; } } //static void BlockTimer::writeLog(std::ostream& os) { - while (!sLogQueue.empty()) - { - LLSD& sd = sLogQueue.front(); - LLSDSerialize::toXML(sd, os); - LLMutexLock lock(sLogLock); - sLogQueue.pop(); - } + while (!sLogQueue.empty()) + { + LLSD& sd = sLogQueue.front(); + LLSDSerialize::toXML(sd, os); + LLMutexLock lock(sLogLock); + sLogQueue.pop(); + } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TimeBlockAccumulator ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TimeBlockAccumulator::TimeBlockAccumulator() -: mTotalTimeCounter(0), - mSelfTimeCounter(0), - mCalls(0), - mLastCaller(NULL), - mActiveCount(0), - mMoveUpTree(false), - mParent(NULL) +TimeBlockAccumulator::TimeBlockAccumulator() +: mTotalTimeCounter(0), + mSelfTimeCounter(0), + mCalls(0), + mLastCaller(NULL), + mActiveCount(0), + mMoveUpTree(false), + mParent(NULL) {} void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other, EBufferAppendType append_type ) { #if LL_TRACE_ENABLED - // we can't merge two unrelated time block samples, as that will screw with the nested timings - // due to the call hierarchy of each thread - llassert(append_type == SEQUENTIAL); - mTotalTimeCounter += other.mTotalTimeCounter; - mSelfTimeCounter += other.mSelfTimeCounter; - mCalls += other.mCalls; - mLastCaller = other.mLastCaller; - mActiveCount = other.mActiveCount; - mMoveUpTree = other.mMoveUpTree; - mParent = other.mParent; + // we can't merge two unrelated time block samples, as that will screw with the nested timings + // due to the call hierarchy of each thread + llassert(append_type == SEQUENTIAL); + mTotalTimeCounter += other.mTotalTimeCounter; + mSelfTimeCounter += other.mSelfTimeCounter; + mCalls += other.mCalls; + mLastCaller = other.mLastCaller; + mActiveCount = other.mActiveCount; + mMoveUpTree = other.mMoveUpTree; + mParent = other.mParent; #endif } void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other ) { - mCalls = 0; - mSelfTimeCounter = 0; - mTotalTimeCounter = 0; + mCalls = 0; + mSelfTimeCounter = 0; + mTotalTimeCounter = 0; - if (other) + if (other) { - mLastCaller = other->mLastCaller; - mActiveCount = other->mActiveCount; - mMoveUpTree = other->mMoveUpTree; - mParent = other->mParent; - } + mLastCaller = other->mLastCaller; + mActiveCount = other->mActiveCount; + mMoveUpTree = other->mMoveUpTree; + mParent = other->mParent; + } } F64Seconds BlockTimer::getElapsedTime() { - U64 total_time = getCPUClockCount64() - mStartTime; + U64 total_time = getCPUClockCount64() - mStartTime; - return F64Seconds((F64)total_time / (F64)BlockTimer::countsPerSecond()); + return F64Seconds((F64)total_time / (F64)BlockTimer::countsPerSecond()); } diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 9bd93d7240..17ad37b031 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,77 +51,77 @@ class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer); class BlockTimer { public: - typedef BlockTimer self_t; - typedef class BlockTimerStatHandle DeclareTimer; + typedef BlockTimer self_t; + typedef class BlockTimerStatHandle DeclareTimer; - ~BlockTimer(); + ~BlockTimer(); - F64Seconds getElapsedTime(); + F64Seconds getElapsedTime(); - ////////////////////////////////////////////////////////////////////////////// - // - // Important note: These implementations must be FAST! - // + ////////////////////////////////////////////////////////////////////////////// + // + // Important note: These implementations must be FAST! + // #if LL_WINDOWS - // - // Windows implementation of CPU clock - // - - // - // NOTE: put back in when we aren't using platform sdk anymore - // - // because MS has different signatures for these functions in winnt.h - // need to rename them to avoid conflicts - //#define _interlockedbittestandset _renamed_interlockedbittestandset - //#define _interlockedbittestandreset _renamed_interlockedbittestandreset - //#include <intrin.h> - //#undef _interlockedbittestandset - //#undef _interlockedbittestandreset - - //inline U32 getCPUClockCount32() - //{ - // U64 time_stamp = __rdtsc(); - // return (U32)(time_stamp >> 8); - //} - // - //// return full timer value, *not* shifted by 8 bits - //inline U64 getCPUClockCount64() - //{ - // return __rdtsc(); - //} - - - - // shift off lower 8 bits for lower resolution but longer term timing - // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing + // + // Windows implementation of CPU clock + // + + // + // NOTE: put back in when we aren't using platform sdk anymore + // + // because MS has different signatures for these functions in winnt.h + // need to rename them to avoid conflicts + //#define _interlockedbittestandset _renamed_interlockedbittestandset + //#define _interlockedbittestandreset _renamed_interlockedbittestandreset + //#include <intrin.h> + //#undef _interlockedbittestandset + //#undef _interlockedbittestandreset + + //inline U32 getCPUClockCount32() + //{ + // U64 time_stamp = __rdtsc(); + // return (U32)(time_stamp >> 8); + //} + // + //// return full timer value, *not* shifted by 8 bits + //inline U64 getCPUClockCount64() + //{ + // return __rdtsc(); + //} + + + + // shift off lower 8 bits for lower resolution but longer term timing + // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing #if LL_FASTTIMER_USE_RDTSC - static U32 getCPUClockCount32() - { - unsigned __int64 val = __rdtsc(); - val = val >> 8; - return static_cast<U32>(val); - } - - // return full timer value, *not* shifted by 8 bits - static U64 getCPUClockCount64() - { - return static_cast<U64>( __rdtsc() ); - } + static U32 getCPUClockCount32() + { + unsigned __int64 val = __rdtsc(); + val = val >> 8; + return static_cast<U32>(val); + } + + // return full timer value, *not* shifted by 8 bits + static U64 getCPUClockCount64() + { + return static_cast<U64>( __rdtsc() ); + } #else - //U64 get_clock_count(); // in lltimer.cpp - // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. - static U32 getCPUClockCount32() - { - return (U32)(get_clock_count()>>8); - } - - static U64 getCPUClockCount64() - { - return get_clock_count(); - } + //U64 get_clock_count(); // in lltimer.cpp + // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. + static U32 getCPUClockCount32() + { + return (U32)(get_clock_count()>>8); + } + + static U64 getCPUClockCount64() + { + return get_clock_count(); + } #endif @@ -129,142 +129,142 @@ public: #if (LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) - // - // Linux implementation of CPU clock - non-x86. - // This is accurate but SLOW! Only use out of desperation. - // - // Try to use the MONOTONIC clock if available, this is a constant time counter - // with nanosecond resolution (but not necessarily accuracy) and attempts are - // made to synchronize this value between cores at kernel start. It should not - // be affected by CPU frequency. If not available use the REALTIME clock, but - // this may be affected by NTP adjustments or other user activity affecting - // the system time. - static U64 getCPUClockCount64() - { - struct timespec tp; + // + // Linux implementation of CPU clock - non-x86. + // This is accurate but SLOW! Only use out of desperation. + // + // Try to use the MONOTONIC clock if available, this is a constant time counter + // with nanosecond resolution (but not necessarily accuracy) and attempts are + // made to synchronize this value between cores at kernel start. It should not + // be affected by CPU frequency. If not available use the REALTIME clock, but + // this may be affected by NTP adjustments or other user activity affecting + // the system time. + static U64 getCPUClockCount64() + { + struct timespec tp; #ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time? - if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME + if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME #endif - clock_gettime(CLOCK_REALTIME,&tp); + clock_gettime(CLOCK_REALTIME,&tp); - return (tp.tv_sec*sClockResolution)+tp.tv_nsec; - } + return (tp.tv_sec*sClockResolution)+tp.tv_nsec; + } - static U32 getCPUClockCount32() - { - return (U32)(getCPUClockCount64() >> 8); - } + static U32 getCPUClockCount32() + { + return (U32)(getCPUClockCount64() >> 8); + } #endif // (LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) #if (LL_LINUX || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) - // - // Mac+Linux FAST x86 implementation of CPU clock - static U32 getCPUClockCount32() - { - U32 low(0),high(0); - __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); - return (low>>8) | (high<<24); - } - - static U64 getCPUClockCount64() - { - U32 low(0),high(0); - __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); - return (U64)low | ( ((U64)high) << 32); - } + // + // Mac+Linux FAST x86 implementation of CPU clock + static U32 getCPUClockCount32() + { + U32 low(0),high(0); + __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); + return (low>>8) | (high<<24); + } + + static U64 getCPUClockCount64() + { + U32 low(0),high(0); + __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); + return (U64)low | ( ((U64)high) << 32); + } #endif - static BlockTimerStatHandle& getRootTimeBlock(); - static void pushLog(LLSD sd); - static void setLogLock(class LLMutex* mutex); - static void writeLog(std::ostream& os); - static void updateTimes(); - - static U64 countsPerSecond(); + static BlockTimerStatHandle& getRootTimeBlock(); + static void pushLog(LLSD sd); + static void setLogLock(class LLMutex* mutex); + static void writeLog(std::ostream& os); + static void updateTimes(); + + static U64 countsPerSecond(); - // updates cumulative times and hierarchy, - // can be called multiple times in a frame, at any point - static void processTimes(); + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); - static void bootstrapTimerTree(); - static void incrementalUpdateTimerTree(); + static void bootstrapTimerTree(); + static void incrementalUpdateTimerTree(); - // call this once a frame to periodically log timers - static void logStats(); + // call this once a frame to periodically log timers + static void logStats(); - // dumps current cumulative frame stats to log - // call nextFrame() to reset timers - static void dumpCurTimes(); + // dumps current cumulative frame stats to log + // call nextFrame() to reset timers + static void dumpCurTimes(); private: - friend class BlockTimerStatHandle; - // FIXME: this friendship exists so that each thread can instantiate a root timer, - // which could be a derived class with a public constructor instead, possibly - friend class ThreadRecorder; - friend BlockTimer timeThisBlock(BlockTimerStatHandle&); + friend class BlockTimerStatHandle; + // FIXME: this friendship exists so that each thread can instantiate a root timer, + // which could be a derived class with a public constructor instead, possibly + friend class ThreadRecorder; + friend BlockTimer timeThisBlock(BlockTimerStatHandle&); - BlockTimer(BlockTimerStatHandle& timer); + BlockTimer(BlockTimerStatHandle& timer); - // no-copy - BlockTimer(const BlockTimer& other); - BlockTimer& operator=(const BlockTimer& other); + // no-copy + BlockTimer(const BlockTimer& other); + BlockTimer& operator=(const BlockTimer& other); private: - U64 mStartTime; - BlockTimerStackRecord mParentTimerData; + U64 mStartTime; + BlockTimerStackRecord mParentTimerData; public: - // statics - static std::string sLogName; - static bool sMetricLog, - sLog; - static U64 sClockResolution; + // statics + static std::string sLogName; + static bool sMetricLog, + sLog; + static U64 sClockResolution; }; // this dummy function assists in allocating a block timer with stack-based lifetime. -// this is done by capturing the return value in a stack-allocated const reference variable. +// this is done by capturing the return value in a stack-allocated const reference variable. // (This is most easily done using the macro LL_RECORD_BLOCK_TIME) -// Otherwise, it would be possible to store a BlockTimer on the heap, resulting in non-nested lifetimes, +// Otherwise, it would be possible to store a BlockTimer on the heap, resulting in non-nested lifetimes, // which would break the invariants of the timing hierarchy logic LL_FORCE_INLINE class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer) { - return BlockTimer(timer); + return BlockTimer(timer); } // stores a "named" timer instance to be reused via multiple BlockTimer stack instances -class BlockTimerStatHandle -: public StatType<TimeBlockAccumulator> +class BlockTimerStatHandle +: public StatType<TimeBlockAccumulator> { public: - BlockTimerStatHandle(const char* name, const char* description = ""); - - TimeBlockTreeNode& getTreeNode() const; - BlockTimerStatHandle* getParent() const { return getTreeNode().getParent(); } - void setParent(BlockTimerStatHandle* parent) { getTreeNode().setParent(parent); } - - typedef std::vector<BlockTimerStatHandle*>::iterator child_iter; - typedef std::vector<BlockTimerStatHandle*>::const_iterator child_const_iter; - child_iter beginChildren(); - child_iter endChildren(); - bool hasChildren(); - std::vector<BlockTimerStatHandle*>& getChildren(); - - StatType<TimeBlockAccumulator::CallCountFacet>& callCount() - { - return static_cast<StatType<TimeBlockAccumulator::CallCountFacet>&>(*(StatType<TimeBlockAccumulator>*)this); - } - - StatType<TimeBlockAccumulator::SelfTimeFacet>& selfTime() - { - return static_cast<StatType<TimeBlockAccumulator::SelfTimeFacet>&>(*(StatType<TimeBlockAccumulator>*)this); - } - - bool mCollapsed; // don't show children + BlockTimerStatHandle(const char* name, const char* description = ""); + + TimeBlockTreeNode& getTreeNode() const; + BlockTimerStatHandle* getParent() const { return getTreeNode().getParent(); } + void setParent(BlockTimerStatHandle* parent) { getTreeNode().setParent(parent); } + + typedef std::vector<BlockTimerStatHandle*>::iterator child_iter; + typedef std::vector<BlockTimerStatHandle*>::const_iterator child_const_iter; + child_iter beginChildren(); + child_iter endChildren(); + bool hasChildren(); + std::vector<BlockTimerStatHandle*>& getChildren(); + + StatType<TimeBlockAccumulator::CallCountFacet>& callCount() + { + return static_cast<StatType<TimeBlockAccumulator::CallCountFacet>&>(*(StatType<TimeBlockAccumulator>*)this); + } + + StatType<TimeBlockAccumulator::SelfTimeFacet>& selfTime() + { + return static_cast<StatType<TimeBlockAccumulator::SelfTimeFacet>&>(*(StatType<TimeBlockAccumulator>*)this); + } + + bool mCollapsed; // don't show children }; // iterators and helper functions for walking the call hierarchy of block timers in different ways @@ -282,61 +282,61 @@ block_timer_tree_bf_iterator_t end_block_timer_tree_bf(); LL_FORCE_INLINE BlockTimer::BlockTimer(BlockTimerStatHandle& timer) { #if LL_FAST_TIMER_ON - BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); - if (!cur_timer_data) - { - // How likely is it that - // LLThreadLocalSingletonPointer<T>::getInstance() will return NULL? - // Even without researching, what we can say is that if we exit - // without setting mStartTime at all, gcc 4.7 produces (fatal) - // warnings about a possibly-uninitialized data member. - mStartTime = 0; - return; - } - TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); - accumulator.mActiveCount++; - // keep current parent as long as it is active when we are - accumulator.mMoveUpTree |= (accumulator.mParent->getCurrentAccumulator().mActiveCount == 0); - - // store top of stack - mParentTimerData = *cur_timer_data; - // push new information - cur_timer_data->mActiveTimer = this; - cur_timer_data->mTimeBlock = &timer; - cur_timer_data->mChildTime = 0; - - mStartTime = getCPUClockCount64(); + BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + if (!cur_timer_data) + { + // How likely is it that + // LLThreadLocalSingletonPointer<T>::getInstance() will return NULL? + // Even without researching, what we can say is that if we exit + // without setting mStartTime at all, gcc 4.7 produces (fatal) + // warnings about a possibly-uninitialized data member. + mStartTime = 0; + return; + } + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); + accumulator.mActiveCount++; + // keep current parent as long as it is active when we are + accumulator.mMoveUpTree |= (accumulator.mParent->getCurrentAccumulator().mActiveCount == 0); + + // store top of stack + mParentTimerData = *cur_timer_data; + // push new information + cur_timer_data->mActiveTimer = this; + cur_timer_data->mTimeBlock = &timer; + cur_timer_data->mChildTime = 0; + + mStartTime = getCPUClockCount64(); #endif } LL_FORCE_INLINE BlockTimer::~BlockTimer() { #if LL_FAST_TIMER_ON - U64 total_time = getCPUClockCount64() - mStartTime; - BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); - if (!cur_timer_data) return; + U64 total_time = getCPUClockCount64() - mStartTime; + BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + if (!cur_timer_data) return; - TimeBlockAccumulator& accumulator = cur_timer_data->mTimeBlock->getCurrentAccumulator(); + TimeBlockAccumulator& accumulator = cur_timer_data->mTimeBlock->getCurrentAccumulator(); - accumulator.mCalls++; - accumulator.mTotalTimeCounter += total_time; - accumulator.mSelfTimeCounter += total_time - cur_timer_data->mChildTime; - accumulator.mActiveCount--; + accumulator.mCalls++; + accumulator.mTotalTimeCounter += total_time; + accumulator.mSelfTimeCounter += total_time - cur_timer_data->mChildTime; + accumulator.mActiveCount--; - // store last caller to bootstrap tree creation - // do this in the destructor in case of recursion to get topmost caller - accumulator.mLastCaller = mParentTimerData.mTimeBlock; + // store last caller to bootstrap tree creation + // do this in the destructor in case of recursion to get topmost caller + accumulator.mLastCaller = mParentTimerData.mTimeBlock; - // we are only tracking self time, so subtract our total time delta from parents - mParentTimerData.mChildTime += total_time; + // we are only tracking self time, so subtract our total time delta from parents + mParentTimerData.mChildTime += total_time; - //pop stack - *cur_timer_data = mParentTimerData; + //pop stack + *cur_timer_data = mParentTimerData; #endif } } -typedef LLTrace::BlockTimer LLFastTimer; +typedef LLTrace::BlockTimer LLFastTimer; #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 8355b1e797..1877dd54ed 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -52,9 +52,9 @@ static std::string empty; // On Windows, use strerror_s(). std::string strerr(int errn) { - char buffer[256]; - strerror_s(buffer, errn); // infers sizeof(buffer) -- love it! - return buffer; + char buffer[256]; + strerror_s(buffer, errn); // infers sizeof(buffer) -- love it! + return buffer; } typedef std::basic_ios<char,std::char_traits < char > > _Myios; @@ -69,295 +69,295 @@ typedef std::basic_ios<char,std::char_traits < char > > _Myios; // strerror_r() returns char* std::string message_from(int /*orig_errno*/, const char* /*buffer*/, size_t /*bufflen*/, - const char* strerror_ret) + const char* strerror_ret) { - return strerror_ret; + return strerror_ret; } // strerror_r() returns int std::string message_from(int orig_errno, const char* buffer, size_t bufflen, - int strerror_ret) + int strerror_ret) { - if (strerror_ret == 0) - { - return buffer; - } - // Here strerror_r() has set errno. Since strerror_r() has already failed, - // seems like a poor bet to call it again to diagnose its own error... - int stre_errno = errno; - if (stre_errno == ERANGE) - { - return STRINGIZE("strerror_r() can't explain errno " << orig_errno - << " (" << bufflen << "-byte buffer too small)"); - } - if (stre_errno == EINVAL) - { - return STRINGIZE("unknown errno " << orig_errno); - } - // Here we don't even understand the errno from strerror_r()! - return STRINGIZE("strerror_r() can't explain errno " << orig_errno - << " (error " << stre_errno << ')'); + if (strerror_ret == 0) + { + return buffer; + } + // Here strerror_r() has set errno. Since strerror_r() has already failed, + // seems like a poor bet to call it again to diagnose its own error... + int stre_errno = errno; + if (stre_errno == ERANGE) + { + return STRINGIZE("strerror_r() can't explain errno " << orig_errno + << " (" << bufflen << "-byte buffer too small)"); + } + if (stre_errno == EINVAL) + { + return STRINGIZE("unknown errno " << orig_errno); + } + // Here we don't even understand the errno from strerror_r()! + return STRINGIZE("strerror_r() can't explain errno " << orig_errno + << " (error " << stre_errno << ')'); } std::string strerr(int errn) { - char buffer[256]; - // Select message_from() function matching the strerror_r() we have on hand. - return message_from(errn, buffer, sizeof(buffer), - strerror_r(errn, buffer, sizeof(buffer))); + char buffer[256]; + // Select message_from() function matching the strerror_r() we have on hand. + return message_from(errn, buffer, sizeof(buffer), + strerror_r(errn, buffer, sizeof(buffer))); } -#endif // ! LL_WINDOWS +#endif // ! LL_WINDOWS // On either system, shorthand call just infers global 'errno'. std::string strerr() { - return strerr(errno); + return strerr(errno); } int warnif(const std::string& desc, const std::string& filename, int rc, int accept=0) { - if (rc < 0) - { - // Capture errno before we start emitting output - int errn = errno; - // For certain operations, a particular errno value might be - // acceptable -- e.g. stat() could permit ENOENT, mkdir() could permit - // EEXIST. Don't warn if caller explicitly says this errno is okay. - if (errn != accept) - { - LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename - << "' (errno " << errn << "): " << strerr(errn) << LL_ENDL; - } + if (rc < 0) + { + // Capture errno before we start emitting output + int errn = errno; + // For certain operations, a particular errno value might be + // acceptable -- e.g. stat() could permit ENOENT, mkdir() could permit + // EEXIST. Don't warn if caller explicitly says this errno is okay. + if (errn != accept) + { + LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename + << "' (errno " << errn << "): " << strerr(errn) << LL_ENDL; + } #if 0 && LL_WINDOWS // turn on to debug file-locking problems - // If the problem is "Permission denied," maybe it's because another - // process has the file open. Try to find out. - if (errn == EACCES) // *not* EPERM - { - // Only do any of this stuff (before LL_ENDL) if it will be logged. - LL_DEBUGS("LLFile") << empty; - // would be nice to use LLDir for this, but dependency goes the - // wrong way - const char* TEMP = LLFile::tmpdir(); - if (! (TEMP && *TEMP)) - { - LL_CONT << "No $TEMP, not running 'handle'"; - } - else - { - std::string tf(TEMP); - tf += "\\handle.tmp"; - // http://technet.microsoft.com/en-us/sysinternals/bb896655 - std::string cmd(STRINGIZE("handle \"" << filename - // "openfiles /query /v | fgrep -i \"" << filename - << "\" > \"" << tf << '"')); - LL_CONT << cmd; - if (system(cmd.c_str()) != 0) - { - LL_CONT << "\nDownload 'handle.exe' from http://technet.microsoft.com/en-us/sysinternals/bb896655"; - } - else - { - std::ifstream inf(tf); - std::string line; - while (std::getline(inf, line)) - { - LL_CONT << '\n' << line; - } - } - LLFile::remove(tf); - } - LL_CONT << LL_ENDL; - } + // If the problem is "Permission denied," maybe it's because another + // process has the file open. Try to find out. + if (errn == EACCES) // *not* EPERM + { + // Only do any of this stuff (before LL_ENDL) if it will be logged. + LL_DEBUGS("LLFile") << empty; + // would be nice to use LLDir for this, but dependency goes the + // wrong way + const char* TEMP = LLFile::tmpdir(); + if (! (TEMP && *TEMP)) + { + LL_CONT << "No $TEMP, not running 'handle'"; + } + else + { + std::string tf(TEMP); + tf += "\\handle.tmp"; + // http://technet.microsoft.com/en-us/sysinternals/bb896655 + std::string cmd(STRINGIZE("handle \"" << filename + // "openfiles /query /v | fgrep -i \"" << filename + << "\" > \"" << tf << '"')); + LL_CONT << cmd; + if (system(cmd.c_str()) != 0) + { + LL_CONT << "\nDownload 'handle.exe' from http://technet.microsoft.com/en-us/sysinternals/bb896655"; + } + else + { + std::ifstream inf(tf); + std::string line; + while (std::getline(inf, line)) + { + LL_CONT << '\n' << line; + } + } + LLFile::remove(tf); + } + LL_CONT << LL_ENDL; + } #endif // LL_WINDOWS hack to identify processes holding file open - } - return rc; + } + return rc; } // static -int LLFile::mkdir(const std::string& dirname, int perms) +int LLFile::mkdir(const std::string& dirname, int perms) { #if LL_WINDOWS - // permissions are ignored on Windows - std::string utf8dirname = dirname; - llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); - int rc = _wmkdir(utf16dirname.c_str()); + // permissions are ignored on Windows + std::string utf8dirname = dirname; + llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); + int rc = _wmkdir(utf16dirname.c_str()); #else - int rc = ::mkdir(dirname.c_str(), (mode_t)perms); + int rc = ::mkdir(dirname.c_str(), (mode_t)perms); #endif - // We often use mkdir() to ensure the existence of a directory that might - // already exist. There is no known case in which we want to call out as - // an error the requested directory already existing. - if (rc < 0 && errno == EEXIST) - { - // this is not the error you want, move along - return 0; - } - // anything else might be a problem - return warnif("mkdir", dirname, rc, EEXIST); + // We often use mkdir() to ensure the existence of a directory that might + // already exist. There is no known case in which we want to call out as + // an error the requested directory already existing. + if (rc < 0 && errno == EEXIST) + { + // this is not the error you want, move along + return 0; + } + // anything else might be a problem + return warnif("mkdir", dirname, rc, EEXIST); } // static -int LLFile::rmdir(const std::string& dirname) +int LLFile::rmdir(const std::string& dirname) { #if LL_WINDOWS - // permissions are ignored on Windows - std::string utf8dirname = dirname; - llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); - int rc = _wrmdir(utf16dirname.c_str()); + // permissions are ignored on Windows + std::string utf8dirname = dirname; + llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); + int rc = _wrmdir(utf16dirname.c_str()); #else - int rc = ::rmdir(dirname.c_str()); + int rc = ::rmdir(dirname.c_str()); #endif - return warnif("rmdir", dirname, rc); + return warnif("rmdir", dirname, rc); } // static -LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawfinder: ignore */ +LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawfinder: ignore */ { -#if LL_WINDOWS - std::string utf8filename = filename; - std::string utf8mode = std::string(mode); - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - llutf16string utf16mode = utf8str_to_utf16str(utf8mode); - return _wfopen(utf16filename.c_str(),utf16mode.c_str()); +#if LL_WINDOWS + std::string utf8filename = filename; + std::string utf8mode = std::string(mode); + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + llutf16string utf16mode = utf8str_to_utf16str(utf8mode); + return _wfopen(utf16filename.c_str(),utf16mode.c_str()); #else - return ::fopen(filename.c_str(),mode); /* Flawfinder: ignore */ + return ::fopen(filename.c_str(),mode); /* Flawfinder: ignore */ #endif } -LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int sharingFlag) +LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int sharingFlag) { -#if LL_WINDOWS - std::string utf8filename = filename; - std::string utf8mode = std::string(mode); - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - llutf16string utf16mode = utf8str_to_utf16str(utf8mode); - return _wfsopen(utf16filename.c_str(),utf16mode.c_str(),sharingFlag); +#if LL_WINDOWS + std::string utf8filename = filename; + std::string utf8mode = std::string(mode); + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + llutf16string utf16mode = utf8str_to_utf16str(utf8mode); + return _wfsopen(utf16filename.c_str(),utf16mode.c_str(),sharingFlag); #else - llassert(0);//No corresponding function on non-windows - return NULL; + llassert(0);//No corresponding function on non-windows + return NULL; #endif } -int LLFile::close(LLFILE * file) +int LLFile::close(LLFILE * file) { - int ret_value = 0; - if (file) - { - ret_value = fclose(file); - } - return ret_value; + int ret_value = 0; + if (file) + { + ret_value = fclose(file); + } + return ret_value; } -int LLFile::remove(const std::string& filename, int supress_error) +int LLFile::remove(const std::string& filename, int supress_error) { -#if LL_WINDOWS - std::string utf8filename = filename; - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - int rc = _wremove(utf16filename.c_str()); +#if LL_WINDOWS + std::string utf8filename = filename; + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + int rc = _wremove(utf16filename.c_str()); #else - int rc = ::remove(filename.c_str()); + int rc = ::remove(filename.c_str()); #endif - return warnif("remove", filename, rc, supress_error); + return warnif("remove", filename, rc, supress_error); } -int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) +int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) { -#if LL_WINDOWS - std::string utf8filename = filename; - std::string utf8newname = newname; - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - llutf16string utf16newname = utf8str_to_utf16str(utf8newname); - int rc = _wrename(utf16filename.c_str(),utf16newname.c_str()); +#if LL_WINDOWS + std::string utf8filename = filename; + std::string utf8newname = newname; + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + llutf16string utf16newname = utf8str_to_utf16str(utf8newname); + int rc = _wrename(utf16filename.c_str(),utf16newname.c_str()); #else - int rc = ::rename(filename.c_str(),newname.c_str()); + int rc = ::rename(filename.c_str(),newname.c_str()); #endif - return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); + return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); } bool LLFile::copy(const std::string from, const std::string to) { - bool copied = false; - LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */ - if (in) - { - LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */ - if (out) - { - char buf[16384]; /* Flawfinder: ignore */ - size_t readbytes; - bool write_ok = true; - while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ - { - if (fwrite(buf, 1, readbytes, out) != readbytes) - { - LL_WARNS("LLFile") << "Short write" << LL_ENDL; - write_ok = false; - } - } - if ( write_ok ) - { - copied = true; - } - fclose(out); - } - fclose(in); - } - return copied; + bool copied = false; + LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */ + if (in) + { + LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */ + if (out) + { + char buf[16384]; /* Flawfinder: ignore */ + size_t readbytes; + bool write_ok = true; + while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ + { + if (fwrite(buf, 1, readbytes, out) != readbytes) + { + LL_WARNS("LLFile") << "Short write" << LL_ENDL; + write_ok = false; + } + } + if ( write_ok ) + { + copied = true; + } + fclose(out); + } + fclose(in); + } + return copied; } -int LLFile::stat(const std::string& filename, llstat* filestatus) +int LLFile::stat(const std::string& filename, llstat* filestatus) { #if LL_WINDOWS - std::string utf8filename = filename; - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - int rc = _wstat(utf16filename.c_str(),filestatus); + std::string utf8filename = filename; + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + int rc = _wstat(utf16filename.c_str(),filestatus); #else - int rc = ::stat(filename.c_str(),filestatus); + int rc = ::stat(filename.c_str(),filestatus); #endif - // We use stat() to determine existence (see isfile(), isdir()). - // Don't spam the log if the subject pathname doesn't exist. - return warnif("stat", filename, rc, ENOENT); + // We use stat() to determine existence (see isfile(), isdir()). + // Don't spam the log if the subject pathname doesn't exist. + return warnif("stat", filename, rc, ENOENT); } bool LLFile::isdir(const std::string& filename) { - llstat st; + llstat st; - return stat(filename, &st) == 0 && S_ISDIR(st.st_mode); + return stat(filename, &st) == 0 && S_ISDIR(st.st_mode); } bool LLFile::isfile(const std::string& filename) { - llstat st; + llstat st; - return stat(filename, &st) == 0 && S_ISREG(st.st_mode); + return stat(filename, &st) == 0 && S_ISREG(st.st_mode); } const char *LLFile::tmpdir() { - static std::string utf8path; + static std::string utf8path; - if (utf8path.empty()) - { - char sep; + if (utf8path.empty()) + { + char sep; #if LL_WINDOWS - sep = '\\'; + sep = '\\'; - std::vector<wchar_t> utf16path(MAX_PATH + 1); - GetTempPathW(utf16path.size(), &utf16path[0]); - utf8path = ll_convert_wide_to_string(&utf16path[0]); + std::vector<wchar_t> utf16path(MAX_PATH + 1); + GetTempPathW(utf16path.size(), &utf16path[0]); + utf8path = ll_convert_wide_to_string(&utf16path[0]); #else - sep = '/'; + sep = '/'; - utf8path = LLStringUtil::getenv("TMPDIR", "/tmp/"); + utf8path = LLStringUtil::getenv("TMPDIR", "/tmp/"); #endif - if (utf8path[utf8path.size() - 1] != sep) - { - utf8path += sep; - } - } - return utf8path.c_str(); + if (utf8path[utf8path.size() - 1] != sep) + { + utf8path += sep; + } + } + return utf8path.c_str(); } @@ -365,64 +365,64 @@ const char *LLFile::tmpdir() #if LL_WINDOWS -LLFILE * LLFile::_Fiopen(const std::string& filename, - std::ios::openmode mode) -{ // open a file - static const char *mods[] = - { // fopen mode strings corresponding to valid[i] - "r", "w", "w", "a", "rb", "wb", "wb", "ab", - "r+", "w+", "a+", "r+b", "w+b", "a+b", - 0}; - static const int valid[] = - { // valid combinations of open flags - ios_base::in, - ios_base::out, - ios_base::out | ios_base::trunc, - ios_base::out | ios_base::app, - ios_base::in | ios_base::binary, - ios_base::out | ios_base::binary, - ios_base::out | ios_base::trunc | ios_base::binary, - ios_base::out | ios_base::app | ios_base::binary, - ios_base::in | ios_base::out, - ios_base::in | ios_base::out | ios_base::trunc, - ios_base::in | ios_base::out | ios_base::app, - ios_base::in | ios_base::out | ios_base::binary, - ios_base::in | ios_base::out | ios_base::trunc - | ios_base::binary, - ios_base::in | ios_base::out | ios_base::app - | ios_base::binary, - 0}; - - LLFILE *fp = 0; - int n; - ios_base::openmode atendflag = mode & ios_base::ate; - ios_base::openmode norepflag = mode & ios_base::_Noreplace; - - if (mode & ios_base::_Nocreate) - mode |= ios_base::in; // file must exist - mode &= ~(ios_base::ate | ios_base::_Nocreate | ios_base::_Noreplace); - for (n = 0; valid[n] != 0 && valid[n] != mode; ++n) - ; // look for a valid mode - - if (valid[n] == 0) - return (0); // no valid mode - else if (norepflag && mode & (ios_base::out || ios_base::app) - && (fp = LLFile::fopen(filename, "r")) != 0) /* Flawfinder: ignore */ - { // file must not exist, close and fail - fclose(fp); - return (0); - } - else if (fp != 0 && fclose(fp) != 0) - return (0); // can't close after test open +LLFILE * LLFile::_Fiopen(const std::string& filename, + std::ios::openmode mode) +{ // open a file + static const char *mods[] = + { // fopen mode strings corresponding to valid[i] + "r", "w", "w", "a", "rb", "wb", "wb", "ab", + "r+", "w+", "a+", "r+b", "w+b", "a+b", + 0}; + static const int valid[] = + { // valid combinations of open flags + ios_base::in, + ios_base::out, + ios_base::out | ios_base::trunc, + ios_base::out | ios_base::app, + ios_base::in | ios_base::binary, + ios_base::out | ios_base::binary, + ios_base::out | ios_base::trunc | ios_base::binary, + ios_base::out | ios_base::app | ios_base::binary, + ios_base::in | ios_base::out, + ios_base::in | ios_base::out | ios_base::trunc, + ios_base::in | ios_base::out | ios_base::app, + ios_base::in | ios_base::out | ios_base::binary, + ios_base::in | ios_base::out | ios_base::trunc + | ios_base::binary, + ios_base::in | ios_base::out | ios_base::app + | ios_base::binary, + 0}; + + LLFILE *fp = 0; + int n; + ios_base::openmode atendflag = mode & ios_base::ate; + ios_base::openmode norepflag = mode & ios_base::_Noreplace; + + if (mode & ios_base::_Nocreate) + mode |= ios_base::in; // file must exist + mode &= ~(ios_base::ate | ios_base::_Nocreate | ios_base::_Noreplace); + for (n = 0; valid[n] != 0 && valid[n] != mode; ++n) + ; // look for a valid mode + + if (valid[n] == 0) + return (0); // no valid mode + else if (norepflag && mode & (ios_base::out || ios_base::app) + && (fp = LLFile::fopen(filename, "r")) != 0) /* Flawfinder: ignore */ + { // file must not exist, close and fail + fclose(fp); + return (0); + } + else if (fp != 0 && fclose(fp) != 0) + return (0); // can't close after test open // should open with protection here, if other than default - else if ((fp = LLFile::fopen(filename, mods[n])) == 0) /* Flawfinder: ignore */ - return (0); // open failed + else if ((fp = LLFile::fopen(filename, mods[n])) == 0) /* Flawfinder: ignore */ + return (0); // open failed - if (!atendflag || fseek(fp, 0, SEEK_END) == 0) - return (fp); // no need to seek to end, or seek succeeded + if (!atendflag || fseek(fp, 0, SEEK_END) == 0) + return (fp); // no need to seek to end, or seek succeeded - fclose(fp); // can't position at end - return (0); + fclose(fp); // can't position at end + return (0); } #endif /* LL_WINDOWS */ @@ -469,26 +469,26 @@ void llofstream::open(const std::string& _Filename, ios_base::openmode _Mode) std::streamsize llifstream_size(llifstream& ifstr) { - if(!ifstr.is_open()) return 0; - std::streampos pos_old = ifstr.tellg(); - ifstr.seekg(0, ios_base::beg); - std::streampos pos_beg = ifstr.tellg(); - ifstr.seekg(0, ios_base::end); - std::streampos pos_end = ifstr.tellg(); - ifstr.seekg(pos_old, ios_base::beg); - return pos_end - pos_beg; + if(!ifstr.is_open()) return 0; + std::streampos pos_old = ifstr.tellg(); + ifstr.seekg(0, ios_base::beg); + std::streampos pos_beg = ifstr.tellg(); + ifstr.seekg(0, ios_base::end); + std::streampos pos_end = ifstr.tellg(); + ifstr.seekg(pos_old, ios_base::beg); + return pos_end - pos_beg; } std::streamsize llofstream_size(llofstream& ofstr) { - if(!ofstr.is_open()) return 0; - std::streampos pos_old = ofstr.tellp(); - ofstr.seekp(0, ios_base::beg); - std::streampos pos_beg = ofstr.tellp(); - ofstr.seekp(0, ios_base::end); - std::streampos pos_end = ofstr.tellp(); - ofstr.seekp(pos_old, ios_base::beg); - return pos_end - pos_beg; + if(!ofstr.is_open()) return 0; + std::streampos pos_old = ofstr.tellp(); + ofstr.seekp(0, ios_base::beg); + std::streampos pos_beg = ofstr.tellp(); + ofstr.seekp(0, ios_base::end); + std::streampos pos_end = ofstr.tellp(); + ofstr.seekp(pos_old, ios_base::beg); + return pos_end - pos_beg; } #endif // LL_WINDOWS diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 9de095b45d..08a008c19a 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -1,4 +1,4 @@ -/** +/** * @file llfile.h * @author Michael Schlachter * @date 2006-03-23 @@ -8,21 +8,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,16 +35,16 @@ * Attempts to mostly mirror the POSIX style IO functions. */ -typedef FILE LLFILE; +typedef FILE LLFILE; #include <fstream> #include <sys/stat.h> #if LL_WINDOWS // windows version of stat function and stat data structure are called _stat -typedef struct _stat llstat; +typedef struct _stat llstat; #else -typedef struct stat llstat; +typedef struct stat llstat; #include <sys/types.h> #endif @@ -61,29 +61,29 @@ typedef struct stat llstat; class LL_COMMON_API LLFile { public: - // All these functions take UTF8 path/filenames. - static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */ - static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag); + // All these functions take UTF8 path/filenames. + static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */ + static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag); - static int close(LLFILE * file); + static int close(LLFILE * file); - // perms is a permissions mask like 0777 or 0700. In most cases it will - // be overridden by the user's umask. It is ignored on Windows. - // mkdir() considers "directory already exists" to be SUCCESS. - static int mkdir(const std::string& filename, int perms = 0700); + // perms is a permissions mask like 0777 or 0700. In most cases it will + // be overridden by the user's umask. It is ignored on Windows. + // mkdir() considers "directory already exists" to be SUCCESS. + static int mkdir(const std::string& filename, int perms = 0700); - static int rmdir(const std::string& filename); - static int remove(const std::string& filename, int supress_error = 0); - static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); - static bool copy(const std::string from, const std::string to); + static int rmdir(const std::string& filename); + static int remove(const std::string& filename, int supress_error = 0); + static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); + static bool copy(const std::string from, const std::string to); - static int stat(const std::string& filename,llstat* file_status); - static bool isdir(const std::string& filename); - static bool isfile(const std::string& filename); - static LLFILE * _Fiopen(const std::string& filename, - std::ios::openmode mode); + static int stat(const std::string& filename,llstat* file_status); + static bool isdir(const std::string& filename); + static bool isfile(const std::string& filename); + static LLFILE * _Fiopen(const std::string& filename, + std::ios::openmode mode); - static const char * tmpdir(); + static const char * tmpdir(); }; /// RAII class @@ -158,39 +158,39 @@ private: * Does The Right Thing when passed a non-ASCII pathname. Sadly, that isn't * true of Microsoft's std::ifstream. */ -class LL_COMMON_API llifstream : public std::ifstream +class LL_COMMON_API llifstream : public std::ifstream { - // input stream associated with a C stream + // input stream associated with a C stream public: - // Constructors: - /** - * @brief Default constructor. - * - * Initializes @c sb using its default constructor, and passes - * @c &sb to the base class initializer. Does not open any files - * (you haven't given it a filename to open). + // Constructors: + /** + * @brief Default constructor. + * + * Initializes @c sb using its default constructor, and passes + * @c &sb to the base class initializer. Does not open any files + * (you haven't given it a filename to open). */ - llifstream(); + llifstream(); - /** - * @brief Create an input file stream. - * @param Filename String specifying the filename. - * @param Mode Open file in specified mode (see std::ios_base). - * + /** + * @brief Create an input file stream. + * @param Filename String specifying the filename. + * @param Mode Open file in specified mode (see std::ios_base). + * * @c ios_base::in is automatically included in @a mode. */ - explicit llifstream(const std::string& _Filename, + explicit llifstream(const std::string& _Filename, ios_base::openmode _Mode = ios_base::in); - /** - * @brief Opens an external file. - * @param Filename The name of the file. - * @param Node The open mode flags. - * - * Calls @c llstdio_filebuf::open(s,mode|in). If that function - * fails, @c failbit is set in the stream's error state. + /** + * @brief Opens an external file. + * @param Filename The name of the file. + * @param Node The open mode flags. + * + * Calls @c llstdio_filebuf::open(s,mode|in). If that function + * fails, @c failbit is set in the stream's error state. */ - void open(const std::string& _Filename, + void open(const std::string& _Filename, ios_base::openmode _Mode = ios_base::in); }; @@ -203,37 +203,37 @@ class LL_COMMON_API llifstream : public std::ifstream * Right Thing when passed a non-ASCII pathname. Sadly, that isn't true of * Microsoft's std::ofstream. */ -class LL_COMMON_API llofstream : public std::ofstream +class LL_COMMON_API llofstream : public std::ofstream { public: - // Constructors: - /** - * @brief Default constructor. - * - * Initializes @c sb using its default constructor, and passes - * @c &sb to the base class initializer. Does not open any files - * (you haven't given it a filename to open). + // Constructors: + /** + * @brief Default constructor. + * + * Initializes @c sb using its default constructor, and passes + * @c &sb to the base class initializer. Does not open any files + * (you haven't given it a filename to open). */ - llofstream(); - - /** - * @brief Create an output file stream. - * @param Filename String specifying the filename. - * @param Mode Open file in specified mode (see std::ios_base). - * - * @c ios_base::out is automatically included in @a mode. + llofstream(); + + /** + * @brief Create an output file stream. + * @param Filename String specifying the filename. + * @param Mode Open file in specified mode (see std::ios_base). + * + * @c ios_base::out is automatically included in @a mode. */ - explicit llofstream(const std::string& _Filename, + explicit llofstream(const std::string& _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); - /** - * @brief Opens an external file. - * @param Filename The name of the file. - * @param Node The open mode flags. - * - * @c ios_base::out is automatically included in @a mode. + /** + * @brief Opens an external file. + * @param Filename The name of the file. + * @param Node The open mode flags. + * + * @c ios_base::out is automatically included in @a mode. */ - void open(const std::string& _Filename, + void open(const std::string& _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); }; diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp index f019bd0c64..e39812bfc4 100644 --- a/indra/llcommon/llfindlocale.cpp +++ b/indra/llcommon/llfindlocale.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfindlocale.cpp * @brief Detect system language setting * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llfindlocale.h b/indra/llcommon/llfindlocale.h index 6770db5774..07b59853c3 100644 --- a/indra/llcommon/llfindlocale.h +++ b/indra/llcommon/llfindlocale.h @@ -1,25 +1,25 @@ -/** +/** * @file llfindlocale.h * @brief Detect system language setting * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index bd4db8be84..4f28d2240e 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llfixedbuffer.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,69 +29,69 @@ //////////////////////////////////////////////////////////////////////////// LLFixedBuffer::LLFixedBuffer(const U32 max_lines) - : LLLineBuffer(), - mMaxLines(max_lines), - mMutex() + : LLLineBuffer(), + mMaxLines(max_lines), + mMutex() { - mTimer.reset(); + mTimer.reset(); } LLFixedBuffer::~LLFixedBuffer() { - clear(); + clear(); } void LLFixedBuffer::clear() { - mMutex.lock() ; - mLines.clear(); - mAddTimes.clear(); - mLineLengths.clear(); - mMutex.unlock() ; + mMutex.lock() ; + mLines.clear(); + mAddTimes.clear(); + mLineLengths.clear(); + mMutex.unlock() ; - mTimer.reset(); + mTimer.reset(); } void LLFixedBuffer::addLine(const std::string& utf8line) { - LLWString wstring = utf8str_to_wstring(utf8line); - addWLine(wstring); + LLWString wstring = utf8str_to_wstring(utf8line); + addWLine(wstring); } void LLFixedBuffer::addWLine(const LLWString& line) { - if (line.empty()) - { - return; - } - - removeExtraLines(); - - mMutex.lock() ; - mLines.push_back(line); - mLineLengths.push_back((S32)line.length()); - mAddTimes.push_back(mTimer.getElapsedTimeF32()); - mMutex.unlock() ; + if (line.empty()) + { + return; + } + + removeExtraLines(); + + mMutex.lock() ; + mLines.push_back(line); + mLineLengths.push_back((S32)line.length()); + mAddTimes.push_back(mTimer.getElapsedTimeF32()); + mMutex.unlock() ; } void LLFixedBuffer::setMaxLines(S32 max_lines) { - mMaxLines = max_lines; + mMaxLines = max_lines; - removeExtraLines(); + removeExtraLines(); } void LLFixedBuffer::removeExtraLines() { - mMutex.lock() ; - while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1))) - { - mLines.pop_front(); - mAddTimes.pop_front(); - mLineLengths.pop_front(); - } - mMutex.unlock() ; + mMutex.lock() ; + while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1))) + { + mLines.pop_front(); + mAddTimes.pop_front(); + mLineLengths.pop_front(); + } + mMutex.unlock() ; } diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h index 554cf48a4c..eca0792d35 100644 --- a/indra/llcommon/llfixedbuffer.h +++ b/indra/llcommon/llfixedbuffer.h @@ -1,25 +1,25 @@ -/** +/** * @file llfixedbuffer.h * @brief A fixed size buffer of lines. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,27 +38,27 @@ class LL_COMMON_API LLFixedBuffer : public LLLineBuffer { public: - LLFixedBuffer(const U32 max_lines = 20); - ~LLFixedBuffer(); + LLFixedBuffer(const U32 max_lines = 20); + ~LLFixedBuffer(); + + LLTimer mTimer; + U32 mMaxLines; + std::deque<LLWString> mLines; + std::deque<F32> mAddTimes; + std::deque<S32> mLineLengths; - LLTimer mTimer; - U32 mMaxLines; - std::deque<LLWString> mLines; - std::deque<F32> mAddTimes; - std::deque<S32> mLineLengths; + /*virtual*/ void clear(); // Clear the buffer, and reset it. - /*virtual*/ void clear(); // Clear the buffer, and reset it. + /*virtual*/ void addLine(const std::string& utf8line); - /*virtual*/ void addLine(const std::string& utf8line); + void setMaxLines(S32 max_lines); - void setMaxLines(S32 max_lines); - protected: - void removeExtraLines(); - void addWLine(const LLWString& line); + void removeExtraLines(); + void addWLine(const LLWString& line); protected: - LLMutex mMutex ; + LLMutex mMutex ; }; #endif //LL_FIXED_BUFFER_H diff --git a/indra/llcommon/llformat.cpp b/indra/llcommon/llformat.cpp index 3b2b3038ea..dc5726e29f 100644 --- a/indra/llcommon/llformat.cpp +++ b/indra/llcommon/llformat.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llformat.cpp * @date January 2007 * @brief string formatting utility @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,36 +35,36 @@ // wrapper for vsnprintf to be called from llformatXXX functions. static void va_format(std::string& out, const char *fmt, va_list va) { - char tstr[1024]; /* Flawfinder: ignore */ + char tstr[1024]; /* Flawfinder: ignore */ #if LL_WINDOWS - _vsnprintf(tstr, 1024, fmt, va); + _vsnprintf(tstr, 1024, fmt, va); #else - vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ + vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ #endif - out.assign(tstr); + out.assign(tstr); } std::string llformat(const char *fmt, ...) { - std::string res; - va_list va; - va_start(va, fmt); - va_format(res, fmt, va); - va_end(va); - return res; + std::string res; + va_list va; + va_start(va, fmt); + va_format(res, fmt, va); + va_end(va); + return res; } std::string llformat_to_utf8(const char *fmt, ...) { - std::string res; - va_list va; - va_start(va, fmt); - va_format(res, fmt, va); - va_end(va); + std::string res; + va_list va; + va_start(va, fmt); + va_format(res, fmt, va); + va_end(va); #if LL_WINDOWS - // made converting to utf8. See EXT-8318. - res = ll_convert_string_to_utf8_string(res); + // made converting to utf8. See EXT-8318. + res = ll_convert_string_to_utf8_string(res); #endif - return res; + return res; } diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h index fb8e7cd045..4456a72696 100644 --- a/indra/llcommon/llformat.h +++ b/indra/llcommon/llformat.h @@ -1,4 +1,4 @@ -/** +/** * @file llformat.h * @date January 2007 * @brief string formatting utility @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp index 1e9920746b..2805662d6f 100644 --- a/indra/llcommon/llframetimer.cpp +++ b/indra/llcommon/llframetimer.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llframetimer.cpp * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,7 +30,7 @@ #include "llframetimer.h" // Static members -//LLTimer LLFrameTimer::sInternalTimer; +//LLTimer LLFrameTimer::sInternalTimer; U64 LLFrameTimer::sStartTotalTime = totalTime(); F64 LLFrameTimer::sFrameTime = 0.0; U64 LLFrameTimer::sTotalTime = 0; @@ -42,34 +42,34 @@ const F64 USEC_TO_SEC_F64 = 0.000001; // static void LLFrameTimer::updateFrameTime() { - U64 total_time = totalTime(); - sFrameDeltaTime = total_time - sTotalTime; - sTotalTime = total_time; - sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64; - sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64; -} + U64 total_time = totalTime(); + sFrameDeltaTime = total_time - sTotalTime; + sTotalTime = total_time; + sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64; + sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64; +} void LLFrameTimer::start() { - reset(); - mStarted = TRUE; + reset(); + mStarted = TRUE; } void LLFrameTimer::stop() { - mStarted = FALSE; + mStarted = FALSE; } void LLFrameTimer::reset() { - mStartTime = sFrameTime; - mExpiry = sFrameTime; + mStartTime = sFrameTime; + mExpiry = sFrameTime; } void LLFrameTimer::resetWithExpiry(F32 expiration) { - reset(); - setTimerExpirySec(expiration); + reset(); + setTimerExpirySec(expiration); } // Don't combine pause/unpause with start/stop @@ -82,69 +82,69 @@ void LLFrameTimer::resetWithExpiry(F32 expiration) // Note: elapsed would also be valid with no unpause() call (= time run until pause() called) void LLFrameTimer::pause() { - if (mStarted) - mStartTime = sFrameTime - mStartTime; // save dtime - mStarted = FALSE; + if (mStarted) + mStartTime = sFrameTime - mStartTime; // save dtime + mStarted = FALSE; } void LLFrameTimer::unpause() { - if (!mStarted) - mStartTime = sFrameTime - mStartTime; // restore dtime - mStarted = TRUE; + if (!mStarted) + mStartTime = sFrameTime - mStartTime; // restore dtime + mStarted = TRUE; } void LLFrameTimer::setTimerExpirySec(F32 expiration) { - mExpiry = expiration + mStartTime; + mExpiry = expiration + mStartTime; } void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch) { - mStartTime = sFrameTime; - mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime); + mStartTime = sFrameTime; + mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime); } F64 LLFrameTimer::expiresAt() const { - F64 expires_at = U64_to_F64(sStartTotalTime) * USEC_TO_SEC_F64; - expires_at += mExpiry; - return expires_at; + F64 expires_at = U64_to_F64(sStartTotalTime) * USEC_TO_SEC_F64; + expires_at += mExpiry; + return expires_at; } BOOL LLFrameTimer::checkExpirationAndReset(F32 expiration) { - //LL_INFOS() << "LLFrameTimer::checkExpirationAndReset()" << LL_ENDL; - //LL_INFOS() << " mStartTime:" << mStartTime << LL_ENDL; - //LL_INFOS() << " sFrameTime:" << sFrameTime << LL_ENDL; - //LL_INFOS() << " mExpiry: " << mExpiry << LL_ENDL; - - if(hasExpired()) - { - reset(); - setTimerExpirySec(expiration); - return TRUE; - } - return FALSE; + //LL_INFOS() << "LLFrameTimer::checkExpirationAndReset()" << LL_ENDL; + //LL_INFOS() << " mStartTime:" << mStartTime << LL_ENDL; + //LL_INFOS() << " sFrameTime:" << sFrameTime << LL_ENDL; + //LL_INFOS() << " mExpiry: " << mExpiry << LL_ENDL; + + if(hasExpired()) + { + reset(); + setTimerExpirySec(expiration); + return TRUE; + } + return FALSE; } // static F32 LLFrameTimer::getFrameDeltaTimeF32() { - return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64); + return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64); } -// static +// static // Return seconds since the current frame started F32 LLFrameTimer::getCurrentFrameTime() { - U64 frame_time = totalTime() - sTotalTime; - return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64); + U64 frame_time = totalTime() - sTotalTime; + return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64); } // Glue code to avoid full class .h file #includes F32 getCurrentFrameTime() { - return (F32)(LLFrameTimer::getCurrentFrameTime()); + return (F32)(LLFrameTimer::getCurrentFrameTime()); } diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index 81bd5da8a3..876d933fd1 100644 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -1,4 +1,4 @@ -/** +/** * @file llframetimer.h * @brief A lightweight timer that measures seconds and is only * updated once per frame. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,113 +36,113 @@ #include "lltimer.h" -class LL_COMMON_API LLFrameTimer +class LL_COMMON_API LLFrameTimer { public: - LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {} + LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {} - // Return the number of seconds since the start of this - // application instance. - static F64SecondsImplicit getElapsedSeconds() - { - // Loses msec precision after ~4.5 hours... - return sFrameTime; - } - - // Return a low precision usec since epoch - static U64 getTotalTime() - { - return sTotalTime ? U64MicrosecondsImplicit(sTotalTime) : totalTime(); - } - - // Return a low precision seconds since epoch - static F64 getTotalSeconds() - { - return sTotalSeconds; - } - - // Call this method once per frame to update the current frame time. This is actually called - // at some other times as well - static void updateFrameTime(); - - // Call this method once, and only once, per frame to update the current frame count. - static void updateFrameCount() { sFrameCount++; } - - static U32 getFrameCount() { return sFrameCount; } - - static F32 getFrameDeltaTimeF32(); - - // Return seconds since the current frame started - static F32 getCurrentFrameTime(); - - // MANIPULATORS - void start(); - void stop(); - void reset(); - void resetWithExpiry(F32 expiration); - void pause(); - void unpause(); - void setTimerExpirySec(F32 expiration); - void setExpiryAt(F64 seconds_since_epoch); - BOOL checkExpirationAndReset(F32 expiration); - F32 getElapsedTimeAndResetF32() { F32 t = F32(sFrameTime - mStartTime); reset(); return t; } - - void setAge(const F64 age) { mStartTime = sFrameTime - age; } - - // ACCESSORS - BOOL hasExpired() const { return (sFrameTime >= mExpiry); } - F32 getTimeToExpireF32() const { return (F32)(mExpiry - sFrameTime); } - F32 getElapsedTimeF32() const { return mStarted ? (F32)(sFrameTime - mStartTime) : (F32)mStartTime; } - BOOL getStarted() const { return mStarted; } - - // return the seconds since epoch when this timer will expire. - F64 expiresAt() const; - -protected: - // A single, high resolution timer that drives all LLFrameTimers - // *NOTE: no longer used. - //static LLTimer sInternalTimer; - - // - // Aplication constants - // - - // Start time of opp in usec since epoch - static U64 sStartTotalTime; - - // - // Data updated per frame - // - - // Seconds since application start - static F64 sFrameTime; - - // Time that has elapsed since last call to updateFrameTime() - static U64 sFrameDeltaTime; - - // Total microseconds since epoch. - static U64 sTotalTime; - - // Seconds since epoch. - static F64 sTotalSeconds; - - // Total number of frames elapsed in application - static S32 sFrameCount; - - // - // Member data - // - - // Number of seconds after application start when this timer was - // started. Set equal to sFrameTime when reset. - F64 mStartTime; - - // Timer expires this many seconds after application start time. - F64 mExpiry; - - // Useful bit of state usually associated with timers, but does - // not affect actual functionality - BOOL mStarted; + // Return the number of seconds since the start of this + // application instance. + static F64SecondsImplicit getElapsedSeconds() + { + // Loses msec precision after ~4.5 hours... + return sFrameTime; + } + + // Return a low precision usec since epoch + static U64 getTotalTime() + { + return sTotalTime ? U64MicrosecondsImplicit(sTotalTime) : totalTime(); + } + + // Return a low precision seconds since epoch + static F64 getTotalSeconds() + { + return sTotalSeconds; + } + + // Call this method once per frame to update the current frame time. This is actually called + // at some other times as well + static void updateFrameTime(); + + // Call this method once, and only once, per frame to update the current frame count. + static void updateFrameCount() { sFrameCount++; } + + static U32 getFrameCount() { return sFrameCount; } + + static F32 getFrameDeltaTimeF32(); + + // Return seconds since the current frame started + static F32 getCurrentFrameTime(); + + // MANIPULATORS + void start(); + void stop(); + void reset(); + void resetWithExpiry(F32 expiration); + void pause(); + void unpause(); + void setTimerExpirySec(F32 expiration); + void setExpiryAt(F64 seconds_since_epoch); + BOOL checkExpirationAndReset(F32 expiration); + F32 getElapsedTimeAndResetF32() { F32 t = F32(sFrameTime - mStartTime); reset(); return t; } + + void setAge(const F64 age) { mStartTime = sFrameTime - age; } + + // ACCESSORS + BOOL hasExpired() const { return (sFrameTime >= mExpiry); } + F32 getTimeToExpireF32() const { return (F32)(mExpiry - sFrameTime); } + F32 getElapsedTimeF32() const { return mStarted ? (F32)(sFrameTime - mStartTime) : (F32)mStartTime; } + BOOL getStarted() const { return mStarted; } + + // return the seconds since epoch when this timer will expire. + F64 expiresAt() const; + +protected: + // A single, high resolution timer that drives all LLFrameTimers + // *NOTE: no longer used. + //static LLTimer sInternalTimer; + + // + // Aplication constants + // + + // Start time of opp in usec since epoch + static U64 sStartTotalTime; + + // + // Data updated per frame + // + + // Seconds since application start + static F64 sFrameTime; + + // Time that has elapsed since last call to updateFrameTime() + static U64 sFrameDeltaTime; + + // Total microseconds since epoch. + static U64 sTotalTime; + + // Seconds since epoch. + static F64 sTotalSeconds; + + // Total number of frames elapsed in application + static S32 sFrameCount; + + // + // Member data + // + + // Number of seconds after application start when this timer was + // started. Set equal to sFrameTime when reset. + F64 mStartTime; + + // Timer expires this many seconds after application start time. + F64 mExpiry; + + // Useful bit of state usually associated with timers, but does + // not affect actual functionality + BOOL mStarted; }; // Glue code for Havok (or anything else that doesn't want the full .h files) diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h index 570cd330b8..ceea1d9c48 100644 --- a/indra/llcommon/llhandle.h +++ b/indra/llcommon/llhandle.h @@ -1,4 +1,4 @@ -/** +/** * @file llhandle.h * @brief "Handle" to an object (usually a floater) whose lifetime you don't * control. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,22 +42,22 @@ class LLTombStone : public LLRefCount { public: - LLTombStone(void* target = NULL) : mTarget(target) {} + LLTombStone(void* target = NULL) : mTarget(target) {} - void setTarget(void* target) { mTarget = target; } - void* getTarget() const { return mTarget; } + void setTarget(void* target) { mTarget = target; } + void* getTarget() const { return mTarget; } private: - mutable void* mTarget; + mutable void* mTarget; }; /** - * LLHandles are used to refer to objects whose lifetime you do not control or influence. - * Calling get() on a handle will return a pointer to the referenced object or NULL, - * if the object no longer exists. Note that during the lifetime of the returned pointer, - * you are assuming that the object will not be deleted by any action you perform, - * or any other thread, as normal when using pointers, so avoid using that pointer outside of - * the local code block. - * + * LLHandles are used to refer to objects whose lifetime you do not control or influence. + * Calling get() on a handle will return a pointer to the referenced object or NULL, + * if the object no longer exists. Note that during the lifetime of the returned pointer, + * you are assuming that the object will not be deleted by any action you perform, + * or any other thread, as normal when using pointers, so avoid using that pointer outside of + * the local code block. + * * https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669 * * The implementation is like some "weak pointer" implementations. When we @@ -84,58 +84,58 @@ private: template <typename T> class LLHandle { - template <typename U> friend class LLHandle; - template <typename U> friend class LLHandleProvider; + template <typename U> friend class LLHandle; + template <typename U> friend class LLHandleProvider; public: - LLHandle() : mTombStone(getDefaultTombStone()) {} - - template<typename U> - LLHandle(const LLHandle<U>& other, typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) - : mTombStone(other.mTombStone) - {} - - bool isDead() const - { - return mTombStone->getTarget() == NULL; - } - - void markDead() - { - mTombStone = getDefaultTombStone(); - } - - T* get() const - { - return reinterpret_cast<T*>(mTombStone->getTarget()); - } - - friend bool operator== (const LLHandle<T>& lhs, const LLHandle<T>& rhs) - { - return lhs.mTombStone == rhs.mTombStone; - } - friend bool operator!= (const LLHandle<T>& lhs, const LLHandle<T>& rhs) - { - return !(lhs == rhs); - } - friend bool operator< (const LLHandle<T>& lhs, const LLHandle<T>& rhs) - { - return lhs.mTombStone < rhs.mTombStone; - } - friend bool operator> (const LLHandle<T>& lhs, const LLHandle<T>& rhs) - { - return lhs.mTombStone > rhs.mTombStone; - } + LLHandle() : mTombStone(getDefaultTombStone()) {} + + template<typename U> + LLHandle(const LLHandle<U>& other, typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) + : mTombStone(other.mTombStone) + {} + + bool isDead() const + { + return mTombStone->getTarget() == NULL; + } + + void markDead() + { + mTombStone = getDefaultTombStone(); + } + + T* get() const + { + return reinterpret_cast<T*>(mTombStone->getTarget()); + } + + friend bool operator== (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return lhs.mTombStone == rhs.mTombStone; + } + friend bool operator!= (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return !(lhs == rhs); + } + friend bool operator< (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return lhs.mTombStone < rhs.mTombStone; + } + friend bool operator> (const LLHandle<T>& lhs, const LLHandle<T>& rhs) + { + return lhs.mTombStone > rhs.mTombStone; + } protected: - LLPointer<LLTombStone> mTombStone; + LLPointer<LLTombStone> mTombStone; private: - typedef T* pointer_t; - static LLPointer<LLTombStone>& getDefaultTombStone() - { - static LLPointer<LLTombStone> sDefaultTombStone = new LLTombStone; - return sDefaultTombStone; - } + typedef T* pointer_t; + static LLPointer<LLTombStone>& getDefaultTombStone() + { + static LLPointer<LLTombStone> sDefaultTombStone = new LLTombStone; + return sDefaultTombStone; + } }; /** @@ -150,36 +150,36 @@ template <typename T> class LLRootHandle : public LLHandle<T> { public: - typedef LLRootHandle<T> self_t; - typedef LLHandle<T> base_t; - - LLRootHandle(T* object) { bind(object); } - LLRootHandle() {}; - ~LLRootHandle() { unbind(); } - - // this is redundant, since an LLRootHandle *is* an LLHandle - //LLHandle<T> getHandle() { return LLHandle<T>(*this); } - - void bind(T* object) - { - // unbind existing tombstone - if (LLHandle<T>::mTombStone.notNull()) - { - if (LLHandle<T>::mTombStone->getTarget() == (void*)object) return; - LLHandle<T>::mTombStone->setTarget(NULL); - } - // tombstone reference counted, so no paired delete - LLHandle<T>::mTombStone = new LLTombStone((void*)object); - } - - void unbind() - { - LLHandle<T>::mTombStone->setTarget(NULL); - } - - //don't allow copying of root handles, since there should only be one + typedef LLRootHandle<T> self_t; + typedef LLHandle<T> base_t; + + LLRootHandle(T* object) { bind(object); } + LLRootHandle() {}; + ~LLRootHandle() { unbind(); } + + // this is redundant, since an LLRootHandle *is* an LLHandle + //LLHandle<T> getHandle() { return LLHandle<T>(*this); } + + void bind(T* object) + { + // unbind existing tombstone + if (LLHandle<T>::mTombStone.notNull()) + { + if (LLHandle<T>::mTombStone->getTarget() == (void*)object) return; + LLHandle<T>::mTombStone->setTarget(NULL); + } + // tombstone reference counted, so no paired delete + LLHandle<T>::mTombStone = new LLTombStone((void*)object); + } + + void unbind() + { + LLHandle<T>::mTombStone->setTarget(NULL); + } + + //don't allow copying of root handles, since there should only be one private: - LLRootHandle(const LLRootHandle& other) {}; + LLRootHandle(const LLRootHandle& other) {}; }; /** @@ -190,31 +190,31 @@ template <typename T> class LLHandleProvider { public: - LLHandle<T> getHandle() const - { - // perform lazy binding to avoid small tombstone allocations for handle - // providers whose handles are never referenced - mHandle.bind(static_cast<T*>(const_cast<LLHandleProvider<T>* >(this))); - return mHandle; - } - - template <typename U> - LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const - { - LLHandle<U> downcast_handle; - downcast_handle.mTombStone = getHandle().mTombStone; - return downcast_handle; - } + LLHandle<T> getHandle() const + { + // perform lazy binding to avoid small tombstone allocations for handle + // providers whose handles are never referenced + mHandle.bind(static_cast<T*>(const_cast<LLHandleProvider<T>* >(this))); + return mHandle; + } + + template <typename U> + LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const + { + LLHandle<U> downcast_handle; + downcast_handle.mTombStone = getHandle().mTombStone; + return downcast_handle; + } protected: - typedef LLHandle<T> handle_type_t; - LLHandleProvider() - { - // provided here to enforce T deriving from LLHandleProvider<T> - } + typedef LLHandle<T> handle_type_t; + LLHandleProvider() + { + // provided here to enforce T deriving from LLHandleProvider<T> + } private: - mutable LLRootHandle<T> mHandle; + mutable LLRootHandle<T> mHandle; }; @@ -236,12 +236,12 @@ protected: }; /** - * This is a simple wrapper for Handles, allowing direct calls to the underlying - * pointer. The checked handle will throw a Stale if an attempt - * is made to access the object referenced by the handle and that object has + * This is a simple wrapper for Handles, allowing direct calls to the underlying + * pointer. The checked handle will throw a Stale if an attempt + * is made to access the object referenced by the handle and that object has * been destroyed. **/ -template <typename T> +template <typename T> class LLCheckedHandle: public LLCheckedHandleBase { public: @@ -269,7 +269,7 @@ public: } /** - * Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {} + * Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {} * Does not throw. */ /*explicit*/ operator bool() const // explicit conversion operator not available with Linux compiler @@ -278,8 +278,8 @@ public: } /** - * Attempt to call a method or access a member in the structure referenced - * by the handle. If the handle no longer points to a valid structure + * Attempt to call a method or access a member in the structure referenced + * by the handle. If the handle no longer points to a valid structure * throw a Stale. */ T* operator ->() const diff --git a/indra/llcommon/llhash.h b/indra/llcommon/llhash.h index 4b58e81565..aa1fa2d336 100644 --- a/indra/llcommon/llhash.h +++ b/indra/llcommon/llhash.h @@ -1,25 +1,25 @@ -/** +/** * @file llhash.h * @brief Wrapper for a hash function. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,17 +36,17 @@ inline size_t llhash( const char * value ) { - // boost::hash is defined for std::string and for char, but there's no - // special overload for const char*. The lazy approach would be to - // instantiate a std::string and take its hash, but that might be more - // overhead than our callers want. Or we could use boost::hash_range() -- - // but that would require a preliminary pass over the value to determine - // the end iterator. Instead, use boost::hash_combine() to hash individual - // characters. - std::size_t seed = 0; - for ( ; *value; ++value) - boost::hash_combine(seed, *value); - return seed; + // boost::hash is defined for std::string and for char, but there's no + // special overload for const char*. The lazy approach would be to + // instantiate a std::string and take its hash, but that might be more + // overhead than our callers want. Or we could use boost::hash_range() -- + // but that would require a preliminary pass over the value to determine + // the end iterator. Instead, use boost::hash_combine() to hash individual + // characters. + std::size_t seed = 0; + for ( ; *value; ++value) + boost::hash_combine(seed, *value); + return seed; } #endif diff --git a/indra/llcommon/llheartbeat.cpp b/indra/llcommon/llheartbeat.cpp index 19b7452748..96480050a5 100644 --- a/indra/llcommon/llheartbeat.cpp +++ b/indra/llcommon/llheartbeat.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,28 +33,28 @@ #include "llheartbeat.h" LLHeartbeat::LLHeartbeat(F32 secs_between_heartbeat, - F32 aggressive_heartbeat_panic_secs, - F32 aggressive_heartbeat_max_blocking_secs) - : mSecsBetweenHeartbeat(secs_between_heartbeat), - mAggressiveHeartbeatPanicSecs(aggressive_heartbeat_panic_secs), - mAggressiveHeartbeatMaxBlockingSecs(aggressive_heartbeat_max_blocking_secs), - mSuppressed(false) + F32 aggressive_heartbeat_panic_secs, + F32 aggressive_heartbeat_max_blocking_secs) + : mSecsBetweenHeartbeat(secs_between_heartbeat), + mAggressiveHeartbeatPanicSecs(aggressive_heartbeat_panic_secs), + mAggressiveHeartbeatMaxBlockingSecs(aggressive_heartbeat_max_blocking_secs), + mSuppressed(false) { - mBeatTimer.reset(); - mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); - mPanicTimer.reset(); - mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); + mBeatTimer.reset(); + mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); + mPanicTimer.reset(); + mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); } LLHeartbeat::~LLHeartbeat() { - // do nothing. + // do nothing. } void LLHeartbeat::setSuppressed(bool is_suppressed) { - mSuppressed = is_suppressed; + mSuppressed = is_suppressed; } // returns 0 on success, -1 on permanent failure, 1 on temporary failure @@ -62,104 +62,104 @@ int LLHeartbeat::rawSend() { #if LL_WINDOWS - return 0; // Pretend we succeeded. + return 0; // Pretend we succeeded. #else - if (mSuppressed) - return 0; // Pretend we succeeded. + if (mSuppressed) + return 0; // Pretend we succeeded. - int result; + int result; #ifndef LL_DARWIN - union sigval dummy; - result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy); + union sigval dummy; + result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy); #else - result = kill(getppid(), LL_HEARTBEAT_SIGNAL); + result = kill(getppid(), LL_HEARTBEAT_SIGNAL); #endif - if (result == 0) - return 0; // success + if (result == 0) + return 0; // success - int err = errno; - if (err == EAGAIN) - return 1; // failed to queue, try again + int err = errno; + if (err == EAGAIN) + return 1; // failed to queue, try again - return -1; // other failure. + return -1; // other failure. #endif } int LLHeartbeat::rawSendWithTimeout(F32 timeout_sec) { - int result = 0; - - // Spin tightly until our heartbeat is digested by the watchdog - // or we time-out. We don't really want to sleep because our - // wake-up time might be undesirably synchronised to a hidden - // clock by the system's scheduler. - mTimeoutTimer.reset(); - mTimeoutTimer.setTimerExpirySec(timeout_sec); - do { - result = rawSend(); - //LL_INFOS() << " HEARTSENDc=" << result << LL_ENDL; - } while (result==1 && !mTimeoutTimer.hasExpired()); - - return result; + int result = 0; + + // Spin tightly until our heartbeat is digested by the watchdog + // or we time-out. We don't really want to sleep because our + // wake-up time might be undesirably synchronised to a hidden + // clock by the system's scheduler. + mTimeoutTimer.reset(); + mTimeoutTimer.setTimerExpirySec(timeout_sec); + do { + result = rawSend(); + //LL_INFOS() << " HEARTSENDc=" << result << LL_ENDL; + } while (result==1 && !mTimeoutTimer.hasExpired()); + + return result; } bool LLHeartbeat::send(F32 timeout_sec) { - bool total_success = false; - int result = 1; - - if (timeout_sec > 0.f) { - // force a spin until success or timeout - result = rawSendWithTimeout(timeout_sec); - } else { - if (mBeatTimer.hasExpired()) { - // zero-timeout; we don't care too much whether our - // heartbeat was digested. - result = rawSend(); - //LL_INFOS() << " HEARTSENDb=" << result << LL_ENDL; - } - } - - if (result == -1) { - // big failure. - } else if (result == 0) { - total_success = true; - } else { - // need to retry at some point - } - - if (total_success) { - mBeatTimer.reset(); - mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); - // reset the time until we start panicking about lost - // heartbeats again. - mPanicTimer.reset(); - mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); - } else { - // leave mBeatTimer as expired so we'll lazily poke the - // watchdog again next time through. - } - - if (mPanicTimer.hasExpired()) { - // It's been ages since we successfully had a heartbeat - // digested by the watchdog. Sit here and spin a while - // in the hope that we can force it through. - LL_WARNS() << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; - result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs); - if (result == 0) { - total_success = true; - } else { - // we couldn't even force it through. That's bad, - // but we'll try again in a while. - LL_WARNS() << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; - } - - // in any case, reset the panic timer. - mPanicTimer.reset(); - mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); - } - - return total_success; + bool total_success = false; + int result = 1; + + if (timeout_sec > 0.f) { + // force a spin until success or timeout + result = rawSendWithTimeout(timeout_sec); + } else { + if (mBeatTimer.hasExpired()) { + // zero-timeout; we don't care too much whether our + // heartbeat was digested. + result = rawSend(); + //LL_INFOS() << " HEARTSENDb=" << result << LL_ENDL; + } + } + + if (result == -1) { + // big failure. + } else if (result == 0) { + total_success = true; + } else { + // need to retry at some point + } + + if (total_success) { + mBeatTimer.reset(); + mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); + // reset the time until we start panicking about lost + // heartbeats again. + mPanicTimer.reset(); + mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); + } else { + // leave mBeatTimer as expired so we'll lazily poke the + // watchdog again next time through. + } + + if (mPanicTimer.hasExpired()) { + // It's been ages since we successfully had a heartbeat + // digested by the watchdog. Sit here and spin a while + // in the hope that we can force it through. + LL_WARNS() << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; + result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs); + if (result == 0) { + total_success = true; + } else { + // we couldn't even force it through. That's bad, + // but we'll try again in a while. + LL_WARNS() << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; + } + + // in any case, reset the panic timer. + mPanicTimer.reset(); + mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); + } + + return total_success; } diff --git a/indra/llcommon/llheartbeat.h b/indra/llcommon/llheartbeat.h index 4a75fcc103..54feeb4c92 100644 --- a/indra/llcommon/llheartbeat.h +++ b/indra/llcommon/llheartbeat.h @@ -1,25 +1,25 @@ -/** +/** * @file llheartbeat.h * @brief Class encapsulating logic for telling a watchdog that we live. * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,32 +37,32 @@ class LL_COMMON_API LLHeartbeat { public: - // secs_between_heartbeat: after a heartbeat is successfully delivered, - // we suppress sending more for this length of time. - // aggressive_heartbeat_panic_secs: if we've been failing to - // successfully deliver heartbeats for this length of time then - // we block for a while until we're really sure we got one delivered. - // aggressive_heartbeat_max_blocking_secs: this is the length of - // time we block for when we're aggressively ensuring that a 'panic' - // heartbeat was delivered. - LLHeartbeat(F32 secs_between_heartbeat = 5.0f, - F32 aggressive_heartbeat_panic_secs = 10.0f, - F32 aggressive_heartbeat_max_blocking_secs = 4.0f); - ~LLHeartbeat(); + // secs_between_heartbeat: after a heartbeat is successfully delivered, + // we suppress sending more for this length of time. + // aggressive_heartbeat_panic_secs: if we've been failing to + // successfully deliver heartbeats for this length of time then + // we block for a while until we're really sure we got one delivered. + // aggressive_heartbeat_max_blocking_secs: this is the length of + // time we block for when we're aggressively ensuring that a 'panic' + // heartbeat was delivered. + LLHeartbeat(F32 secs_between_heartbeat = 5.0f, + F32 aggressive_heartbeat_panic_secs = 10.0f, + F32 aggressive_heartbeat_max_blocking_secs = 4.0f); + ~LLHeartbeat(); - bool send(F32 timeout_sec = 0.0f); - void setSuppressed(bool is_suppressed); + bool send(F32 timeout_sec = 0.0f); + void setSuppressed(bool is_suppressed); private: - int rawSend(); - int rawSendWithTimeout(F32 timeout_sec); - F32 mSecsBetweenHeartbeat; - F32 mAggressiveHeartbeatPanicSecs; - F32 mAggressiveHeartbeatMaxBlockingSecs; - bool mSuppressed; - LLTimer mBeatTimer; - LLTimer mPanicTimer; - LLTimer mTimeoutTimer; + int rawSend(); + int rawSendWithTimeout(F32 timeout_sec); + F32 mSecsBetweenHeartbeat; + F32 mAggressiveHeartbeatPanicSecs; + F32 mAggressiveHeartbeatMaxBlockingSecs; + bool mSuppressed; + LLTimer mBeatTimer; + LLTimer mPanicTimer; + LLTimer mTimeoutTimer; }; #endif // LL_HEARTBEAT_H diff --git a/indra/llcommon/llheteromap.cpp b/indra/llcommon/llheteromap.cpp index c84e49d085..823bea7a3c 100644 --- a/indra/llcommon/llheteromap.cpp +++ b/indra/llcommon/llheteromap.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-10-12 * @brief Implementation for llheteromap. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ @@ -22,7 +22,7 @@ LLHeteroMap::~LLHeteroMap() { // For each entry in our map, we must call its deleter, which is the only // record we have of its original type. - for (TypeMap::value_type& pair : mMap) + for (TypeMap::value_type& pair : mMap) { // pair.second is the std::pair; pair.second.first is the void*; // pair.second.second points to the deleter function diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h index 7e96172333..d8e6fefb17 100644 --- a/indra/llcommon/llheteromap.h +++ b/indra/llcommon/llheteromap.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-10-12 * @brief Map capable of storing objects of diverse types, looked up by type. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llindexedvector.h b/indra/llcommon/llindexedvector.h index 68c3821802..de3ae0dcc4 100644 --- a/indra/llcommon/llindexedvector.h +++ b/indra/llcommon/llindexedvector.h @@ -1,25 +1,25 @@ -/** +/** * @file lldarray.h * @brief Wrapped std::vector for backward compatibility. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,65 +36,65 @@ // LLIndexedVector //-------------------------------------------------------- -template <typename Type, typename Key, int BlockSize = 32> +template <typename Type, typename Key, int BlockSize = 32> class LLIndexedVector { public: - typedef typename std::vector<Type>::iterator iterator; - typedef typename std::vector<Type>::const_iterator const_iterator; - typedef typename std::vector<Type>::reverse_iterator reverse_iterator; - typedef typename std::vector<Type>::const_reverse_iterator const_reverse_iterator; - typedef typename std::vector<Type>::size_type size_type; + typedef typename std::vector<Type>::iterator iterator; + typedef typename std::vector<Type>::const_iterator const_iterator; + typedef typename std::vector<Type>::reverse_iterator reverse_iterator; + typedef typename std::vector<Type>::const_reverse_iterator const_reverse_iterator; + typedef typename std::vector<Type>::size_type size_type; protected: - std::vector<Type> mVector; - std::map<Key, U32> mIndexMap; - + std::vector<Type> mVector; + std::map<Key, U32> mIndexMap; + public: - LLIndexedVector() { mVector.reserve(BlockSize); } - - iterator begin() { return mVector.begin(); } - const_iterator begin() const { return mVector.begin(); } - iterator end() { return mVector.end(); } - const_iterator end() const { return mVector.end(); } + LLIndexedVector() { mVector.reserve(BlockSize); } + + iterator begin() { return mVector.begin(); } + const_iterator begin() const { return mVector.begin(); } + iterator end() { return mVector.end(); } + const_iterator end() const { return mVector.end(); } + + reverse_iterator rbegin() { return mVector.rbegin(); } + const_reverse_iterator rbegin() const { return mVector.rbegin(); } + reverse_iterator rend() { return mVector.rend(); } + const_reverse_iterator rend() const { return mVector.rend(); } - reverse_iterator rbegin() { return mVector.rbegin(); } - const_reverse_iterator rbegin() const { return mVector.rbegin(); } - reverse_iterator rend() { return mVector.rend(); } - const_reverse_iterator rend() const { return mVector.rend(); } + void reset() { mVector.resize(0); mIndexMap.resize(0); } + bool empty() const { return mVector.empty(); } + size_type size() const { return mVector.size(); } - void reset() { mVector.resize(0); mIndexMap.resize(0); } - bool empty() const { return mVector.empty(); } - size_type size() const { return mVector.size(); } - - Type& operator[](const Key& k) - { - typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); - if (iter == mIndexMap.end()) - { - U32 n = mVector.size(); - mIndexMap[k] = n; - mVector.push_back(Type()); - llassert(mVector.size() == mIndexMap.size()); - return mVector[n]; - } - else - { - return mVector[iter->second]; - } - } + Type& operator[](const Key& k) + { + typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); + if (iter == mIndexMap.end()) + { + U32 n = mVector.size(); + mIndexMap[k] = n; + mVector.push_back(Type()); + llassert(mVector.size() == mIndexMap.size()); + return mVector[n]; + } + else + { + return mVector[iter->second]; + } + } - const_iterator find(const Key& k) const - { - typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); - if(iter == mIndexMap.end()) - { - return mVector.end(); - } - else - { - return mVector.begin() + iter->second; - } - } + const_iterator find(const Key& k) const + { + typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); + if(iter == mIndexMap.end()) + { + return mVector.end(); + } + else + { + return mVector.begin() + iter->second; + } + } }; #endif diff --git a/indra/llcommon/llinitdestroyclass.cpp b/indra/llcommon/llinitdestroyclass.cpp index e3b9e6d099..50e6e24b8d 100644 --- a/indra/llcommon/llinitdestroyclass.cpp +++ b/indra/llcommon/llinitdestroyclass.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-08-30 * @brief Implementation for llinitdestroyclass. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ @@ -21,9 +21,9 @@ void LLCallbackRegistry::fireCallbacks() const { - for (FuncList::value_type pair : mCallbacks) - { - LL_INFOS("LLInitDestroyClass") << "calling " << pair.first << "()" << LL_ENDL; - pair.second(); - } + for (FuncList::value_type pair : mCallbacks) + { + LL_INFOS("LLInitDestroyClass") << "calling " << pair.first << "()" << LL_ENDL; + pair.second(); + } } diff --git a/indra/llcommon/llinitdestroyclass.h b/indra/llcommon/llinitdestroyclass.h index 5f979614fe..2354c9f2ed 100644 --- a/indra/llcommon/llinitdestroyclass.h +++ b/indra/llcommon/llinitdestroyclass.h @@ -50,21 +50,21 @@ class LLCallbackRegistry { public: - typedef boost::function<void()> func_t; + typedef boost::function<void()> func_t; - void registerCallback(const std::string& name, const func_t& func) - { - mCallbacks.push_back(FuncList::value_type(name, func)); - } + void registerCallback(const std::string& name, const func_t& func) + { + mCallbacks.push_back(FuncList::value_type(name, func)); + } - void fireCallbacks() const; + void fireCallbacks() const; private: - // Arguably this should be a boost::signals2::signal, which is, after all, - // a sequence of callables. We manage it by hand so we can log a name for - // each registered function we call. - typedef std::vector< std::pair<std::string, func_t> > FuncList; - FuncList mCallbacks; + // Arguably this should be a boost::signals2::signal, which is, after all, + // a sequence of callables. We manage it by hand so we can log a name for + // each registered function we call. + typedef std::vector< std::pair<std::string, func_t> > FuncList; + FuncList mCallbacks; }; /** @@ -74,11 +74,11 @@ private: * (before main()), requiring LLInitClassList to be fully constructed on * demand regardless of module initialization order. */ -class LLInitClassList : - public LLCallbackRegistry, - public LLSingleton<LLInitClassList> +class LLInitClassList : + public LLCallbackRegistry, + public LLSingleton<LLInitClassList> { - LLSINGLETON_EMPTY_CTOR(LLInitClassList); + LLSINGLETON_EMPTY_CTOR(LLInitClassList); }; /** @@ -88,11 +88,11 @@ class LLInitClassList : * time (before main()), requiring LLDestroyClassList to be fully constructed * on demand regardless of module initialization order. */ -class LLDestroyClassList : - public LLCallbackRegistry, - public LLSingleton<LLDestroyClassList> +class LLDestroyClassList : + public LLCallbackRegistry, + public LLSingleton<LLDestroyClassList> { - LLSINGLETON_EMPTY_CTOR(LLDestroyClassList); + LLSINGLETON_EMPTY_CTOR(LLDestroyClassList); }; /** @@ -105,19 +105,19 @@ template<typename T> class LLRegisterWith { public: - LLRegisterWith(const std::string& name, const LLCallbackRegistry::func_t& func) - { - T::instance().registerCallback(name, func); - } - - // this avoids a MSVC bug where non-referenced static members are "optimized" away - // even if their constructors have side effects - S32 reference() - { - S32 dummy; - dummy = 0; - return dummy; - } + LLRegisterWith(const std::string& name, const LLCallbackRegistry::func_t& func) + { + T::instance().registerCallback(name, func); + } + + // this avoids a MSVC bug where non-referenced static members are "optimized" away + // even if their constructors have side effects + S32 reference() + { + S32 dummy; + dummy = 0; + return dummy; + } }; /** @@ -133,11 +133,11 @@ template<typename T> class LLInitClass { public: - LLInitClass() { sRegister.reference(); } + LLInitClass() { sRegister.reference(); } - // When this static member is initialized, the subclass initClass() method - // is registered on LLInitClassList. See sRegister definition below. - static LLRegisterWith<LLInitClassList> sRegister; + // When this static member is initialized, the subclass initClass() method + // is registered on LLInitClassList. See sRegister definition below. + static LLRegisterWith<LLInitClassList> sRegister; }; /** @@ -153,23 +153,23 @@ template<typename T> class LLDestroyClass { public: - LLDestroyClass() { sRegister.reference(); } + LLDestroyClass() { sRegister.reference(); } - // When this static member is initialized, the subclass destroyClass() - // method is registered on LLInitClassList. See sRegister definition - // below. - static LLRegisterWith<LLDestroyClassList> sRegister; + // When this static member is initialized, the subclass destroyClass() + // method is registered on LLInitClassList. See sRegister definition + // below. + static LLRegisterWith<LLDestroyClassList> sRegister; }; // Here's where LLInitClass<T> specifies the subclass initClass() method. template <typename T> LLRegisterWith<LLInitClassList> LLInitClass<T>::sRegister(std::string(typeid(T).name()) + "::initClass", - &T::initClass); + &T::initClass); // Here's where LLDestroyClass<T> specifies the subclass destroyClass() method. template <typename T> LLRegisterWith<LLDestroyClassList> LLDestroyClass<T>::sRegister(std::string(typeid(T).name()) + "::destroyClass", - &T::destroyClass); + &T::destroyClass); #endif /* ! defined(LL_LLINITDESTROYCLASS_H) */ diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp index d15bd2f619..7bba1a540d 100644 --- a/indra/llcommon/llinitparam.cpp +++ b/indra/llcommon/llinitparam.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llinitparam.cpp - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,434 +34,434 @@ namespace LLInitParam { - predicate_rule_t default_parse_rules() - { - return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY); - } - - // - // Param - // - Param::Param(BaseBlock* enclosing_block) - : mIsProvided(false) - { - const U8* my_addr = reinterpret_cast<const U8*>(this); - const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); - U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr); - mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff; - mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16; - } - - // - // ParamDescriptor - // - ParamDescriptor::ParamDescriptor(param_handle_t p, - merge_func_t merge_func, - deserialize_func_t deserialize_func, - serialize_func_t serialize_func, - validation_func_t validation_func, - inspect_func_t inspect_func, - S32 min_count, - S32 max_count) - : mParamHandle(p), - mMergeFunc(merge_func), - mDeserializeFunc(deserialize_func), - mSerializeFunc(serialize_func), - mValidationFunc(validation_func), - mInspectFunc(inspect_func), - mMinCount(min_count), - mMaxCount(max_count), - mUserData(NULL) - {} - - ParamDescriptor::ParamDescriptor() - : mParamHandle(0), - mMergeFunc(NULL), - mDeserializeFunc(NULL), - mSerializeFunc(NULL), - mValidationFunc(NULL), - mInspectFunc(NULL), - mMinCount(0), - mMaxCount(0), - mUserData(NULL) - {} - - ParamDescriptor::~ParamDescriptor() - { - delete mUserData; - } - - // - // Parser - // - Parser::~Parser() - {} - - void Parser::parserWarning(const std::string& message) - { - if (mParseSilently) return; - LL_WARNS() << message << LL_ENDL; - } - - void Parser::parserError(const std::string& message) - { - if (mParseSilently) return; - LL_ERRS() << message << LL_ENDL; - } - - - // - // BlockDescriptor - // - void BlockDescriptor::aggregateBlockData(BlockDescriptor& src_block_data) - { - mNamedParams.insert(src_block_data.mNamedParams.begin(), src_block_data.mNamedParams.end()); - std::copy(src_block_data.mUnnamedParams.begin(), src_block_data.mUnnamedParams.end(), std::back_inserter(mUnnamedParams)); - std::copy(src_block_data.mValidationList.begin(), src_block_data.mValidationList.end(), std::back_inserter(mValidationList)); - std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams)); - } - - void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name) - { - // create a copy of the param descriptor in mAllParams - // so other data structures can store a pointer to it - mAllParams.push_back(in_param); - ParamDescriptorPtr param(mAllParams.back()); - - std::string name(char_name); - if ((size_t)param->mParamHandle > mMaxParamOffset) - { - LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << LL_ENDL; - } - - if (name.empty()) - { - mUnnamedParams.push_back(param); - } - else - { - // don't use insert, since we want to overwrite existing entries - mNamedParams[name] = param; - } - - if (param->mValidationFunc) - { - mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); - } - } - - BlockDescriptor::BlockDescriptor() - : mMaxParamOffset(0), - mInitializationState(UNINITIALIZED), - mCurrentBlockPtr(NULL) - {} - - // called by each derived class in least to most derived order - void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) - { - descriptor.mCurrentBlockPtr = this; - descriptor.mMaxParamOffset = block_size; - - switch(descriptor.mInitializationState) - { - case BlockDescriptor::UNINITIALIZED: - // copy params from base class here - descriptor.aggregateBlockData(base_descriptor); - - descriptor.mInitializationState = BlockDescriptor::INITIALIZING; - break; - case BlockDescriptor::INITIALIZING: - descriptor.mInitializationState = BlockDescriptor::INITIALIZED; - break; - case BlockDescriptor::INITIALIZED: - // nothing to do - break; - } - } - - param_handle_t BaseBlock::getHandleFromParam(const Param* param) const - { - const U8* param_address = reinterpret_cast<const U8*>(param); - const U8* baseblock_address = reinterpret_cast<const U8*>(this); - return (param_address - baseblock_address); - } - - bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent) - { - Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end()); - if (!deserializeBlock(p, range, true)) - { - if (!silent) - { - p.parserWarning(llformat("Failed to parse parameter \"%s\"", p.getCurrentElementName().c_str())); - } - return false; - } - return true; - } - - - bool BaseBlock::validateBlock(bool emit_errors) const - { - // only validate block when it hasn't already passed validation with current data - if (!mValidated) - { - const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - for (const BlockDescriptor::param_validation_list_t::value_type& pair : block_data.mValidationList) - { - const Param* param = getParamFromHandle(pair.first); - if (!pair.second(param)) - { - if (emit_errors) - { - LL_WARNS() << "Invalid param \"" << getParamName(block_data, param) << "\"" << LL_ENDL; - } - return false; - } - } - mValidated = true; - } - return mValidated; - } - - bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const - { - bool serialized = false; - if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided()))) - { - return false; - } - // named param is one like LLView::Params::follows - // unnamed param is like LLView::Params::rect - implicit - const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - - for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - param_handle_t param_handle = ptr->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::serialize_func_t serialize_func = ptr->mSerializeFunc; - if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) - { - const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); - } - } - - for (const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) - { - param_handle_t param_handle = pair.second->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::serialize_func_t serialize_func = pair.second->mSerializeFunc; - if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) - { - // Ensure this param has not already been serialized - // Prevents <rect> from being serialized as its own tag. - bool duplicate = false; - for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - if (param_handle == ptr->mParamHandle) - { - duplicate = true; - break; - } - } - - //FIXME: for now, don't attempt to serialize values under synonyms, as current parsers - // don't know how to detect them - if (duplicate) - { - continue; - } - - name_stack.push_back(std::make_pair(pair.first, !duplicate)); - const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); - name_stack.pop_back(); - } - } - - if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) - { - serialized |= parser.writeValue(Flag(), name_stack); - } - // was anything serialized in this block? - return serialized; - } - - bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const - { - // named param is one like LLView::Params::follows - // unnamed param is like LLView::Params::rect - implicit - const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - - for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - param_handle_t param_handle = ptr->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::inspect_func_t inspect_func = ptr->mInspectFunc; - if (inspect_func) - { - name_stack.push_back(std::make_pair("", true)); - inspect_func(*param, parser, name_stack, ptr->mMinCount, ptr->mMaxCount); - name_stack.pop_back(); - } - } - - for(const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) - { - param_handle_t param_handle = pair.second->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::inspect_func_t inspect_func = pair.second->mInspectFunc; - if (inspect_func) - { - // Ensure this param has not already been inspected - bool duplicate = false; + predicate_rule_t default_parse_rules() + { + return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY); + } + + // + // Param + // + Param::Param(BaseBlock* enclosing_block) + : mIsProvided(false) + { + const U8* my_addr = reinterpret_cast<const U8*>(this); + const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); + U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr); + mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff; + mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16; + } + + // + // ParamDescriptor + // + ParamDescriptor::ParamDescriptor(param_handle_t p, + merge_func_t merge_func, + deserialize_func_t deserialize_func, + serialize_func_t serialize_func, + validation_func_t validation_func, + inspect_func_t inspect_func, + S32 min_count, + S32 max_count) + : mParamHandle(p), + mMergeFunc(merge_func), + mDeserializeFunc(deserialize_func), + mSerializeFunc(serialize_func), + mValidationFunc(validation_func), + mInspectFunc(inspect_func), + mMinCount(min_count), + mMaxCount(max_count), + mUserData(NULL) + {} + + ParamDescriptor::ParamDescriptor() + : mParamHandle(0), + mMergeFunc(NULL), + mDeserializeFunc(NULL), + mSerializeFunc(NULL), + mValidationFunc(NULL), + mInspectFunc(NULL), + mMinCount(0), + mMaxCount(0), + mUserData(NULL) + {} + + ParamDescriptor::~ParamDescriptor() + { + delete mUserData; + } + + // + // Parser + // + Parser::~Parser() + {} + + void Parser::parserWarning(const std::string& message) + { + if (mParseSilently) return; + LL_WARNS() << message << LL_ENDL; + } + + void Parser::parserError(const std::string& message) + { + if (mParseSilently) return; + LL_ERRS() << message << LL_ENDL; + } + + + // + // BlockDescriptor + // + void BlockDescriptor::aggregateBlockData(BlockDescriptor& src_block_data) + { + mNamedParams.insert(src_block_data.mNamedParams.begin(), src_block_data.mNamedParams.end()); + std::copy(src_block_data.mUnnamedParams.begin(), src_block_data.mUnnamedParams.end(), std::back_inserter(mUnnamedParams)); + std::copy(src_block_data.mValidationList.begin(), src_block_data.mValidationList.end(), std::back_inserter(mValidationList)); + std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams)); + } + + void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name) + { + // create a copy of the param descriptor in mAllParams + // so other data structures can store a pointer to it + mAllParams.push_back(in_param); + ParamDescriptorPtr param(mAllParams.back()); + + std::string name(char_name); + if ((size_t)param->mParamHandle > mMaxParamOffset) + { + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << LL_ENDL; + } + + if (name.empty()) + { + mUnnamedParams.push_back(param); + } + else + { + // don't use insert, since we want to overwrite existing entries + mNamedParams[name] = param; + } + + if (param->mValidationFunc) + { + mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); + } + } + + BlockDescriptor::BlockDescriptor() + : mMaxParamOffset(0), + mInitializationState(UNINITIALIZED), + mCurrentBlockPtr(NULL) + {} + + // called by each derived class in least to most derived order + void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) + { + descriptor.mCurrentBlockPtr = this; + descriptor.mMaxParamOffset = block_size; + + switch(descriptor.mInitializationState) + { + case BlockDescriptor::UNINITIALIZED: + // copy params from base class here + descriptor.aggregateBlockData(base_descriptor); + + descriptor.mInitializationState = BlockDescriptor::INITIALIZING; + break; + case BlockDescriptor::INITIALIZING: + descriptor.mInitializationState = BlockDescriptor::INITIALIZED; + break; + case BlockDescriptor::INITIALIZED: + // nothing to do + break; + } + } + + param_handle_t BaseBlock::getHandleFromParam(const Param* param) const + { + const U8* param_address = reinterpret_cast<const U8*>(param); + const U8* baseblock_address = reinterpret_cast<const U8*>(this); + return (param_address - baseblock_address); + } + + bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent) + { + Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end()); + if (!deserializeBlock(p, range, true)) + { + if (!silent) + { + p.parserWarning(llformat("Failed to parse parameter \"%s\"", p.getCurrentElementName().c_str())); + } + return false; + } + return true; + } + + + bool BaseBlock::validateBlock(bool emit_errors) const + { + // only validate block when it hasn't already passed validation with current data + if (!mValidated) + { + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + for (const BlockDescriptor::param_validation_list_t::value_type& pair : block_data.mValidationList) + { + const Param* param = getParamFromHandle(pair.first); + if (!pair.second(param)) + { + if (emit_errors) + { + LL_WARNS() << "Invalid param \"" << getParamName(block_data, param) << "\"" << LL_ENDL; + } + return false; + } + } + mValidated = true; + } + return mValidated; + } + + bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const + { + bool serialized = false; + if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided()))) + { + return false; + } + // named param is one like LLView::Params::follows + // unnamed param is like LLView::Params::rect - implicit + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + + for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + param_handle_t param_handle = ptr->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::serialize_func_t serialize_func = ptr->mSerializeFunc; + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) + { + const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); + } + } + + for (const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) + { + param_handle_t param_handle = pair.second->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::serialize_func_t serialize_func = pair.second->mSerializeFunc; + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) + { + // Ensure this param has not already been serialized + // Prevents <rect> from being serialized as its own tag. + bool duplicate = false; + for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + if (param_handle == ptr->mParamHandle) + { + duplicate = true; + break; + } + } + + //FIXME: for now, don't attempt to serialize values under synonyms, as current parsers + // don't know how to detect them + if (duplicate) + { + continue; + } + + name_stack.push_back(std::make_pair(pair.first, !duplicate)); + const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); + name_stack.pop_back(); + } + } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + // was anything serialized in this block? + return serialized; + } + + bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const + { + // named param is one like LLView::Params::follows + // unnamed param is like LLView::Params::rect - implicit + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + + for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + param_handle_t param_handle = ptr->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::inspect_func_t inspect_func = ptr->mInspectFunc; + if (inspect_func) + { + name_stack.push_back(std::make_pair("", true)); + inspect_func(*param, parser, name_stack, ptr->mMinCount, ptr->mMaxCount); + name_stack.pop_back(); + } + } + + for(const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) + { + param_handle_t param_handle = pair.second->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::inspect_func_t inspect_func = pair.second->mInspectFunc; + if (inspect_func) + { + // Ensure this param has not already been inspected + bool duplicate = false; for (const ParamDescriptorPtr &ptr : block_data.mUnnamedParams) - { - if (param_handle == ptr->mParamHandle) - { - duplicate = true; - break; - } - } - - name_stack.push_back(std::make_pair(pair.first, !duplicate)); - inspect_func(*param, parser, name_stack, pair.second->mMinCount, pair.second->mMaxCount); - name_stack.pop_back(); - } - } - - return true; - } - - bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored) - { - BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - bool names_left = name_stack_range.first != name_stack_range.second; - - bool new_name = names_left - ? name_stack_range.first->second - : true; - - if (names_left) - { - const std::string& top_name = name_stack_range.first->first; - - BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name); - if (found_it != block_data.mNamedParams.end()) - { - // find pointer to member parameter from offset table - Param* paramp = getParamFromHandle(found_it->second->mParamHandle); - ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc; - - Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second); - ++new_name_stack.first; - if (deserialize_func(*paramp, p, new_name_stack, new_name)) - { - // value is no longer new, we know about it now - name_stack_range.first->second = false; - return true; - } - else - { - return false; - } - } - } - - // try to parse unnamed parameters, in declaration order - for (ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - Param* paramp = getParamFromHandle(ptr->mParamHandle); - ParamDescriptor::deserialize_func_t deserialize_func = ptr->mDeserializeFunc; - - if (deserialize_func && deserialize_func(*paramp, p, name_stack_range, new_name)) - { - return true; - } - } - - // if no match, and no names left on stack, this is just an existence assertion of this block - // verify by calling readValue with NoParamValue type, an inherently unparseable type - if (!names_left) - { - Flag no_value; - return p.readValue(no_value); - } - - return false; - } - - void BaseBlock::addSynonym(Param& param, const std::string& synonym) - { - BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - if (block_data.mInitializationState == BlockDescriptor::INITIALIZING) - { - param_handle_t handle = getHandleFromParam(¶m); - - // check for invalid derivation from a paramblock (i.e. without using - // Block<T, Base_Class> - if ((size_t)handle > block_data.mMaxParamOffset) - { - LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << LL_ENDL; - } - - ParamDescriptorPtr param_descriptor = findParamDescriptor(param); - if (param_descriptor) - { - if (synonym.empty()) - { - block_data.mUnnamedParams.push_back(param_descriptor); - } - else - { - block_data.mNamedParams[synonym] = param_descriptor; - } - } - } - } - - const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const - { - param_handle_t handle = getHandleFromParam(paramp); - for (BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); it != block_data.mNamedParams.end(); ++it) - { - if (it->second->mParamHandle == handle) - { - return it->first; - } - } - - return LLStringUtil::null; - } - - ParamDescriptorPtr BaseBlock::findParamDescriptor(const Param& param) - { - param_handle_t handle = getHandleFromParam(¶m); - BlockDescriptor& descriptor = mostDerivedBlockDescriptor(); - for (ParamDescriptorPtr& ptr : descriptor.mAllParams) - { - if (ptr->mParamHandle == handle) return ptr; - } - return ParamDescriptorPtr(); - } - - // take all provided params from other and apply to self - // NOTE: this requires that "other" is of the same derived type as this - bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) - { - bool some_param_changed = false; - for (const ParamDescriptorPtr& ptr : block_data.mAllParams) - { - const Param* other_paramp = other.getParamFromHandle(ptr->mParamHandle); - ParamDescriptor::merge_func_t merge_func = ptr->mMergeFunc; - if (merge_func) - { - Param* paramp = getParamFromHandle(ptr->mParamHandle); - llassert(paramp->getEnclosingBlockOffset() == ptr->mParamHandle); - some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); - } - } - return some_param_changed; - } + { + if (param_handle == ptr->mParamHandle) + { + duplicate = true; + break; + } + } + + name_stack.push_back(std::make_pair(pair.first, !duplicate)); + inspect_func(*param, parser, name_stack, pair.second->mMinCount, pair.second->mMaxCount); + name_stack.pop_back(); + } + } + + return true; + } + + bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored) + { + BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + bool names_left = name_stack_range.first != name_stack_range.second; + + bool new_name = names_left + ? name_stack_range.first->second + : true; + + if (names_left) + { + const std::string& top_name = name_stack_range.first->first; + + BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name); + if (found_it != block_data.mNamedParams.end()) + { + // find pointer to member parameter from offset table + Param* paramp = getParamFromHandle(found_it->second->mParamHandle); + ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc; + + Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second); + ++new_name_stack.first; + if (deserialize_func(*paramp, p, new_name_stack, new_name)) + { + // value is no longer new, we know about it now + name_stack_range.first->second = false; + return true; + } + else + { + return false; + } + } + } + + // try to parse unnamed parameters, in declaration order + for (ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + Param* paramp = getParamFromHandle(ptr->mParamHandle); + ParamDescriptor::deserialize_func_t deserialize_func = ptr->mDeserializeFunc; + + if (deserialize_func && deserialize_func(*paramp, p, name_stack_range, new_name)) + { + return true; + } + } + + // if no match, and no names left on stack, this is just an existence assertion of this block + // verify by calling readValue with NoParamValue type, an inherently unparseable type + if (!names_left) + { + Flag no_value; + return p.readValue(no_value); + } + + return false; + } + + void BaseBlock::addSynonym(Param& param, const std::string& synonym) + { + BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + if (block_data.mInitializationState == BlockDescriptor::INITIALIZING) + { + param_handle_t handle = getHandleFromParam(¶m); + + // check for invalid derivation from a paramblock (i.e. without using + // Block<T, Base_Class> + if ((size_t)handle > block_data.mMaxParamOffset) + { + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << LL_ENDL; + } + + ParamDescriptorPtr param_descriptor = findParamDescriptor(param); + if (param_descriptor) + { + if (synonym.empty()) + { + block_data.mUnnamedParams.push_back(param_descriptor); + } + else + { + block_data.mNamedParams[synonym] = param_descriptor; + } + } + } + } + + const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const + { + param_handle_t handle = getHandleFromParam(paramp); + for (BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); it != block_data.mNamedParams.end(); ++it) + { + if (it->second->mParamHandle == handle) + { + return it->first; + } + } + + return LLStringUtil::null; + } + + ParamDescriptorPtr BaseBlock::findParamDescriptor(const Param& param) + { + param_handle_t handle = getHandleFromParam(¶m); + BlockDescriptor& descriptor = mostDerivedBlockDescriptor(); + for (ParamDescriptorPtr& ptr : descriptor.mAllParams) + { + if (ptr->mParamHandle == handle) return ptr; + } + return ParamDescriptorPtr(); + } + + // take all provided params from other and apply to self + // NOTE: this requires that "other" is of the same derived type as this + bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) + { + bool some_param_changed = false; + for (const ParamDescriptorPtr& ptr : block_data.mAllParams) + { + const Param* other_paramp = other.getParamFromHandle(ptr->mParamHandle); + ParamDescriptor::merge_func_t merge_func = ptr->mMergeFunc; + if (merge_func) + { + Param* paramp = getParamFromHandle(ptr->mParamHandle); + llassert(paramp->getEnclosingBlockOffset() == ptr->mParamHandle); + some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); + } + } + return some_param_changed; + } } diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index e0d0ab9ac7..206aa51ba3 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -1,26 +1,26 @@ -/** +/** * @file llinitparam.h - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,2796 +43,2796 @@ namespace LLTypeTags { - template <typename INNER_TYPE, int _SORT_ORDER> - struct TypeTagBase - { - typedef void is_tag_t; - typedef INNER_TYPE inner_t; - static const int SORT_ORDER=_SORT_ORDER; - }; - - template <int VAL1, int VAL2> - struct GreaterThan - { - static const bool value = VAL1 > VAL2; - }; - - template<typename ITEM, typename REST, bool NEEDS_SWAP = GreaterThan<ITEM::SORT_ORDER, REST::SORT_ORDER>::value > - struct Swap - { - typedef typename ITEM::template Cons<REST>::value_t value_t; - }; - - template<typename ITEM, typename REST> - struct Swap<ITEM, REST, true> - { - typedef typename REST::template Cons<Swap<ITEM, typename REST::inner_t>::value_t>::value_t value_t; - }; - - template<typename T, typename SORTABLE = void> - struct IsSortable - { - static const bool value = false; - }; - - template<typename T> - struct IsSortable<T, typename T::is_tag_t> - { - static const bool value = true; - }; - - template<typename ITEM, typename REST, bool IS_REST_SORTABLE = IsSortable<REST>::value> - struct InsertInto - { - typedef typename ITEM::template Cons<REST>::value_t value_t; - }; - - template<typename ITEM, typename REST> - struct InsertInto <ITEM, REST, true> - { - typedef typename Swap<ITEM, REST>::value_t value_t; - }; - - template<typename T, bool SORTABLE = IsSortable<T>::value> - struct Sorted - { - typedef T value_t; - }; - - template<typename T> - struct Sorted <T, true> - { - typedef typename InsertInto<T, typename Sorted<typename T::inner_t>::value_t>::value_t value_t; - }; + template <typename INNER_TYPE, int _SORT_ORDER> + struct TypeTagBase + { + typedef void is_tag_t; + typedef INNER_TYPE inner_t; + static const int SORT_ORDER=_SORT_ORDER; + }; + + template <int VAL1, int VAL2> + struct GreaterThan + { + static const bool value = VAL1 > VAL2; + }; + + template<typename ITEM, typename REST, bool NEEDS_SWAP = GreaterThan<ITEM::SORT_ORDER, REST::SORT_ORDER>::value > + struct Swap + { + typedef typename ITEM::template Cons<REST>::value_t value_t; + }; + + template<typename ITEM, typename REST> + struct Swap<ITEM, REST, true> + { + typedef typename REST::template Cons<Swap<ITEM, typename REST::inner_t>::value_t>::value_t value_t; + }; + + template<typename T, typename SORTABLE = void> + struct IsSortable + { + static const bool value = false; + }; + + template<typename T> + struct IsSortable<T, typename T::is_tag_t> + { + static const bool value = true; + }; + + template<typename ITEM, typename REST, bool IS_REST_SORTABLE = IsSortable<REST>::value> + struct InsertInto + { + typedef typename ITEM::template Cons<REST>::value_t value_t; + }; + + template<typename ITEM, typename REST> + struct InsertInto <ITEM, REST, true> + { + typedef typename Swap<ITEM, REST>::value_t value_t; + }; + + template<typename T, bool SORTABLE = IsSortable<T>::value> + struct Sorted + { + typedef T value_t; + }; + + template<typename T> + struct Sorted <T, true> + { + typedef typename InsertInto<T, typename Sorted<typename T::inner_t>::value_t>::value_t value_t; + }; } namespace LLInitParam { - // used to indicate no matching value to a given name when parsing - struct Flag{}; - - template<typename T> const T& defaultValue() { static T value; return value; } - - // wraps comparison operator between any 2 values of the same type - // specialize to handle cases where equality isn't defined well, or at all - template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value > - struct ParamCompare - { - static bool equals(const T &a, const T &b) - { - return a == b; - } + // used to indicate no matching value to a given name when parsing + struct Flag{}; + + template<typename T> const T& defaultValue() { static T value; return value; } + + // wraps comparison operator between any 2 values of the same type + // specialize to handle cases where equality isn't defined well, or at all + template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value > + struct ParamCompare + { + static bool equals(const T &a, const T &b) + { + return a == b; + } + }; + + // boost function types are not comparable + template<typename T> + struct ParamCompare<T, true> + { + static bool equals(const T&a, const T &b) + { + return false; + } + }; + + template<> + struct ParamCompare<LLSD, false> + { + static bool equals(const LLSD &a, const LLSD &b) { return false; } + }; + + template<> + struct ParamCompare<Flag, false> + { + static bool equals(const Flag& a, const Flag& b) { return false; } + }; + + + // helper functions and classes + typedef ptrdiff_t param_handle_t; + struct IS_A_BLOCK {}; + struct NOT_BLOCK {}; + + // these templates allow us to distinguish between template parameters + // that derive from BaseBlock and those that don't + template<typename T, typename BLOCK_IDENTIFIER = void> + struct IsBlock + { + typedef NOT_BLOCK value_t; + }; + + template<typename T> + struct IsBlock<T, typename T::baseblock_base_class_t> + { + typedef IS_A_BLOCK value_t; + }; + + // ParamValue class directly manages the wrapped value + // by holding on to a copy (scalar params) + // or deriving from it (blocks) + // has specializations for custom value behavior + // and "tag" values like Lazy and Atomic + template<typename T, typename VALUE_IS_BLOCK = typename IsBlock<T>::value_t> + class ParamValue + { + typedef ParamValue<T, VALUE_IS_BLOCK> self_t; + + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue(): mValue() {} + ParamValue(const default_value_t& other) : mValue(other) {} + + void setValue(const value_t& val) + { + mValue = val; + } + + const value_t& getValue() const + { + return mValue; + } + + T& getValue() + { + return mValue; + } + + bool isValid() const { return true; } + + protected: + T mValue; + }; + + template<typename T> + class ParamValue<T, IS_A_BLOCK> + : public T + { + typedef ParamValue<T, IS_A_BLOCK> self_t; + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue() + : T() + {} + + ParamValue(const default_value_t& other) + : T(other) + {} + + void setValue(const value_t& val) + { + *this = val; + } + + const value_t& getValue() const + { + return *this; + } + + T& getValue() + { + return *this; + } }; - // boost function types are not comparable - template<typename T> - struct ParamCompare<T, true> - { - static bool equals(const T&a, const T &b) - { - return false; - } - }; - - template<> - struct ParamCompare<LLSD, false> - { - static bool equals(const LLSD &a, const LLSD &b) { return false; } - }; - - template<> - struct ParamCompare<Flag, false> - { - static bool equals(const Flag& a, const Flag& b) { return false; } - }; - - - // helper functions and classes - typedef ptrdiff_t param_handle_t; - struct IS_A_BLOCK {}; - struct NOT_BLOCK {}; - - // these templates allow us to distinguish between template parameters - // that derive from BaseBlock and those that don't - template<typename T, typename BLOCK_IDENTIFIER = void> - struct IsBlock - { - typedef NOT_BLOCK value_t; - }; - - template<typename T> - struct IsBlock<T, typename T::baseblock_base_class_t> - { - typedef IS_A_BLOCK value_t; - }; - - // ParamValue class directly manages the wrapped value - // by holding on to a copy (scalar params) - // or deriving from it (blocks) - // has specializations for custom value behavior - // and "tag" values like Lazy and Atomic - template<typename T, typename VALUE_IS_BLOCK = typename IsBlock<T>::value_t> - class ParamValue - { - typedef ParamValue<T, VALUE_IS_BLOCK> self_t; - - public: - typedef T default_value_t; - typedef T value_t; - - ParamValue(): mValue() {} - ParamValue(const default_value_t& other) : mValue(other) {} - - void setValue(const value_t& val) - { - mValue = val; - } - - const value_t& getValue() const - { - return mValue; - } - - T& getValue() - { - return mValue; - } - - bool isValid() const { return true; } - - protected: - T mValue; - }; - - template<typename T> - class ParamValue<T, IS_A_BLOCK> - : public T - { - typedef ParamValue<T, IS_A_BLOCK> self_t; - public: - typedef T default_value_t; - typedef T value_t; - - ParamValue() - : T() - {} - - ParamValue(const default_value_t& other) - : T(other) - {} - - void setValue(const value_t& val) - { - *this = val; - } - - const value_t& getValue() const - { - return *this; - } - - T& getValue() - { - return *this; - } - }; - - - // empty default implementation of key cache - // leverages empty base class optimization - template <typename T> - class TypeValues - : public ParamValue<typename LLTypeTags::Sorted<T>::value_t> - { - private: - struct Inaccessable{}; - public: - typedef std::map<std::string, T> value_name_map_t; - typedef Inaccessable name_t; - typedef TypeValues<T> type_value_t; - typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; - typedef typename param_value_t::value_t value_t; - - TypeValues(const typename param_value_t::value_t& val) - : param_value_t(val) - {} - - void setValueName(const std::string& key) {} - std::string getValueName() const { return ""; } - std::string calcValueName(const value_t& value) const { return ""; } - void clearValueName() const {} - - static bool getValueFromName(const std::string& name, value_t& value) - { - return false; - } - - static bool valueNamesExist() - { - return false; - } - - static std::vector<std::string>* getPossibleValues() - { - return NULL; - } - - void assignNamedValue(const Inaccessable& name) - {} - - operator const value_t&() const - { - return param_value_t::getValue(); - } - - const value_t& operator()() const - { - return param_value_t::getValue(); - } - - static value_name_map_t* getValueNames() {return NULL;} - }; - - // helper class to implement name value lookups - // and caching of last used name - template <typename T, typename DERIVED_TYPE = TypeValues<T>, bool IS_SPECIALIZED = true > - class TypeValuesHelper - : public ParamValue<typename LLTypeTags::Sorted<T>::value_t> - { - typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t; - public: - typedef typename std::map<std::string, T> value_name_map_t; - typedef std::string name_t; - typedef self_t type_value_t; - typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; - typedef typename param_value_t::value_t value_t; - - TypeValuesHelper(const typename param_value_t::value_t& val) - : param_value_t(val) - {} - - //TODO: cache key by index to save on param block size - void setValueName(const std::string& value_name) - { - mValueName = value_name; - } - - std::string getValueName() const - { - return mValueName; - } - - std::string calcValueName(const value_t& value) const - { - value_name_map_t* map = getValueNames(); - for (typename value_name_map_t::value_type& map_pair : *map) - { - if (ParamCompare<T>::equals(map_pair.second, value)) - { - return map_pair.first; - } - } - - return ""; - } - - void clearValueName() const - { - mValueName.clear(); - } - - static bool getValueFromName(const std::string& name, value_t& value) - { - value_name_map_t* map = getValueNames(); - typename value_name_map_t::iterator found_it = map->find(name); - if (found_it == map->end()) return false; - - value = found_it->second; - return true; - } - - static bool valueNamesExist() - { - return !getValueNames()->empty(); - } - - static value_name_map_t* getValueNames() - { - static value_name_map_t sMap; - static bool sInitialized = false; - - if (!sInitialized) - { - sInitialized = true; - DERIVED_TYPE::declareValues(); - } - return &sMap; - } - - static std::vector<std::string>* getPossibleValues() - { - static std::vector<std::string> sValues; - - value_name_map_t* map = getValueNames(); - for (typename value_name_map_t::value_type& map_pair : *map) - { - sValues.push_back(map_pair.first); - } - return &sValues; - } - - static void declare(const std::string& name, const value_t& value) - { - (*getValueNames())[name] = value; - } - - void operator ()(const std::string& name) - { - *this = name; - } - - void assignNamedValue(const std::string& name) - { - if (getValueFromName(name, param_value_t::getValue())) - { - setValueName(name); - } - } - - operator const value_t&() const - { - return param_value_t::getValue(); - } - - const value_t& operator()() const - { - return param_value_t::getValue(); - } - - protected: - static void getName(const std::string& name, const value_t& value) - {} - - mutable std::string mValueName; - }; - - // string types can support custom named values, but need - // to disambiguate in code between a string that is a named value - // and a string that is a name - template <typename DERIVED_TYPE> - class TypeValuesHelper<std::string, DERIVED_TYPE, true> - : public TypeValuesHelper<std::string, DERIVED_TYPE, false> - { - public: - typedef TypeValuesHelper<std::string, DERIVED_TYPE, true> self_t; - typedef TypeValuesHelper<std::string, DERIVED_TYPE, false> base_t; - typedef std::string value_t; - typedef std::string name_t; - typedef self_t type_value_t; - - TypeValuesHelper(const std::string& val) - : base_t(val) - {} - - void operator ()(const std::string& name) - { - *this = name; - } - - self_t& operator =(const std::string& name) - { - if (base_t::getValueFromName(name, ParamValue<std::string>::getValue())) - { - base_t::setValueName(name); - } - else - { - ParamValue<std::string>::setValue(name); - } - return *this; - } - - operator const value_t&() const - { - return ParamValue<std::string>::getValue(); - } - - const value_t& operator()() const - { - return ParamValue<std::string>::getValue(); - } - - }; - - // parser base class with mechanisms for registering readers/writers/inspectors of different types - class LL_COMMON_API Parser - { - LOG_CLASS(Parser); - public: - typedef std::vector<std::pair<std::string, bool> > name_stack_t; - typedef std::pair<name_stack_t::iterator, name_stack_t::iterator> name_stack_range_t; - typedef std::vector<std::string> possible_values_t; - - typedef bool (*parser_read_func_t)(Parser& parser, void* output); - typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&); - typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t; - - typedef std::map<const std::type_info*, parser_read_func_t> parser_read_func_map_t; - typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t; - typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t; - - public: - - Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) - : mParseSilently(false), - mParserReadFuncs(&read_map), - mParserWriteFuncs(&write_map), - mParserInspectFuncs(&inspect_map) - {} - - virtual ~Parser(); - - template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0) - { - parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); - if (found_it != mParserReadFuncs->end()) - { - return found_it->second(*this, (void*)¶m); - } - - return false; - } - - template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0) - { - parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); - if (found_it != mParserReadFuncs->end()) - { - return found_it->second(*this, (void*)¶m); - } - else - { - found_it = mParserReadFuncs->find(&typeid(S32)); - if (found_it != mParserReadFuncs->end()) - { - S32 int_value; - bool parsed = found_it->second(*this, (void*)&int_value); - param = (T)int_value; - return parsed; - } - } - return false; - } - - template <typename T> bool writeValue(const T& param, name_stack_t& name_stack) - { - parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); - if (found_it != mParserWriteFuncs->end()) - { - return found_it->second(*this, (const void*)¶m, name_stack); - } - return false; - } - - // dispatch inspection to registered inspection functions, for each parameter in a param block - template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) - { - parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T)); - if (found_it != mParserInspectFuncs->end()) - { - found_it->second(name_stack, min_count, max_count, possible_values); - return true; - } - return false; - } - - virtual std::string getCurrentElementName() = 0; - virtual std::string getCurrentFileName() = 0; - virtual void parserWarning(const std::string& message); - virtual void parserError(const std::string& message); - void setParseSilently(bool silent) { mParseSilently = silent; } - - protected: - template <typename T> - void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL) - { - mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func)); - mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func)); - } - - template <typename T> - void registerInspectFunc(parser_inspect_func_t inspect_func) - { - mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func)); - } - - bool mParseSilently; - - private: - parser_read_func_map_t* mParserReadFuncs; - parser_write_func_map_t* mParserWriteFuncs; - parser_inspect_func_map_t* mParserInspectFuncs; - }; - - class Param; - - enum ESerializePredicates - { - PROVIDED, - REQUIRED, - VALID, - HAS_DEFAULT_VALUE, - EMPTY - }; - - typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t; - - predicate_rule_t default_parse_rules(); - - // various callbacks and constraints associated with an individual param - struct LL_COMMON_API ParamDescriptor - { - struct UserData - { - virtual ~UserData() {} - }; - - typedef bool(*merge_func_t)(Param&, const Param&, bool); - typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); - typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param); - typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); - typedef bool(*validation_func_t)(const Param*); - - ParamDescriptor(param_handle_t p, - merge_func_t merge_func, - deserialize_func_t deserialize_func, - serialize_func_t serialize_func, - validation_func_t validation_func, - inspect_func_t inspect_func, - S32 min_count, - S32 max_count); - - ParamDescriptor(); - ~ParamDescriptor(); - - param_handle_t mParamHandle; - merge_func_t mMergeFunc; - deserialize_func_t mDeserializeFunc; - serialize_func_t mSerializeFunc; - inspect_func_t mInspectFunc; - validation_func_t mValidationFunc; - S32 mMinCount; - S32 mMaxCount; - S32 mNumRefs; - UserData* mUserData; - }; - - typedef std::shared_ptr<ParamDescriptor> ParamDescriptorPtr; - - // each derived Block class keeps a static data structure maintaining offsets to various params - class LL_COMMON_API BlockDescriptor - { - public: - BlockDescriptor(); - - typedef enum e_initialization_state - { - UNINITIALIZED, - INITIALIZING, - INITIALIZED - } EInitializationState; - - void aggregateBlockData(BlockDescriptor& src_block_data); - void addParam(ParamDescriptorPtr param, const char* name); - - typedef boost::unordered_map<const std::string, ParamDescriptorPtr> param_map_t; - typedef std::vector<ParamDescriptorPtr> param_list_t; - typedef std::list<ParamDescriptorPtr> all_params_list_t; - typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t; - - param_map_t mNamedParams; // parameters with associated names - param_list_t mUnnamedParams; // parameters with_out_ associated names - param_validation_list_t mValidationList; // parameters that must be validated - all_params_list_t mAllParams; // all parameters, owns descriptors - size_t mMaxParamOffset; - EInitializationState mInitializationState; // whether or not static block data has been initialized - class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed - }; - - //TODO: implement in terms of owned_ptr - template<typename T> - class LazyValue - { - public: - LazyValue() - : mPtr(NULL) - {} - - ~LazyValue() - { - delete mPtr; - } - - LazyValue(const T& value) - { - mPtr = new T(value); - } - - LazyValue(const LazyValue& other) - : mPtr(NULL) - { - *this = other; - } - - LazyValue& operator = (const LazyValue& other) - { - if (!other.mPtr) - { - delete mPtr; - mPtr = NULL; - } - else - { - if (!mPtr) - { - mPtr = new T(*other.mPtr); - } - else - { - *mPtr = *(other.mPtr); - } - } - return *this; - } - - bool operator==(const LazyValue& other) const - { - if (empty() || other.empty()) return false; - return *mPtr == *other.mPtr; - } - - bool empty() const - { - return mPtr == NULL; - } - - void set(const T& other) - { - if (!mPtr) - { - mPtr = new T(other); - } - else - { - *mPtr = other; - } - } - - const T& get() const - { - return *ensureInstance(); - } - - T& get() - { - return *ensureInstance(); - } - - operator const T&() const - { - return get(); - } - - private: - // lazily allocate an instance of T - T* ensureInstance() const - { - if (mPtr == NULL) - { - mPtr = new T(); - } - return mPtr; - } - - private: - - mutable T* mPtr; - }; - - // root class of all parameter blocks - - class LL_COMMON_API BaseBlock - { - public: - // lift block tags into baseblock namespace so derived classes do not need to qualify them - typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK; - typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK; - - template<typename T> - struct Sequential : public LLTypeTags::TypeTagBase<T, 2> - { - template <typename S> struct Cons { typedef Sequential<ParamValue<S> > value_t; }; - template <typename S> struct Cons<Sequential<S> > { typedef Sequential<S> value_t; }; - }; - - template<typename T> - struct Atomic : public LLTypeTags::TypeTagBase<T, 1> - { - template <typename S> struct Cons { typedef Atomic<ParamValue<S> > value_t; }; - template <typename S> struct Cons<Atomic<S> > { typedef Atomic<S> value_t; }; - }; - - template<typename T, typename BLOCK_T = typename IsBlock<T>::value_t > - struct Lazy : public LLTypeTags::TypeTagBase<T, 0> - { - template <typename S> struct Cons - { - typedef Lazy<ParamValue<S, BLOCK_T>, BLOCK_T> value_t; - }; - template <typename S> struct Cons<Lazy<S, IS_A_BLOCK> > - { - typedef Lazy<S, IS_A_BLOCK> value_t; - }; - template <typename S> struct Cons<Lazy<S, NOT_A_BLOCK> > - { - typedef Lazy<S, BLOCK_T> value_t; - }; - }; - - // "Multiple" constraint types, put here in root class to avoid ambiguity during use - struct AnyAmount - { - enum { minCount = 0 }; - enum { maxCount = U32_MAX }; - }; - - template<U32 MIN_AMOUNT> - struct AtLeast - { - enum { minCount = MIN_AMOUNT }; - enum { maxCount = U32_MAX }; - }; - - template<U32 MAX_AMOUNT> - struct AtMost - { - enum { minCount = 0 }; - enum { maxCount = MAX_AMOUNT }; - }; - - template<U32 MIN_AMOUNT, U32 MAX_AMOUNT> - struct Between - { - enum { minCount = MIN_AMOUNT }; - enum { maxCount = MAX_AMOUNT }; - }; - - template<U32 EXACT_COUNT> - struct Exactly - { - enum { minCount = EXACT_COUNT }; - enum { maxCount = EXACT_COUNT }; - }; - - // this typedef identifies derived classes as being blocks - typedef void baseblock_base_class_t; - LOG_CLASS(BaseBlock); - friend class Param; - - BaseBlock() - : mValidated(false), - mParamProvided(false) - {} - - virtual ~BaseBlock() {} - bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); - - param_handle_t getHandleFromParam(const Param* param) const; - bool validateBlock(bool emit_errors = true) const; - - bool isProvided() const - { - return mParamProvided; - } - - bool isValid() const - { - return validateBlock(false); - } - - - Param* getParamFromHandle(const param_handle_t param_handle) - { - if (param_handle == 0) return NULL; - - U8* baseblock_address = reinterpret_cast<U8*>(this); - return reinterpret_cast<Param*>(baseblock_address + param_handle); - } - - const Param* getParamFromHandle(const param_handle_t param_handle) const - { - const U8* baseblock_address = reinterpret_cast<const U8*>(this); - return reinterpret_cast<const Param*>(baseblock_address + param_handle); - } - - void addSynonym(Param& param, const std::string& synonym); - - // Blocks can override this to do custom tracking of changes - virtual void paramChanged(const Param& changed_param, bool user_provided) - { - if (user_provided) - { - // a child param has been explicitly changed - // so *some* aspect of this block is now provided - mValidated = false; - mParamProvided = true; - } - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const; - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; - - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } - - // take all provided params from other and apply to self - bool overwriteFrom(const BaseBlock& other) - { - return false; - } - - // take all provided params that are not already provided, and apply to self - bool fillFrom(const BaseBlock& other) - { - return false; - } - - ParamDescriptorPtr findParamDescriptor(const Param& param); - - // take all provided params from other and apply to self - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); - - static BlockDescriptor& getBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } - - protected: - void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); - - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) - { - return mergeBlock(block_data, source, overwrite); - } - - mutable bool mValidated; // lazy validation flag - bool mParamProvided; - - private: - const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; - }; - - class LL_COMMON_API Param - { - public: - void setProvided(bool is_provided = true) - { - mIsProvided = is_provided; - enclosingBlock().paramChanged(*this, is_provided); - } - - Param& operator =(const Param& other) - { - mIsProvided = other.mIsProvided; - // don't change mEnclosingblockoffset - return *this; - } - protected: - - bool anyProvided() const { return mIsProvided; } - - Param(BaseBlock* enclosing_block); - - // store pointer to enclosing block as offset to reduce space and allow for quick copying - BaseBlock& enclosingBlock() const - { - const U8* my_addr = reinterpret_cast<const U8*>(this); - // get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class - return *const_cast<BaseBlock*> - (reinterpret_cast<const BaseBlock*> - (my_addr - (ptrdiff_t)getEnclosingBlockOffset())); - } - - U32 getEnclosingBlockOffset() const - { - return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow; - } - - private: - friend class BaseBlock; - - //24 bits for member offset field and 1 bit for provided flag - U16 mEnclosingBlockOffsetLow; - U8 mEnclosingBlockOffsetHigh:7; - U8 mIsProvided:1; - - }; - - template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> > - struct ParamIterator - { - typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::const_iterator const_iterator; - typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::iterator iterator; - }; - - // wrapper for parameter with a known type - // specialized to handle 4 cases: - // simple "scalar" value - // parameter that is itself a block - // multiple scalar values, stored in a vector - // multiple blocks, stored in a vector - template<typename T, - typename NAME_VALUE_LOOKUP = TypeValues<T>, - bool HAS_MULTIPLE_VALUES = false, - typename VALUE_IS_BLOCK = typename IsBlock<ParamValue<typename LLTypeTags::Sorted<T>::value_t> >::value_t> - class TypedParam - : public Param, - public NAME_VALUE_LOOKUP::type_value_t - { - protected: - typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t; - typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; - typedef typename param_value_t::default_value_t default_value_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - public: - typedef typename param_value_t::value_t value_t; - - using named_value_t::operator(); - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - named_value_t(value) - { - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - } - } - - bool isProvided() const { return Param::anyProvided(); } - - bool isValid() const { return true; } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - self_t& typed_param = static_cast<self_t&>(param); - // no further names in stack, attempt to parse value now - if (name_stack_range.first == name_stack_range.second) - { - std::string name; - - // try to parse a known named value - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } - // try to read value directly - else if (parser.readValue(typed_param.getValue())) - { - typed_param.clearValueName(); - typed_param.setProvided(); - return true; - } - } - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - bool serialized = false; - const self_t& typed_param = static_cast<const self_t&>(param); - const self_t* diff_typed_param = static_cast<const self_t*>(diff_param); - - LLPredicate::Value<ESerializePredicates> predicate; - if (diff_typed_param && ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) - { - predicate.set(HAS_DEFAULT_VALUE); - } - - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - predicate.set(EMPTY, false); - - if (!predicate_rule.check(predicate)) return false; - - if (!name_stack.empty()) - { - name_stack.back().second = true; - } - - std::string key = typed_param.getValueName(); - - // first try to write out name of name/value pair - - if (!key.empty()) - { - if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key)) - { - serialized = parser.writeValue(key, name_stack); - } - } - // then try to serialize value directly - else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) - { - serialized = parser.writeValue(typed_param.getValue(), name_stack); - if (!serialized) - { - std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); - if (calculated_key.size() - && (!diff_typed_param - || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))) - { - serialized = parser.writeValue(calculated_key, name_stack); - } - } - } - return serialized; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - // tell parser about our actual type - parser.inspectValue<T>(name_stack, min_count, max_count, NULL); - // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (named_value_t::getPossibleValues()) - { - parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - } - - void set(const value_t& val, bool flag_as_provided = true) - { - named_value_t::clearValueName(); - named_value_t::setValue(val); - setProvided(flag_as_provided); - } - - self_t& operator =(const typename named_value_t::name_t& name) - { - named_value_t::assignNamedValue(name); - return *this; - } - - protected: - - self_t& operator =(const self_t& other) - { - param_value_t::operator =(other); - Param::operator =(other); - return *this; - } - - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast<const self_t&>(src); - self_t& dst_typed_param = static_cast<self_t&>(dst); - - if (src_typed_param.isProvided() - && (overwrite || !dst_typed_param.isProvided())) - { - dst_typed_param.set(src_typed_param.getValue()); - return true; - } - return false; - } - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - // parameter that is a block - template <typename BLOCK_T, typename NAME_VALUE_LOOKUP> - class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> - : public Param, - public NAME_VALUE_LOOKUP::type_value_t - { - protected: - typedef ParamValue<typename LLTypeTags::Sorted<BLOCK_T>::value_t> param_value_t; - typedef typename param_value_t::default_value_t default_value_t; - typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - public: - using named_value_t::operator(); - typedef typename param_value_t::value_t value_t; - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - named_value_t(value) - { - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - } - } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - self_t& typed_param = static_cast<self_t&>(param); - - if (name_stack_range.first == name_stack_range.second) - { // try to parse a known named value - std::string name; - - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } - } - - if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) - { // attempt to parse block... - typed_param.clearValueName(); - typed_param.setProvided(); - return true; - } - - - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - const self_t& typed_param = static_cast<const self_t&>(param); - - LLPredicate::Value<ESerializePredicates> predicate; - - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - - if (!predicate_rule.check(predicate)) return false; - - if (!name_stack.empty()) - { - name_stack.back().second = true; - } - - std::string key = typed_param.getValueName(); - if (!key.empty()) - { - if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key)) - { - parser.writeValue(key, name_stack); - return true; - } - } - else - { - return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param)); - } - - return false; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - const self_t& typed_param = static_cast<const self_t&>(param); - - // tell parser about our actual type - parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL); - // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (named_value_t::getPossibleValues()) - { - parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - - typed_param.inspectBlock(parser, name_stack, min_count, max_count); - } - - // a param-that-is-a-block is provided when the user has set one of its child params - // *and* the block as a whole validates - bool isProvided() const - { - return Param::anyProvided() && isValid(); - } - - bool isValid() const - { - return param_value_t::isValid(); - } - - // assign block contents to this param-that-is-a-block - void set(const value_t& val, bool flag_as_provided = true) - { - named_value_t::setValue(val); - named_value_t::clearValueName(); - setProvided(flag_as_provided); - } - - self_t& operator =(const typename named_value_t::name_t& name) - { - named_value_t::assignNamedValue(name); - return *this; - } - - // propagate changed status up to enclosing block - /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) - { - param_value_t::paramChanged(changed_param, user_provided); - - if (user_provided) - { - setProvided(); - named_value_t::clearValueName(); - } - else - { - Param::enclosingBlock().paramChanged(*this, user_provided); - } - } - - protected: - - self_t& operator =(const self_t& other) - { - param_value_t::operator =(other); - Param::operator =(other); - return *this; - } - - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast<const self_t&>(src); - self_t& dst_typed_param = static_cast<self_t&>(dst); - - if (src_typed_param.anyProvided()) - { - if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite)) - { - dst_typed_param.clearValueName(); - dst_typed_param.setProvided(true); - return true; - } - } - return false; - } - - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - // list of non-block parameters - template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP> - class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> - : public Param - { - protected: - typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t; - typedef ParamValue<typename LLTypeTags::Sorted<MULTI_VALUE_T>::value_t> param_value_t; - typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; - typedef container_t default_value_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - - public: - typedef typename param_value_t::value_t value_t; - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - mMinCount(min_count), - mMaxCount(max_count) - { - std::copy(value.begin(), value.end(), std::back_inserter(mValues)); - - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - - } - } - - bool isProvided() const { return Param::anyProvided() && isValid(); } - - bool isValid() const - { - size_t num_elements = numValidElements(); - return mMinCount < num_elements && num_elements < mMaxCount; - } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - Parser::name_stack_range_t new_name_stack_range(name_stack_range); - self_t& typed_param = static_cast<self_t&>(param); - value_t value; - - // pop first element if empty string - if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) - { - ++new_name_stack_range.first; - } - - // no further names in stack, attempt to parse value now - if (new_name_stack_range.first == new_name_stack_range.second) - { - std::string name; - - // try to parse a known named value - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, value)) - { - typed_param.add(value); - typed_param.mValues.back().setValueName(name); - return true; - } - else if (parser.readValue(value)) // attempt to read value directly - { - typed_param.add(value); - return true; - } - } - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - bool serialized = false; - const self_t& typed_param = static_cast<const self_t&>(param); - - LLPredicate::Value<ESerializePredicates> predicate; - - predicate.set(REQUIRED, typed_param.mMinCount > 0); - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - predicate.set(EMPTY, typed_param.mValues.empty()); - - if (!predicate_rule.check(predicate)) return false; - - for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); - it != end_it; - ++it) - { - std::string key = it->getValueName(); - name_stack.push_back(std::make_pair(std::string(), true)); - - if(key.empty()) - // not parsed via name values, write out value directly - { - bool value_written = parser.writeValue(*it, name_stack); - if (!value_written) - { - std::string calculated_key = it->calcValueName(it->getValue()); - if (parser.writeValue(calculated_key, name_stack)) - { - serialized = true; - } - else - { - break; - } - } - } - else - { - if(parser.writeValue(key, name_stack)) - { - serialized = true; - } - else - { - break; - } - } - } - - return serialized; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL); - if (named_value_t::getPossibleValues()) - { - parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - } - - void set(const container_t& val, bool flag_as_provided = true) - { - mValues = val; - setProvided(flag_as_provided); - } - - param_value_t& add() - { - mValues.push_back(value_t()); - Param::setProvided(); - return mValues.back(); - } - - self_t& add(const value_t& item) - { - mValues.push_back(item); - setProvided(); - return *this; - } - - self_t& add(const typename named_value_t::name_t& name) - { - value_t value; - - // try to parse a per type named value - if (named_value_t::getValueFromName(name, value)) - { - add(value); - mValues.back().setValueName(name); - } - - return *this; - } - - // implicit conversion - operator const container_t&() const { return mValues; } - // explicit conversion - const container_t& operator()() const { return mValues; } - - typedef typename container_t::iterator iterator; - typedef typename container_t::const_iterator const_iterator; - iterator begin() { return mValues.begin(); } - iterator end() { return mValues.end(); } - const_iterator begin() const { return mValues.begin(); } - const_iterator end() const { return mValues.end(); } - bool empty() const { return mValues.empty(); } - size_t size() const { return mValues.size(); } - - size_t numValidElements() const - { - return mValues.size(); - } - - protected: - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast<const self_t&>(src); - self_t& dst_typed_param = static_cast<self_t&>(dst); - - if (overwrite) - { - std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); - } - else - { - container_t new_values(src_typed_param.mValues); - std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); - std::swap(dst_typed_param.mValues, new_values); - } - - if (src_typed_param.begin() != src_typed_param.end()) - { - dst_typed_param.setProvided(); - } - return true; - } - - container_t mValues; - size_t mMinCount, - mMaxCount; - - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - // list of block parameters - template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP> - class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> - : public Param - { - protected: - typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t; - typedef ParamValue<typename LLTypeTags::Sorted<MULTI_BLOCK_T>::value_t> param_value_t; - typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - typedef container_t default_value_t; - typedef typename container_t::iterator iterator; - typedef typename container_t::const_iterator const_iterator; - public: - typedef typename param_value_t::value_t value_t; - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - mMinCount(min_count), - mMaxCount(max_count) - { - std::copy(value.begin(), value.end(), back_inserter(mValues)); - - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - } - } - - bool isProvided() const { return Param::anyProvided() && isValid(); } - - bool isValid() const - { - size_t num_elements = numValidElements(); - return mMinCount < num_elements && num_elements < mMaxCount; - } - - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - Parser::name_stack_range_t new_name_stack_range(name_stack_range); - self_t& typed_param = static_cast<self_t&>(param); - bool new_value = false; - bool new_array_value = false; - - // pop first element if empty string - if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) - { - new_array_value = new_name_stack_range.first->second; - ++new_name_stack_range.first; - } - - if (new_name || new_array_value || typed_param.mValues.empty()) - { - new_value = true; - typed_param.mValues.push_back(value_t()); - } - param_value_t& value = typed_param.mValues.back(); - - if (new_name_stack_range.first == new_name_stack_range.second) - { // try to parse a known named value - std::string name; - - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, value.getValue())) - { - typed_param.mValues.back().setValueName(name); - typed_param.setProvided(); - if (new_array_value) - { - name_stack_range.first->second = false; - } - return true; - } - } - - // attempt to parse block... - if(value.deserializeBlock(parser, new_name_stack_range, new_name)) - { - typed_param.setProvided(); - if (new_array_value) - { - name_stack_range.first->second = false; - } - return true; - } - - - if (new_value) - { // failed to parse new value, pop it off - typed_param.mValues.pop_back(); - } - - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - bool serialized = false; - const self_t& typed_param = static_cast<const self_t&>(param); - LLPredicate::Value<ESerializePredicates> predicate; - - predicate.set(REQUIRED, typed_param.mMinCount > 0); - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - predicate.set(EMPTY, typed_param.mValues.empty()); - - if (!predicate_rule.check(predicate)) return false; - - for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); - it != end_it; - ++it) - { - name_stack.push_back(std::make_pair(std::string(), true)); - - std::string key = it->getValueName(); - if (!key.empty()) - { - serialized |= parser.writeValue(key, name_stack); - } - // Not parsed via named values, write out value directly - // NOTE: currently we don't do diffing of Multiples - else - { - serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL); - } - - name_stack.pop_back(); - } - - if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) - { - serialized |= parser.writeValue(Flag(), name_stack); - } - - return serialized; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - const param_value_t& value_param = param_value_t(value_t()); - - // tell parser about our actual type - parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL); - // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (named_value_t::getPossibleValues()) - { - parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - - value_param.inspectBlock(parser, name_stack, min_count, max_count); - } - - void set(const container_t& val, bool flag_as_provided = true) - { - mValues = val; - setProvided(flag_as_provided); - } - - param_value_t& add() - { - mValues.push_back(value_t()); - setProvided(); - return mValues.back(); - } - - self_t& add(const value_t& item) - { - mValues.push_back(item); - setProvided(); - return *this; - } - - self_t& add(const typename named_value_t::name_t& name) - { - value_t value; - - // try to parse a per type named value - if (named_value_t::getValueFromName(name, value)) - { - add(value); - mValues.back().setValueName(name); - } - return *this; - } - - // implicit conversion - operator const container_t&() const { return mValues; } - // explicit conversion - const container_t& operator()() const { return mValues; } - - iterator begin() { return mValues.begin(); } - iterator end() { return mValues.end(); } - const_iterator begin() const { return mValues.begin(); } - const_iterator end() const { return mValues.end(); } - bool empty() const { return mValues.empty(); } - size_t size() const { return mValues.size(); } - - size_t numValidElements() const - { - size_t count = 0; - for (const_iterator it = mValues.begin(), end_it = mValues.end(); - it != end_it; - ++it) - { - if(it->isValid()) count++; - } - return count; - } - - protected: - - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast<const self_t&>(src); - self_t& dst_typed_param = static_cast<self_t&>(dst); - - if (overwrite) - { - std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); - } - else - { - container_t new_values(src_typed_param.mValues); - std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); - std::swap(dst_typed_param.mValues, new_values); - } - - if (src_typed_param.begin() != src_typed_param.end()) - { - dst_typed_param.setProvided(); - } - - return true; - } - - container_t mValues; - size_t mMinCount, - mMaxCount; - - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock> - class ChoiceBlock : public BASE_BLOCK - { - typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> self_t; - typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> enclosing_block_t; - typedef BASE_BLOCK base_block_t; - - LOG_CLASS(self_t); - public: - // take all provided params from other and apply to self - bool overwriteFrom(const self_t& other) - { - return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true); - } - - // take all provided params that are not already provided, and apply to self - bool fillFrom(const self_t& other) - { - return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false); - } - - bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - bool source_override = source_provided && (overwrite || !dest_provided); - - if (source_override || source.mCurChoice == mCurChoice) - { - return mergeBlock(block_data, source, overwrite); - } - return false; - } - - // merge with other block - bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite) - { - mCurChoice = other.mCurChoice; - return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite); - } - - // clear out old choice when param has changed - /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) - { - param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param); - // if we have a new choice... - if (changed_param_handle != mCurChoice) - { - // clear provided flag on previous choice - Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice); - if (previous_choice) - { - previous_choice->setProvided(false); - } - mCurChoice = changed_param_handle; - } - base_block_t::paramChanged(changed_param, user_provided); - } - - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } - - protected: - ChoiceBlock() - : mCurChoice(0) - { - BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); - } - - // Alternatives are mutually exclusive wrt other Alternatives in the same block. - // One alternative in a block will always have isChosen() == true. - // At most one alternative in a block will have isProvided() == true. - template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > - class Alternative : public TypedParam<T, NAME_VALUE_LOOKUP, false> - { - typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t; - typedef typename super_t::value_t value_t; - typedef typename super_t::default_value_t default_value_t; - - public: - friend class ChoiceBlock<DERIVED_BLOCK>; - - using super_t::operator =; - - explicit Alternative(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1), - mOriginalValue(val) - { - // assign initial choice to first declared option - DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr); - if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) - { - if(blockp->mCurChoice == 0) - { - blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this); - } - } - } - - void choose() - { - static_cast<enclosing_block_t&>(Param::enclosingBlock()).paramChanged(*this, true); - } - - void chooseAs(const value_t& val) - { - super_t::set(val); - } - - void operator =(const value_t& val) - { - super_t::set(val); - } - - void operator()(const value_t& val) - { - super_t::set(val); - } - - operator const value_t&() const - { - return (*this)(); - } - - const value_t& operator()() const - { - if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this) - { - return super_t::getValue(); - } - return mOriginalValue; - } - - bool isChosen() const - { - return static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this; - } - - private: - default_value_t mOriginalValue; - }; - - public: - static BlockDescriptor& getBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } - - private: - param_handle_t mCurChoice; - - const Param* getCurrentChoice() const - { - return base_block_t::getParamFromHandle(mCurChoice); - } - }; - - template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock> - class Block - : public BASE_BLOCK - { - typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t; - - protected: - typedef Block<DERIVED_BLOCK, BASE_BLOCK> block_t; - - public: - typedef BASE_BLOCK base_block_t; - - // take all provided params from other and apply to self - bool overwriteFrom(const self_t& other) - { - return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true); - } - - // take all provided params that are not already provided, and apply to self - bool fillFrom(const self_t& other) - { - return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false); - } - - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } - - protected: - Block() - { - //#pragma message("Parsing LLInitParam::Block") - BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); - } - - // - // Nested classes for declaring parameters - // - template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > - class Optional : public TypedParam<T, NAME_VALUE_LOOKUP, false> - { - typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t; - typedef typename super_t::value_t value_t; - typedef typename super_t::default_value_t default_value_t; - - public: - using super_t::operator(); - using super_t::operator =; - - explicit Optional(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1) - { - //#pragma message("Parsing LLInitParam::Block::Optional") - } - - Optional& operator =(const value_t& val) - { - super_t::set(val); - return *this; - } - - DERIVED_BLOCK& operator()(const value_t& val) - { - super_t::set(val); - return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); - } - }; - - template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > - class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false> - { - typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t; - typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t; - typedef typename super_t::value_t value_t; - typedef typename super_t::default_value_t default_value_t; - - public: - using super_t::operator(); - using super_t::operator =; - - // mandatory parameters require a name to be parseable - explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1) - {} - - Mandatory& operator =(const value_t& val) - { - super_t::set(val); - return *this; - } - - DERIVED_BLOCK& operator()(const value_t& val) - { - super_t::set(val); - return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); - } - - static bool validate(const Param* p) - { - // valid only if provided - return static_cast<const self_t*>(p)->isProvided(); - } - - }; - - template <typename T, typename RANGE = BaseBlock::AnyAmount, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > - class Multiple : public TypedParam<T, NAME_VALUE_LOOKUP, true> - { - typedef TypedParam<T, NAME_VALUE_LOOKUP, true> super_t; - typedef Multiple<T, RANGE, NAME_VALUE_LOOKUP> self_t; - typedef typename super_t::container_t container_t; - typedef typename super_t::value_t value_t; - - public: - typedef typename super_t::iterator iterator; - typedef typename super_t::const_iterator const_iterator; - - using super_t::operator(); - using super_t::operator const container_t&; - - explicit Multiple(const char* name = "") - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) - {} - - Multiple& operator =(const container_t& val) - { - super_t::set(val); - return *this; - } - - DERIVED_BLOCK& operator()(const container_t& val) - { - super_t::set(val); - return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); - } - - static bool validate(const Param* paramp) - { - size_t num_valid = ((super_t*)paramp)->numValidElements(); - return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; - } - }; - - // can appear in data files, but will ignored during parsing - // cannot read or write in code - class Ignored : public Param - { - public: - explicit Ignored(const char* name) - : Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr) - { - BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor(); - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - NULL, - &deserializeParam, - NULL, - NULL, - NULL, - 0, S32_MAX)); - block_descriptor.addParam(param_descriptor, name); - } - } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - if (name_stack_range.first == name_stack_range.second) - { - //std::string message = llformat("Deprecated value %s ignored", getName().c_str()); - //parser.parserWarning(message); - return true; - } - - return false; - } - }; - - // can appear in data files, or be written to in code, but data will be ignored - // cannot be read in code - class Deprecated : public Ignored - { - public: - explicit Deprecated(const char* name) : Ignored(name) {} - - // dummy writer interfaces - template<typename T> - Deprecated& operator =(const T& val) - { - // do nothing - return *this; - } - - template<typename T> - DERIVED_BLOCK& operator()(const T& val) - { - // do nothing - return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); - } - - template<typename T> - void set(const T& val, bool flag_as_provided = true) - { - // do nothing - } - }; - - public: - static BlockDescriptor& getBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } - - protected: - template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, typename is_block> - void changeDefault(TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>& param, - const typename TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>::value_t& value) - { - if (!param.isProvided()) - { - param.set(value, false); - } - } - - }; - - template<typename T, typename BLOCK_T> - struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void> - { - typedef IS_A_BLOCK value_t; - }; - - template<typename T, typename BLOCK_T> - struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::NOT_A_BLOCK>, BLOCK_T >, void> - { - typedef NOT_BLOCK value_t; - }; - - template<typename T, typename BLOCK_IDENTIFIER> - struct IsBlock<ParamValue<BaseBlock::Atomic<T>, typename IsBlock<BaseBlock::Atomic<T> >::value_t >, BLOCK_IDENTIFIER> - { - typedef typename IsBlock<T>::value_t value_t; - }; - - template<typename T, typename BLOCK_IDENTIFIER> - struct IsBlock<ParamValue<BaseBlock::Sequential<T>, typename IsBlock<BaseBlock::Sequential<T> >::value_t >, BLOCK_IDENTIFIER> - { - typedef typename IsBlock<T>::value_t value_t; - }; - - - template<typename T> - struct InnerMostType - { - typedef T value_t; - }; - - template<typename T> - struct InnerMostType<ParamValue<T, NOT_BLOCK> > - { - typedef typename InnerMostType<T>::value_t value_t; - }; - - template<typename T> - struct InnerMostType<ParamValue<T, IS_A_BLOCK> > - { - typedef typename InnerMostType<T>::value_t value_t; - }; - - template<typename T, typename BLOCK_T> - class ParamValue <BaseBlock::Atomic<T>, BLOCK_T> - { - typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t; - - public: - typedef typename InnerMostType<T>::value_t value_t; - typedef T default_value_t; - - ParamValue() - : mValue() - {} - - ParamValue(const default_value_t& value) - : mValue(value) - {} - - void setValue(const value_t& val) - { - mValue.setValue(val); - } - - const value_t& getValue() const - { - return mValue.getValue(); - } - - value_t& getValue() - { - return mValue.getValue(); - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - if (new_name) - { - resetToDefault(); - } - return mValue.deserializeBlock(p, name_stack_range, new_name); - } - - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const - { - const BaseBlock* base_block = diff_block - ? &(diff_block->mValue) - : NULL; - return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); - } - - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - return mValue.inspectBlock(p, name_stack, min_count, max_count); - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - if ((overwrite && source_provided) // new values coming in on top or... - || (!overwrite && !dst_provided)) // values being pushed under with nothing already there - { - // clear away what is there and take the new stuff as a whole - resetToDefault(); - return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - - bool validateBlock(bool emit_errors = true) const - { - return mValue.validateBlock(emit_errors); - } - - bool isValid() const - { - return validateBlock(false); - } - - static BlockDescriptor& getBlockDescriptor() - { - return value_t::getBlockDescriptor(); - } - - - private: - void resetToDefault() - { - static T default_value; - mValue = default_value; - } - - T mValue; - }; - - template<typename T> - class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> - { - typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t; - - public: - typedef typename InnerMostType<T>::value_t value_t; - typedef T default_value_t; - - ParamValue() - : mValue() - { - mCurParam = getBlockDescriptor().mAllParams.begin(); - } - - ParamValue(const default_value_t& value) - : mValue(value) - { - mCurParam = getBlockDescriptor().mAllParams.begin(); - } - - void setValue(const value_t& val) - { - mValue.setValue(val); - } - - const value_t& getValue() const - { - return mValue.getValue(); - } - - value_t& getValue() - { - return mValue.getValue(); - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - if (new_name) - { - mCurParam = getBlockDescriptor().mAllParams.begin(); - } - if (name_stack_range.first == name_stack_range.second - && mCurParam != getBlockDescriptor().mAllParams.end()) - { - // deserialize to mCurParam - ParamDescriptor& pd = *(*mCurParam); - ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc; - Param* paramp = mValue.getParamFromHandle(pd.mParamHandle); - - if (deserialize_func - && paramp - && deserialize_func(*paramp, p, name_stack_range, new_name)) - { - ++mCurParam; - return true; - } - else - { - return false; - } - } - else - { - return mValue.deserializeBlock(p, name_stack_range, new_name); - } - } - - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const - { - const BaseBlock* base_block = diff_block - ? &(diff_block->mValue) - : NULL; - return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); - } - - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - return mValue.inspectBlock(p, name_stack, min_count, max_count); - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - - bool validateBlock(bool emit_errors = true) const - { - return mValue.validateBlock(emit_errors); - } - - bool isValid() const - { - return validateBlock(false); - } - - static BlockDescriptor& getBlockDescriptor() - { - return value_t::getBlockDescriptor(); - } - - private: - - BlockDescriptor::all_params_list_t::iterator mCurParam; - T mValue; - }; - - template<typename T> - class ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> - : public T - { - typedef ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> self_t; - - public: - typedef typename InnerMostType<T>::value_t value_t; - typedef T default_value_t; - - ParamValue() - : T() - {} - - ParamValue(const default_value_t& value) - : T(value.getValue()) - {} - - bool isValid() const { return true; } - }; - - template<typename T, typename BLOCK_T> - class ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> - { - typedef ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> self_t; - - public: - typedef typename InnerMostType<T>::value_t value_t; - typedef LazyValue<T> default_value_t; - - ParamValue() - : mValue() - {} - - ParamValue(const default_value_t& other) - : mValue(other) - {} - - ParamValue(const T& value) - : mValue(value) - {} - - void setValue(const value_t& val) - { - mValue.set(val); - } - - const value_t& getValue() const - { - return mValue.get().getValue(); - } - - value_t& getValue() - { - return mValue.get().getValue(); - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - return mValue.get().deserializeBlock(p, name_stack_range, new_name); - } - - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const - { - if (mValue.empty()) return false; - - const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) - ? &(diff_block->mValue.get().getValue()) - : NULL; - return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_block); - } - - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - return mValue.get().inspectBlock(p, name_stack, min_count, max_count); - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); - } - - bool validateBlock(bool emit_errors = true) const - { - return mValue.empty() || mValue.get().validateBlock(emit_errors); - } - - bool isValid() const - { - return validateBlock(false); - } - - static BlockDescriptor& getBlockDescriptor() - { - return value_t::getBlockDescriptor(); - } - - private: - LazyValue<T> mValue; - }; - - template<typename T, typename BLOCK_T> - class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> - { - typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t; - - public: - typedef typename InnerMostType<T>::value_t value_t; - typedef LazyValue<T> default_value_t; - - ParamValue() - : mValue() - {} - - ParamValue(const default_value_t& other) - : mValue(other) - {} - - ParamValue(const T& value) - : mValue(value) - {} - - void setValue(const value_t& val) - { - mValue.set(val); - } - - const value_t& getValue() const - { - return mValue.get().getValue(); - } - - value_t& getValue() - { - return mValue.get().getValue(); - } - - bool isValid() const - { - return true; - } - - private: - LazyValue<T> mValue; - }; - - template <> - class ParamValue <LLSD, NOT_BLOCK> - : public BaseBlock - { - public: - typedef LLSD value_t; - typedef LLSD default_value_t; - - ParamValue() - {} - - ParamValue(const default_value_t& other) - : mValue(other) - {} - - void setValue(const value_t& val) { mValue = val; } - - const value_t& getValue() const { return mValue; } - LLSD& getValue() { return mValue; } - - // block param interface - LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const; - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - //TODO: implement LLSD params as schema type Any - return true; - } - - private: - static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); - - LLSD mValue; - }; - - template<typename T> - class CustomParamValue - : public Block<ParamValue<T> > - { - public: - typedef enum e_value_age - { - VALUE_NEEDS_UPDATE, // mValue needs to be refreshed from the block parameters - VALUE_AUTHORITATIVE, // mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue) - BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative - } EValueAge; - - typedef TypeValues<T> derived_t; - typedef CustomParamValue<T> self_t; - typedef Block<ParamValue<T> > block_t; - typedef T default_value_t; - typedef T value_t; - typedef void baseblock_base_class_t; - - - CustomParamValue(const default_value_t& value = T()) - : mValue(value), - mValueAge(VALUE_AUTHORITATIVE) - {} - - bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - derived_t& typed_param = static_cast<derived_t&>(*this); - // try to parse direct value T - if (name_stack_range.first == name_stack_range.second) - { - if(parser.readValue(typed_param.mValue)) - { - typed_param.mValueAge = VALUE_AUTHORITATIVE; - typed_param.updateBlockFromValue(false); - - return true; - } - } - - // fall back on parsing block components for T - return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); - } - - bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const - { - const derived_t& typed_param = static_cast<const derived_t&>(*this); - const derived_t* diff_param = static_cast<const derived_t*>(diff_block); - - //std::string key = typed_param.getValueName(); - - //// first try to write out name of name/value pair - //if (!key.empty()) - //{ - // if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key)) - // { - // return parser.writeValue(key, name_stack); - // } - //} - // then try to serialize value directly - if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue())) - { - - if (parser.writeValue(typed_param.getValue(), name_stack)) - { - return true; - } - else - { - //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), - // since these tend to be viewed as the constructor arguments for the value T. It seems - // cleaner to treat the uniqueness of a BlockValue according to the generated value, and - // not the individual components. This way <color red="0" green="1" blue="0"/> will not - // be exported as <color green="1"/>, since it was probably the intent of the user to - // be specific about the RGB color values. This also fixes an issue where we distinguish - // between rect.left not being provided and rect.left being explicitly set to 0 (same as default) - - if (typed_param.mValueAge == VALUE_AUTHORITATIVE) - { - // if the value is authoritative but the parser doesn't accept the value type - // go ahead and make a copy, and splat the value out to its component params - // and serialize those params - derived_t copy(typed_param); - copy.updateBlockFromValue(true); - return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); - } - else - { - return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); - } - } - } - return false; - } - - bool validateBlock(bool emit_errors = true) const - { - if (mValueAge == VALUE_NEEDS_UPDATE) - { - if (block_t::validateBlock(emit_errors)) - { - // clear stale keyword associated with old value - mValueAge = BLOCK_AUTHORITATIVE; - static_cast<derived_t*>(const_cast<self_t*>(this))->updateValueFromBlock(); - return true; - } - else - { - //block value incomplete, so not considered provided - // will attempt to revalidate on next call to isProvided() - return false; - } - } - else - { - // we have a valid value in hand - return true; - } - } - - // propagate change status up to enclosing block - /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) - { - BaseBlock::paramChanged(changed_param, user_provided); - if (user_provided) - { - // a parameter changed, so our value is out of date - mValueAge = VALUE_NEEDS_UPDATE; - } - } - - void setValue(const value_t& val) - { - // set param version number to be up to date, so we ignore block contents - mValueAge = VALUE_AUTHORITATIVE; - mValue = val; - static_cast<derived_t*>(this)->updateBlockFromValue(false); - } - - const value_t& getValue() const - { - validateBlock(true); - return mValue; - } - - T& getValue() - { - validateBlock(true); - return mValue; - } - - protected: - - // use this from within updateValueFromBlock() to set the value without making it authoritative - void updateValue(const value_t& value) - { - mValue = value; - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) - { - bool source_override = source_provided && (overwrite || !dst_provided); - - const derived_t& src_typed_param = static_cast<const derived_t&>(source); - - if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE) - { - // copy value over - setValue(src_typed_param.getValue()); - return true; - } - // merge individual parameters into destination - if (mValueAge == VALUE_AUTHORITATIVE) - { - static_cast<derived_t*>(this)->updateBlockFromValue(dst_provided); - } - return mergeBlock(block_data, source, overwrite); - } - - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) - { - return block_t::mergeBlock(block_data, source, overwrite); - } - - private: - mutable T mValue; - mutable EValueAge mValueAge; - }; + + // empty default implementation of key cache + // leverages empty base class optimization + template <typename T> + class TypeValues + : public ParamValue<typename LLTypeTags::Sorted<T>::value_t> + { + private: + struct Inaccessable{}; + public: + typedef std::map<std::string, T> value_name_map_t; + typedef Inaccessable name_t; + typedef TypeValues<T> type_value_t; + typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValues(const typename param_value_t::value_t& val) + : param_value_t(val) + {} + + void setValueName(const std::string& key) {} + std::string getValueName() const { return ""; } + std::string calcValueName(const value_t& value) const { return ""; } + void clearValueName() const {} + + static bool getValueFromName(const std::string& name, value_t& value) + { + return false; + } + + static bool valueNamesExist() + { + return false; + } + + static std::vector<std::string>* getPossibleValues() + { + return NULL; + } + + void assignNamedValue(const Inaccessable& name) + {} + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + + static value_name_map_t* getValueNames() {return NULL;} + }; + + // helper class to implement name value lookups + // and caching of last used name + template <typename T, typename DERIVED_TYPE = TypeValues<T>, bool IS_SPECIALIZED = true > + class TypeValuesHelper + : public ParamValue<typename LLTypeTags::Sorted<T>::value_t> + { + typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t; + public: + typedef typename std::map<std::string, T> value_name_map_t; + typedef std::string name_t; + typedef self_t type_value_t; + typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValuesHelper(const typename param_value_t::value_t& val) + : param_value_t(val) + {} + + //TODO: cache key by index to save on param block size + void setValueName(const std::string& value_name) + { + mValueName = value_name; + } + + std::string getValueName() const + { + return mValueName; + } + + std::string calcValueName(const value_t& value) const + { + value_name_map_t* map = getValueNames(); + for (typename value_name_map_t::value_type& map_pair : *map) + { + if (ParamCompare<T>::equals(map_pair.second, value)) + { + return map_pair.first; + } + } + + return ""; + } + + void clearValueName() const + { + mValueName.clear(); + } + + static bool getValueFromName(const std::string& name, value_t& value) + { + value_name_map_t* map = getValueNames(); + typename value_name_map_t::iterator found_it = map->find(name); + if (found_it == map->end()) return false; + + value = found_it->second; + return true; + } + + static bool valueNamesExist() + { + return !getValueNames()->empty(); + } + + static value_name_map_t* getValueNames() + { + static value_name_map_t sMap; + static bool sInitialized = false; + + if (!sInitialized) + { + sInitialized = true; + DERIVED_TYPE::declareValues(); + } + return &sMap; + } + + static std::vector<std::string>* getPossibleValues() + { + static std::vector<std::string> sValues; + + value_name_map_t* map = getValueNames(); + for (typename value_name_map_t::value_type& map_pair : *map) + { + sValues.push_back(map_pair.first); + } + return &sValues; + } + + static void declare(const std::string& name, const value_t& value) + { + (*getValueNames())[name] = value; + } + + void operator ()(const std::string& name) + { + *this = name; + } + + void assignNamedValue(const std::string& name) + { + if (getValueFromName(name, param_value_t::getValue())) + { + setValueName(name); + } + } + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + + protected: + static void getName(const std::string& name, const value_t& value) + {} + + mutable std::string mValueName; + }; + + // string types can support custom named values, but need + // to disambiguate in code between a string that is a named value + // and a string that is a name + template <typename DERIVED_TYPE> + class TypeValuesHelper<std::string, DERIVED_TYPE, true> + : public TypeValuesHelper<std::string, DERIVED_TYPE, false> + { + public: + typedef TypeValuesHelper<std::string, DERIVED_TYPE, true> self_t; + typedef TypeValuesHelper<std::string, DERIVED_TYPE, false> base_t; + typedef std::string value_t; + typedef std::string name_t; + typedef self_t type_value_t; + + TypeValuesHelper(const std::string& val) + : base_t(val) + {} + + void operator ()(const std::string& name) + { + *this = name; + } + + self_t& operator =(const std::string& name) + { + if (base_t::getValueFromName(name, ParamValue<std::string>::getValue())) + { + base_t::setValueName(name); + } + else + { + ParamValue<std::string>::setValue(name); + } + return *this; + } + + operator const value_t&() const + { + return ParamValue<std::string>::getValue(); + } + + const value_t& operator()() const + { + return ParamValue<std::string>::getValue(); + } + + }; + + // parser base class with mechanisms for registering readers/writers/inspectors of different types + class LL_COMMON_API Parser + { + LOG_CLASS(Parser); + public: + typedef std::vector<std::pair<std::string, bool> > name_stack_t; + typedef std::pair<name_stack_t::iterator, name_stack_t::iterator> name_stack_range_t; + typedef std::vector<std::string> possible_values_t; + + typedef bool (*parser_read_func_t)(Parser& parser, void* output); + typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&); + typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t; + + typedef std::map<const std::type_info*, parser_read_func_t> parser_read_func_map_t; + typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t; + typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t; + + public: + + Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) + : mParseSilently(false), + mParserReadFuncs(&read_map), + mParserWriteFuncs(&write_map), + mParserInspectFuncs(&inspect_map) + {} + + virtual ~Parser(); + + template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0) + { + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + + return false; + } + + template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0) + { + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + else + { + found_it = mParserReadFuncs->find(&typeid(S32)); + if (found_it != mParserReadFuncs->end()) + { + S32 int_value; + bool parsed = found_it->second(*this, (void*)&int_value); + param = (T)int_value; + return parsed; + } + } + return false; + } + + template <typename T> bool writeValue(const T& param, name_stack_t& name_stack) + { + parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); + if (found_it != mParserWriteFuncs->end()) + { + return found_it->second(*this, (const void*)¶m, name_stack); + } + return false; + } + + // dispatch inspection to registered inspection functions, for each parameter in a param block + template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) + { + parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T)); + if (found_it != mParserInspectFuncs->end()) + { + found_it->second(name_stack, min_count, max_count, possible_values); + return true; + } + return false; + } + + virtual std::string getCurrentElementName() = 0; + virtual std::string getCurrentFileName() = 0; + virtual void parserWarning(const std::string& message); + virtual void parserError(const std::string& message); + void setParseSilently(bool silent) { mParseSilently = silent; } + + protected: + template <typename T> + void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL) + { + mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func)); + mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func)); + } + + template <typename T> + void registerInspectFunc(parser_inspect_func_t inspect_func) + { + mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func)); + } + + bool mParseSilently; + + private: + parser_read_func_map_t* mParserReadFuncs; + parser_write_func_map_t* mParserWriteFuncs; + parser_inspect_func_map_t* mParserInspectFuncs; + }; + + class Param; + + enum ESerializePredicates + { + PROVIDED, + REQUIRED, + VALID, + HAS_DEFAULT_VALUE, + EMPTY + }; + + typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t; + + predicate_rule_t default_parse_rules(); + + // various callbacks and constraints associated with an individual param + struct LL_COMMON_API ParamDescriptor + { + struct UserData + { + virtual ~UserData() {} + }; + + typedef bool(*merge_func_t)(Param&, const Param&, bool); + typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); + typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param); + typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); + typedef bool(*validation_func_t)(const Param*); + + ParamDescriptor(param_handle_t p, + merge_func_t merge_func, + deserialize_func_t deserialize_func, + serialize_func_t serialize_func, + validation_func_t validation_func, + inspect_func_t inspect_func, + S32 min_count, + S32 max_count); + + ParamDescriptor(); + ~ParamDescriptor(); + + param_handle_t mParamHandle; + merge_func_t mMergeFunc; + deserialize_func_t mDeserializeFunc; + serialize_func_t mSerializeFunc; + inspect_func_t mInspectFunc; + validation_func_t mValidationFunc; + S32 mMinCount; + S32 mMaxCount; + S32 mNumRefs; + UserData* mUserData; + }; + + typedef std::shared_ptr<ParamDescriptor> ParamDescriptorPtr; + + // each derived Block class keeps a static data structure maintaining offsets to various params + class LL_COMMON_API BlockDescriptor + { + public: + BlockDescriptor(); + + typedef enum e_initialization_state + { + UNINITIALIZED, + INITIALIZING, + INITIALIZED + } EInitializationState; + + void aggregateBlockData(BlockDescriptor& src_block_data); + void addParam(ParamDescriptorPtr param, const char* name); + + typedef boost::unordered_map<const std::string, ParamDescriptorPtr> param_map_t; + typedef std::vector<ParamDescriptorPtr> param_list_t; + typedef std::list<ParamDescriptorPtr> all_params_list_t; + typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t; + + param_map_t mNamedParams; // parameters with associated names + param_list_t mUnnamedParams; // parameters with_out_ associated names + param_validation_list_t mValidationList; // parameters that must be validated + all_params_list_t mAllParams; // all parameters, owns descriptors + size_t mMaxParamOffset; + EInitializationState mInitializationState; // whether or not static block data has been initialized + class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed + }; + + //TODO: implement in terms of owned_ptr + template<typename T> + class LazyValue + { + public: + LazyValue() + : mPtr(NULL) + {} + + ~LazyValue() + { + delete mPtr; + } + + LazyValue(const T& value) + { + mPtr = new T(value); + } + + LazyValue(const LazyValue& other) + : mPtr(NULL) + { + *this = other; + } + + LazyValue& operator = (const LazyValue& other) + { + if (!other.mPtr) + { + delete mPtr; + mPtr = NULL; + } + else + { + if (!mPtr) + { + mPtr = new T(*other.mPtr); + } + else + { + *mPtr = *(other.mPtr); + } + } + return *this; + } + + bool operator==(const LazyValue& other) const + { + if (empty() || other.empty()) return false; + return *mPtr == *other.mPtr; + } + + bool empty() const + { + return mPtr == NULL; + } + + void set(const T& other) + { + if (!mPtr) + { + mPtr = new T(other); + } + else + { + *mPtr = other; + } + } + + const T& get() const + { + return *ensureInstance(); + } + + T& get() + { + return *ensureInstance(); + } + + operator const T&() const + { + return get(); + } + + private: + // lazily allocate an instance of T + T* ensureInstance() const + { + if (mPtr == NULL) + { + mPtr = new T(); + } + return mPtr; + } + + private: + + mutable T* mPtr; + }; + + // root class of all parameter blocks + + class LL_COMMON_API BaseBlock + { + public: + // lift block tags into baseblock namespace so derived classes do not need to qualify them + typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK; + typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK; + + template<typename T> + struct Sequential : public LLTypeTags::TypeTagBase<T, 2> + { + template <typename S> struct Cons { typedef Sequential<ParamValue<S> > value_t; }; + template <typename S> struct Cons<Sequential<S> > { typedef Sequential<S> value_t; }; + }; + + template<typename T> + struct Atomic : public LLTypeTags::TypeTagBase<T, 1> + { + template <typename S> struct Cons { typedef Atomic<ParamValue<S> > value_t; }; + template <typename S> struct Cons<Atomic<S> > { typedef Atomic<S> value_t; }; + }; + + template<typename T, typename BLOCK_T = typename IsBlock<T>::value_t > + struct Lazy : public LLTypeTags::TypeTagBase<T, 0> + { + template <typename S> struct Cons + { + typedef Lazy<ParamValue<S, BLOCK_T>, BLOCK_T> value_t; + }; + template <typename S> struct Cons<Lazy<S, IS_A_BLOCK> > + { + typedef Lazy<S, IS_A_BLOCK> value_t; + }; + template <typename S> struct Cons<Lazy<S, NOT_A_BLOCK> > + { + typedef Lazy<S, BLOCK_T> value_t; + }; + }; + + // "Multiple" constraint types, put here in root class to avoid ambiguity during use + struct AnyAmount + { + enum { minCount = 0 }; + enum { maxCount = U32_MAX }; + }; + + template<U32 MIN_AMOUNT> + struct AtLeast + { + enum { minCount = MIN_AMOUNT }; + enum { maxCount = U32_MAX }; + }; + + template<U32 MAX_AMOUNT> + struct AtMost + { + enum { minCount = 0 }; + enum { maxCount = MAX_AMOUNT }; + }; + + template<U32 MIN_AMOUNT, U32 MAX_AMOUNT> + struct Between + { + enum { minCount = MIN_AMOUNT }; + enum { maxCount = MAX_AMOUNT }; + }; + + template<U32 EXACT_COUNT> + struct Exactly + { + enum { minCount = EXACT_COUNT }; + enum { maxCount = EXACT_COUNT }; + }; + + // this typedef identifies derived classes as being blocks + typedef void baseblock_base_class_t; + LOG_CLASS(BaseBlock); + friend class Param; + + BaseBlock() + : mValidated(false), + mParamProvided(false) + {} + + virtual ~BaseBlock() {} + bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); + + param_handle_t getHandleFromParam(const Param* param) const; + bool validateBlock(bool emit_errors = true) const; + + bool isProvided() const + { + return mParamProvided; + } + + bool isValid() const + { + return validateBlock(false); + } + + + Param* getParamFromHandle(const param_handle_t param_handle) + { + if (param_handle == 0) return NULL; + + U8* baseblock_address = reinterpret_cast<U8*>(this); + return reinterpret_cast<Param*>(baseblock_address + param_handle); + } + + const Param* getParamFromHandle(const param_handle_t param_handle) const + { + const U8* baseblock_address = reinterpret_cast<const U8*>(this); + return reinterpret_cast<const Param*>(baseblock_address + param_handle); + } + + void addSynonym(Param& param, const std::string& synonym); + + // Blocks can override this to do custom tracking of changes + virtual void paramChanged(const Param& changed_param, bool user_provided) + { + if (user_provided) + { + // a child param has been explicitly changed + // so *some* aspect of this block is now provided + mValidated = false; + mParamProvided = true; + } + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const; + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } + + // take all provided params from other and apply to self + bool overwriteFrom(const BaseBlock& other) + { + return false; + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const BaseBlock& other) + { + return false; + } + + ParamDescriptorPtr findParamDescriptor(const Param& param); + + // take all provided params from other and apply to self + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); + + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + protected: + void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); + + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + return mergeBlock(block_data, source, overwrite); + } + + mutable bool mValidated; // lazy validation flag + bool mParamProvided; + + private: + const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; + }; + + class LL_COMMON_API Param + { + public: + void setProvided(bool is_provided = true) + { + mIsProvided = is_provided; + enclosingBlock().paramChanged(*this, is_provided); + } + + Param& operator =(const Param& other) + { + mIsProvided = other.mIsProvided; + // don't change mEnclosingblockoffset + return *this; + } + protected: + + bool anyProvided() const { return mIsProvided; } + + Param(BaseBlock* enclosing_block); + + // store pointer to enclosing block as offset to reduce space and allow for quick copying + BaseBlock& enclosingBlock() const + { + const U8* my_addr = reinterpret_cast<const U8*>(this); + // get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class + return *const_cast<BaseBlock*> + (reinterpret_cast<const BaseBlock*> + (my_addr - (ptrdiff_t)getEnclosingBlockOffset())); + } + + U32 getEnclosingBlockOffset() const + { + return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow; + } + + private: + friend class BaseBlock; + + //24 bits for member offset field and 1 bit for provided flag + U16 mEnclosingBlockOffsetLow; + U8 mEnclosingBlockOffsetHigh:7; + U8 mIsProvided:1; + + }; + + template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> > + struct ParamIterator + { + typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::const_iterator const_iterator; + typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::iterator iterator; + }; + + // wrapper for parameter with a known type + // specialized to handle 4 cases: + // simple "scalar" value + // parameter that is itself a block + // multiple scalar values, stored in a vector + // multiple blocks, stored in a vector + template<typename T, + typename NAME_VALUE_LOOKUP = TypeValues<T>, + bool HAS_MULTIPLE_VALUES = false, + typename VALUE_IS_BLOCK = typename IsBlock<ParamValue<typename LLTypeTags::Sorted<T>::value_t> >::value_t> + class TypedParam + : public Param, + public NAME_VALUE_LOOKUP::type_value_t + { + protected: + typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t; + typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + public: + typedef typename param_value_t::value_t value_t; + + using named_value_t::operator(); + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + named_value_t(value) + { + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + } + } + + bool isProvided() const { return Param::anyProvided(); } + + bool isValid() const { return true; } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast<self_t&>(param); + // no further names in stack, attempt to parse value now + if (name_stack_range.first == name_stack_range.second) + { + std::string name; + + // try to parse a known named value + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + // try to read value directly + else if (parser.readValue(typed_param.getValue())) + { + typed_param.clearValueName(); + typed_param.setProvided(); + return true; + } + } + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + bool serialized = false; + const self_t& typed_param = static_cast<const self_t&>(param); + const self_t* diff_typed_param = static_cast<const self_t*>(diff_param); + + LLPredicate::Value<ESerializePredicates> predicate; + if (diff_typed_param && ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) + { + predicate.set(HAS_DEFAULT_VALUE); + } + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, false); + + if (!predicate_rule.check(predicate)) return false; + + if (!name_stack.empty()) + { + name_stack.back().second = true; + } + + std::string key = typed_param.getValueName(); + + // first try to write out name of name/value pair + + if (!key.empty()) + { + if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key)) + { + serialized = parser.writeValue(key, name_stack); + } + } + // then try to serialize value directly + else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) + { + serialized = parser.writeValue(typed_param.getValue(), name_stack); + if (!serialized) + { + std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); + if (calculated_key.size() + && (!diff_typed_param + || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))) + { + serialized = parser.writeValue(calculated_key, name_stack); + } + } + } + return serialized; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + // tell parser about our actual type + parser.inspectValue<T>(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + } + + void set(const value_t& val, bool flag_as_provided = true) + { + named_value_t::clearValueName(); + named_value_t::setValue(val); + setProvided(flag_as_provided); + } + + self_t& operator =(const typename named_value_t::name_t& name) + { + named_value_t::assignNamedValue(name); + return *this; + } + + protected: + + self_t& operator =(const self_t& other) + { + param_value_t::operator =(other); + Param::operator =(other); + return *this; + } + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast<const self_t&>(src); + self_t& dst_typed_param = static_cast<self_t&>(dst); + + if (src_typed_param.isProvided() + && (overwrite || !dst_typed_param.isProvided())) + { + dst_typed_param.set(src_typed_param.getValue()); + return true; + } + return false; + } + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + // parameter that is a block + template <typename BLOCK_T, typename NAME_VALUE_LOOKUP> + class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> + : public Param, + public NAME_VALUE_LOOKUP::type_value_t + { + protected: + typedef ParamValue<typename LLTypeTags::Sorted<BLOCK_T>::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + public: + using named_value_t::operator(); + typedef typename param_value_t::value_t value_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + named_value_t(value) + { + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + } + } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast<self_t&>(param); + + if (name_stack_range.first == name_stack_range.second) + { // try to parse a known named value + std::string name; + + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + } + + if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) + { // attempt to parse block... + typed_param.clearValueName(); + typed_param.setProvided(); + return true; + } + + + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + const self_t& typed_param = static_cast<const self_t&>(param); + + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + + if (!predicate_rule.check(predicate)) return false; + + if (!name_stack.empty()) + { + name_stack.back().second = true; + } + + std::string key = typed_param.getValueName(); + if (!key.empty()) + { + if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key)) + { + parser.writeValue(key, name_stack); + return true; + } + } + else + { + return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param)); + } + + return false; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + const self_t& typed_param = static_cast<const self_t&>(param); + + // tell parser about our actual type + parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + + typed_param.inspectBlock(parser, name_stack, min_count, max_count); + } + + // a param-that-is-a-block is provided when the user has set one of its child params + // *and* the block as a whole validates + bool isProvided() const + { + return Param::anyProvided() && isValid(); + } + + bool isValid() const + { + return param_value_t::isValid(); + } + + // assign block contents to this param-that-is-a-block + void set(const value_t& val, bool flag_as_provided = true) + { + named_value_t::setValue(val); + named_value_t::clearValueName(); + setProvided(flag_as_provided); + } + + self_t& operator =(const typename named_value_t::name_t& name) + { + named_value_t::assignNamedValue(name); + return *this; + } + + // propagate changed status up to enclosing block + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + param_value_t::paramChanged(changed_param, user_provided); + + if (user_provided) + { + setProvided(); + named_value_t::clearValueName(); + } + else + { + Param::enclosingBlock().paramChanged(*this, user_provided); + } + } + + protected: + + self_t& operator =(const self_t& other) + { + param_value_t::operator =(other); + Param::operator =(other); + return *this; + } + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast<const self_t&>(src); + self_t& dst_typed_param = static_cast<self_t&>(dst); + + if (src_typed_param.anyProvided()) + { + if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite)) + { + dst_typed_param.clearValueName(); + dst_typed_param.setProvided(true); + return true; + } + } + return false; + } + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + // list of non-block parameters + template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP> + class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> + : public Param + { + protected: + typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t; + typedef ParamValue<typename LLTypeTags::Sorted<MULTI_VALUE_T>::value_t> param_value_t; + typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; + typedef container_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + + public: + typedef typename param_value_t::value_t value_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) + { + std::copy(value.begin(), value.end(), std::back_inserter(mValues)); + + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + + } + } + + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); + self_t& typed_param = static_cast<self_t&>(param); + value_t value; + + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + ++new_name_stack_range.first; + } + + // no further names in stack, attempt to parse value now + if (new_name_stack_range.first == new_name_stack_range.second) + { + std::string name; + + // try to parse a known named value + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, value)) + { + typed_param.add(value); + typed_param.mValues.back().setValueName(name); + return true; + } + else if (parser.readValue(value)) // attempt to read value directly + { + typed_param.add(value); + return true; + } + } + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + bool serialized = false; + const self_t& typed_param = static_cast<const self_t&>(param); + + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; + + for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); + it != end_it; + ++it) + { + std::string key = it->getValueName(); + name_stack.push_back(std::make_pair(std::string(), true)); + + if(key.empty()) + // not parsed via name values, write out value directly + { + bool value_written = parser.writeValue(*it, name_stack); + if (!value_written) + { + std::string calculated_key = it->calcValueName(it->getValue()); + if (parser.writeValue(calculated_key, name_stack)) + { + serialized = true; + } + else + { + break; + } + } + } + else + { + if(parser.writeValue(key, name_stack)) + { + serialized = true; + } + else + { + break; + } + } + } + + return serialized; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL); + if (named_value_t::getPossibleValues()) + { + parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + } + + void set(const container_t& val, bool flag_as_provided = true) + { + mValues = val; + setProvided(flag_as_provided); + } + + param_value_t& add() + { + mValues.push_back(value_t()); + Param::setProvided(); + return mValues.back(); + } + + self_t& add(const value_t& item) + { + mValues.push_back(item); + setProvided(); + return *this; + } + + self_t& add(const typename named_value_t::name_t& name) + { + value_t value; + + // try to parse a per type named value + if (named_value_t::getValueFromName(name, value)) + { + add(value); + mValues.back().setValueName(name); + } + + return *this; + } + + // implicit conversion + operator const container_t&() const { return mValues; } + // explicit conversion + const container_t& operator()() const { return mValues; } + + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; + iterator begin() { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator begin() const { return mValues.begin(); } + const_iterator end() const { return mValues.end(); } + bool empty() const { return mValues.empty(); } + size_t size() const { return mValues.size(); } + + size_t numValidElements() const + { + return mValues.size(); + } + + protected: + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast<const self_t&>(src); + self_t& dst_typed_param = static_cast<self_t&>(dst); + + if (overwrite) + { + std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); + } + else + { + container_t new_values(src_typed_param.mValues); + std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); + std::swap(dst_typed_param.mValues, new_values); + } + + if (src_typed_param.begin() != src_typed_param.end()) + { + dst_typed_param.setProvided(); + } + return true; + } + + container_t mValues; + size_t mMinCount, + mMaxCount; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + // list of block parameters + template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP> + class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> + : public Param + { + protected: + typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t; + typedef ParamValue<typename LLTypeTags::Sorted<MULTI_BLOCK_T>::value_t> param_value_t; + typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + typedef container_t default_value_t; + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; + public: + typedef typename param_value_t::value_t value_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) + { + std::copy(value.begin(), value.end(), back_inserter(mValues)); + + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + } + } + + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } + + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); + self_t& typed_param = static_cast<self_t&>(param); + bool new_value = false; + bool new_array_value = false; + + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + new_array_value = new_name_stack_range.first->second; + ++new_name_stack_range.first; + } + + if (new_name || new_array_value || typed_param.mValues.empty()) + { + new_value = true; + typed_param.mValues.push_back(value_t()); + } + param_value_t& value = typed_param.mValues.back(); + + if (new_name_stack_range.first == new_name_stack_range.second) + { // try to parse a known named value + std::string name; + + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, value.getValue())) + { + typed_param.mValues.back().setValueName(name); + typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } + return true; + } + } + + // attempt to parse block... + if(value.deserializeBlock(parser, new_name_stack_range, new_name)) + { + typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } + return true; + } + + + if (new_value) + { // failed to parse new value, pop it off + typed_param.mValues.pop_back(); + } + + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + bool serialized = false; + const self_t& typed_param = static_cast<const self_t&>(param); + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; + + for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); + it != end_it; + ++it) + { + name_stack.push_back(std::make_pair(std::string(), true)); + + std::string key = it->getValueName(); + if (!key.empty()) + { + serialized |= parser.writeValue(key, name_stack); + } + // Not parsed via named values, write out value directly + // NOTE: currently we don't do diffing of Multiples + else + { + serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL); + } + + name_stack.pop_back(); + } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + + return serialized; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + const param_value_t& value_param = param_value_t(value_t()); + + // tell parser about our actual type + parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + + value_param.inspectBlock(parser, name_stack, min_count, max_count); + } + + void set(const container_t& val, bool flag_as_provided = true) + { + mValues = val; + setProvided(flag_as_provided); + } + + param_value_t& add() + { + mValues.push_back(value_t()); + setProvided(); + return mValues.back(); + } + + self_t& add(const value_t& item) + { + mValues.push_back(item); + setProvided(); + return *this; + } + + self_t& add(const typename named_value_t::name_t& name) + { + value_t value; + + // try to parse a per type named value + if (named_value_t::getValueFromName(name, value)) + { + add(value); + mValues.back().setValueName(name); + } + return *this; + } + + // implicit conversion + operator const container_t&() const { return mValues; } + // explicit conversion + const container_t& operator()() const { return mValues; } + + iterator begin() { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator begin() const { return mValues.begin(); } + const_iterator end() const { return mValues.end(); } + bool empty() const { return mValues.empty(); } + size_t size() const { return mValues.size(); } + + size_t numValidElements() const + { + size_t count = 0; + for (const_iterator it = mValues.begin(), end_it = mValues.end(); + it != end_it; + ++it) + { + if(it->isValid()) count++; + } + return count; + } + + protected: + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast<const self_t&>(src); + self_t& dst_typed_param = static_cast<self_t&>(dst); + + if (overwrite) + { + std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); + } + else + { + container_t new_values(src_typed_param.mValues); + std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); + std::swap(dst_typed_param.mValues, new_values); + } + + if (src_typed_param.begin() != src_typed_param.end()) + { + dst_typed_param.setProvided(); + } + + return true; + } + + container_t mValues; + size_t mMinCount, + mMaxCount; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock> + class ChoiceBlock : public BASE_BLOCK + { + typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> self_t; + typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> enclosing_block_t; + typedef BASE_BLOCK base_block_t; + + LOG_CLASS(self_t); + public: + // take all provided params from other and apply to self + bool overwriteFrom(const self_t& other) + { + return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true); + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const self_t& other) + { + return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false); + } + + bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + bool source_override = source_provided && (overwrite || !dest_provided); + + if (source_override || source.mCurChoice == mCurChoice) + { + return mergeBlock(block_data, source, overwrite); + } + return false; + } + + // merge with other block + bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite) + { + mCurChoice = other.mCurChoice; + return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite); + } + + // clear out old choice when param has changed + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param); + // if we have a new choice... + if (changed_param_handle != mCurChoice) + { + // clear provided flag on previous choice + Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice); + if (previous_choice) + { + previous_choice->setProvided(false); + } + mCurChoice = changed_param_handle; + } + base_block_t::paramChanged(changed_param, user_provided); + } + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } + + protected: + ChoiceBlock() + : mCurChoice(0) + { + BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); + } + + // Alternatives are mutually exclusive wrt other Alternatives in the same block. + // One alternative in a block will always have isChosen() == true. + // At most one alternative in a block will have isProvided() == true. + template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > + class Alternative : public TypedParam<T, NAME_VALUE_LOOKUP, false> + { + typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + + public: + friend class ChoiceBlock<DERIVED_BLOCK>; + + using super_t::operator =; + + explicit Alternative(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1), + mOriginalValue(val) + { + // assign initial choice to first declared option + DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr); + if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) + { + if(blockp->mCurChoice == 0) + { + blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this); + } + } + } + + void choose() + { + static_cast<enclosing_block_t&>(Param::enclosingBlock()).paramChanged(*this, true); + } + + void chooseAs(const value_t& val) + { + super_t::set(val); + } + + void operator =(const value_t& val) + { + super_t::set(val); + } + + void operator()(const value_t& val) + { + super_t::set(val); + } + + operator const value_t&() const + { + return (*this)(); + } + + const value_t& operator()() const + { + if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this) + { + return super_t::getValue(); + } + return mOriginalValue; + } + + bool isChosen() const + { + return static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this; + } + + private: + default_value_t mOriginalValue; + }; + + public: + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + private: + param_handle_t mCurChoice; + + const Param* getCurrentChoice() const + { + return base_block_t::getParamFromHandle(mCurChoice); + } + }; + + template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock> + class Block + : public BASE_BLOCK + { + typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t; + + protected: + typedef Block<DERIVED_BLOCK, BASE_BLOCK> block_t; + + public: + typedef BASE_BLOCK base_block_t; + + // take all provided params from other and apply to self + bool overwriteFrom(const self_t& other) + { + return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true); + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const self_t& other) + { + return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false); + } + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } + + protected: + Block() + { + //#pragma message("Parsing LLInitParam::Block") + BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); + } + + // + // Nested classes for declaring parameters + // + template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > + class Optional : public TypedParam<T, NAME_VALUE_LOOKUP, false> + { + typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + + public: + using super_t::operator(); + using super_t::operator =; + + explicit Optional(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1) + { + //#pragma message("Parsing LLInitParam::Block::Optional") + } + + Optional& operator =(const value_t& val) + { + super_t::set(val); + return *this; + } + + DERIVED_BLOCK& operator()(const value_t& val) + { + super_t::set(val); + return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); + } + }; + + template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > + class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false> + { + typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t; + typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + + public: + using super_t::operator(); + using super_t::operator =; + + // mandatory parameters require a name to be parseable + explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1) + {} + + Mandatory& operator =(const value_t& val) + { + super_t::set(val); + return *this; + } + + DERIVED_BLOCK& operator()(const value_t& val) + { + super_t::set(val); + return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); + } + + static bool validate(const Param* p) + { + // valid only if provided + return static_cast<const self_t*>(p)->isProvided(); + } + + }; + + template <typename T, typename RANGE = BaseBlock::AnyAmount, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t > + class Multiple : public TypedParam<T, NAME_VALUE_LOOKUP, true> + { + typedef TypedParam<T, NAME_VALUE_LOOKUP, true> super_t; + typedef Multiple<T, RANGE, NAME_VALUE_LOOKUP> self_t; + typedef typename super_t::container_t container_t; + typedef typename super_t::value_t value_t; + + public: + typedef typename super_t::iterator iterator; + typedef typename super_t::const_iterator const_iterator; + + using super_t::operator(); + using super_t::operator const container_t&; + + explicit Multiple(const char* name = "") + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) + {} + + Multiple& operator =(const container_t& val) + { + super_t::set(val); + return *this; + } + + DERIVED_BLOCK& operator()(const container_t& val) + { + super_t::set(val); + return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); + } + + static bool validate(const Param* paramp) + { + size_t num_valid = ((super_t*)paramp)->numValidElements(); + return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; + } + }; + + // can appear in data files, but will ignored during parsing + // cannot read or write in code + class Ignored : public Param + { + public: + explicit Ignored(const char* name) + : Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr) + { + BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor(); + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + NULL, + &deserializeParam, + NULL, + NULL, + NULL, + 0, S32_MAX)); + block_descriptor.addParam(param_descriptor, name); + } + } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (name_stack_range.first == name_stack_range.second) + { + //std::string message = llformat("Deprecated value %s ignored", getName().c_str()); + //parser.parserWarning(message); + return true; + } + + return false; + } + }; + + // can appear in data files, or be written to in code, but data will be ignored + // cannot be read in code + class Deprecated : public Ignored + { + public: + explicit Deprecated(const char* name) : Ignored(name) {} + + // dummy writer interfaces + template<typename T> + Deprecated& operator =(const T& val) + { + // do nothing + return *this; + } + + template<typename T> + DERIVED_BLOCK& operator()(const T& val) + { + // do nothing + return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); + } + + template<typename T> + void set(const T& val, bool flag_as_provided = true) + { + // do nothing + } + }; + + public: + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + protected: + template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, typename is_block> + void changeDefault(TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>& param, + const typename TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>::value_t& value) + { + if (!param.isProvided()) + { + param.set(value, false); + } + } + + }; + + template<typename T, typename BLOCK_T> + struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void> + { + typedef IS_A_BLOCK value_t; + }; + + template<typename T, typename BLOCK_T> + struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::NOT_A_BLOCK>, BLOCK_T >, void> + { + typedef NOT_BLOCK value_t; + }; + + template<typename T, typename BLOCK_IDENTIFIER> + struct IsBlock<ParamValue<BaseBlock::Atomic<T>, typename IsBlock<BaseBlock::Atomic<T> >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock<T>::value_t value_t; + }; + + template<typename T, typename BLOCK_IDENTIFIER> + struct IsBlock<ParamValue<BaseBlock::Sequential<T>, typename IsBlock<BaseBlock::Sequential<T> >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock<T>::value_t value_t; + }; + + + template<typename T> + struct InnerMostType + { + typedef T value_t; + }; + + template<typename T> + struct InnerMostType<ParamValue<T, NOT_BLOCK> > + { + typedef typename InnerMostType<T>::value_t value_t; + }; + + template<typename T> + struct InnerMostType<ParamValue<T, IS_A_BLOCK> > + { + typedef typename InnerMostType<T>::value_t value_t; + }; + + template<typename T, typename BLOCK_T> + class ParamValue <BaseBlock::Atomic<T>, BLOCK_T> + { + typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t; + + public: + typedef typename InnerMostType<T>::value_t value_t; + typedef T default_value_t; + + ParamValue() + : mValue() + {} + + ParamValue(const default_value_t& value) + : mValue(value) + {} + + void setValue(const value_t& val) + { + mValue.setValue(val); + } + + const value_t& getValue() const + { + return mValue.getValue(); + } + + value_t& getValue() + { + return mValue.getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (new_name) + { + resetToDefault(); + } + return mValue.deserializeBlock(p, name_stack_range, new_name); + } + + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const + { + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + if ((overwrite && source_provided) // new values coming in on top or... + || (!overwrite && !dst_provided)) // values being pushed under with nothing already there + { + // clear away what is there and take the new stuff as a whole + resetToDefault(); + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + + private: + void resetToDefault() + { + static T default_value; + mValue = default_value; + } + + T mValue; + }; + + template<typename T> + class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> + { + typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t; + + public: + typedef typename InnerMostType<T>::value_t value_t; + typedef T default_value_t; + + ParamValue() + : mValue() + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + + ParamValue(const default_value_t& value) + : mValue(value) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + + void setValue(const value_t& val) + { + mValue.setValue(val); + } + + const value_t& getValue() const + { + return mValue.getValue(); + } + + value_t& getValue() + { + return mValue.getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (new_name) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + if (name_stack_range.first == name_stack_range.second + && mCurParam != getBlockDescriptor().mAllParams.end()) + { + // deserialize to mCurParam + ParamDescriptor& pd = *(*mCurParam); + ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc; + Param* paramp = mValue.getParamFromHandle(pd.mParamHandle); + + if (deserialize_func + && paramp + && deserialize_func(*paramp, p, name_stack_range, new_name)) + { + ++mCurParam; + return true; + } + else + { + return false; + } + } + else + { + return mValue.deserializeBlock(p, name_stack_range, new_name); + } + } + + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const + { + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + private: + + BlockDescriptor::all_params_list_t::iterator mCurParam; + T mValue; + }; + + template<typename T> + class ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> + : public T + { + typedef ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> self_t; + + public: + typedef typename InnerMostType<T>::value_t value_t; + typedef T default_value_t; + + ParamValue() + : T() + {} + + ParamValue(const default_value_t& value) + : T(value.getValue()) + {} + + bool isValid() const { return true; } + }; + + template<typename T, typename BLOCK_T> + class ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> + { + typedef ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> self_t; + + public: + typedef typename InnerMostType<T>::value_t value_t; + typedef LazyValue<T> default_value_t; + + ParamValue() + : mValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) + {} + + ParamValue(const T& value) + : mValue(value) + {} + + void setValue(const value_t& val) + { + mValue.set(val); + } + + const value_t& getValue() const + { + return mValue.get().getValue(); + } + + value_t& getValue() + { + return mValue.get().getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + return mValue.get().deserializeBlock(p, name_stack_range, new_name); + } + + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const + { + if (mValue.empty()) return false; + + const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) + ? &(diff_block->mValue.get().getValue()) + : NULL; + return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.get().inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.empty() || mValue.get().validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + private: + LazyValue<T> mValue; + }; + + template<typename T, typename BLOCK_T> + class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> + { + typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t; + + public: + typedef typename InnerMostType<T>::value_t value_t; + typedef LazyValue<T> default_value_t; + + ParamValue() + : mValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) + {} + + ParamValue(const T& value) + : mValue(value) + {} + + void setValue(const value_t& val) + { + mValue.set(val); + } + + const value_t& getValue() const + { + return mValue.get().getValue(); + } + + value_t& getValue() + { + return mValue.get().getValue(); + } + + bool isValid() const + { + return true; + } + + private: + LazyValue<T> mValue; + }; + + template <> + class ParamValue <LLSD, NOT_BLOCK> + : public BaseBlock + { + public: + typedef LLSD value_t; + typedef LLSD default_value_t; + + ParamValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) + {} + + void setValue(const value_t& val) { mValue = val; } + + const value_t& getValue() const { return mValue; } + LLSD& getValue() { return mValue; } + + // block param interface + LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); + LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const; + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + //TODO: implement LLSD params as schema type Any + return true; + } + + private: + static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); + + LLSD mValue; + }; + + template<typename T> + class CustomParamValue + : public Block<ParamValue<T> > + { + public: + typedef enum e_value_age + { + VALUE_NEEDS_UPDATE, // mValue needs to be refreshed from the block parameters + VALUE_AUTHORITATIVE, // mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue) + BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative + } EValueAge; + + typedef TypeValues<T> derived_t; + typedef CustomParamValue<T> self_t; + typedef Block<ParamValue<T> > block_t; + typedef T default_value_t; + typedef T value_t; + typedef void baseblock_base_class_t; + + + CustomParamValue(const default_value_t& value = T()) + : mValue(value), + mValueAge(VALUE_AUTHORITATIVE) + {} + + bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + derived_t& typed_param = static_cast<derived_t&>(*this); + // try to parse direct value T + if (name_stack_range.first == name_stack_range.second) + { + if(parser.readValue(typed_param.mValue)) + { + typed_param.mValueAge = VALUE_AUTHORITATIVE; + typed_param.updateBlockFromValue(false); + + return true; + } + } + + // fall back on parsing block components for T + return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); + } + + bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const + { + const derived_t& typed_param = static_cast<const derived_t&>(*this); + const derived_t* diff_param = static_cast<const derived_t*>(diff_block); + + //std::string key = typed_param.getValueName(); + + //// first try to write out name of name/value pair + //if (!key.empty()) + //{ + // if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key)) + // { + // return parser.writeValue(key, name_stack); + // } + //} + // then try to serialize value directly + if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue())) + { + + if (parser.writeValue(typed_param.getValue(), name_stack)) + { + return true; + } + else + { + //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), + // since these tend to be viewed as the constructor arguments for the value T. It seems + // cleaner to treat the uniqueness of a BlockValue according to the generated value, and + // not the individual components. This way <color red="0" green="1" blue="0"/> will not + // be exported as <color green="1"/>, since it was probably the intent of the user to + // be specific about the RGB color values. This also fixes an issue where we distinguish + // between rect.left not being provided and rect.left being explicitly set to 0 (same as default) + + if (typed_param.mValueAge == VALUE_AUTHORITATIVE) + { + // if the value is authoritative but the parser doesn't accept the value type + // go ahead and make a copy, and splat the value out to its component params + // and serialize those params + derived_t copy(typed_param); + copy.updateBlockFromValue(true); + return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); + } + else + { + return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); + } + } + } + return false; + } + + bool validateBlock(bool emit_errors = true) const + { + if (mValueAge == VALUE_NEEDS_UPDATE) + { + if (block_t::validateBlock(emit_errors)) + { + // clear stale keyword associated with old value + mValueAge = BLOCK_AUTHORITATIVE; + static_cast<derived_t*>(const_cast<self_t*>(this))->updateValueFromBlock(); + return true; + } + else + { + //block value incomplete, so not considered provided + // will attempt to revalidate on next call to isProvided() + return false; + } + } + else + { + // we have a valid value in hand + return true; + } + } + + // propagate change status up to enclosing block + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + BaseBlock::paramChanged(changed_param, user_provided); + if (user_provided) + { + // a parameter changed, so our value is out of date + mValueAge = VALUE_NEEDS_UPDATE; + } + } + + void setValue(const value_t& val) + { + // set param version number to be up to date, so we ignore block contents + mValueAge = VALUE_AUTHORITATIVE; + mValue = val; + static_cast<derived_t*>(this)->updateBlockFromValue(false); + } + + const value_t& getValue() const + { + validateBlock(true); + return mValue; + } + + T& getValue() + { + validateBlock(true); + return mValue; + } + + protected: + + // use this from within updateValueFromBlock() to set the value without making it authoritative + void updateValue(const value_t& value) + { + mValue = value; + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + bool source_override = source_provided && (overwrite || !dst_provided); + + const derived_t& src_typed_param = static_cast<const derived_t&>(source); + + if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE) + { + // copy value over + setValue(src_typed_param.getValue()); + return true; + } + // merge individual parameters into destination + if (mValueAge == VALUE_AUTHORITATIVE) + { + static_cast<derived_t*>(this)->updateBlockFromValue(dst_provided); + } + return mergeBlock(block_data, source, overwrite); + } + + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + return block_t::mergeBlock(block_data, source, overwrite); + } + + private: + mutable T mValue; + mutable EValueAge mValueAge; + }; } diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index e7193b70b5..d1b02066bd 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -1,24 +1,24 @@ /** * @file lllinstancetracker.cpp - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 27422e1266..3232a0e219 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -1,4 +1,4 @@ -/** +/** * @file llinstancetracker.h * @brief LLInstanceTracker is a mixin class that automatically tracks object * instances with or without an associated key @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -99,11 +99,11 @@ public: return mSelf; } - static size_t instanceCount() - { - return LockStatic()->mMap.size(); + static size_t instanceCount() + { + return LockStatic()->mMap.size(); } - + // snapshot of std::pair<const KEY, std::shared_ptr<SUBCLASS>> pairs, for // some SUBCLASS derived from T template <typename SUBCLASS> @@ -243,7 +243,7 @@ public: } protected: - LLInstanceTracker(const KEY& key) + LLInstanceTracker(const KEY& key) { // We do not intend to manage the lifespan of this object with // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our @@ -286,9 +286,9 @@ private: static std::string report(const char* key) { return report(std::string(key)); } // caller must instantiate LockStatic - void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) - { - mInstanceKey = key; + void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) + { + mInstanceKey = key; InstanceMap& map = lock->mMap; switch(KEY_COLLISION_BEHAVIOR) { @@ -373,7 +373,7 @@ public: { return mSelf; } - + static size_t instanceCount() { return LockStatic()->mSet.size(); diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp index b89160cc55..e36c1d0a4c 100644 --- a/indra/llcommon/llkeybind.cpp +++ b/indra/llcommon/llkeybind.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llkeybind.cpp * @brief Information about key combinations. * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2019, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -207,7 +207,7 @@ bool LLKeyBind::operator!=(const LLKeyBind& rhs) bool LLKeyBind::isEmpty() const { - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { if (!key_data.isEmpty()) return false; } @@ -225,7 +225,7 @@ LLKeyBind::data_vector_t::const_iterator LLKeyBind::endNonEmpty() const LLSD LLKeyBind::asLLSD() const { LLSD data; - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { // append intermediate entries even if empty to not affect visual // representation @@ -242,7 +242,7 @@ bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const return false; } - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { if (key_data.canHandle(mouse, key, mask)) { @@ -266,7 +266,7 @@ bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignor { if (mouse != CLICK_NONE || key != KEY_NONE) { - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { if (key_data.mKey == key && key_data.mMask == mask @@ -353,7 +353,7 @@ void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index) { // if both click and key are none (isEmpty()), we are inserting a placeholder, we don't want to reset anything // otherwise reset identical key - for (LLKeyData& key_data : mData) + for (LLKeyData& key_data : mData) { if (key_data.mKey == data.mKey && key_data.mMouse == data.mMouse diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h index 488f509411..1bbb2fadb5 100644 --- a/indra/llcommon/llkeybind.h +++ b/indra/llcommon/llkeybind.h @@ -1,25 +1,25 @@ -/** +/** * @file llkeybind.h * @brief Information about key combinations. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -54,7 +54,7 @@ public: KEY mKey; MASK mMask; // Either to expect exact match or ignore not expected masks as long as expected mask-bit is present - bool mIgnoreMasks; + bool mIgnoreMasks; }; // One function can bind to multiple Key options diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 1f576cc19e..a5b5eaa946 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -1,24 +1,24 @@ -/** +/** * @file llkeythrottle.h * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,44 +46,44 @@ template <class T> class LLKeyThrottle; template <class T> class LLKeyThrottleImpl { - friend class LLKeyThrottle<T>; + friend class LLKeyThrottle<T>; protected: - struct Entry { - U32 count; - bool blocked; - - Entry() : count(0), blocked(false) { } - }; - - typedef std::map<T, Entry> EntryMap; - - EntryMap* prevMap; - EntryMap* currMap; - - U32 countLimit; - // maximum number of keys allowed per interval - - U64 intervalLength; // each map covers this time period (usec or frame number) - U64 startTime; // start of the time period (usec or frame number) - // currMap started counting at this time - // prevMap covers the previous interval - - LLKeyThrottleImpl() : - prevMap(NULL), - currMap(NULL), - countLimit(0), - intervalLength(1), - startTime(0) - {} - - static U64 getTime() - { - return LLFrameTimer::getTotalTime(); - } - static U64 getFrame() // Return the current frame number - { - return (U64) LLFrameTimer::getFrameCount(); - } + struct Entry { + U32 count; + bool blocked; + + Entry() : count(0), blocked(false) { } + }; + + typedef std::map<T, Entry> EntryMap; + + EntryMap* prevMap; + EntryMap* currMap; + + U32 countLimit; + // maximum number of keys allowed per interval + + U64 intervalLength; // each map covers this time period (usec or frame number) + U64 startTime; // start of the time period (usec or frame number) + // currMap started counting at this time + // prevMap covers the previous interval + + LLKeyThrottleImpl() : + prevMap(NULL), + currMap(NULL), + countLimit(0), + intervalLength(1), + startTime(0) + {} + + static U64 getTime() + { + return LLFrameTimer::getTotalTime(); + } + static U64 getFrame() // Return the current frame number + { + return (U64) LLFrameTimer::getFrameCount(); + } }; @@ -91,241 +91,241 @@ template< class T > class LLKeyThrottle { public: - // @param realtime = FALSE for frame-based throttle, TRUE for usec - // real-time throttle - LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE) - : m(* new LLKeyThrottleImpl<T>) - { - setParameters( limit, interval, realtime ); - } - - ~LLKeyThrottle() - { - delete m.prevMap; - delete m.currMap; - delete &m; - } - - enum State { - THROTTLE_OK, // rate not exceeded, let pass - THROTTLE_NEWLY_BLOCKED, // rate exceed for the first time - THROTTLE_BLOCKED, // rate exceed, block key - }; - - F64 getActionCount(const T& id) - { - U64 now = 0; - if ( mIsRealtime ) - { - now = LLKeyThrottleImpl<T>::getTime(); - } - else - { - now = LLKeyThrottleImpl<T>::getFrame(); - } - - if (now >= (m.startTime + m.intervalLength)) - { - if (now < (m.startTime + 2 * m.intervalLength)) - { - // prune old data - delete m.prevMap; - m.prevMap = m.currMap; - m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; - - m.startTime += m.intervalLength; - } - else - { - // lots of time has passed, all data is stale - delete m.prevMap; - delete m.currMap; - m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; - m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; - - m.startTime = now; - } - } - - U32 prevCount = 0; - - typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); - if (prev != m.prevMap->end()) - { - prevCount = prev->second.count; - } - - typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; - - // curr.count is the number of keys in - // this current 'time slice' from the beginning of it until now - // prevCount is the number of keys in the previous - // time slice scaled to be one full time slice back from the current - // (now) time. - - // compute current, windowed rate - F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength); - F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); - return averageCount; - } - - // call each time the key wants use - State noteAction(const T& id, S32 weight = 1) - { - U64 now = 0; - if ( mIsRealtime ) - { - now = LLKeyThrottleImpl<T>::getTime(); - } - else - { - now = LLKeyThrottleImpl<T>::getFrame(); - } - - if (now >= (m.startTime + m.intervalLength)) - { - if (now < (m.startTime + 2 * m.intervalLength)) - { - // prune old data - delete m.prevMap; - m.prevMap = m.currMap; - m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; - - m.startTime += m.intervalLength; - } - else - { - // lots of time has passed, all data is stale - delete m.prevMap; - delete m.currMap; - m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; - m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; - - m.startTime = now; - } - } - - U32 prevCount = 0; - bool prevBlocked = false; - - typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); - if (prev != m.prevMap->end()) - { - prevCount = prev->second.count; - prevBlocked = prev->second.blocked; - } - - typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; - - bool wereBlocked = curr.blocked || prevBlocked; - - curr.count += weight; - - // curr.count is the number of keys in - // this current 'time slice' from the beginning of it until now - // prevCount is the number of keys in the previous - // time slice scaled to be one full time slice back from the current - // (now) time. - - // compute current, windowed rate - F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength); - F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); - - curr.blocked |= averageCount > m.countLimit; - - bool nowBlocked = curr.blocked || prevBlocked; - - if (!nowBlocked) - { - return THROTTLE_OK; - } - else if (!wereBlocked) - { - return THROTTLE_NEWLY_BLOCKED; - } - else - { - return THROTTLE_BLOCKED; - } - } - - // call to force throttle conditions for id - void throttleAction(const T& id) - { - noteAction(id); - typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; - curr.count = llmax(m.countLimit, curr.count); - curr.blocked = true; - } - - // returns true if key is blocked - bool isThrottled(const T& id) const - { - if (m.currMap->empty() - && m.prevMap->empty()) - { - // most of the time we'll fall in here - return false; - } - - // NOTE, we ignore the case where id is in the map but the map is stale. - // You might think that we'd stop throttling things in such a case, - // however it may be that a god has disabled scripts in the region or - // estate --> we probably want to report the state of the id when the - // scripting engine was paused. - typename LLKeyThrottleImpl<T>::EntryMap::const_iterator entry = m.currMap->find(id); - if (entry != m.currMap->end()) - { - return entry->second.blocked; - } - entry = m.prevMap->find(id); - if (entry != m.prevMap->end()) - { - return entry->second.blocked; - } - return false; - } - - // Get the throttling parameters - void getParameters( U32 & out_limit, F32 & out_interval, BOOL & out_realtime ) - { - out_limit = m.countLimit; - out_interval = m.intervalLength; - out_realtime = mIsRealtime; - } - - // Set the throttling behavior - void setParameters( U32 limit, F32 interval, BOOL realtime = TRUE ) - { - // limit is the maximum number of keys - // allowed per interval (in seconds or frames) - mIsRealtime = realtime; - m.countLimit = limit; - if ( mIsRealtime ) - { - m.intervalLength = (U64)(interval * USEC_PER_SEC); - m.startTime = LLKeyThrottleImpl<T>::getTime(); - } - else - { - m.intervalLength = (U64)interval; - m.startTime = LLKeyThrottleImpl<T>::getFrame(); - } - - if ( m.intervalLength == 0 ) - { // Don't allow zero intervals - m.intervalLength = 1; - } - - delete m.prevMap; - m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; - delete m.currMap; - m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; - } + // @param realtime = FALSE for frame-based throttle, TRUE for usec + // real-time throttle + LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE) + : m(* new LLKeyThrottleImpl<T>) + { + setParameters( limit, interval, realtime ); + } + + ~LLKeyThrottle() + { + delete m.prevMap; + delete m.currMap; + delete &m; + } + + enum State { + THROTTLE_OK, // rate not exceeded, let pass + THROTTLE_NEWLY_BLOCKED, // rate exceed for the first time + THROTTLE_BLOCKED, // rate exceed, block key + }; + + F64 getActionCount(const T& id) + { + U64 now = 0; + if ( mIsRealtime ) + { + now = LLKeyThrottleImpl<T>::getTime(); + } + else + { + now = LLKeyThrottleImpl<T>::getFrame(); + } + + if (now >= (m.startTime + m.intervalLength)) + { + if (now < (m.startTime + 2 * m.intervalLength)) + { + // prune old data + delete m.prevMap; + m.prevMap = m.currMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime += m.intervalLength; + } + else + { + // lots of time has passed, all data is stale + delete m.prevMap; + delete m.currMap; + m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime = now; + } + } + + U32 prevCount = 0; + + typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); + if (prev != m.prevMap->end()) + { + prevCount = prev->second.count; + } + + typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + + // curr.count is the number of keys in + // this current 'time slice' from the beginning of it until now + // prevCount is the number of keys in the previous + // time slice scaled to be one full time slice back from the current + // (now) time. + + // compute current, windowed rate + F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength); + F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); + return averageCount; + } + + // call each time the key wants use + State noteAction(const T& id, S32 weight = 1) + { + U64 now = 0; + if ( mIsRealtime ) + { + now = LLKeyThrottleImpl<T>::getTime(); + } + else + { + now = LLKeyThrottleImpl<T>::getFrame(); + } + + if (now >= (m.startTime + m.intervalLength)) + { + if (now < (m.startTime + 2 * m.intervalLength)) + { + // prune old data + delete m.prevMap; + m.prevMap = m.currMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime += m.intervalLength; + } + else + { + // lots of time has passed, all data is stale + delete m.prevMap; + delete m.currMap; + m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime = now; + } + } + + U32 prevCount = 0; + bool prevBlocked = false; + + typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); + if (prev != m.prevMap->end()) + { + prevCount = prev->second.count; + prevBlocked = prev->second.blocked; + } + + typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + + bool wereBlocked = curr.blocked || prevBlocked; + + curr.count += weight; + + // curr.count is the number of keys in + // this current 'time slice' from the beginning of it until now + // prevCount is the number of keys in the previous + // time slice scaled to be one full time slice back from the current + // (now) time. + + // compute current, windowed rate + F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength); + F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); + + curr.blocked |= averageCount > m.countLimit; + + bool nowBlocked = curr.blocked || prevBlocked; + + if (!nowBlocked) + { + return THROTTLE_OK; + } + else if (!wereBlocked) + { + return THROTTLE_NEWLY_BLOCKED; + } + else + { + return THROTTLE_BLOCKED; + } + } + + // call to force throttle conditions for id + void throttleAction(const T& id) + { + noteAction(id); + typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + curr.count = llmax(m.countLimit, curr.count); + curr.blocked = true; + } + + // returns true if key is blocked + bool isThrottled(const T& id) const + { + if (m.currMap->empty() + && m.prevMap->empty()) + { + // most of the time we'll fall in here + return false; + } + + // NOTE, we ignore the case where id is in the map but the map is stale. + // You might think that we'd stop throttling things in such a case, + // however it may be that a god has disabled scripts in the region or + // estate --> we probably want to report the state of the id when the + // scripting engine was paused. + typename LLKeyThrottleImpl<T>::EntryMap::const_iterator entry = m.currMap->find(id); + if (entry != m.currMap->end()) + { + return entry->second.blocked; + } + entry = m.prevMap->find(id); + if (entry != m.prevMap->end()) + { + return entry->second.blocked; + } + return false; + } + + // Get the throttling parameters + void getParameters( U32 & out_limit, F32 & out_interval, BOOL & out_realtime ) + { + out_limit = m.countLimit; + out_interval = m.intervalLength; + out_realtime = mIsRealtime; + } + + // Set the throttling behavior + void setParameters( U32 limit, F32 interval, BOOL realtime = TRUE ) + { + // limit is the maximum number of keys + // allowed per interval (in seconds or frames) + mIsRealtime = realtime; + m.countLimit = limit; + if ( mIsRealtime ) + { + m.intervalLength = (U64)(interval * USEC_PER_SEC); + m.startTime = LLKeyThrottleImpl<T>::getTime(); + } + else + { + m.intervalLength = (U64)interval; + m.startTime = LLKeyThrottleImpl<T>::getFrame(); + } + + if ( m.intervalLength == 0 ) + { // Don't allow zero intervals + m.intervalLength = 1; + } + + delete m.prevMap; + m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; + delete m.currMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + } protected: - LLKeyThrottleImpl<T>& m; - BOOL mIsRealtime; // TRUE to be time based (default), FALSE for frame based + LLKeyThrottleImpl<T>& m; + BOOL mIsRealtime; // TRUE to be time based (default), FALSE for frame based }; #endif diff --git a/indra/llcommon/llkeyusetracker.h b/indra/llcommon/llkeyusetracker.h index 1fb222dd40..790c7b713b 100644 --- a/indra/llcommon/llkeyusetracker.h +++ b/indra/llcommon/llkeyusetracker.h @@ -1,25 +1,25 @@ -/** +/** * @file llkeyusetracker.h * @brief Declaration of the LLKeyUseTracker class. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,176 +40,176 @@ template <class TKey, class TData> class KeyUseTrackerNodeImpl { public: - U64 mLastUse; - U32 mUseCount; - TKey mKey; - TData mData; - - KeyUseTrackerNodeImpl( TKey k, TData d ) : - mLastUse(0), - mUseCount(0), - mKey( k ), - mData( d ) - { - } + U64 mLastUse; + U32 mUseCount; + TKey mKey; + TData mData; + + KeyUseTrackerNodeImpl( TKey k, TData d ) : + mLastUse(0), + mUseCount(0), + mKey( k ), + mData( d ) + { + } }; template <class TKey, class TData> class LLKeyUseTracker { - typedef KeyUseTrackerNodeImpl<TKey,TData> TKeyUseTrackerNode; - typedef std::list<TKeyUseTrackerNode *> TKeyList; - TKeyList mKeyList; - U64 mMemUsecs; - U64 mLastExpire; - U32 mMaxCount; - U32 mCount; - - static U64 getTime() - { - // This function operates on a frame basis, not instantaneous. - // We can rely on its output for determining first use in a - // frame. - return LLFrameTimer::getTotalTime(); - } - - void ageKeys() - { - U64 now = getTime(); - if( now == mLastExpire ) - { - return; - } - mLastExpire = now; - - while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) ) - { - delete mKeyList.front(); - mKeyList.pop_front(); - mCount--; - } - } - - TKeyUseTrackerNode *findNode( TKey key ) - { - ageKeys(); - - typename TKeyList::iterator i; - for( i = mKeyList.begin(); i != mKeyList.end(); i++ ) - { - if( (*i)->mKey == key ) - return *i; - } - - return NULL; - } - - TKeyUseTrackerNode *removeNode( TKey key ) - { - TKeyUseTrackerNode *i; - i = findNode( key ); - if( i ) - { - mKeyList.remove( i ); - mCount--; - return i; - } - - return NULL; - } + typedef KeyUseTrackerNodeImpl<TKey,TData> TKeyUseTrackerNode; + typedef std::list<TKeyUseTrackerNode *> TKeyList; + TKeyList mKeyList; + U64 mMemUsecs; + U64 mLastExpire; + U32 mMaxCount; + U32 mCount; + + static U64 getTime() + { + // This function operates on a frame basis, not instantaneous. + // We can rely on its output for determining first use in a + // frame. + return LLFrameTimer::getTotalTime(); + } + + void ageKeys() + { + U64 now = getTime(); + if( now == mLastExpire ) + { + return; + } + mLastExpire = now; + + while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) ) + { + delete mKeyList.front(); + mKeyList.pop_front(); + mCount--; + } + } + + TKeyUseTrackerNode *findNode( TKey key ) + { + ageKeys(); + + typename TKeyList::iterator i; + for( i = mKeyList.begin(); i != mKeyList.end(); i++ ) + { + if( (*i)->mKey == key ) + return *i; + } + + return NULL; + } + + TKeyUseTrackerNode *removeNode( TKey key ) + { + TKeyUseTrackerNode *i; + i = findNode( key ); + if( i ) + { + mKeyList.remove( i ); + mCount--; + return i; + } + + return NULL; + } public: - LLKeyUseTracker( U32 memory_seconds, U32 max_count ) : - mLastExpire(0), - mMaxCount( max_count ), - mCount(0) - { - mMemUsecs = ((U64)memory_seconds) * 1000000; - } - - ~LLKeyUseTracker() - { - // Flush list - while( !mKeyList.empty() ) - { - delete mKeyList.front(); - mKeyList.pop_front(); - mCount--; - } - } - - void markUse( TKey key, TData data ) - { - TKeyUseTrackerNode *node = removeNode( key ); - if( !node ) - { - node = new TKeyUseTrackerNode(key, data); - } - else - { - // Update data - node->mData = data; - } - node->mLastUse = getTime(); - node->mUseCount++; - mKeyList.push_back( node ); - mCount++; - - // Too many items? Drop head - if( mCount > mMaxCount ) - { - delete mKeyList.front(); - mKeyList.pop_front(); - mCount--; - } - } - - void forgetKey( TKey key ) - { - TKeyUseTrackerNode *node = removeNode( key ); - if( node ) - { - delete node; - } - } - - U32 getUseCount( TKey key ) - { - TKeyUseTrackerNode *node = findNode( key ); - if( node ) - { - return node->mUseCount; - } - return 0; - } - - U64 getTimeSinceUse( TKey key ) - { - TKeyUseTrackerNode *node = findNode( key ); - if( node ) - { - U64 now = getTime(); - U64 delta = now - node->mLastUse; - return (U32)( delta / 1000000 ); - } - return 0; - } - - TData *getLastUseData( TKey key ) - { - TKeyUseTrackerNode *node = findNode( key ); - if( node ) - { - return &node->mData; - } - return NULL; - } - - U32 getKeyCount() - { - return mCount; - } + LLKeyUseTracker( U32 memory_seconds, U32 max_count ) : + mLastExpire(0), + mMaxCount( max_count ), + mCount(0) + { + mMemUsecs = ((U64)memory_seconds) * 1000000; + } + + ~LLKeyUseTracker() + { + // Flush list + while( !mKeyList.empty() ) + { + delete mKeyList.front(); + mKeyList.pop_front(); + mCount--; + } + } + + void markUse( TKey key, TData data ) + { + TKeyUseTrackerNode *node = removeNode( key ); + if( !node ) + { + node = new TKeyUseTrackerNode(key, data); + } + else + { + // Update data + node->mData = data; + } + node->mLastUse = getTime(); + node->mUseCount++; + mKeyList.push_back( node ); + mCount++; + + // Too many items? Drop head + if( mCount > mMaxCount ) + { + delete mKeyList.front(); + mKeyList.pop_front(); + mCount--; + } + } + + void forgetKey( TKey key ) + { + TKeyUseTrackerNode *node = removeNode( key ); + if( node ) + { + delete node; + } + } + + U32 getUseCount( TKey key ) + { + TKeyUseTrackerNode *node = findNode( key ); + if( node ) + { + return node->mUseCount; + } + return 0; + } + + U64 getTimeSinceUse( TKey key ) + { + TKeyUseTrackerNode *node = findNode( key ); + if( node ) + { + U64 now = getTime(); + U64 delta = now - node->mLastUse; + return (U32)( delta / 1000000 ); + } + return 0; + } + + TData *getLastUseData( TKey key ) + { + TKeyUseTrackerNode *node = findNode( key ); + if( node ) + { + return &node->mData; + } + return NULL; + } + + U32 getKeyCount() + { + return mCount; + } }; #endif diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index b2b1162f63..d0fb586459 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-20 * @brief Implementation for llleap. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h index 7cecdf2f8f..acf9edf418 100644 --- a/indra/llcommon/llleap.h +++ b/indra/llcommon/llleap.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-20 * @brief Class that implements "LLSD Event API Plugin" - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp index 471f52e91c..050d71c327 100644 --- a/indra/llcommon/llleaplistener.cpp +++ b/indra/llcommon/llleaplistener.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-03-16 * @brief Implementation for llleaplistener. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llleaplistener.h b/indra/llcommon/llleaplistener.h index 0ca5893657..cad4543d02 100644 --- a/indra/llcommon/llleaplistener.h +++ b/indra/llcommon/llleaplistener.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-03-16 * @brief LLEventAPI supporting LEAP plugins - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp index a9b1cdf4f6..559bfc443c 100644 --- a/indra/llcommon/llliveappconfig.cpp +++ b/indra/llcommon/llliveappconfig.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llliveappconfig.cpp * @brief Configuration information for an LLApp that overrides indra.xml * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,48 +33,48 @@ #include "llsdserialize.h" LLLiveAppConfig::LLLiveAppConfig( - const std::string& filename, - F32 refresh_period, - LLApp::OptionPriority priority) : - LLLiveFile(filename, refresh_period), - mPriority(priority) + const std::string& filename, + F32 refresh_period, + LLApp::OptionPriority priority) : + LLLiveFile(filename, refresh_period), + mPriority(priority) { } LLLiveAppConfig::~LLLiveAppConfig() { } -// virtual +// virtual bool LLLiveAppConfig::loadFile() { - LL_INFOS() << "LLLiveAppConfig::loadFile(): reading from " - << filename() << LL_ENDL; + LL_INFOS() << "LLLiveAppConfig::loadFile(): reading from " + << filename() << LL_ENDL; llifstream file(filename().c_str()); - LLSD config; + LLSD config; if (file.is_open()) { LLSDSerialize::fromXML(config, file); - if(!config.isMap()) - { - LL_WARNS() << "Live app config not an map in " << filename() - << " Ignoring the data." << LL_ENDL; - return false; - } - file.close(); + if(!config.isMap()) + { + LL_WARNS() << "Live app config not an map in " << filename() + << " Ignoring the data." << LL_ENDL; + return false; + } + file.close(); + } + else + { + LL_INFOS() << "Live file " << filename() << " does not exit." << LL_ENDL; } - else - { - LL_INFOS() << "Live file " << filename() << " does not exit." << LL_ENDL; - } - // *NOTE: we do not handle the else case here because we would not - // have attempted to load the file unless LLLiveFile had - // determined there was a reason to load it. This only happens - // when either the file has been updated or it is either suddenly - // in existence or has passed out of existence. Therefore, we want - // to set the config to an empty config, and return that it - // changed. + // *NOTE: we do not handle the else case here because we would not + // have attempted to load the file unless LLLiveFile had + // determined there was a reason to load it. This only happens + // when either the file has been updated or it is either suddenly + // in existence or has passed out of existence. Therefore, we want + // to set the config to an empty config, and return that it + // changed. - LLApp* app = LLApp::instance(); - if(app) app->setOptionData(mPriority, config); - return true; + LLApp* app = LLApp::instance(); + if(app) app->setOptionData(mPriority, config); + return true; } diff --git a/indra/llcommon/llliveappconfig.h b/indra/llcommon/llliveappconfig.h index 4fd7c26a07..0dea643d87 100644 --- a/indra/llcommon/llliveappconfig.h +++ b/indra/llcommon/llliveappconfig.h @@ -1,25 +1,25 @@ -/** +/** * @file llliveappconfig.h * @brief Configuration information for an LLApp that overrides indra.xml * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,27 +43,27 @@ class LL_COMMON_API LLLiveAppConfig : public LLLiveFile { public: - /** - * @brief Constructor - * - * @param filename. The name of the file for periodically checking - * configuration. - * @param refresh_period How often the internal timer should - * bother checking the filesystem. - * @param The application priority level of that configuration file. - */ - LLLiveAppConfig( - const std::string& filename, - F32 refresh_period, - LLApp::OptionPriority priority); + /** + * @brief Constructor + * + * @param filename. The name of the file for periodically checking + * configuration. + * @param refresh_period How often the internal timer should + * bother checking the filesystem. + * @param The application priority level of that configuration file. + */ + LLLiveAppConfig( + const std::string& filename, + F32 refresh_period, + LLApp::OptionPriority priority); - ~LLLiveAppConfig(); ///< Destructor + ~LLLiveAppConfig(); ///< Destructor protected: - /*virtual*/ bool loadFile(); + /*virtual*/ bool loadFile(); private: - LLApp::OptionPriority mPriority; + LLApp::OptionPriority mPriority; }; #endif diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp index ea485c2d86..15651a6813 100644 --- a/indra/llcommon/lllivefile.cpp +++ b/indra/llcommon/lllivefile.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lllivefile.cpp * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,51 +35,51 @@ const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f; class LLLiveFile::Impl { public: - Impl(const std::string& filename, const F32 refresh_period); - ~Impl(); - - bool check(); - void changed(); - - bool mForceCheck; - F32 mRefreshPeriod; - LLFrameTimer mRefreshTimer; - - std::string mFilename; - time_t mLastModTime; - time_t mLastStatTime; - bool mLastExists; - - LLEventTimer* mEventTimer; + Impl(const std::string& filename, const F32 refresh_period); + ~Impl(); + + bool check(); + void changed(); + + bool mForceCheck; + F32 mRefreshPeriod; + LLFrameTimer mRefreshTimer; + + std::string mFilename; + time_t mLastModTime; + time_t mLastStatTime; + bool mLastExists; + + LLEventTimer* mEventTimer; private: LOG_CLASS(LLLiveFile); }; LLLiveFile::Impl::Impl(const std::string& filename, const F32 refresh_period) - : - mForceCheck(true), - mRefreshPeriod(refresh_period), - mFilename(filename), - mLastModTime(0), - mLastStatTime(0), - mLastExists(false), - mEventTimer(NULL) + : + mForceCheck(true), + mRefreshPeriod(refresh_period), + mFilename(filename), + mLastModTime(0), + mLastStatTime(0), + mLastExists(false), + mEventTimer(NULL) { } LLLiveFile::Impl::~Impl() { - delete mEventTimer; + delete mEventTimer; } LLLiveFile::LLLiveFile(const std::string& filename, const F32 refresh_period) - : impl(* new Impl(filename, refresh_period)) + : impl(* new Impl(filename, refresh_period)) { } LLLiveFile::~LLLiveFile() { - delete &impl; + delete &impl; } @@ -88,8 +88,8 @@ bool LLLiveFile::Impl::check() bool detected_change = false; // Skip the check if not enough time has elapsed and we're not // forcing a check of the file - if (mForceCheck || mRefreshTimer.getElapsedTimeF32() >= mRefreshPeriod) - { + if (mForceCheck || mRefreshTimer.getElapsedTimeF32() >= mRefreshPeriod) + { mForceCheck = false; // force only forces one check mRefreshTimer.reset(); // don't check again until mRefreshPeriod has passed @@ -98,11 +98,11 @@ bool LLLiveFile::Impl::check() if (LLFile::stat(mFilename, &stat_data)) { // Couldn't stat the file, that means it doesn't exist or is - // broken somehow. + // broken somehow. if (mLastExists) { mLastExists = false; - detected_change = true; // no longer existing is a change! + detected_change = true; // no longer existing is a change! LL_DEBUGS() << "detected deleted file '" << mFilename << "'" << LL_ENDL; } } @@ -134,65 +134,65 @@ bool LLLiveFile::Impl::check() void LLLiveFile::Impl::changed() { - // we wanted to read this file, and we were successful. - mLastModTime = mLastStatTime; + // we wanted to read this file, and we were successful. + mLastModTime = mLastStatTime; } bool LLLiveFile::checkAndReload() { - bool changed = impl.check(); - if (changed) - { - if(loadFile()) - { - impl.changed(); - this->changed(); - } - else - { - changed = false; - } - } - return changed; + bool changed = impl.check(); + if (changed) + { + if(loadFile()) + { + impl.changed(); + this->changed(); + } + else + { + changed = false; + } + } + return changed; } std::string LLLiveFile::filename() const { - return impl.mFilename; + return impl.mFilename; } namespace { - class LiveFileEventTimer : public LLEventTimer - { - public: - LiveFileEventTimer(LLLiveFile& f, F32 refresh) - : LLEventTimer(refresh), mLiveFile(f) - { } - - BOOL tick() - { - mLiveFile.checkAndReload(); - return FALSE; - } - - private: - LLLiveFile& mLiveFile; - }; - + class LiveFileEventTimer : public LLEventTimer + { + public: + LiveFileEventTimer(LLLiveFile& f, F32 refresh) + : LLEventTimer(refresh), mLiveFile(f) + { } + + BOOL tick() + { + mLiveFile.checkAndReload(); + return FALSE; + } + + private: + LLLiveFile& mLiveFile; + }; + } void LLLiveFile::addToEventTimer() { - impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod); + impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod); } void LLLiveFile::setRefreshPeriod(F32 seconds) { - if (seconds < 0.f) - { - seconds = -seconds; - } - impl.mRefreshPeriod = seconds; + if (seconds < 0.f) + { + seconds = -seconds; + } + impl.mRefreshPeriod = seconds; } diff --git a/indra/llcommon/lllivefile.h b/indra/llcommon/lllivefile.h index 320aa4bc3e..305b205a68 100644 --- a/indra/llcommon/lllivefile.h +++ b/indra/llcommon/lllivefile.h @@ -1,25 +1,25 @@ -/** +/** * @file lllivefile.h * @brief Automatically reloads a file whenever it changes or is removed. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,63 +33,63 @@ extern const F32 DEFAULT_CONFIG_FILE_REFRESH; class LL_COMMON_API LLLiveFile { public: - LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f); - virtual ~LLLiveFile(); + LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f); + virtual ~LLLiveFile(); + + /** + * @brief Check to see if this live file should reload. + * + * Call this before using anything that was read & cached + * from the file. + * + * This method calls the <code>loadFile()</code> method if + * any of: + * file has a new modify time since the last check + * file used to exist and now does not + * file used to not exist but now does + * @return Returns true if the file was reloaded. + */ + bool checkAndReload(); - /** - * @brief Check to see if this live file should reload. - * - * Call this before using anything that was read & cached - * from the file. - * - * This method calls the <code>loadFile()</code> method if - * any of: - * file has a new modify time since the last check - * file used to exist and now does not - * file used to not exist but now does - * @return Returns true if the file was reloaded. - */ - bool checkAndReload(); - - std::string filename() const; + std::string filename() const; - /** - * @brief Add this live file to an automated recheck. - * - * Normally, just calling checkAndReload() is enough. In some - * cases though, you may need to let the live file periodically - * check itself. - */ - void addToEventTimer(); + /** + * @brief Add this live file to an automated recheck. + * + * Normally, just calling checkAndReload() is enough. In some + * cases though, you may need to let the live file periodically + * check itself. + */ + void addToEventTimer(); - void setRefreshPeriod(F32 seconds); + void setRefreshPeriod(F32 seconds); protected: - /** - * @breif Implement this to load your file if it changed. - * - * This method is called automatically by <code>checkAndReload()</code>, - * so though you must implement this in derived classes, you do - * not need to call it manually. - * @return Returns true if the file was successfully loaded. - */ - virtual bool loadFile() = 0; + /** + * @breif Implement this to load your file if it changed. + * + * This method is called automatically by <code>checkAndReload()</code>, + * so though you must implement this in derived classes, you do + * not need to call it manually. + * @return Returns true if the file was successfully loaded. + */ + virtual bool loadFile() = 0; - /** - * @brief Implement this method if you want to get a change callback. - * - * This virtual function will be called automatically at the end - * of <code>checkAndReload()</code> if a new configuration was - * loaded. This does not track differences between the current and - * newly loaded file, so any successful load event will trigger a - * <code>changed()</code> callback. Default is to do nothing. - */ - virtual void changed() {} + /** + * @brief Implement this method if you want to get a change callback. + * + * This virtual function will be called automatically at the end + * of <code>checkAndReload()</code> if a new configuration was + * loaded. This does not track differences between the current and + * newly loaded file, so any successful load event will trigger a + * <code>changed()</code> callback. Default is to do nothing. + */ + virtual void changed() {} private: - class Impl; - Impl& impl; + class Impl; + Impl& impl; }; #endif //LL_LLLIVEFILE_H diff --git a/indra/llcommon/llmainthreadtask.cpp b/indra/llcommon/llmainthreadtask.cpp index e0d70cacd8..eb26ded63f 100644 --- a/indra/llcommon/llmainthreadtask.cpp +++ b/indra/llcommon/llmainthreadtask.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-12-05 * @brief Implementation for llmainthreadtask. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llmainthreadtask.h b/indra/llcommon/llmainthreadtask.h index d509b687c0..28ad62830b 100644 --- a/indra/llcommon/llmainthreadtask.h +++ b/indra/llcommon/llmainthreadtask.h @@ -4,7 +4,7 @@ * @date 2019-12-04 * @brief LLMainThreadTask dispatches work to the main thread. When invoked on * the main thread, it performs the work inline. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llmake.h b/indra/llcommon/llmake.h index 02463d97ea..e575128be7 100644 --- a/indra/llcommon/llmake.h +++ b/indra/llcommon/llmake.h @@ -9,7 +9,7 @@ * make an instance with arguments of arbitrary type. llmake() * eliminates the need to declare a new helper function for every such * class template. - * + * * also relevant: * * Template argument deduction for class templates (C++17) diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index 0abe817f1d..f64f54c262 100644 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -1,42 +1,42 @@ -/** +/** * @file llmd5.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -// llMD5.CC - source code for the C++/object oriented translation and +// llMD5.CC - source code for the C++/object oriented translation and // modification of MD5. // // Adapted to Linden Lab by Frank Filipanits, 6/25/2002 // Fixed potential memory leak, James Cook, 6/27/2002 -// Translation and modification (c) 1995 by Mordechai T. Abzug +// Translation and modification (c) 1995 by Mordechai T. Abzug -// This translation/ modification is provided "as is," without express or +// This translation/ modification is provided "as is," without express or // implied warranty of any kind. -// The translator/ modifier does not claim (1) that MD5 will do what you think -// it does; (2) that this translation/ modification is accurate; or (3) that -// this software is "merchantible." (Language for this disclaimer partially +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially // copied from the disclaimer below). /* based on: @@ -76,7 +76,7 @@ documentation and/or software. #include "llmd5.h" -#include <iostream> // cerr +#include <iostream> // cerr // how many bytes to grab at a time when checking files const int LLMD5::BLOCK_LEN = 4096; @@ -102,7 +102,7 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { size_t buffer_space; // how much space is left in buffer if (finalized){ // so we can't update! - std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl; + std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl; return; } @@ -116,21 +116,21 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { // now, transform each 64-byte piece of the input, bypassing the buffer if (input == NULL || input_length == 0){ - std::cerr << "LLMD5::update: Invalid input!" << std::endl; - return; + std::cerr << "LLMD5::update: Invalid input!" << std::endl; + return; } // Transform as many times as possible. if (input_length >= buffer_space) { // ie. we have enough to fill the buffer // fill the rest of the buffer and transform - memcpy( /* Flawfinder: ignore */ - buffer + buffer_index, - input, - buffer_space); + memcpy( /* Flawfinder: ignore */ + buffer + buffer_index, + input, + buffer_space); transform (buffer); - for (input_index = buffer_space; input_index + 63 < input_length; - input_index += 64) + for (input_index = buffer_space; input_index + 63 < input_length; + input_index += 64) transform (input+input_index); buffer_index = 0; // so we can buffer remaining @@ -140,7 +140,7 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { // and here we do the buffering: - memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */ + memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */ } @@ -150,7 +150,7 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { void LLMD5::update(FILE* file){ - unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ + unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ int len; while ( (len=(int)fread(buffer, 1, BLOCK_LEN, file)) ) @@ -165,11 +165,11 @@ void LLMD5::update(FILE* file){ void LLMD5::update(std::istream& stream){ - unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ + unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ int len; while (stream.good()){ - stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable. + stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable. len=(int)stream.gcount(); update(buffer, len); } @@ -178,7 +178,7 @@ void LLMD5::update(std::istream& stream){ void LLMD5::update(const std::string& s) { - update((unsigned char *)s.c_str(),s.length()); + update((unsigned char *)s.c_str(),s.length()); } // MD5 finalization. Ends an MD5 message-digest operation, writing the @@ -187,7 +187,7 @@ void LLMD5::update(const std::string& s) void LLMD5::finalize (){ - unsigned char bits[8]; /* Flawfinder: ignore */ + unsigned char bits[8]; /* Flawfinder: ignore */ size_t index, padLen; static uint8_t PADDING[64]={ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -245,60 +245,60 @@ LLMD5::LLMD5(std::istream& stream){ // Digest a string of the format ("%s:%i" % (s, number)) LLMD5::LLMD5(const unsigned char *string, const unsigned int number) { - const char *colon = ":"; - char tbuf[16]; /* Flawfinder: ignore */ - init(); - update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */ - update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ - snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */ - update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */ - finalize(); + const char *colon = ":"; + char tbuf[16]; /* Flawfinder: ignore */ + init(); + update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */ + update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ + snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */ + update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */ + finalize(); } // Digest a string LLMD5::LLMD5(const unsigned char *s) { - init(); - update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */ - finalize(); + init(); + update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */ + finalize(); } void LLMD5::raw_digest(unsigned char *s) const { - if (!finalized) - { - std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<< - "finalized the digest!" << std::endl; - s[0] = '\0'; - return; - } - - memcpy(s, digest, 16); /* Flawfinder: ignore */ - return; + if (!finalized) + { + std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<< + "finalized the digest!" << std::endl; + s[0] = '\0'; + return; + } + + memcpy(s, digest, 16); /* Flawfinder: ignore */ + return; } void LLMD5::hex_digest(char *s) const { - int i; + int i; - if (!finalized) - { - std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<< - "finalized the digest!" <<std::endl; - s[0] = '\0'; - return; - } + if (!finalized) + { + std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<< + "finalized the digest!" <<std::endl; + s[0] = '\0'; + return; + } - for (i=0; i<16; i++) - { - sprintf(s+i*2, "%02x", digest[i]); /* Flawfinder: ignore */ - } + for (i=0; i<16; i++) + { + sprintf(s+i*2, "%02x", digest[i]); /* Flawfinder: ignore */ + } - s[32]='\0'; + s[32]='\0'; - return; + return; } @@ -308,27 +308,27 @@ void LLMD5::hex_digest(char *s) const std::ostream& operator<<(std::ostream &stream, LLMD5 context) { - char s[33]; /* Flawfinder: ignore */ - context.hex_digest(s); - stream << s; - return stream; + char s[33]; /* Flawfinder: ignore */ + context.hex_digest(s); + stream << s; + return stream; } bool operator==(const LLMD5& a, const LLMD5& b) { - unsigned char a_guts[16]; - unsigned char b_guts[16]; - a.raw_digest(a_guts); - b.raw_digest(b_guts); - if (memcmp(a_guts,b_guts,16)==0) - return true; - else - return false; + unsigned char a_guts[16]; + unsigned char b_guts[16]; + a.raw_digest(a_guts); + b.raw_digest(b_guts); + if (memcmp(a_guts,b_guts,16)==0) + return true; + else + return false; } bool operator!=(const LLMD5& a, const LLMD5& b) { - return !(a==b); + return !(a==b); } // PRIVATE METHODS: diff --git a/indra/llcommon/llmd5.h b/indra/llcommon/llmd5.h index 7d6373c20c..46c79cf5a2 100644 --- a/indra/llcommon/llmd5.h +++ b/indra/llcommon/llmd5.h @@ -1,24 +1,24 @@ -/** +/** * @file llmd5.h * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -26,17 +26,17 @@ #ifndef LL_LLMD5_H #define LL_LLMD5_H -// LLMD5.CC - source code for the C++/object oriented translation and +// LLMD5.CC - source code for the C++/object oriented translation and // modification of MD5. -// Translation and modification (c) 1995 by Mordechai T. Abzug +// Translation and modification (c) 1995 by Mordechai T. Abzug -// This translation/ modification is provided "as is," without express or +// This translation/ modification is provided "as is," without express or // implied warranty of any kind. -// The translator/ modifier does not claim (1) that MD5 will do what you think -// it does; (2) that this translation/ modification is accurate; or (3) that -// this software is "merchantible." (Language for this disclaimer partially +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially // copied from the disclaimer below). /* based on: @@ -95,10 +95,10 @@ public: LLMD5 (std::istream& stream); // digest stream, finalize LLMD5 (FILE *file); // digest file, close, finalize LLMD5 (const unsigned char *string, const unsigned int number); - + // methods to acquire finalized result - void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data - void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string + void raw_digest(unsigned char *array) const; // provide 16-byte array for binary data + void hex_digest(char *string) const; // provide 33-byte array for ascii-hex string friend LL_COMMON_API std::ostream& operator<< (std::ostream&, LLMD5 context); @@ -114,7 +114,7 @@ private: // last, the private methods, mostly static: void init (); // called by all constructors - void transform (const uint8_t *buffer); // does the real update work. Note + void transform (const uint8_t *buffer); // does the real update work. Note // that length is implied to be 64. static void encode (uint8_t *dest, const uint32_t *src, const size_t length); diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 574b9b8b3b..cf5ead718d 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmemory.cpp * @brief Very special memory allocation/deallocation stuff here * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -61,56 +61,56 @@ U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX); void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) { #if defined(LL_WINDOWS) && defined(LL_DEBUG_BUFFER_OVERRUN) - //do not check - return; + //do not check + return; #else - #ifdef SHOW_ASSERT - // Redundant, place to set breakpoints. - if (ptr%alignment!=0) - { - LL_WARNS() << "alignment check failed" << LL_ENDL; - } - llassert(ptr%alignment==0); - #endif + #ifdef SHOW_ASSERT + // Redundant, place to set breakpoints. + if (ptr%alignment!=0) + { + LL_WARNS() << "alignment check failed" << LL_ENDL; + } + llassert(ptr%alignment==0); + #endif #endif } -//static +//static void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size) { - sMaxHeapSizeInKB = U32Kilobytes::convert(max_heap_size); + sMaxHeapSizeInKB = U32Kilobytes::convert(max_heap_size); } -//static -void LLMemory::updateMemoryInfo() +//static +void LLMemory::updateMemoryInfo() { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED #if LL_WINDOWS - PROCESS_MEMORY_COUNTERS counters; - - if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) - { - LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; - return ; - } - - sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize)); - sample(sAllocatedMem, sAllocatedMemInKB); - sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage)); - sample(sVirtualMem, sAllocatedPageSizeInKB); - - U32Kilobytes avail_phys, avail_virtual; - LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; - sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); - - if(sMaxPhysicalMemInKB > sAllocatedMemInKB) - { - sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; - } - else - { - sAvailPhysicalMemInKB = U32Kilobytes(0); - } + PROCESS_MEMORY_COUNTERS counters; + + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + { + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; + return ; + } + + sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize)); + sample(sAllocatedMem, sAllocatedMemInKB); + sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage)); + sample(sVirtualMem, sAllocatedPageSizeInKB); + + U32Kilobytes avail_phys, avail_virtual; + LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; + sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); + + if(sMaxPhysicalMemInKB > sAllocatedMemInKB) + { + sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; + } + else + { + sAvailPhysicalMemInKB = U32Kilobytes(0); + } #elif defined(LL_DARWIN) task_vm_info info; @@ -156,13 +156,13 @@ void LLMemory::updateMemoryInfo() } #else - //not valid for other systems for now. - sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS()); - sMaxPhysicalMemInKB = U64Bytes(U32_MAX); - sAvailPhysicalMemInKB = U64Bytes(U32_MAX); + //not valid for other systems for now. + sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS()); + sMaxPhysicalMemInKB = U64Bytes(U32_MAX); + sAvailPhysicalMemInKB = U64Bytes(U32_MAX); #endif - return ; + return ; } // @@ -171,126 +171,126 @@ void LLMemory::updateMemoryInfo() //if success, it returns the address where the memory chunk can fit in; //otherwise it returns NULL. // -//static +//static void* LLMemory::tryToAlloc(void* address, U32 size) { #if LL_WINDOWS - address = VirtualAlloc(address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) ; - if(address) - { - if(!VirtualFree(address, 0, MEM_RELEASE)) - { - LL_ERRS() << "error happens when free some memory reservation." << LL_ENDL ; - } - } - return address ; + address = VirtualAlloc(address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) ; + if(address) + { + if(!VirtualFree(address, 0, MEM_RELEASE)) + { + LL_ERRS() << "error happens when free some memory reservation." << LL_ENDL ; + } + } + return address ; #else - return (void*)0x01 ; //skip checking + return (void*)0x01 ; //skip checking #endif } -//static +//static void LLMemory::logMemoryInfo(BOOL update) { - LL_PROFILE_ZONE_SCOPED - if(update) - { - updateMemoryInfo() ; - } - - LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ; - LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ; - LL_INFOS() << "Current available physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ; - LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ; + LL_PROFILE_ZONE_SCOPED + if(update) + { + updateMemoryInfo() ; + } + + LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ; + LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ; + LL_INFOS() << "Current available physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ; + LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ; } -//static -U32Kilobytes LLMemory::getAvailableMemKB() +//static +U32Kilobytes LLMemory::getAvailableMemKB() { - return sAvailPhysicalMemInKB ; + return sAvailPhysicalMemInKB ; } -//static -U32Kilobytes LLMemory::getMaxMemKB() +//static +U32Kilobytes LLMemory::getMaxMemKB() { - return sMaxPhysicalMemInKB ; + return sMaxPhysicalMemInKB ; } -//static -U32Kilobytes LLMemory::getAllocatedMemKB() +//static +U32Kilobytes LLMemory::getAllocatedMemKB() { - return sAllocatedMemInKB ; + return sAllocatedMemInKB ; } //---------------------------------------------------------------------------- #if defined(LL_WINDOWS) -//static +//static U64 LLMemory::getCurrentRSS() { - PROCESS_MEMORY_COUNTERS counters; + PROCESS_MEMORY_COUNTERS counters; - if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) - { - LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; - return 0; - } + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + { + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; + return 0; + } - return counters.WorkingSetSize; + return counters.WorkingSetSize; } #elif defined(LL_DARWIN) -// if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1) -// { -// LL_WARNS() << "Couldn't get page size" << LL_ENDL; -// return 0; -// } else { -// return page_size; -// } +// if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1) +// { +// LL_WARNS() << "Couldn't get page size" << LL_ENDL; +// return 0; +// } else { +// return page_size; +// } // } U64 LLMemory::getCurrentRSS() { - U64 residentSize = 0; - mach_task_basic_info_data_t basicInfo; - mach_msg_type_number_t basicInfoCount = MACH_TASK_BASIC_INFO_COUNT; - if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS) - { + U64 residentSize = 0; + mach_task_basic_info_data_t basicInfo; + mach_msg_type_number_t basicInfoCount = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS) + { residentSize = basicInfo.resident_size; // 64-bit macos apps allocate 32 GB or more at startup, and this is reflected in virtual_size. // basicInfo.virtual_size is not what we want. - } - else - { - LL_WARNS() << "task_info failed" << LL_ENDL; - } + } + else + { + LL_WARNS() << "task_info failed" << LL_ENDL; + } - return residentSize; + return residentSize; } #elif defined(LL_LINUX) U64 LLMemory::getCurrentRSS() { - struct rusage usage; + struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage) != 0) { - // Error handling code could be here - return 0; - } + if (getrusage(RUSAGE_SELF, &usage) != 0) { + // Error handling code could be here + return 0; + } - // ru_maxrss (since Linux 2.6.32) - // This is the maximum resident set size used (in kilobytes). - return usage.ru_maxrss * 1024; + // ru_maxrss (since Linux 2.6.32) + // This is the maximum resident set size used (in kilobytes). + return usage.ru_maxrss * 1024; } #else U64 LLMemory::getCurrentRSS() { - return 0; + return 0; } #endif @@ -302,53 +302,53 @@ U64 LLMemory::getCurrentRSS() #include <map> struct mem_info { - std::map<void*, void*> memory_info; - LLMutex mutex; + std::map<void*, void*> memory_info; + LLMutex mutex; - static mem_info& get() { - static mem_info instance; - return instance; - } + static mem_info& get() { + static mem_info instance; + return instance; + } private: - mem_info(){} + mem_info(){} }; void* ll_aligned_malloc_fallback( size_t size, int align ) { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - - unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize; - - void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); - if(NULL == p) { - // call debugger - __asm int 3; - } - DWORD old; - BOOL Res = VirtualProtect((void*)((char*)p + for_alloc), sysinfo.dwPageSize, PAGE_NOACCESS, &old); - if(FALSE == Res) { - // call debugger - __asm int 3; - } - - void* ret = (void*)((char*)p + for_alloc-size); - - { - LLMutexLock lock(&mem_info::get().mutex); - mem_info::get().memory_info.insert(std::pair<void*, void*>(ret, p)); - } - - - return ret; + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + + unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize; + + void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + if(NULL == p) { + // call debugger + __asm int 3; + } + DWORD old; + BOOL Res = VirtualProtect((void*)((char*)p + for_alloc), sysinfo.dwPageSize, PAGE_NOACCESS, &old); + if(FALSE == Res) { + // call debugger + __asm int 3; + } + + void* ret = (void*)((char*)p + for_alloc-size); + + { + LLMutexLock lock(&mem_info::get().mutex); + mem_info::get().memory_info.insert(std::pair<void*, void*>(ret, p)); + } + + + return ret; } void ll_aligned_free_fallback( void* ptr ) { - LLMutexLock lock(&mem_info::get().mutex); - VirtualFree(mem_info::get().memory_info.find(ptr)->second, 0, MEM_RELEASE); - mem_info::get().memory_info.erase(ptr); + LLMutexLock lock(&mem_info::get().mutex); + VirtualFree(mem_info::get().memory_info.find(ptr)->second, 0, MEM_RELEASE); + mem_info::get().memory_info.erase(ptr); } #endif diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index ac6c969d70..313c380587 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -38,7 +38,7 @@ class LLMutex ; #if LL_WINDOWS && LL_DEBUG #define LL_CHECK_MEMORY llassert(_CrtCheckMemory()); #else -#define LL_CHECK_MEMORY +#define LL_CHECK_MEMORY #endif @@ -73,27 +73,27 @@ LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment); #include <xmmintrin.h> -template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address) -{ - return reinterpret_cast<T*>( - (uintptr_t(address) + 0xF) & ~0xF); +template <typename T> T* LL_NEXT_ALIGNED_ADDRESS(T* address) +{ + return reinterpret_cast<T*>( + (uintptr_t(address) + 0xF) & ~0xF); } -template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) -{ - return reinterpret_cast<T*>( - (uintptr_t(address) + 0x3F) & ~0x3F); +template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) +{ + return reinterpret_cast<T*>( + (uintptr_t(address) + 0x3F) & ~0x3F); } #if LL_LINUX || LL_DARWIN -#define LL_ALIGN_PREFIX(x) -#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x))) +#define LL_ALIGN_PREFIX(x) +#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x))) #elif LL_WINDOWS -#define LL_ALIGN_PREFIX(x) __declspec(align(x)) -#define LL_ALIGN_POSTFIX(x) +#define LL_ALIGN_PREFIX(x) __declspec(align(x)) +#define LL_ALIGN_POSTFIX(x) #else #error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined" @@ -126,22 +126,22 @@ public: \ //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ - // for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library - // change preprocessor code to: #if 1 && defined(LL_WINDOWS) + // for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library + // change preprocessor code to: #if 1 && defined(LL_WINDOWS) #if 0 && defined(LL_WINDOWS) - void* ll_aligned_malloc_fallback( size_t size, int align ); - void ll_aligned_free_fallback( void* ptr ); + void* ll_aligned_malloc_fallback( size_t size, int align ); + void ll_aligned_free_fallback( void* ptr ); //------------------------------------------------------------------------------------------------ #else - inline void* ll_aligned_malloc_fallback( size_t size, int align ) - { + inline void* ll_aligned_malloc_fallback( size_t size, int align ) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; - #if defined(LL_WINDOWS) + #if defined(LL_WINDOWS) void* ret = _aligned_malloc(size, align); - #else + #else char* aligned = NULL; - void* mem = malloc( size + (align - 1) + sizeof(void*) ); + void* mem = malloc( size + (align - 1) + sizeof(void*) ); if (mem) { aligned = ((char*)mem) + sizeof(void*); @@ -149,25 +149,25 @@ public: \ ((void**)aligned)[-1] = mem; } - void* ret = aligned; - #endif + void* ret = aligned; + #endif LL_PROFILE_ALLOC(ret, size); return ret; - } + } - inline void ll_aligned_free_fallback( void* ptr ) - { + inline void ll_aligned_free_fallback( void* ptr ) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(ptr); - #if defined(LL_WINDOWS) - _aligned_free(ptr); - #else - if (ptr) - { - free( ((void**)ptr)[-1] ); - } - #endif - } + #if defined(LL_WINDOWS) + _aligned_free(ptr); + #else + if (ptr) + { + free( ((void**)ptr)[-1] ); + } + #endif + } #endif //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ @@ -176,11 +176,11 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if defined(LL_WINDOWS) - void* ret = _aligned_malloc(size, 16); + void* ret = _aligned_malloc(size, 16); #elif defined(LL_DARWIN) - void* ret = malloc(size); // default osx malloc is 16 byte aligned. + void* ret = malloc(size); // default osx malloc is 16 byte aligned. #else - void *ret; + void *ret; if (0 != posix_memalign(&ret, 16, size)) return nullptr; #endif @@ -193,11 +193,11 @@ inline void ll_aligned_free_16(void *p) LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(p); #if defined(LL_WINDOWS) - _aligned_free(p); + _aligned_free(p); #elif defined(LL_DARWIN) - return free(p); + return free(p); #else - free(p); // posix_memalign() is compatible with heap deallocator + free(p); // posix_memalign() is compatible with heap deallocator #endif } @@ -206,21 +206,21 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(ptr); #if defined(LL_WINDOWS) - void* ret = _aligned_realloc(ptr, size, 16); + void* ret = _aligned_realloc(ptr, size, 16); #elif defined(LL_DARWIN) - void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned. + void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned. #else - //FIXME: memcpy is SLOW - void* ret = ll_aligned_malloc_16(size); - if (ptr) - { - if (ret) - { - // Only copy the size of the smallest memory block to avoid memory corruption. - memcpy(ret, ptr, llmin(old_size, size)); - } - ll_aligned_free_16(ptr); - } + //FIXME: memcpy is SLOW + void* ret = ll_aligned_malloc_16(size); + if (ptr) + { + if (ret) + { + // Only copy the size of the smallest memory block to avoid memory corruption. + memcpy(ret, ptr, llmin(old_size, size)); + } + ll_aligned_free_16(ptr); + } #endif LL_PROFILE_ALLOC(ptr, size); return ret; @@ -230,11 +230,11 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if defined(LL_WINDOWS) - void* ret = _aligned_malloc(size, 32); + void* ret = _aligned_malloc(size, 32); #elif defined(LL_DARWIN) - void* ret = ll_aligned_malloc_fallback( size, 32 ); + void* ret = ll_aligned_malloc_fallback( size, 32 ); #else - void *ret; + void *ret; if (0 != posix_memalign(&ret, 32, size)) return nullptr; #endif @@ -247,11 +247,11 @@ inline void ll_aligned_free_32(void *p) LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(p); #if defined(LL_WINDOWS) - _aligned_free(p); + _aligned_free(p); #elif defined(LL_DARWIN) - ll_aligned_free_fallback( p ); + ll_aligned_free_fallback( p ); #else - free(p); // posix_memalign() is compatible with heap deallocator + free(p); // posix_memalign() is compatible with heap deallocator #endif } @@ -261,23 +261,23 @@ LL_FORCE_INLINE void* ll_aligned_malloc(size_t size) { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; void* ret; - if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0) - { - ret = malloc(size); + if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0) + { + ret = malloc(size); LL_PROFILE_ALLOC(ret, size); - } - else if (ALIGNMENT == 16) - { - ret = ll_aligned_malloc_16(size); - } - else if (ALIGNMENT == 32) - { - ret = ll_aligned_malloc_32(size); - } - else - { - ret = ll_aligned_malloc_fallback(size, ALIGNMENT); - } + } + else if (ALIGNMENT == 16) + { + ret = ll_aligned_malloc_16(size); + } + else if (ALIGNMENT == 32) + { + ret = ll_aligned_malloc_32(size); + } + else + { + ret = ll_aligned_malloc_fallback(size, ALIGNMENT); + } return ret; } @@ -285,96 +285,96 @@ template<size_t ALIGNMENT> LL_FORCE_INLINE void ll_aligned_free(void* ptr) { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; - if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN) - { + if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN) + { LL_PROFILE_FREE(ptr); - free(ptr); - } - else if (ALIGNMENT == 16) - { - ll_aligned_free_16(ptr); - } - else if (ALIGNMENT == 32) - { - return ll_aligned_free_32(ptr); - } - else - { - return ll_aligned_free_fallback(ptr); - } + free(ptr); + } + else if (ALIGNMENT == 16) + { + ll_aligned_free_16(ptr); + } + else if (ALIGNMENT == 32) + { + return ll_aligned_free_32(ptr); + } + else + { + return ll_aligned_free_fallback(ptr); + } } -// Copy words 16-byte blocks from src to dst. Source and destination MUST NOT OVERLAP. +// Copy words 16-byte blocks from src to dst. Source and destination MUST NOT OVERLAP. // Source and dest must be 16-byte aligned and size must be multiple of 16. // inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes) { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; - assert(src != NULL); - assert(dst != NULL); - assert(bytes > 0); - assert((bytes % sizeof(F32))== 0); - ll_assert_aligned(src,16); - ll_assert_aligned(dst,16); - - assert((src < dst) ? ((src + bytes) <= dst) : ((dst + bytes) <= src)); - assert(bytes%16==0); - - char* end = dst + bytes; - - if (bytes > 64) - { - - // Find start of 64b aligned area within block - // - void* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst); - - //at least 64 bytes before the end of the destination, switch to 16 byte copies - void* end_64 = end-64; - - // Prefetch the head of the 64b area now - // - _mm_prefetch((char*)begin_64, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA); - - // Copy 16b chunks until we're 64b aligned - // - while (dst < begin_64) - { - - _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); - dst += 16; - src += 16; - } - - // Copy 64b chunks up to your tail - // - // might be good to shmoo the 512b prefetch offset - // (characterize performance for various values) - // - while (dst < end_64) - { - _mm_prefetch((char*)src + 512, _MM_HINT_NTA); - _mm_prefetch((char*)dst + 512, _MM_HINT_NTA); - _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); - _mm_store_ps((F32*)(dst + 16), _mm_load_ps((F32*)(src + 16))); - _mm_store_ps((F32*)(dst + 32), _mm_load_ps((F32*)(src + 32))); - _mm_store_ps((F32*)(dst + 48), _mm_load_ps((F32*)(src + 48))); - dst += 64; - src += 64; - } - } - - // Copy remainder 16b tail chunks (or ALL 16b chunks for sub-64b copies) - // - while (dst < end) - { - _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); - dst += 16; - src += 16; - } + assert(src != NULL); + assert(dst != NULL); + assert(bytes > 0); + assert((bytes % sizeof(F32))== 0); + ll_assert_aligned(src,16); + ll_assert_aligned(dst,16); + + assert((src < dst) ? ((src + bytes) <= dst) : ((dst + bytes) <= src)); + assert(bytes%16==0); + + char* end = dst + bytes; + + if (bytes > 64) + { + + // Find start of 64b aligned area within block + // + void* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst); + + //at least 64 bytes before the end of the destination, switch to 16 byte copies + void* end_64 = end-64; + + // Prefetch the head of the 64b area now + // + _mm_prefetch((char*)begin_64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA); + + // Copy 16b chunks until we're 64b aligned + // + while (dst < begin_64) + { + + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + dst += 16; + src += 16; + } + + // Copy 64b chunks up to your tail + // + // might be good to shmoo the 512b prefetch offset + // (characterize performance for various values) + // + while (dst < end_64) + { + _mm_prefetch((char*)src + 512, _MM_HINT_NTA); + _mm_prefetch((char*)dst + 512, _MM_HINT_NTA); + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + _mm_store_ps((F32*)(dst + 16), _mm_load_ps((F32*)(src + 16))); + _mm_store_ps((F32*)(dst + 32), _mm_load_ps((F32*)(src + 32))); + _mm_store_ps((F32*)(dst + 48), _mm_load_ps((F32*)(src + 48))); + dst += 64; + src += 64; + } + } + + // Copy remainder 16b tail chunks (or ALL 16b chunks for sub-64b copies) + // + while (dst < end) + { + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + dst += 16; + src += 16; + } } #ifndef __DEBUG_PRIVATE_MEM__ @@ -384,24 +384,24 @@ inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __ class LL_COMMON_API LLMemory { public: - // Return the resident set size of the current process, in bytes. - // Return value is zero if not known. - static U64 getCurrentRSS(); - static void* tryToAlloc(void* address, U32 size); - static void initMaxHeapSizeGB(F32Gigabytes max_heap_size); - static void updateMemoryInfo() ; - static void logMemoryInfo(BOOL update = FALSE); - - static U32Kilobytes getAvailableMemKB() ; - static U32Kilobytes getMaxMemKB() ; - static U32Kilobytes getAllocatedMemKB() ; + // Return the resident set size of the current process, in bytes. + // Return value is zero if not known. + static U64 getCurrentRSS(); + static void* tryToAlloc(void* address, U32 size); + static void initMaxHeapSizeGB(F32Gigabytes max_heap_size); + static void updateMemoryInfo() ; + static void logMemoryInfo(BOOL update = FALSE); + + static U32Kilobytes getAvailableMemKB() ; + static U32Kilobytes getMaxMemKB() ; + static U32Kilobytes getAllocatedMemKB() ; private: - static U32Kilobytes sAvailPhysicalMemInKB ; - static U32Kilobytes sMaxPhysicalMemInKB ; - static U32Kilobytes sAllocatedMemInKB; - static U32Kilobytes sAllocatedPageSizeInKB ; + static U32Kilobytes sAvailPhysicalMemInKB ; + static U32Kilobytes sMaxPhysicalMemInKB ; + static U32Kilobytes sAllocatedMemInKB; + static U32Kilobytes sAllocatedPageSizeInKB ; - static U32Kilobytes sMaxHeapSizeInKB; + static U32Kilobytes sMaxHeapSizeInKB; }; // LLRefCount moved to llrefcount.h diff --git a/indra/llcommon/llmemorystream.cpp b/indra/llcommon/llmemorystream.cpp index 707ac8fd0f..b3acc8c7d3 100644 --- a/indra/llcommon/llmemorystream.cpp +++ b/indra/llcommon/llmemorystream.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llmemorystream.cpp * @author Phoenix * @date 2005-06-03 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,7 +31,7 @@ LLMemoryStreamBuf::LLMemoryStreamBuf(const U8* start, S32 length) { - reset(start, length); + reset(start, length); } LLMemoryStreamBuf::~LLMemoryStreamBuf() @@ -40,26 +40,26 @@ LLMemoryStreamBuf::~LLMemoryStreamBuf() void LLMemoryStreamBuf::reset(const U8* start, S32 length) { - setg((char*)start, (char*)start, (char*)start + length); + setg((char*)start, (char*)start, (char*)start + length); } int LLMemoryStreamBuf::underflow() { - //LL_DEBUGS() << "LLMemoryStreamBuf::underflow()" << LL_ENDL; - if(gptr() < egptr()) - { - return *gptr(); - } - return EOF; + //LL_DEBUGS() << "LLMemoryStreamBuf::underflow()" << LL_ENDL; + if(gptr() < egptr()) + { + return *gptr(); + } + return EOF; } -/** +/** * @class LLMemoryStreamBuf */ LLMemoryStream::LLMemoryStream(const U8* start, S32 length) : - std::istream(&mStreamBuf), - mStreamBuf(start, length) + std::istream(&mStreamBuf), + mStreamBuf(start, length) { } diff --git a/indra/llcommon/llmemorystream.h b/indra/llcommon/llmemorystream.h index e28f012192..6024bc5d37 100644 --- a/indra/llcommon/llmemorystream.h +++ b/indra/llcommon/llmemorystream.h @@ -1,4 +1,4 @@ -/** +/** * @file llmemorystream.h * @author Phoenix * @date 2005-06-03 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,7 +29,7 @@ #ifndef LL_LLMEMORYSTREAM_H #define LL_LLMEMORYSTREAM_H -/** +/** * This is a simple but effective optimization when you want to treat * a chunk of memory as an istream. I wrote this to avoid turing a * buffer into a string, and then throwing the string into an @@ -38,7 +38,7 @@ #include <iostream> -/** +/** * @class LLMemoryStreamBuf * @brief This implements a wrapper around a piece of memory for istreams * @@ -49,18 +49,18 @@ class LL_COMMON_API LLMemoryStreamBuf : public std::streambuf { public: - LLMemoryStreamBuf(const U8* start, S32 length); - ~LLMemoryStreamBuf(); + LLMemoryStreamBuf(const U8* start, S32 length); + ~LLMemoryStreamBuf(); - void reset(const U8* start, S32 length); + void reset(const U8* start, S32 length); protected: - int underflow(); - //std::streamsize xsgetn(char* dest, std::streamsize n); + int underflow(); + //std::streamsize xsgetn(char* dest, std::streamsize n); }; -/** +/** * @class LLMemoryStream * @brief This implements a wrapper around a piece of memory for istreams * @@ -71,11 +71,11 @@ protected: class LL_COMMON_API LLMemoryStream : public std::istream { public: - LLMemoryStream(const U8* start, S32 length); - ~LLMemoryStream(); + LLMemoryStream(const U8* start, S32 length); + ~LLMemoryStream(); protected: - LLMemoryStreamBuf mStreamBuf; + LLMemoryStreamBuf mStreamBuf; }; #endif // LL_LLMEMORYSTREAM_H diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp index ab509b46eb..e05c2558f6 100644 --- a/indra/llcommon/llmetricperformancetester.cpp +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmetricperformancetester.cpp * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes implementation * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,129 +39,129 @@ LLMetricPerformanceTesterBasic::name_tester_map_t LLMetricPerformanceTesterBasic::sTesterMap ; -/*static*/ -void LLMetricPerformanceTesterBasic::cleanupClass() +/*static*/ +void LLMetricPerformanceTesterBasic::cleanupClass() { - for (name_tester_map_t::value_type& pair : sTesterMap) - { - delete pair.second; - } - sTesterMap.clear() ; + for (name_tester_map_t::value_type& pair : sTesterMap) + { + delete pair.second; + } + sTesterMap.clear() ; } -/*static*/ -BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester) +/*static*/ +BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester) { - llassert_always(tester != NULL); - std::string name = tester->getTesterName() ; - if (getTester(name)) - { - LL_ERRS() << "Tester name is already used by some other tester : " << name << LL_ENDL ; - return FALSE; - } - - sTesterMap.insert(std::make_pair(name, tester)); - return TRUE; + llassert_always(tester != NULL); + std::string name = tester->getTesterName() ; + if (getTester(name)) + { + LL_ERRS() << "Tester name is already used by some other tester : " << name << LL_ENDL ; + return FALSE; + } + + sTesterMap.insert(std::make_pair(name, tester)); + return TRUE; } -/*static*/ +/*static*/ void LLMetricPerformanceTesterBasic::deleteTester(std::string name) { - name_tester_map_t::iterator tester = sTesterMap.find(name); - if (tester != sTesterMap.end()) - { - delete tester->second; - sTesterMap.erase(tester); - } + name_tester_map_t::iterator tester = sTesterMap.find(name); + if (tester != sTesterMap.end()) + { + delete tester->second; + sTesterMap.erase(tester); + } } -/*static*/ -LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name) +/*static*/ +LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name) { - // Check for the requested metric name - name_tester_map_t::iterator found_it = sTesterMap.find(name) ; - if (found_it != sTesterMap.end()) - { - return found_it->second ; - } - return NULL ; + // Check for the requested metric name + name_tester_map_t::iterator found_it = sTesterMap.find(name) ; + if (found_it != sTesterMap.end()) + { + return found_it->second ; + } + return NULL ; } -/*static*/ +/*static*/ // Return TRUE if this metric is requested or if the general default "catch all" metric is requested BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name) { - return (LLTrace::BlockTimer::sMetricLog && ((LLTrace::BlockTimer::sLogName == name) || (LLTrace::BlockTimer::sLogName == DEFAULT_METRIC_NAME))); + return (LLTrace::BlockTimer::sMetricLog && ((LLTrace::BlockTimer::sLogName == name) || (LLTrace::BlockTimer::sLogName == DEFAULT_METRIC_NAME))); } -/*static*/ +/*static*/ LLSD LLMetricPerformanceTesterBasic::analyzeMetricPerformanceLog(std::istream& is) { - LLSD ret; - LLSD cur; - - while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is)) - { - for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) - { - std::string label = iter->first; - - LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ; - if(tester) - { - ret[label]["Name"] = iter->second["Name"] ; - - auto num_of_metrics = tester->getNumberOfMetrics() ; - for(size_t index = 0 ; index < num_of_metrics ; index++) - { - ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ; - } - } - } - } - - return ret; + LLSD ret; + LLSD cur; + + while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is)) + { + for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) + { + std::string label = iter->first; + + LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ; + if(tester) + { + ret[label]["Name"] = iter->second["Name"] ; + + auto num_of_metrics = tester->getNumberOfMetrics() ; + for(size_t index = 0 ; index < num_of_metrics ; index++) + { + ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ; + } + } + } + } + + return ret; } -/*static*/ +/*static*/ void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std::string target, std::string output) { - if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) - { - return ; - } - - // Open baseline and current target, exit if one is inexistent - llifstream base_is(baseline.c_str()); - llifstream target_is(target.c_str()); - if (!base_is.is_open() || !target_is.is_open()) - { - LL_WARNS() << "'-analyzeperformance' error : baseline or current target file inexistent" << LL_ENDL; - base_is.close(); - target_is.close(); - return; - } - - //analyze baseline - LLSD base = analyzeMetricPerformanceLog(base_is); - base_is.close(); - - //analyze current - LLSD current = analyzeMetricPerformanceLog(target_is); - target_is.close(); - - //output comparision - llofstream os(output.c_str()); - - os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; - for (LLMetricPerformanceTesterBasic::name_tester_map_t::value_type& pair : LLMetricPerformanceTesterBasic::sTesterMap) - { - LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)pair.second); - tester->analyzePerformance(&os, &base, ¤t) ; - } - - os.flush(); - os.close(); + if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) + { + return ; + } + + // Open baseline and current target, exit if one is inexistent + llifstream base_is(baseline.c_str()); + llifstream target_is(target.c_str()); + if (!base_is.is_open() || !target_is.is_open()) + { + LL_WARNS() << "'-analyzeperformance' error : baseline or current target file inexistent" << LL_ENDL; + base_is.close(); + target_is.close(); + return; + } + + //analyze baseline + LLSD base = analyzeMetricPerformanceLog(base_is); + base_is.close(); + + //analyze current + LLSD current = analyzeMetricPerformanceLog(target_is); + target_is.close(); + + //output comparision + llofstream os(output.c_str()); + + os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; + for (LLMetricPerformanceTesterBasic::name_tester_map_t::value_type& pair : LLMetricPerformanceTesterBasic::sTesterMap) + { + LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)pair.second); + tester->analyzePerformance(&os, &base, ¤t) ; + } + + os.flush(); + os.close(); } @@ -169,157 +169,157 @@ void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std // LLMetricPerformanceTesterBasic : Tester instance methods //---------------------------------------------------------------------------------------------- -LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) : - mName(name), - mCount(0) +LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) : + mName(name), + mCount(0) { - if (mName == std::string()) - { - LL_ERRS() << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << LL_ENDL ; - } + if (mName == std::string()) + { + LL_ERRS() << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << LL_ENDL ; + } - mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ; + mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ; } -LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic() +LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic() { } -void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) +void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) { - incrementCurrentCount() ; + incrementCurrentCount() ; } void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd) { - LLTrace::BlockTimer::pushLog(*sd); + LLTrace::BlockTimer::pushLog(*sd); } -void LLMetricPerformanceTesterBasic::outputTestResults() +void LLMetricPerformanceTesterBasic::outputTestResults() { - LLSD sd; + LLSD sd; - preOutputTestResults(&sd) ; - outputTestRecord(&sd) ; - postOutputTestResults(&sd) ; + preOutputTestResults(&sd) ; + outputTestRecord(&sd) ; + postOutputTestResults(&sd) ; } void LLMetricPerformanceTesterBasic::addMetric(std::string str) { - mMetricStrings.push_back(str) ; + mMetricStrings.push_back(str) ; } -/*virtual*/ -void LLMetricPerformanceTesterBasic::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) +/*virtual*/ +void LLMetricPerformanceTesterBasic::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) { - resetCurrentCount() ; - - std::string current_label = getCurrentLabelName(); - BOOL in_base = (*base).has(current_label) ; - BOOL in_current = (*current).has(current_label) ; - - while(in_base || in_current) - { - LLSD::String label = current_label ; - - if(in_base && in_current) - { - *os << llformat("%s\n", label.c_str()) ; - - for(U32 index = 0 ; index < mMetricStrings.size() ; index++) - { - switch((*current)[label][ mMetricStrings[index] ].type()) - { - case LLSD::TypeInteger: - compareTestResults(os, mMetricStrings[index], - (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ; - break ; - case LLSD::TypeReal: - compareTestResults(os, mMetricStrings[index], - (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ; - break; - default: - LL_ERRS() << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << LL_ENDL ; - } - } - } - - incrementCurrentCount(); - current_label = getCurrentLabelName(); - in_base = (*base).has(current_label) ; - in_current = (*current).has(current_label) ; - } + resetCurrentCount() ; + + std::string current_label = getCurrentLabelName(); + BOOL in_base = (*base).has(current_label) ; + BOOL in_current = (*current).has(current_label) ; + + while(in_base || in_current) + { + LLSD::String label = current_label ; + + if(in_base && in_current) + { + *os << llformat("%s\n", label.c_str()) ; + + for(U32 index = 0 ; index < mMetricStrings.size() ; index++) + { + switch((*current)[label][ mMetricStrings[index] ].type()) + { + case LLSD::TypeInteger: + compareTestResults(os, mMetricStrings[index], + (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ; + break ; + case LLSD::TypeReal: + compareTestResults(os, mMetricStrings[index], + (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ; + break; + default: + LL_ERRS() << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << LL_ENDL ; + } + } + } + + incrementCurrentCount(); + current_label = getCurrentLabelName(); + in_base = (*base).has(current_label) ; + in_current = (*current).has(current_label) ; + } } -/*virtual*/ -void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) +/*virtual*/ +void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) { - *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current, - v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ; + *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current, + v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ; } -/*virtual*/ -void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) +/*virtual*/ +void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) { - *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current, - v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ; + *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current, + v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ; } //---------------------------------------------------------------------------------------------- // LLMetricPerformanceTesterWithSession //---------------------------------------------------------------------------------------------- -LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) : - LLMetricPerformanceTesterBasic(name), - mBaseSessionp(NULL), - mCurrentSessionp(NULL) +LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) : + LLMetricPerformanceTesterBasic(name), + mBaseSessionp(NULL), + mCurrentSessionp(NULL) { } LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession() { - if (mBaseSessionp) - { - delete mBaseSessionp ; - mBaseSessionp = NULL ; - } - if (mCurrentSessionp) - { - delete mCurrentSessionp ; - mCurrentSessionp = NULL ; - } + if (mBaseSessionp) + { + delete mBaseSessionp ; + mBaseSessionp = NULL ; + } + if (mCurrentSessionp) + { + delete mCurrentSessionp ; + mCurrentSessionp = NULL ; + } } -/*virtual*/ -void LLMetricPerformanceTesterWithSession::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) +/*virtual*/ +void LLMetricPerformanceTesterWithSession::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) { - // Load the base session - resetCurrentCount() ; - mBaseSessionp = loadTestSession(base) ; - - // Load the current session - resetCurrentCount() ; - mCurrentSessionp = loadTestSession(current) ; - - if (!mBaseSessionp || !mCurrentSessionp) - { - LL_ERRS() << "Error loading test sessions." << LL_ENDL ; - } - - // Compare - compareTestSessions(os) ; - - // Release memory - if (mBaseSessionp) - { - delete mBaseSessionp ; - mBaseSessionp = NULL ; - } - if (mCurrentSessionp) - { - delete mCurrentSessionp ; - mCurrentSessionp = NULL ; - } + // Load the base session + resetCurrentCount() ; + mBaseSessionp = loadTestSession(base) ; + + // Load the current session + resetCurrentCount() ; + mCurrentSessionp = loadTestSession(current) ; + + if (!mBaseSessionp || !mCurrentSessionp) + { + LL_ERRS() << "Error loading test sessions." << LL_ENDL ; + } + + // Compare + compareTestSessions(os) ; + + // Release memory + if (mBaseSessionp) + { + delete mBaseSessionp ; + mBaseSessionp = NULL ; + } + if (mCurrentSessionp) + { + delete mCurrentSessionp ; + mCurrentSessionp = NULL ; + } } @@ -327,7 +327,7 @@ void LLMetricPerformanceTesterWithSession::analyzePerformance(llofstream* os, LL // LLTestSession //---------------------------------------------------------------------------------------------- -LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession() +LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession() { } diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h index 6561a78f03..15c564f2ca 100644 --- a/indra/llcommon/llmetricperformancetester.h +++ b/indra/llcommon/llmetricperformancetester.h @@ -1,31 +1,31 @@ -/** - * @file llmetricperformancetester.h +/** + * @file llmetricperformancetester.h * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes definition * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_METRICPERFORMANCETESTER_H -#define LL_METRICPERFORMANCETESTER_H +#ifndef LL_METRICPERFORMANCETESTER_H +#define LL_METRICPERFORMANCETESTER_H char const* const DEFAULT_METRIC_NAME = "metric"; @@ -36,179 +36,179 @@ char const* const DEFAULT_METRIC_NAME = "metric"; class LL_COMMON_API LLMetricPerformanceTesterBasic { public: - /** - * @brief Creates a basic tester instance. - * @param[in] name - Unique string identifying this tester instance. - */ - LLMetricPerformanceTesterBasic(std::string name); - virtual ~LLMetricPerformanceTesterBasic(); - - /** - * @return Returns true if the instance has been added to the tester map. - * Need to be tested after creation of a tester instance so to know if the tester is correctly handled. - * A tester might not be added to the map if another tester with the same name already exists. - */ - BOOL isValid() const { return mValidInstance; } - - /** - * @brief Write a set of test results to the log LLSD. - */ - void outputTestResults() ; - - /** - * @brief Compare the test results. - * By default, compares the test results against the baseline one by one, item by item, - * in the increasing order of the LLSD record counter, starting from the first one. - */ - virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; - - static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ; - - /** - * @return Returns the number of the test metrics in this tester instance. - */ - auto getNumberOfMetrics() const { return mMetricStrings.size() ;} - /** - * @return Returns the metric name at index - * @param[in] index - Index on the list of metrics managed by this tester instance. - */ - std::string getMetricName(size_t index) const { return mMetricStrings[index] ;} + /** + * @brief Creates a basic tester instance. + * @param[in] name - Unique string identifying this tester instance. + */ + LLMetricPerformanceTesterBasic(std::string name); + virtual ~LLMetricPerformanceTesterBasic(); + + /** + * @return Returns true if the instance has been added to the tester map. + * Need to be tested after creation of a tester instance so to know if the tester is correctly handled. + * A tester might not be added to the map if another tester with the same name already exists. + */ + BOOL isValid() const { return mValidInstance; } + + /** + * @brief Write a set of test results to the log LLSD. + */ + void outputTestResults() ; + + /** + * @brief Compare the test results. + * By default, compares the test results against the baseline one by one, item by item, + * in the increasing order of the LLSD record counter, starting from the first one. + */ + virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; + + static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ; + + /** + * @return Returns the number of the test metrics in this tester instance. + */ + auto getNumberOfMetrics() const { return mMetricStrings.size() ;} + /** + * @return Returns the metric name at index + * @param[in] index - Index on the list of metrics managed by this tester instance. + */ + std::string getMetricName(size_t index) const { return mMetricStrings[index] ;} protected: - /** - * @return Returns the name of this tester instance. - */ - std::string getTesterName() const { return mName ;} - - /** - * @brief Insert a new metric to be managed by this tester instance. - * @param[in] str - Unique string identifying the new metric. - */ - void addMetric(std::string str) ; - - /** - * @brief Compare test results, provided in 2 flavors: compare integers and compare floats. - * @param[out] os - Formatted output string holding the compared values. - * @param[in] metric_string - Name of the metric. - * @param[in] v_base - Base value of the metric. - * @param[in] v_current - Current value of the metric. - */ - virtual void compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) ; - virtual void compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) ; - - /** - * @brief Reset internal record count. Count starts with 1. - */ - void resetCurrentCount() { mCount = 1; } - /** - * @brief Increment internal record count. - */ - void incrementCurrentCount() { mCount++; } - /** - * @return Returns the label to be used for the current count. It's "TesterName"-"Count". - */ - std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;} - - /** - * @brief Write a test record to the LLSD. Implementers need to overload this method. - * @param[out] sd - The LLSD record to store metric data into. - */ - virtual void outputTestRecord(LLSD* sd) = 0 ; + /** + * @return Returns the name of this tester instance. + */ + std::string getTesterName() const { return mName ;} + + /** + * @brief Insert a new metric to be managed by this tester instance. + * @param[in] str - Unique string identifying the new metric. + */ + void addMetric(std::string str) ; + + /** + * @brief Compare test results, provided in 2 flavors: compare integers and compare floats. + * @param[out] os - Formatted output string holding the compared values. + * @param[in] metric_string - Name of the metric. + * @param[in] v_base - Base value of the metric. + * @param[in] v_current - Current value of the metric. + */ + virtual void compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) ; + virtual void compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) ; + + /** + * @brief Reset internal record count. Count starts with 1. + */ + void resetCurrentCount() { mCount = 1; } + /** + * @brief Increment internal record count. + */ + void incrementCurrentCount() { mCount++; } + /** + * @return Returns the label to be used for the current count. It's "TesterName"-"Count". + */ + std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;} + + /** + * @brief Write a test record to the LLSD. Implementers need to overload this method. + * @param[out] sd - The LLSD record to store metric data into. + */ + virtual void outputTestRecord(LLSD* sd) = 0 ; private: - void preOutputTestResults(LLSD* sd) ; - void postOutputTestResults(LLSD* sd) ; - static LLSD analyzeMetricPerformanceLog(std::istream& is) ; + void preOutputTestResults(LLSD* sd) ; + void postOutputTestResults(LLSD* sd) ; + static LLSD analyzeMetricPerformanceLog(std::istream& is) ; - std::string mName ; // Name of this tester instance - S32 mCount ; // Current record count - BOOL mValidInstance; // TRUE if the instance is managed by the map - std::vector< std::string > mMetricStrings ; // Metrics strings + std::string mName ; // Name of this tester instance + S32 mCount ; // Current record count + BOOL mValidInstance; // TRUE if the instance is managed by the map + std::vector< std::string > mMetricStrings ; // Metrics strings // Static members managing the collection of testers -public: - // Map of all the tester instances in use - typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t; - static name_tester_map_t sTesterMap ; - - /** - * @return Returns a pointer to the tester - * @param[in] name - Name of the tester instance queried. - */ - static LLMetricPerformanceTesterBasic* getTester(std::string name) ; - - /** - * @return Delete the named tester from the list - * @param[in] name - Name of the tester instance to delete. - */ - static void deleteTester(std::string name); - - /** - * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged - * @param[in] name - Name of the tester queried. - */ - static BOOL isMetricLogRequested(std::string name); - - /** - * @return Returns TRUE if there's a tester defined, FALSE otherwise. - */ - static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;} - /** - * @brief Delete all testers and reset the tester map - */ - static void cleanupClass() ; +public: + // Map of all the tester instances in use + typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t; + static name_tester_map_t sTesterMap ; + + /** + * @return Returns a pointer to the tester + * @param[in] name - Name of the tester instance queried. + */ + static LLMetricPerformanceTesterBasic* getTester(std::string name) ; + + /** + * @return Delete the named tester from the list + * @param[in] name - Name of the tester instance to delete. + */ + static void deleteTester(std::string name); + + /** + * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged + * @param[in] name - Name of the tester queried. + */ + static BOOL isMetricLogRequested(std::string name); + + /** + * @return Returns TRUE if there's a tester defined, FALSE otherwise. + */ + static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;} + /** + * @brief Delete all testers and reset the tester map + */ + static void cleanupClass() ; private: - // Add a tester to the map. Returns false if adding fails. - static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ; + // Add a tester to the map. Returns false if adding fails. + static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ; }; /** * @class LLMetricPerformanceTesterWithSession - * @brief Performance Metric Class with custom session + * @brief Performance Metric Class with custom session */ class LL_COMMON_API LLMetricPerformanceTesterWithSession : public LLMetricPerformanceTesterBasic { public: - /** - * @param[in] name - Unique string identifying this tester instance. - */ - LLMetricPerformanceTesterWithSession(std::string name); - virtual ~LLMetricPerformanceTesterWithSession(); - - /** - * @brief Compare the test results. - * This will be loading the base and current sessions and compare them using the virtual - * abstract methods loadTestSession() and compareTestSessions() - */ - virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; + /** + * @param[in] name - Unique string identifying this tester instance. + */ + LLMetricPerformanceTesterWithSession(std::string name); + virtual ~LLMetricPerformanceTesterWithSession(); + + /** + * @brief Compare the test results. + * This will be loading the base and current sessions and compare them using the virtual + * abstract methods loadTestSession() and compareTestSessions() + */ + virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; protected: - /** - * @class LLMetricPerformanceTesterWithSession::LLTestSession - * @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions() - */ - class LL_COMMON_API LLTestSession - { - public: - virtual ~LLTestSession() ; - }; - - /** - * @brief Convert an LLSD log into a test session. - * @param[in] log - The LLSD record - * @return Returns the record as a test session - */ - virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0; - - /** - * @brief Compare the base session and the target session. Assumes base and current sessions have been loaded. - * @param[out] os - The comparison result as a standard stream - */ - virtual void compareTestSessions(llofstream* os) = 0; - - LLTestSession* mBaseSessionp; - LLTestSession* mCurrentSessionp; + /** + * @class LLMetricPerformanceTesterWithSession::LLTestSession + * @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions() + */ + class LL_COMMON_API LLTestSession + { + public: + virtual ~LLTestSession() ; + }; + + /** + * @brief Convert an LLSD log into a test session. + * @param[in] log - The LLSD record + * @return Returns the record as a test session + */ + virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0; + + /** + * @brief Compare the base session and the target session. Assumes base and current sessions have been loaded. + * @param[out] os - The comparison result as a standard stream + */ + virtual void compareTestSessions(llofstream* os) = 0; + + LLTestSession* mBaseSessionp; + LLTestSession* mCurrentSessionp; }; #endif diff --git a/indra/llcommon/llmetrics.cpp b/indra/llcommon/llmetrics.cpp index d40afe5160..7c37b18bab 100644 --- a/indra/llcommon/llmetrics.cpp +++ b/indra/llcommon/llmetrics.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llmetrics.cpp * @author Kelly * @date 2007-05-25 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,128 +36,128 @@ class LLMetricsImpl { public: - LLMetricsImpl() { } - ~LLMetricsImpl(); - - void recordEvent(const std::string& location, const std::string& mesg, bool success); - void printTotals(LLSD metadata); - void recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats); + LLMetricsImpl() { } + ~LLMetricsImpl(); + + void recordEvent(const std::string& location, const std::string& mesg, bool success); + void printTotals(LLSD metadata); + void recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats); private: - LLFrameTimer mLastPrintTimer; - LLSD mMetricsMap; + LLFrameTimer mLastPrintTimer; + LLSD mMetricsMap; }; LLMetricsImpl::~LLMetricsImpl() { } -void LLMetricsImpl::recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats) +void LLMetricsImpl::recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats) { - recordEvent(location,mesg,success); + recordEvent(location,mesg,success); - LLSD metrics = LLSD::emptyMap(); - metrics["location"] = location; - metrics["stats"] = stats; - - LL_INFOS() << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << LL_ENDL; + LLSD metrics = LLSD::emptyMap(); + metrics["location"] = location; + metrics["stats"] = stats; + + LL_INFOS() << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << LL_ENDL; } // Store this: // [ {'location_1':{'mesg_1':{'success':i10, 'fail':i0}, -// 'mesg_2':{'success':i10, 'fail':i0}}, +// 'mesg_2':{'success':i10, 'fail':i0}}, // {'location_2',{'mesg_3':{'success':i10, 'fail':i0}} ] void LLMetricsImpl::recordEvent(const std::string& location, const std::string& mesg, bool success) { - LLSD& stats = mMetricsMap[location][mesg]; - if (success) - { - stats["success"] = stats["success"].asInteger() + 1; - } - else - { - stats["fail"] = stats["fail"].asInteger() + 1; - } + LLSD& stats = mMetricsMap[location][mesg]; + if (success) + { + stats["success"] = stats["success"].asInteger() + 1; + } + else + { + stats["fail"] = stats["fail"].asInteger() + 1; + } } // Print this: // { 'meta': -// { 'elapsed_time':r3600.000 } +// { 'elapsed_time':r3600.000 } // 'stats': -// [ {'location':'location_1', 'mesg':'mesg_1', 'success':i10, 'fail':i0}, -// {'location':'location_1', 'mesg':'mesg_2', 'success':i10, 'fail':i0}, -// {'location':'location_2', 'mesg':'mesg_3', 'success':i10, 'fail':i0} ] } +// [ {'location':'location_1', 'mesg':'mesg_1', 'success':i10, 'fail':i0}, +// {'location':'location_1', 'mesg':'mesg_2', 'success':i10, 'fail':i0}, +// {'location':'location_2', 'mesg':'mesg_3', 'success':i10, 'fail':i0} ] } void LLMetricsImpl::printTotals(LLSD metadata) { - F32 elapsed_time = mLastPrintTimer.getElapsedTimeAndResetF32(); - metadata["elapsed_time"] = elapsed_time; - - LLSD out_sd = LLSD::emptyMap(); - out_sd["meta"] = metadata; - - LLSD stats = LLSD::emptyArray(); - - LLSD::map_const_iterator loc_it = mMetricsMap.beginMap(); - LLSD::map_const_iterator loc_end = mMetricsMap.endMap(); - for ( ; loc_it != loc_end; ++loc_it) - { - const std::string& location = (*loc_it).first; - - const LLSD& loc_map = (*loc_it).second; - LLSD::map_const_iterator mesg_it = loc_map.beginMap(); - LLSD::map_const_iterator mesg_end = loc_map.endMap(); - for ( ; mesg_it != mesg_end; ++mesg_it) - { - const std::string& mesg = (*mesg_it).first; - const LLSD& mesg_map = (*mesg_it).second; - - LLSD entry = LLSD::emptyMap(); - entry["location"] = location; - entry["mesg"] = mesg; - entry["success"] = mesg_map["success"]; - entry["fail"] = mesg_map["fail"]; - - stats.append(entry); - } - } - - out_sd["stats"] = stats; - - LL_INFOS() << "LLMETRICS: AGGREGATE: " << LLSDOStreamer<LLSDNotationFormatter>(out_sd) << LL_ENDL; + F32 elapsed_time = mLastPrintTimer.getElapsedTimeAndResetF32(); + metadata["elapsed_time"] = elapsed_time; + + LLSD out_sd = LLSD::emptyMap(); + out_sd["meta"] = metadata; + + LLSD stats = LLSD::emptyArray(); + + LLSD::map_const_iterator loc_it = mMetricsMap.beginMap(); + LLSD::map_const_iterator loc_end = mMetricsMap.endMap(); + for ( ; loc_it != loc_end; ++loc_it) + { + const std::string& location = (*loc_it).first; + + const LLSD& loc_map = (*loc_it).second; + LLSD::map_const_iterator mesg_it = loc_map.beginMap(); + LLSD::map_const_iterator mesg_end = loc_map.endMap(); + for ( ; mesg_it != mesg_end; ++mesg_it) + { + const std::string& mesg = (*mesg_it).first; + const LLSD& mesg_map = (*mesg_it).second; + + LLSD entry = LLSD::emptyMap(); + entry["location"] = location; + entry["mesg"] = mesg; + entry["success"] = mesg_map["success"]; + entry["fail"] = mesg_map["fail"]; + + stats.append(entry); + } + } + + out_sd["stats"] = stats; + + LL_INFOS() << "LLMETRICS: AGGREGATE: " << LLSDOStreamer<LLSDNotationFormatter>(out_sd) << LL_ENDL; } LLMetrics::LLMetrics() { - mImpl = new LLMetricsImpl(); + mImpl = new LLMetricsImpl(); } LLMetrics::~LLMetrics() { - delete mImpl; - mImpl = NULL; + delete mImpl; + mImpl = NULL; } void LLMetrics::recordEvent(const std::string& location, const std::string& mesg, bool success) { - if (mImpl) mImpl->recordEvent(location,mesg,success); + if (mImpl) mImpl->recordEvent(location,mesg,success); } void LLMetrics::printTotals(LLSD meta) { - if (mImpl) mImpl->printTotals(meta); + if (mImpl) mImpl->printTotals(meta); } -void LLMetrics::recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats) +void LLMetrics::recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats) { - if (mImpl) mImpl->recordEventDetails(location,mesg,success,stats); + if (mImpl) mImpl->recordEventDetails(location,mesg,success,stats); } diff --git a/indra/llcommon/llmetrics.h b/indra/llcommon/llmetrics.h index 85a6986049..a6df49fc6a 100644 --- a/indra/llcommon/llmetrics.h +++ b/indra/llcommon/llmetrics.h @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,25 +35,25 @@ class LLSD; class LL_COMMON_API LLMetrics { public: - LLMetrics(); - virtual ~LLMetrics(); + LLMetrics(); + virtual ~LLMetrics(); - // Adds this event to aggregate totals and records details to syslog (LL_INFOS()) - virtual void recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats); + // Adds this event to aggregate totals and records details to syslog (LL_INFOS()) + virtual void recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats); - // Adds this event to aggregate totals - virtual void recordEvent(const std::string& location, const std::string& mesg, bool success); + // Adds this event to aggregate totals + virtual void recordEvent(const std::string& location, const std::string& mesg, bool success); - // Prints aggregate totals and resets the counts. - virtual void printTotals(LLSD meta); + // Prints aggregate totals and resets the counts. + virtual void printTotals(LLSD meta); private: - - LLMetricsImpl* mImpl; + + LLMetricsImpl* mImpl; }; #endif diff --git a/indra/llcommon/llmortician.cpp b/indra/llcommon/llmortician.cpp index b6ad40c2af..00d4a32553 100644 --- a/indra/llcommon/llmortician.cpp +++ b/indra/llcommon/llmortician.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llmortician.cpp * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,9 +32,9 @@ std::list<LLMortician*> LLMortician::sGraveyard; BOOL LLMortician::sDestroyImmediate = FALSE; -LLMortician::~LLMortician() +LLMortician::~LLMortician() { - sGraveyard.remove(this); + sGraveyard.remove(this); } size_t LLMortician::logClass(std::stringstream &str) @@ -73,34 +73,34 @@ size_t LLMortician::logClass(std::stringstream &str) return size; } -void LLMortician::updateClass() +void LLMortician::updateClass() { - while (!sGraveyard.empty()) - { - LLMortician* dead = sGraveyard.front(); - delete dead; - } + while (!sGraveyard.empty()) + { + LLMortician* dead = sGraveyard.front(); + delete dead; + } } -void LLMortician::die() +void LLMortician::die() { - // It is valid to call die() more than once on something that hasn't died yet - if (sDestroyImmediate) - { - // *NOTE: This is a hack to ensure destruction order on shutdown (relative to non-mortician controlled classes). - mIsDead = TRUE; - delete this; - return; - } - else if (!mIsDead) - { - mIsDead = TRUE; - sGraveyard.push_back(this); - } + // It is valid to call die() more than once on something that hasn't died yet + if (sDestroyImmediate) + { + // *NOTE: This is a hack to ensure destruction order on shutdown (relative to non-mortician controlled classes). + mIsDead = TRUE; + delete this; + return; + } + else if (!mIsDead) + { + mIsDead = TRUE; + sGraveyard.push_back(this); + } } // static void LLMortician::setZealous(BOOL b) { - sDestroyImmediate = b; + sDestroyImmediate = b; } diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h index f92c5a11db..6dca4da0c9 100644 --- a/indra/llcommon/llmortician.h +++ b/indra/llcommon/llmortician.h @@ -1,25 +1,25 @@ -/** +/** * @file llmortician.h * @brief Base class for delayed deletions. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,26 +30,26 @@ #include "stdtypes.h" #include <list> -class LL_COMMON_API LLMortician +class LL_COMMON_API LLMortician { public: - LLMortician() { mIsDead = FALSE; } - static auto graveyardCount() { return sGraveyard.size(); }; - static size_t logClass(std::stringstream &str); - static void updateClass(); - virtual ~LLMortician(); - void die(); - BOOL isDead() { return mIsDead; } + LLMortician() { mIsDead = FALSE; } + static auto graveyardCount() { return sGraveyard.size(); }; + static size_t logClass(std::stringstream &str); + static void updateClass(); + virtual ~LLMortician(); + void die(); + BOOL isDead() { return mIsDead; } - // sets destroy immediate true - static void setZealous(BOOL b); + // sets destroy immediate true + static void setZealous(BOOL b); private: - static BOOL sDestroyImmediate; + static BOOL sDestroyImmediate; - BOOL mIsDead; + BOOL mIsDead; - static std::list<LLMortician*> sGraveyard; + static std::list<LLMortician*> sGraveyard; }; #endif diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 0273dd5970..db14abb1fe 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llmutex.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,100 +45,100 @@ LLMutex::~LLMutex() void LLMutex::lock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(isSelfLocked()) - { //redundant lock - mCount++; - return; - } - - mMutex.lock(); - + if(isSelfLocked()) + { //redundant lock + mCount++; + return; + } + + mMutex.lock(); + #if MUTEX_DEBUG - // Have to have the lock before we can access the debug info - auto id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) - LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = TRUE; + // Have to have the lock before we can access the debug info + auto id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = TRUE; #endif - mLockingThread = LLThread::currentID(); + mLockingThread = LLThread::currentID(); } void LLMutex::unlock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if (mCount > 0) - { //not the root unlock - mCount--; - return; - } - + if (mCount > 0) + { //not the root unlock + mCount--; + return; + } + #if MUTEX_DEBUG - // Access the debug info while we have the lock - auto id = LLThread::currentID(); - if (mIsLocked[id] != TRUE) - LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = FALSE; + // Access the debug info while we have the lock + auto id = LLThread::currentID(); + if (mIsLocked[id] != TRUE) + LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = FALSE; #endif - mLockingThread = LLThread::id_t(); - mMutex.unlock(); + mLockingThread = LLThread::id_t(); + mMutex.unlock(); } bool LLMutex::isLocked() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if (!mMutex.try_lock()) - { - return true; - } - else - { - mMutex.unlock(); - return false; - } + if (!mMutex.try_lock()) + { + return true; + } + else + { + mMutex.unlock(); + return false; + } } bool LLMutex::isSelfLocked() { - return mLockingThread == LLThread::currentID(); + return mLockingThread == LLThread::currentID(); } LLThread::id_t LLMutex::lockingThread() const { - return mLockingThread; + return mLockingThread; } bool LLMutex::trylock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(isSelfLocked()) - { //redundant lock - mCount++; - return true; - } - - if (!mMutex.try_lock()) - { - return false; - } - + if(isSelfLocked()) + { //redundant lock + mCount++; + return true; + } + + if (!mMutex.try_lock()) + { + return false; + } + #if MUTEX_DEBUG - // Have to have the lock before we can access the debug info - auto id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) - LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = TRUE; + // Have to have the lock before we can access the debug info + auto id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = TRUE; #endif - mLockingThread = LLThread::currentID(); - return true; + mLockingThread = LLThread::currentID(); + return true; } //============================================================================ LLCondition::LLCondition() : - LLMutex() + LLMutex() { } @@ -151,20 +151,20 @@ LLCondition::~LLCondition() void LLCondition::wait() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - std::unique_lock< std::mutex > lock(mMutex); - mCond.wait(lock); + std::unique_lock< std::mutex > lock(mMutex); + mCond.wait(lock); } void LLCondition::signal() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - mCond.notify_one(); + mCond.notify_one(); } void LLCondition::broadcast() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - mCond.notify_all(); + mCond.notify_all(); } @@ -210,30 +210,30 @@ LLMutexTrylock::~LLMutexTrylock() LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex) { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(mutex) - { - mutex->lock(); - mLocked = true; - } - else - { - mLocked = false; - } + if(mutex) + { + mutex->lock(); + mLocked = true; + } + else + { + mLocked = false; + } } LLScopedLock::~LLScopedLock() { - unlock(); + unlock(); } void LLScopedLock::unlock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(mLocked) - { - mMutex->unlock(); - mLocked = false; - } + if(mLocked) + { + mMutex->unlock(); + mLocked = false; + } } //============================================================================ diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index 0d70da6178..9a888f1220 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -1,25 +1,25 @@ -/** +/** * @file llmutex.h * @brief Base classes for mutex and condition handling. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,23 +46,23 @@ class LL_COMMON_API LLMutex { public: - LLMutex(); - virtual ~LLMutex(); - - void lock(); // blocks - bool trylock(); // non-blocking, returns true if lock held. - void unlock(); // undefined behavior when called on mutex not being held - bool isLocked(); // non-blocking, but does do a lock/unlock so not free - bool isSelfLocked(); //return true if locked in a same thread - LLThread::id_t lockingThread() const; //get ID of locking thread + LLMutex(); + virtual ~LLMutex(); + + void lock(); // blocks + bool trylock(); // non-blocking, returns true if lock held. + void unlock(); // undefined behavior when called on mutex not being held + bool isLocked(); // non-blocking, but does do a lock/unlock so not free + bool isSelfLocked(); //return true if locked in a same thread + LLThread::id_t lockingThread() const; //get ID of locking thread protected: - std::mutex mMutex; - mutable U32 mCount; - mutable LLThread::id_t mLockingThread; - + std::mutex mMutex; + mutable U32 mCount; + mutable LLThread::id_t mLockingThread; + #if MUTEX_DEBUG - std::unordered_map<LLThread::id_t, BOOL> mIsLocked; + std::unordered_map<LLThread::id_t, BOOL> mIsLocked; #endif }; @@ -70,34 +70,34 @@ protected: class LL_COMMON_API LLCondition : public LLMutex { public: - LLCondition(); - ~LLCondition(); - - void wait(); // blocks - void signal(); - void broadcast(); - + LLCondition(); + ~LLCondition(); + + void wait(); // blocks + void signal(); + void broadcast(); + protected: - std::condition_variable mCond; + std::condition_variable mCond; }; class LLMutexLock { public: - LLMutexLock(LLMutex* mutex) - { - mMutex = mutex; - - if(mMutex) - mMutex->lock(); - } - ~LLMutexLock() - { - if(mMutex) - mMutex->unlock(); - } + LLMutexLock(LLMutex* mutex) + { + mMutex = mutex; + + if(mMutex) + mMutex->lock(); + } + ~LLMutexLock() + { + if(mMutex) + mMutex->unlock(); + } private: - LLMutex* mMutex; + LLMutex* mMutex; }; //============================================================================ @@ -113,18 +113,18 @@ private: class LLMutexTrylock { public: - LLMutexTrylock(LLMutex* mutex); - LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10); - ~LLMutexTrylock(); - - bool isLocked() const - { - return mLocked; - } - + LLMutexTrylock(LLMutex* mutex); + LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10); + ~LLMutexTrylock(); + + bool isLocked() const + { + return mLocked; + } + private: - LLMutex* mMutex; - bool mLocked; + LLMutex* mMutex; + bool mLocked; }; /** diff --git a/indra/llcommon/llnametable.h b/indra/llcommon/llnametable.h index 2c8e71263e..b3a9df8fc3 100644 --- a/indra/llcommon/llnametable.h +++ b/indra/llcommon/llnametable.h @@ -1,25 +1,25 @@ -/** +/** * @file llnametable.h * @brief LLNameTable class is a table to associate pointers with string names * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,69 +35,69 @@ template <class DATA> class LLNameTable { public: - LLNameTable() - : mNameMap() - { - } + LLNameTable() + : mNameMap() + { + } - ~LLNameTable() - { - } + ~LLNameTable() + { + } - void addEntry(const std::string& name, DATA data) - { - addEntry(name.c_str(), data); - } + void addEntry(const std::string& name, DATA data) + { + addEntry(name.c_str(), data); + } - void addEntry(const char *name, DATA data) - { - char *tablename = gStringTable.addString(name); - mNameMap[tablename] = data; - } + void addEntry(const char *name, DATA data) + { + char *tablename = gStringTable.addString(name); + mNameMap[tablename] = data; + } - BOOL checkName(const std::string& name) const - { - return checkName(name.c_str()); - } + BOOL checkName(const std::string& name) const + { + return checkName(name.c_str()); + } - // "logically const" even though it modifies the global nametable - BOOL checkName(const char *name) const - { - char *tablename = gStringTable.addString(name); - return mNameMap.count(tablename) ? TRUE : FALSE; - } + // "logically const" even though it modifies the global nametable + BOOL checkName(const char *name) const + { + char *tablename = gStringTable.addString(name); + return mNameMap.count(tablename) ? TRUE : FALSE; + } - DATA resolveName(const std::string& name) const - { - return resolveName(name.c_str()); - } + DATA resolveName(const std::string& name) const + { + return resolveName(name.c_str()); + } - // "logically const" even though it modifies the global nametable - DATA resolveName(const char *name) const - { - char *tablename = gStringTable.addString(name); - const_iter_t iter = mNameMap.find(tablename); - if (iter != mNameMap.end()) - return iter->second; - else - return 0; - } + // "logically const" even though it modifies the global nametable + DATA resolveName(const char *name) const + { + char *tablename = gStringTable.addString(name); + const_iter_t iter = mNameMap.find(tablename); + if (iter != mNameMap.end()) + return iter->second; + else + return 0; + } - // O(N)! (currently only used in one place... (newsim/llstate.cpp)) - const char *resolveData(const DATA &data) const - { - for (const name_map_t::value_type& pair : mNameMap) - { - if (pair.second == data) - return pair.first; - } - return NULL; - } + // O(N)! (currently only used in one place... (newsim/llstate.cpp)) + const char *resolveData(const DATA &data) const + { + for (const name_map_t::value_type& pair : mNameMap) + { + if (pair.second == data) + return pair.first; + } + return NULL; + } - typedef std::map<const char *, DATA> name_map_t; - typedef typename std::map<const char *,DATA>::iterator iter_t; - typedef typename std::map<const char *,DATA>::const_iterator const_iter_t; - name_map_t mNameMap; + typedef std::map<const char *, DATA> name_map_t; + typedef typename std::map<const char *,DATA>::iterator iter_t; + typedef typename std::map<const char *,DATA>::const_iterator const_iter_t; + name_map_t mNameMap; }; #endif diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 64aceddf32..f5916f9d58 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -1,32 +1,32 @@ -/** +/** * @file llpointer.h * @brief A reference-counted pointer for objects derived from LLRefCount * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLPOINTER_H #define LLPOINTER_H -#include "llerror.h" // *TODO: consider eliminating this +#include "llerror.h" // *TODO: consider eliminating this #include "llmutex.h" //---------------------------------------------------------------------------- @@ -46,299 +46,299 @@ template <class Type> class LLPointer { public: - LLPointer() : - mPointer(NULL) - { - } - - LLPointer(Type* ptr) : - mPointer(ptr) - { - ref(); - } - - LLPointer(const LLPointer<Type>& ptr) : - mPointer(ptr.mPointer) - { - ref(); - } - - // Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template<typename Subclass> - LLPointer(const LLPointer<Subclass>& ptr) : - mPointer(ptr.get()) - { - ref(); - } - - ~LLPointer() - { - unref(); - } - - Type* get() const { return mPointer; } - const Type* operator->() const { return mPointer; } - Type* operator->() { return mPointer; } - const Type& operator*() const { return *mPointer; } - Type& operator*() { return *mPointer; } - - operator BOOL() const { return (mPointer != NULL); } - operator bool() const { return (mPointer != NULL); } - bool operator!() const { return (mPointer == NULL); } - bool isNull() const { return (mPointer == NULL); } - bool notNull() const { return (mPointer != NULL); } - - operator Type*() const { return mPointer; } - bool operator !=(Type* ptr) const { return (mPointer != ptr); } - bool operator ==(Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); } - - LLPointer<Type>& operator =(Type* ptr) - { - assign(ptr); - return *this; - } - - LLPointer<Type>& operator =(const LLPointer<Type>& ptr) - { - assign(ptr); - 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) - { - assign(ptr.get()); - return *this; - } - - // Just exchange the pointers, which will not change the reference counts. - static void swap(LLPointer<Type>& a, LLPointer<Type>& b) - { - Type* temp = a.mPointer; - a.mPointer = b.mPointer; - b.mPointer = temp; - } + LLPointer() : + mPointer(NULL) + { + } + + LLPointer(Type* ptr) : + mPointer(ptr) + { + ref(); + } + + LLPointer(const LLPointer<Type>& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template<typename Subclass> + LLPointer(const LLPointer<Subclass>& ptr) : + mPointer(ptr.get()) + { + ref(); + } + + ~LLPointer() + { + unref(); + } + + Type* get() const { return mPointer; } + const Type* operator->() const { return mPointer; } + Type* operator->() { return mPointer; } + const Type& operator*() const { return *mPointer; } + Type& operator*() { return *mPointer; } + + operator BOOL() const { return (mPointer != NULL); } + operator bool() const { return (mPointer != NULL); } + bool operator!() const { return (mPointer == NULL); } + bool isNull() const { return (mPointer == NULL); } + bool notNull() const { return (mPointer != NULL); } + + operator Type*() const { return mPointer; } + bool operator !=(Type* ptr) const { return (mPointer != ptr); } + bool operator ==(Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); } + + LLPointer<Type>& operator =(Type* ptr) + { + assign(ptr); + return *this; + } + + LLPointer<Type>& operator =(const LLPointer<Type>& ptr) + { + assign(ptr); + 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) + { + assign(ptr.get()); + return *this; + } + + // Just exchange the pointers, which will not change the reference counts. + static void swap(LLPointer<Type>& a, LLPointer<Type>& b) + { + Type* temp = a.mPointer; + a.mPointer = b.mPointer; + b.mPointer = temp; + } protected: #ifdef LL_LIBRARY_INCLUDE - void ref(); - void unref(); + void ref(); + void unref(); #else - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - Type *temp = mPointer; - mPointer = NULL; - temp->unref(); - if (mPointer != NULL) - { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; - unref(); - } - } - } + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + Type *temp = mPointer; + mPointer = NULL; + temp->unref(); + if (mPointer != NULL) + { + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + unref(); + } + } + } #endif // LL_LIBRARY_INCLUDE - void assign(const LLPointer<Type>& ptr) - { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - } + void assign(const LLPointer<Type>& ptr) + { + if (mPointer != ptr.mPointer) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + } protected: - Type* mPointer; + Type* mPointer; }; template <class Type> class LLConstPointer { public: - LLConstPointer() : - mPointer(NULL) - { - } - - LLConstPointer(const Type* ptr) : - mPointer(ptr) - { - ref(); - } - - LLConstPointer(const LLConstPointer<Type>& ptr) : - mPointer(ptr.mPointer) - { - ref(); - } - - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template<typename Subclass> - LLConstPointer(const LLConstPointer<Subclass>& ptr) : - mPointer(ptr.get()) - { - ref(); - } - - ~LLConstPointer() - { - unref(); - } - - const Type* get() const { return mPointer; } - const Type* operator->() const { return mPointer; } - const Type& operator*() const { return *mPointer; } - - operator BOOL() const { return (mPointer != NULL); } - operator bool() const { return (mPointer != NULL); } - bool operator!() const { return (mPointer == NULL); } - bool isNull() const { return (mPointer == NULL); } - bool notNull() const { return (mPointer != NULL); } - - operator const Type*() const { return mPointer; } - bool operator !=(const Type* ptr) const { return (mPointer != ptr); } - bool operator ==(const Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLConstPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLConstPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLConstPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); } - - LLConstPointer<Type>& operator =(const Type* ptr) - { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - - return *this; - } - - LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr) - { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template<typename Subclass> - LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr) - { - if( mPointer != ptr.get() ) - { - unref(); - mPointer = ptr.get(); - ref(); - } - return *this; - } - - // Just exchange the pointers, which will not change the reference counts. - static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b) - { - const Type* temp = a.mPointer; - a.mPointer = b.mPointer; - b.mPointer = temp; - } + LLConstPointer() : + mPointer(NULL) + { + } + + LLConstPointer(const Type* ptr) : + mPointer(ptr) + { + ref(); + } + + LLConstPointer(const LLConstPointer<Type>& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template<typename Subclass> + LLConstPointer(const LLConstPointer<Subclass>& ptr) : + mPointer(ptr.get()) + { + ref(); + } + + ~LLConstPointer() + { + unref(); + } + + const Type* get() const { return mPointer; } + const Type* operator->() const { return mPointer; } + const Type& operator*() const { return *mPointer; } + + operator BOOL() const { return (mPointer != NULL); } + operator bool() const { return (mPointer != NULL); } + bool operator!() const { return (mPointer == NULL); } + bool isNull() const { return (mPointer == NULL); } + bool notNull() const { return (mPointer != NULL); } + + operator const Type*() const { return mPointer; } + bool operator !=(const Type* ptr) const { return (mPointer != ptr); } + bool operator ==(const Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLConstPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLConstPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLConstPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); } + + LLConstPointer<Type>& operator =(const Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = ptr; + ref(); + } + + return *this; + } + + LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr) + { + if( mPointer != ptr.mPointer ) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template<typename Subclass> + LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr) + { + if( mPointer != ptr.get() ) + { + unref(); + mPointer = ptr.get(); + ref(); + } + return *this; + } + + // Just exchange the pointers, which will not change the reference counts. + static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b) + { + const Type* temp = a.mPointer; + a.mPointer = b.mPointer; + b.mPointer = temp; + } protected: #ifdef LL_LIBRARY_INCLUDE - void ref(); - void unref(); + void ref(); + void unref(); #else // LL_LIBRARY_INCLUDE - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - const Type *temp = mPointer; - mPointer = NULL; - temp->unref(); - if (mPointer != NULL) - { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; - unref(); - } - } - } + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + const Type *temp = mPointer; + mPointer = NULL; + temp->unref(); + if (mPointer != NULL) + { + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + unref(); + } + } + } #endif // LL_LIBRARY_INCLUDE protected: - const Type* mPointer; + const Type* mPointer; }; template<typename Type> class LLCopyOnWritePointer : public LLPointer<Type> { public: - typedef LLCopyOnWritePointer<Type> self_t; - typedef LLPointer<Type> pointer_t; - - LLCopyOnWritePointer() - : mStayUnique(false) - {} - - LLCopyOnWritePointer(Type* ptr) - : LLPointer<Type>(ptr), - mStayUnique(false) - {} - - LLCopyOnWritePointer(LLPointer<Type>& ptr) - : LLPointer<Type>(ptr), - mStayUnique(false) - { - if (ptr.mForceUnique) - { - makeUnique(); - } - } - - Type* write() - { - makeUnique(); - return pointer_t::mPointer; - } - - void makeUnique() - { - if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) - { - *(pointer_t* )(this) = new Type(*pointer_t::mPointer); - } - } - - const Type* operator->() const { return pointer_t::mPointer; } - const Type& operator*() const { return *pointer_t::mPointer; } - - void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } + typedef LLCopyOnWritePointer<Type> self_t; + typedef LLPointer<Type> pointer_t; + + LLCopyOnWritePointer() + : mStayUnique(false) + {} + + LLCopyOnWritePointer(Type* ptr) + : LLPointer<Type>(ptr), + mStayUnique(false) + {} + + LLCopyOnWritePointer(LLPointer<Type>& ptr) + : LLPointer<Type>(ptr), + mStayUnique(false) + { + if (ptr.mForceUnique) + { + makeUnique(); + } + } + + Type* write() + { + makeUnique(); + return pointer_t::mPointer; + } + + void makeUnique() + { + if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) + { + *(pointer_t* )(this) = new Type(*pointer_t::mPointer); + } + } + + const Type* operator->() const { return pointer_t::mPointer; } + const Type& operator*() const { return *pointer_t::mPointer; } + + void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } private: - bool mStayUnique; + bool mStayUnique; }; diff --git a/indra/llcommon/llpredicate.cpp b/indra/llcommon/llpredicate.cpp index 1278948e24..fe80b77b63 100644 --- a/indra/llcommon/llpredicate.cpp +++ b/indra/llcommon/llpredicate.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpredicate.cpp * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,13 +29,13 @@ namespace LLPredicate { - const U32 cPredicateFlagsFromEnum[5] = - { - 0xAAAAaaaa, // 10101010101010101010101010101010 - 0xCCCCcccc, // 11001100110011001100110011001100 - 0xF0F0F0F0, // 11110000111100001111000011110000 - 0xFF00FF00, // 11111111000000001111111100000000 - 0xFFFF0000 // 11111111111111110000000000000000 - }; + const U32 cPredicateFlagsFromEnum[5] = + { + 0xAAAAaaaa, // 10101010101010101010101010101010 + 0xCCCCcccc, // 11001100110011001100110011001100 + 0xF0F0F0F0, // 11110000111100001111000011110000 + 0xFF00FF00, // 11111111000000001111111100000000 + 0xFFFF0000 // 11111111111111110000000000000000 + }; } diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h index e6c56a5711..7c6874d279 100644 --- a/indra/llcommon/llpredicate.h +++ b/indra/llcommon/llpredicate.h @@ -1,25 +1,25 @@ -/** +/** * @file llpredicate.h * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,179 +31,179 @@ namespace LLPredicate { - template<typename ENUM> class Rule; - - extern const U32 cPredicateFlagsFromEnum[5]; - - template<typename ENUM> - class Value - { - public: - typedef U32 predicate_flag_t; - static const S32 cMaxEnum = 5; - - Value(ENUM e, bool predicate_value = true) - : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e]) - { - llassert(0 <= e && e < cMaxEnum); - } - - Value() - : mPredicateFlags(0xFFFFffff) - {} - - Value operator!() const - { - Value new_value; - new_value.mPredicateFlags = ~mPredicateFlags; - return new_value; - } - - Value operator &&(const Value other) const - { - Value new_value; - new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags; - return new_value; - } - - Value operator ||(const Value other) const - { - Value new_value; - new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags; - return new_value; - } - - void set(ENUM e, bool value = true) - { - llassert(0 <= e && e < cMaxEnum); - predicate_flag_t flags_to_modify; - predicate_flag_t mask = cPredicateFlagsFromEnum[e]; - if (value) - { // add predicate "e" to flags that don't contain it already - flags_to_modify = (mPredicateFlags & ~mask); - // clear flags not containing e - mPredicateFlags &= mask; - // add back flags shifted to contain e - mPredicateFlags |= flags_to_modify << (0x1 << e); - } - else - { // remove predicate "e" from flags that contain it - flags_to_modify = (mPredicateFlags & mask); - // clear flags containing e - mPredicateFlags &= ~mask; - // add back flags shifted to not contain e - mPredicateFlags |= flags_to_modify >> (0x1 << e); - } - } - - void forget(ENUM e) - { - set(e, true); - U32 flags_with_predicate = mPredicateFlags; - set(e, false); - // ambiguous value is result of adding and removing predicate at the same time! - mPredicateFlags |= flags_with_predicate; - } - - bool allSet() const - { - return mPredicateFlags == ~0; - } - - bool noneSet() const - { - return mPredicateFlags == 0; - } - - bool someSet() const - { - return mPredicateFlags != 0; - } - - private: - predicate_flag_t mPredicateFlags; - }; - - template<typename ENUM> - class Rule - { - public: - Rule(ENUM value) - : mRule(value) - {} - - Rule(const Value<ENUM> other) - : mRule(other) - {} - - Rule() - {} - - void require(ENUM e, bool match) - { - mRule.set(e, match); - } - - void allow(ENUM e) - { - mRule.forget(e); - } - - bool check(const Value<ENUM> value) const - { - return (mRule && value).someSet(); - } - - bool requires(const Value<ENUM> value) const - { - return (mRule && value).someSet() && (!mRule && value).noneSet(); - } - - bool isAmbivalent(const Value<ENUM> value) const - { - return (mRule && value).someSet() && (!mRule && value).someSet(); - } - - bool acceptsAll() const - { - return mRule.allSet(); - } - - bool acceptsNone() const - { - return mRule.noneSet(); - } - - Rule operator!() const - { - Rule new_rule; - new_rule.mRule = !mRule; - return new_rule; - } - - Rule operator &&(const Rule other) const - { - Rule new_rule; - new_rule.mRule = mRule && other.mRule; - return new_rule; - } - - Rule operator ||(const Rule other) const - { - Rule new_rule; - new_rule.mRule = mRule || other.mRule; - return new_rule; - } - - private: - Value<ENUM> mRule; - }; + template<typename ENUM> class Rule; + + extern const U32 cPredicateFlagsFromEnum[5]; + + template<typename ENUM> + class Value + { + public: + typedef U32 predicate_flag_t; + static const S32 cMaxEnum = 5; + + Value(ENUM e, bool predicate_value = true) + : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e]) + { + llassert(0 <= e && e < cMaxEnum); + } + + Value() + : mPredicateFlags(0xFFFFffff) + {} + + Value operator!() const + { + Value new_value; + new_value.mPredicateFlags = ~mPredicateFlags; + return new_value; + } + + Value operator &&(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags; + return new_value; + } + + Value operator ||(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags; + return new_value; + } + + void set(ENUM e, bool value = true) + { + llassert(0 <= e && e < cMaxEnum); + predicate_flag_t flags_to_modify; + predicate_flag_t mask = cPredicateFlagsFromEnum[e]; + if (value) + { // add predicate "e" to flags that don't contain it already + flags_to_modify = (mPredicateFlags & ~mask); + // clear flags not containing e + mPredicateFlags &= mask; + // add back flags shifted to contain e + mPredicateFlags |= flags_to_modify << (0x1 << e); + } + else + { // remove predicate "e" from flags that contain it + flags_to_modify = (mPredicateFlags & mask); + // clear flags containing e + mPredicateFlags &= ~mask; + // add back flags shifted to not contain e + mPredicateFlags |= flags_to_modify >> (0x1 << e); + } + } + + void forget(ENUM e) + { + set(e, true); + U32 flags_with_predicate = mPredicateFlags; + set(e, false); + // ambiguous value is result of adding and removing predicate at the same time! + mPredicateFlags |= flags_with_predicate; + } + + bool allSet() const + { + return mPredicateFlags == ~0; + } + + bool noneSet() const + { + return mPredicateFlags == 0; + } + + bool someSet() const + { + return mPredicateFlags != 0; + } + + private: + predicate_flag_t mPredicateFlags; + }; + + template<typename ENUM> + class Rule + { + public: + Rule(ENUM value) + : mRule(value) + {} + + Rule(const Value<ENUM> other) + : mRule(other) + {} + + Rule() + {} + + void require(ENUM e, bool match) + { + mRule.set(e, match); + } + + void allow(ENUM e) + { + mRule.forget(e); + } + + bool check(const Value<ENUM> value) const + { + return (mRule && value).someSet(); + } + + bool requires(const Value<ENUM> value) const + { + return (mRule && value).someSet() && (!mRule && value).noneSet(); + } + + bool isAmbivalent(const Value<ENUM> value) const + { + return (mRule && value).someSet() && (!mRule && value).someSet(); + } + + bool acceptsAll() const + { + return mRule.allSet(); + } + + bool acceptsNone() const + { + return mRule.noneSet(); + } + + Rule operator!() const + { + Rule new_rule; + new_rule.mRule = !mRule; + return new_rule; + } + + Rule operator &&(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule && other.mRule; + return new_rule; + } + + Rule operator ||(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule || other.mRule; + return new_rule; + } + + private: + Value<ENUM> mRule; + }; } template<typename ENUM> LLPredicate::Value<ENUM> ll_make_predicate(ENUM e, bool predicate_value = true) { - return LLPredicate::Value<ENUM>(e, predicate_value); + return LLPredicate::Value<ENUM>(e, predicate_value); } diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index dc586b0008..a54408a852 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -1,4 +1,4 @@ -/** +/** * @file llpreprocessor.h * @brief This file should be included in all Linden Lab files and * should only contain special preprocessor directives @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #ifdef LL_LINUX #define __ENABLE_WSTRING #include <endian.h> -#endif // LL_LINUX +#endif // LL_LINUX #if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__))) #define LL_LITTLE_ENDIAN 1 @@ -64,31 +64,31 @@ // Figure out differences between compilers #if defined(__GNUC__) - #define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - #ifndef LL_GNUC - #define LL_GNUC 1 - #endif + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + #ifndef LL_GNUC + #define LL_GNUC 1 + #endif #elif defined(__MSVC_VER__) || defined(_MSC_VER) - #ifndef LL_MSVC - #define LL_MSVC 1 - #endif - #if _MSC_VER < 1400 - #define LL_MSVC7 //Visual C++ 2003 or earlier - #endif + #ifndef LL_MSVC + #define LL_MSVC 1 + #endif + #if _MSC_VER < 1400 + #define LL_MSVC7 //Visual C++ 2003 or earlier + #endif #endif // Deal with minor differences on Unixy OSes. #if LL_DARWIN || LL_LINUX - // Different name, same functionality. - #define stricmp strcasecmp - #define strnicmp strncasecmp + // Different name, same functionality. + #define stricmp strcasecmp + #define strnicmp strncasecmp - // Not sure why this is different, but... - #ifndef MAX_PATH - #define MAX_PATH PATH_MAX - #endif // not MAX_PATH + // Not sure why this is different, but... + #ifndef MAX_PATH + #define MAX_PATH PATH_MAX + #endif // not MAX_PATH #endif @@ -117,33 +117,33 @@ #ifndef XML_STATIC #define XML_STATIC #endif -#endif // LL_WINDOWS +#endif // LL_WINDOWS // Deal with VC6 problems #if LL_MSVC -#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. -#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. -#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. -//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. -#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function -#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" -#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" -#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden -#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored -//#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file +#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. +#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. +#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. +//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. +#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function +#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" +#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" +#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden +#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored +//#pragma warning( disable : 4284 ) // silly MS warning deep inside their <map> include file #if ADDRESS_SIZE == 64 // That one is all over the place for x64 builds. #pragma warning( disable : 4267 ) // 'var' : conversion from 'size_t' to 'type', possible loss of data) #endif -#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. -#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) -#pragma warning( disable : 4996 ) // warning: deprecated +#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. +#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable : 4996 ) // warning: deprecated // Linker optimization with "extern template" generates these warnings -#pragma warning( disable : 4231 ) // nonstandard extension used : 'extern' before template explicit instantiation +#pragma warning( disable : 4231 ) // nonstandard extension used : 'extern' before template explicit instantiation #pragma warning( disable : 4506 ) // no definition for inline function // level 4 warnings that we need to disable: @@ -156,9 +156,9 @@ #pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class #pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class -#pragma warning (disable : 4018) // '<' : signed/unsigned mismatch +#pragma warning (disable : 4018) // '<' : signed/unsigned mismatch -#endif // LL_MSVC +#endif // LL_MSVC #if LL_WINDOWS #define LL_DLLEXPORT __declspec(dllexport) @@ -232,4 +232,4 @@ #define LL_PRETTY_FUNCTION __PRETTY_FUNCTION__ #endif -#endif // not LL_LINDEN_PREPROCESSOR_H +#endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llpriqueuemap.h b/indra/llcommon/llpriqueuemap.h index 030e2e0f21..79934d094b 100644 --- a/indra/llcommon/llpriqueuemap.h +++ b/indra/llcommon/llpriqueuemap.h @@ -1,25 +1,25 @@ -/** +/** * @file llpriqueuemap.h * @brief Priority queue implementation * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,107 +39,107 @@ template <class DATA> class LLPQMKey { public: - LLPQMKey(const F32 priority, DATA data) : mPriority(priority), mData(data) - { - } - - bool operator<(const LLPQMKey &b) const - { - if (mPriority > b.mPriority) - { - return TRUE; - } - if (mPriority < b.mPriority) - { - return FALSE; - } - if (mData > b.mData) - { - return TRUE; - } - return FALSE; - } - - F32 mPriority; - DATA mData; + LLPQMKey(const F32 priority, DATA data) : mPriority(priority), mData(data) + { + } + + bool operator<(const LLPQMKey &b) const + { + if (mPriority > b.mPriority) + { + return TRUE; + } + if (mPriority < b.mPriority) + { + return FALSE; + } + if (mData > b.mData) + { + return TRUE; + } + return FALSE; + } + + F32 mPriority; + DATA mData; }; template <class DATA_TYPE> class LLPriQueueMap { public: - typedef typename std::map<LLPQMKey<DATA_TYPE>, DATA_TYPE>::iterator pqm_iter; - typedef std::pair<LLPQMKey<DATA_TYPE>, DATA_TYPE> pqm_pair; - typedef void (*set_pri_fn)(DATA_TYPE &data, const F32 priority); - typedef F32 (*get_pri_fn)(DATA_TYPE &data); + typedef typename std::map<LLPQMKey<DATA_TYPE>, DATA_TYPE>::iterator pqm_iter; + typedef std::pair<LLPQMKey<DATA_TYPE>, DATA_TYPE> pqm_pair; + typedef void (*set_pri_fn)(DATA_TYPE &data, const F32 priority); + typedef F32 (*get_pri_fn)(DATA_TYPE &data); - LLPriQueueMap(set_pri_fn set_pri, get_pri_fn get_pri) : mSetPriority(set_pri), mGetPriority(get_pri) - { - } + LLPriQueueMap(set_pri_fn set_pri, get_pri_fn get_pri) : mSetPriority(set_pri), mGetPriority(get_pri) + { + } - void push(const F32 priority, DATA_TYPE data) - { + void push(const F32 priority, DATA_TYPE data) + { #ifdef _DEBUG - pqm_iter iter = mMap.find(LLPQMKey<DATA_TYPE>(priority, data)); - if (iter != mMap.end()) - { - LL_ERRS() << "Pushing already existing data onto queue!" << LL_ENDL; - } + pqm_iter iter = mMap.find(LLPQMKey<DATA_TYPE>(priority, data)); + if (iter != mMap.end()) + { + LL_ERRS() << "Pushing already existing data onto queue!" << LL_ENDL; + } #endif - mMap.insert(pqm_pair(LLPQMKey<DATA_TYPE>(priority, data), data)); - } - - BOOL pop(DATA_TYPE *datap) - { - pqm_iter iter; - iter = mMap.begin(); - if (iter == mMap.end()) - { - return FALSE; - } - *datap = (*(iter)).second; - mMap.erase(iter); - - return TRUE; - } - - void reprioritize(const F32 new_priority, DATA_TYPE data) - { - pqm_iter iter; - F32 cur_priority = mGetPriority(data); - LLPQMKey<DATA_TYPE> cur_key(cur_priority, data); - iter = mMap.find(cur_key); - if (iter == mMap.end()) - { - LL_WARNS() << "Data not on priority queue!" << LL_ENDL; - // OK, try iterating through all of the data and seeing if we just screwed up the priority - // somehow. - for (pqm_pair pair : mMap) - { - if (pair.second == data) - { - LL_ERRS() << "Data on priority queue but priority not matched!" << LL_ENDL; - } - } - return; - } - - mMap.erase(iter); - mSetPriority(data, new_priority); - push(new_priority, data); - } - - S32 getLength() const - { - return (S32)mMap.size(); - } - - // Hack: public for use by the transfer manager, ugh. - std::map<LLPQMKey<DATA_TYPE>, DATA_TYPE> mMap; + mMap.insert(pqm_pair(LLPQMKey<DATA_TYPE>(priority, data), data)); + } + + BOOL pop(DATA_TYPE *datap) + { + pqm_iter iter; + iter = mMap.begin(); + if (iter == mMap.end()) + { + return FALSE; + } + *datap = (*(iter)).second; + mMap.erase(iter); + + return TRUE; + } + + void reprioritize(const F32 new_priority, DATA_TYPE data) + { + pqm_iter iter; + F32 cur_priority = mGetPriority(data); + LLPQMKey<DATA_TYPE> cur_key(cur_priority, data); + iter = mMap.find(cur_key); + if (iter == mMap.end()) + { + LL_WARNS() << "Data not on priority queue!" << LL_ENDL; + // OK, try iterating through all of the data and seeing if we just screwed up the priority + // somehow. + for (pqm_pair pair : mMap) + { + if (pair.second == data) + { + LL_ERRS() << "Data on priority queue but priority not matched!" << LL_ENDL; + } + } + return; + } + + mMap.erase(iter); + mSetPriority(data, new_priority); + push(new_priority, data); + } + + S32 getLength() const + { + return (S32)mMap.size(); + } + + // Hack: public for use by the transfer manager, ugh. + std::map<LLPQMKey<DATA_TYPE>, DATA_TYPE> mMap; protected: - void (*mSetPriority)(DATA_TYPE &data, const F32 priority); - F32 (*mGetPriority)(DATA_TYPE &data); + void (*mSetPriority)(DATA_TYPE &data, const F32 priority); + F32 (*mGetPriority)(DATA_TYPE &data); }; #endif // LL_LLPRIQUEUEMAP_H diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 0d6a147da3..2208b33b94 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocess.cpp * @brief Utility class for launching, terminating, and tracking the state of processes. * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -57,9 +57,9 @@ static std::string getDesc(const LLProcess::Params& params); static std::string whichfile(LLProcess::FILESLOT index) { - if (index < LL_ARRAY_SIZE(whichfile_)) - return whichfile_[index]; - return STRINGIZE("file slot " << index); + if (index < LL_ARRAY_SIZE(whichfile_)) + return whichfile_[index]; + return STRINGIZE("file slot " << index); } /** @@ -69,64 +69,64 @@ static std::string whichfile(LLProcess::FILESLOT index) */ class LLProcessListener { - LOG_CLASS(LLProcessListener); + LOG_CLASS(LLProcessListener); public: - LLProcessListener(): - mCount(0) - {} - - void addPoll(const LLProcess&) - { - // Unconditionally increment mCount. If it was zero before - // incrementing, listen on "mainloop". - if (mCount++ == 0) - { - LL_DEBUGS("LLProcess") << "listening on \"mainloop\"" << LL_ENDL; - mConnection = LLEventPumps::instance().obtain("mainloop") - .listen("LLProcessListener", boost::bind(&LLProcessListener::tick, this, _1)); - } - } - - void dropPoll(const LLProcess&) - { - // Unconditionally decrement mCount. If it's zero after decrementing, - // stop listening on "mainloop". - if (--mCount == 0) - { - LL_DEBUGS("LLProcess") << "disconnecting from \"mainloop\"" << LL_ENDL; - mConnection.disconnect(); - } - } + LLProcessListener(): + mCount(0) + {} + + void addPoll(const LLProcess&) + { + // Unconditionally increment mCount. If it was zero before + // incrementing, listen on "mainloop". + if (mCount++ == 0) + { + LL_DEBUGS("LLProcess") << "listening on \"mainloop\"" << LL_ENDL; + mConnection = LLEventPumps::instance().obtain("mainloop") + .listen("LLProcessListener", boost::bind(&LLProcessListener::tick, this, _1)); + } + } + + void dropPoll(const LLProcess&) + { + // Unconditionally decrement mCount. If it's zero after decrementing, + // stop listening on "mainloop". + if (--mCount == 0) + { + LL_DEBUGS("LLProcess") << "disconnecting from \"mainloop\"" << LL_ENDL; + mConnection.disconnect(); + } + } private: - /// called once per frame by the "mainloop" LLEventPump - bool tick(const LLSD&) - { - // Tell APR to sense whether each registered LLProcess is still - // running and call handle_status() appropriately. We should be able - // to get the same info from an apr_proc_wait(APR_NOWAIT) call; but at - // least in APR 1.4.2, testing suggests that even with APR_NOWAIT, - // apr_proc_wait() blocks the caller. We can't have that in the - // viewer. Hence the callback rigmarole. (Once we update APR, it's - // probably worth testing again.) Also -- although there's an - // apr_proc_other_child_refresh() call, i.e. get that information for - // one specific child, it accepts an 'apr_other_child_rec_t*' that's - // mentioned NOWHERE else in the documentation or header files! I - // would use the specific call in LLProcess::getStatus() if I knew - // how. As it is, each call to apr_proc_other_child_refresh_all() will - // call callbacks for ALL still-running child processes. That's why we - // centralize such calls, using "mainloop" to ensure it happens once - // per frame, and refcounting running LLProcess objects to remain - // registered only while needed. - LL_DEBUGS("LLProcess") << "calling apr_proc_other_child_refresh_all()" << LL_ENDL; - apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); - return false; - } - - /// If this object is destroyed before mCount goes to zero, stop - /// listening on "mainloop" anyway. - LLTempBoundListener mConnection; - unsigned mCount; + /// called once per frame by the "mainloop" LLEventPump + bool tick(const LLSD&) + { + // Tell APR to sense whether each registered LLProcess is still + // running and call handle_status() appropriately. We should be able + // to get the same info from an apr_proc_wait(APR_NOWAIT) call; but at + // least in APR 1.4.2, testing suggests that even with APR_NOWAIT, + // apr_proc_wait() blocks the caller. We can't have that in the + // viewer. Hence the callback rigmarole. (Once we update APR, it's + // probably worth testing again.) Also -- although there's an + // apr_proc_other_child_refresh() call, i.e. get that information for + // one specific child, it accepts an 'apr_other_child_rec_t*' that's + // mentioned NOWHERE else in the documentation or header files! I + // would use the specific call in LLProcess::getStatus() if I knew + // how. As it is, each call to apr_proc_other_child_refresh_all() will + // call callbacks for ALL still-running child processes. That's why we + // centralize such calls, using "mainloop" to ensure it happens once + // per frame, and refcounting running LLProcess objects to remain + // registered only while needed. + LL_DEBUGS("LLProcess") << "calling apr_proc_other_child_refresh_all()" << LL_ENDL; + apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); + return false; + } + + /// If this object is destroyed before mCount goes to zero, stop + /// listening on "mainloop" anyway. + LLTempBoundListener mConnection; + unsigned mCount; }; static LLProcessListener sProcessListener; @@ -135,141 +135,141 @@ static LLProcessListener sProcessListener; *****************************************************************************/ LLProcess::BasePipe::~BasePipe() {} const LLProcess::BasePipe::size_type - // use funky syntax to call max() to avoid blighted max() macros - LLProcess::BasePipe::npos((std::numeric_limits<LLProcess::BasePipe::size_type>::max)()); + // use funky syntax to call max() to avoid blighted max() macros + LLProcess::BasePipe::npos((std::numeric_limits<LLProcess::BasePipe::size_type>::max)()); class WritePipeImpl: public LLProcess::WritePipe { - LOG_CLASS(WritePipeImpl); + LOG_CLASS(WritePipeImpl); public: - WritePipeImpl(const std::string& desc, apr_file_t* pipe): - mDesc(desc), - mPipe(pipe), - // Essential to initialize our std::ostream with our special streambuf! - mStream(&mStreambuf) - { - mConnection = LLEventPumps::instance().obtain("mainloop") - .listen(LLEventPump::inventName("WritePipe"), - boost::bind(&WritePipeImpl::tick, this, _1)); + WritePipeImpl(const std::string& desc, apr_file_t* pipe): + mDesc(desc), + mPipe(pipe), + // Essential to initialize our std::ostream with our special streambuf! + mStream(&mStreambuf) + { + mConnection = LLEventPumps::instance().obtain("mainloop") + .listen(LLEventPump::inventName("WritePipe"), + boost::bind(&WritePipeImpl::tick, this, _1)); #if ! LL_WINDOWS - // We can't count on every child process reading everything we try to - // write to it. And if the child terminates with WritePipe data still - // pending, unless we explicitly suppress it, Posix will hit us with - // SIGPIPE. That would terminate the viewer, boom. "Ignoring" it means - // APR gets the correct errno, passes it back to us, we log it, etc. - signal(SIGPIPE, SIG_IGN); + // We can't count on every child process reading everything we try to + // write to it. And if the child terminates with WritePipe data still + // pending, unless we explicitly suppress it, Posix will hit us with + // SIGPIPE. That would terminate the viewer, boom. "Ignoring" it means + // APR gets the correct errno, passes it back to us, we log it, etc. + signal(SIGPIPE, SIG_IGN); #endif - } - - virtual std::ostream& get_ostream() { return mStream; } - virtual size_type size() const { return mStreambuf.size(); } - - bool tick(const LLSD&) - { - typedef boost::asio::streambuf::const_buffers_type const_buffer_sequence; - // If there's anything to send, try to send it. - std::size_t total(mStreambuf.size()), consumed(0); - if (total) - { - const_buffer_sequence bufs = mStreambuf.data(); - // In general, our streambuf might contain a number of different - // physical buffers; iterate over those. - bool keepwriting = true; - for (const_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); - bufi != bufend && keepwriting; ++bufi) - { - // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents - // Although apr_file_write() accepts const void*, we - // manipulate const char* so we can increment the pointer. - const char* remainptr = boost::asio::buffer_cast<const char*>(*bufi); - std::size_t remainlen = boost::asio::buffer_size(*bufi); - while (remainlen) - { - // Tackle the current buffer in discrete chunks. On - // Windows, we've observed strange failures when trying to - // write big lengths (~1 MB) in a single operation. Even a - // 32K chunk seems too large. At some point along the way - // apr_file_write() returns 11 (Resource temporarily - // unavailable, i.e. EAGAIN) and says it wrote 0 bytes -- - // even though it did write the chunk! Our next write - // attempt retries with the same chunk, resulting in the - // chunk being duplicated at the child end. Using smaller - // chunks is empirically more reliable. - std::size_t towrite((std::min)(remainlen, std::size_t(4*1024))); - apr_size_t written(towrite); - apr_status_t err = apr_file_write(mPipe, remainptr, &written); - // EAGAIN is exactly what we want from a nonblocking pipe. - // Rather than waiting for data, it should return immediately. - if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) - { - LL_WARNS("LLProcess") << "apr_file_write(" << towrite << ") on " << mDesc - << " got " << err << ":" << LL_ENDL; - ll_apr_warn_status(err); - } - - // 'written' is modified to reflect the number of bytes actually - // written. Make sure we consume those later. (Don't consume them - // now, that would invalidate the buffer iterator sequence!) - consumed += written; - // don't forget to advance to next chunk of current buffer - remainptr += written; - remainlen -= written; - - char msgbuf[512]; - LL_DEBUGS("LLProcess") << "wrote " << written << " of " << towrite - << " bytes to " << mDesc - << " (original " << total << ")," - << " code " << err << ": " - << apr_strerror(err, msgbuf, sizeof(msgbuf)) - << LL_ENDL; - - // The parent end of this pipe is nonblocking. If we weren't able - // to write everything we wanted, don't keep banging on it -- that - // won't change until the child reads some. Wait for next tick(). - if (written < towrite) - { - keepwriting = false; // break outer loop over buffers too - break; - } - } // next chunk of current buffer - } // next buffer - // In all, we managed to write 'consumed' bytes. Remove them from the - // streambuf so we don't keep trying to send them. This could be - // anywhere from 0 up to mStreambuf.size(); anything we haven't yet - // sent, we'll try again later. - mStreambuf.consume(consumed); - } - - return false; - } + } + + virtual std::ostream& get_ostream() { return mStream; } + virtual size_type size() const { return mStreambuf.size(); } + + bool tick(const LLSD&) + { + typedef boost::asio::streambuf::const_buffers_type const_buffer_sequence; + // If there's anything to send, try to send it. + std::size_t total(mStreambuf.size()), consumed(0); + if (total) + { + const_buffer_sequence bufs = mStreambuf.data(); + // In general, our streambuf might contain a number of different + // physical buffers; iterate over those. + bool keepwriting = true; + for (const_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); + bufi != bufend && keepwriting; ++bufi) + { + // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents + // Although apr_file_write() accepts const void*, we + // manipulate const char* so we can increment the pointer. + const char* remainptr = boost::asio::buffer_cast<const char*>(*bufi); + std::size_t remainlen = boost::asio::buffer_size(*bufi); + while (remainlen) + { + // Tackle the current buffer in discrete chunks. On + // Windows, we've observed strange failures when trying to + // write big lengths (~1 MB) in a single operation. Even a + // 32K chunk seems too large. At some point along the way + // apr_file_write() returns 11 (Resource temporarily + // unavailable, i.e. EAGAIN) and says it wrote 0 bytes -- + // even though it did write the chunk! Our next write + // attempt retries with the same chunk, resulting in the + // chunk being duplicated at the child end. Using smaller + // chunks is empirically more reliable. + std::size_t towrite((std::min)(remainlen, std::size_t(4*1024))); + apr_size_t written(towrite); + apr_status_t err = apr_file_write(mPipe, remainptr, &written); + // EAGAIN is exactly what we want from a nonblocking pipe. + // Rather than waiting for data, it should return immediately. + if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) + { + LL_WARNS("LLProcess") << "apr_file_write(" << towrite << ") on " << mDesc + << " got " << err << ":" << LL_ENDL; + ll_apr_warn_status(err); + } + + // 'written' is modified to reflect the number of bytes actually + // written. Make sure we consume those later. (Don't consume them + // now, that would invalidate the buffer iterator sequence!) + consumed += written; + // don't forget to advance to next chunk of current buffer + remainptr += written; + remainlen -= written; + + char msgbuf[512]; + LL_DEBUGS("LLProcess") << "wrote " << written << " of " << towrite + << " bytes to " << mDesc + << " (original " << total << ")," + << " code " << err << ": " + << apr_strerror(err, msgbuf, sizeof(msgbuf)) + << LL_ENDL; + + // The parent end of this pipe is nonblocking. If we weren't able + // to write everything we wanted, don't keep banging on it -- that + // won't change until the child reads some. Wait for next tick(). + if (written < towrite) + { + keepwriting = false; // break outer loop over buffers too + break; + } + } // next chunk of current buffer + } // next buffer + // In all, we managed to write 'consumed' bytes. Remove them from the + // streambuf so we don't keep trying to send them. This could be + // anywhere from 0 up to mStreambuf.size(); anything we haven't yet + // sent, we'll try again later. + mStreambuf.consume(consumed); + } + + return false; + } private: - std::string mDesc; - apr_file_t* mPipe; - LLTempBoundListener mConnection; - boost::asio::streambuf mStreambuf; - std::ostream mStream; + std::string mDesc; + apr_file_t* mPipe; + LLTempBoundListener mConnection; + boost::asio::streambuf mStreambuf; + std::ostream mStream; }; class ReadPipeImpl: public LLProcess::ReadPipe { - LOG_CLASS(ReadPipeImpl); + LOG_CLASS(ReadPipeImpl); public: - ReadPipeImpl(const std::string& desc, apr_file_t* pipe, LLProcess::FILESLOT index): - mDesc(desc), - mPipe(pipe), - mIndex(index), - // Essential to initialize our std::istream with our special streambuf! - mStream(&mStreambuf), - mPump("ReadPipe", true), // tweak name as needed to avoid collisions - mLimit(0), - mEOF(false) - { - mConnection = LLEventPumps::instance().obtain("mainloop") - .listen(LLEventPump::inventName("ReadPipe"), - boost::bind(&ReadPipeImpl::tick, this, _1)); - } + ReadPipeImpl(const std::string& desc, apr_file_t* pipe, LLProcess::FILESLOT index): + mDesc(desc), + mPipe(pipe), + mIndex(index), + // Essential to initialize our std::istream with our special streambuf! + mStream(&mStreambuf), + mPump("ReadPipe", true), // tweak name as needed to avoid collisions + mLimit(0), + mEOF(false) + { + mConnection = LLEventPumps::instance().obtain("mainloop") + .listen(LLEventPump::inventName("ReadPipe"), + boost::bind(&ReadPipeImpl::tick, this, _1)); + } ~ReadPipeImpl() { @@ -279,200 +279,200 @@ public: } } - // Much of the implementation is simply connecting the abstract virtual - // methods with implementation data concealed from the base class. - virtual std::istream& get_istream() { return mStream; } - virtual std::string getline() { return LLProcess::getline(mStream); } - virtual LLEventPump& getPump() { return mPump; } - virtual void setLimit(size_type limit) { mLimit = limit; } - virtual size_type getLimit() const { return mLimit; } - virtual size_type size() const { return mStreambuf.size(); } - - virtual std::string read(size_type len) - { - // Read specified number of bytes into a buffer. - size_type readlen((std::min)(size(), len)); - // Formally, &buffer[0] is invalid for a vector of size() 0. Exit - // early in that situation. - if (! readlen) - return ""; - // Make a buffer big enough. - std::vector<char> buffer(readlen); - mStream.read(&buffer[0], readlen); - // Since we've already clamped 'readlen', we can think of no reason - // why mStream.read() should read fewer than 'readlen' bytes. - // Nonetheless, use the actual retrieved length. - return std::string(&buffer[0], mStream.gcount()); - } - - virtual std::string peek(size_type offset=0, size_type len=npos) const - { - // Constrain caller's offset and len to overlap actual buffer content. - std::size_t real_offset = (std::min)(mStreambuf.size(), std::size_t(offset)); - size_type want_end = (len == npos)? npos : (real_offset + len); - std::size_t real_end = (std::min)(mStreambuf.size(), std::size_t(want_end)); - boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); - return std::string(boost::asio::buffers_begin(cbufs) + real_offset, - boost::asio::buffers_begin(cbufs) + real_end); - } - - virtual size_type find(const std::string& seek, size_type offset=0) const - { - // If we're passing a string of length 1, use find(char), which can - // use an O(n) std::find() rather than the O(n^2) std::search(). - if (seek.length() == 1) - { - return find(seek[0], offset); - } - - // If offset is beyond the whole buffer, can't even construct a valid - // iterator range; can't possibly find the string we seek. - if (offset > mStreambuf.size()) - { - return npos; - } - - boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); - boost::asio::buffers_iterator<boost::asio::streambuf::const_buffers_type> - begin(boost::asio::buffers_begin(cbufs)), - end (boost::asio::buffers_end(cbufs)), - found(std::search(begin + offset, end, seek.begin(), seek.end())); - return (found == end)? npos : (found - begin); - } - - virtual size_type find(char seek, size_type offset=0) const - { - // If offset is beyond the whole buffer, can't even construct a valid - // iterator range; can't possibly find the char we seek. - if (offset > mStreambuf.size()) - { - return npos; - } - - boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); - boost::asio::buffers_iterator<boost::asio::streambuf::const_buffers_type> - begin(boost::asio::buffers_begin(cbufs)), - end (boost::asio::buffers_end(cbufs)), - found(std::find(begin + offset, end, seek)); - return (found == end)? npos : (found - begin); - } - - bool tick(const LLSD&) - { - // Once we've hit EOF, skip all the rest of this. - if (mEOF) - return false; - - typedef boost::asio::streambuf::mutable_buffers_type mutable_buffer_sequence; - // Try, every time, to read into our streambuf. In fact, we have no - // idea how much data the child might be trying to send: keep trying - // until we're convinced we've temporarily exhausted the pipe. - enum PipeState { RETRY, EXHAUSTED, CLOSED }; - PipeState state = RETRY; - std::size_t committed(0); - do - { - // attempt to read an arbitrary size - mutable_buffer_sequence bufs = mStreambuf.prepare(4096); - // In general, the mutable_buffer_sequence returned by prepare() might - // contain a number of different physical buffers; iterate over those. - std::size_t tocommit(0); - for (mutable_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); - bufi != bufend; ++bufi) - { - // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents - std::size_t toread(boost::asio::buffer_size(*bufi)); - apr_size_t gotten(toread); - apr_status_t err = apr_file_read(mPipe, - boost::asio::buffer_cast<void*>(*bufi), - &gotten); - // EAGAIN is exactly what we want from a nonblocking pipe. - // Rather than waiting for data, it should return immediately. - if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) - { - // Handle EOF specially: it's part of normal-case processing. - if (err == APR_EOF) - { - LL_DEBUGS("LLProcess") << "EOF on " << mDesc << LL_ENDL; - } - else - { - LL_WARNS("LLProcess") << "apr_file_read(" << toread << ") on " << mDesc - << " got " << err << ":" << LL_ENDL; - ll_apr_warn_status(err); - } - // Either way, though, we won't need any more tick() calls. - mConnection.disconnect(); - // Ignore any subsequent calls we might get anyway. - mEOF = true; - state = CLOSED; // also break outer retry loop - break; - } - - // 'gotten' was modified to reflect the number of bytes actually - // received. Make sure we commit those later. (Don't commit them - // now, that would invalidate the buffer iterator sequence!) - tocommit += gotten; - LL_DEBUGS("LLProcess") << "filled " << gotten << " of " << toread - << " bytes from " << mDesc << LL_ENDL; - - // The parent end of this pipe is nonblocking. If we weren't even - // able to fill this buffer, don't loop to try to fill the next -- - // that won't change until the child writes more. Wait for next - // tick(). - if (gotten < toread) - { - // break outer retry loop too - state = EXHAUSTED; - break; - } - } - - // Don't forget to "commit" the data! - mStreambuf.commit(tocommit); - committed += tocommit; - - // state is changed from RETRY when we can't fill any one buffer - // of the mutable_buffer_sequence established by the current - // prepare() call -- whether due to error or not enough bytes. - // That is, if state is still RETRY, we've filled every physical - // buffer in the mutable_buffer_sequence. In that case, for all we - // know, the child might have still more data pending -- go for it! - } while (state == RETRY); - - // Once we recognize that the pipe is closed, make one more call to - // listener. The listener might be waiting for a particular substring - // to arrive, or a particular length of data or something. The event - // with "eof" == true announces that nothing further will arrive, so - // use it or lose it. - if (committed || state == CLOSED) - { - // If we actually received new data, publish it on our LLEventPump - // as advertised. Constrain it by mLimit. But show listener the - // actual accumulated buffer size, regardless of mLimit. - size_type datasize((std::min)(mLimit, size_type(mStreambuf.size()))); - mPump.post(LLSDMap - ("data", peek(0, datasize)) - ("len", LLSD::Integer(mStreambuf.size())) - ("slot", LLSD::Integer(mIndex)) - ("name", whichfile(mIndex)) - ("desc", mDesc) - ("eof", state == CLOSED)); - } - - return false; - } + // Much of the implementation is simply connecting the abstract virtual + // methods with implementation data concealed from the base class. + virtual std::istream& get_istream() { return mStream; } + virtual std::string getline() { return LLProcess::getline(mStream); } + virtual LLEventPump& getPump() { return mPump; } + virtual void setLimit(size_type limit) { mLimit = limit; } + virtual size_type getLimit() const { return mLimit; } + virtual size_type size() const { return mStreambuf.size(); } + + virtual std::string read(size_type len) + { + // Read specified number of bytes into a buffer. + size_type readlen((std::min)(size(), len)); + // Formally, &buffer[0] is invalid for a vector of size() 0. Exit + // early in that situation. + if (! readlen) + return ""; + // Make a buffer big enough. + std::vector<char> buffer(readlen); + mStream.read(&buffer[0], readlen); + // Since we've already clamped 'readlen', we can think of no reason + // why mStream.read() should read fewer than 'readlen' bytes. + // Nonetheless, use the actual retrieved length. + return std::string(&buffer[0], mStream.gcount()); + } + + virtual std::string peek(size_type offset=0, size_type len=npos) const + { + // Constrain caller's offset and len to overlap actual buffer content. + std::size_t real_offset = (std::min)(mStreambuf.size(), std::size_t(offset)); + size_type want_end = (len == npos)? npos : (real_offset + len); + std::size_t real_end = (std::min)(mStreambuf.size(), std::size_t(want_end)); + boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); + return std::string(boost::asio::buffers_begin(cbufs) + real_offset, + boost::asio::buffers_begin(cbufs) + real_end); + } + + virtual size_type find(const std::string& seek, size_type offset=0) const + { + // If we're passing a string of length 1, use find(char), which can + // use an O(n) std::find() rather than the O(n^2) std::search(). + if (seek.length() == 1) + { + return find(seek[0], offset); + } + + // If offset is beyond the whole buffer, can't even construct a valid + // iterator range; can't possibly find the string we seek. + if (offset > mStreambuf.size()) + { + return npos; + } + + boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); + boost::asio::buffers_iterator<boost::asio::streambuf::const_buffers_type> + begin(boost::asio::buffers_begin(cbufs)), + end (boost::asio::buffers_end(cbufs)), + found(std::search(begin + offset, end, seek.begin(), seek.end())); + return (found == end)? npos : (found - begin); + } + + virtual size_type find(char seek, size_type offset=0) const + { + // If offset is beyond the whole buffer, can't even construct a valid + // iterator range; can't possibly find the char we seek. + if (offset > mStreambuf.size()) + { + return npos; + } + + boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); + boost::asio::buffers_iterator<boost::asio::streambuf::const_buffers_type> + begin(boost::asio::buffers_begin(cbufs)), + end (boost::asio::buffers_end(cbufs)), + found(std::find(begin + offset, end, seek)); + return (found == end)? npos : (found - begin); + } + + bool tick(const LLSD&) + { + // Once we've hit EOF, skip all the rest of this. + if (mEOF) + return false; + + typedef boost::asio::streambuf::mutable_buffers_type mutable_buffer_sequence; + // Try, every time, to read into our streambuf. In fact, we have no + // idea how much data the child might be trying to send: keep trying + // until we're convinced we've temporarily exhausted the pipe. + enum PipeState { RETRY, EXHAUSTED, CLOSED }; + PipeState state = RETRY; + std::size_t committed(0); + do + { + // attempt to read an arbitrary size + mutable_buffer_sequence bufs = mStreambuf.prepare(4096); + // In general, the mutable_buffer_sequence returned by prepare() might + // contain a number of different physical buffers; iterate over those. + std::size_t tocommit(0); + for (mutable_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); + bufi != bufend; ++bufi) + { + // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents + std::size_t toread(boost::asio::buffer_size(*bufi)); + apr_size_t gotten(toread); + apr_status_t err = apr_file_read(mPipe, + boost::asio::buffer_cast<void*>(*bufi), + &gotten); + // EAGAIN is exactly what we want from a nonblocking pipe. + // Rather than waiting for data, it should return immediately. + if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) + { + // Handle EOF specially: it's part of normal-case processing. + if (err == APR_EOF) + { + LL_DEBUGS("LLProcess") << "EOF on " << mDesc << LL_ENDL; + } + else + { + LL_WARNS("LLProcess") << "apr_file_read(" << toread << ") on " << mDesc + << " got " << err << ":" << LL_ENDL; + ll_apr_warn_status(err); + } + // Either way, though, we won't need any more tick() calls. + mConnection.disconnect(); + // Ignore any subsequent calls we might get anyway. + mEOF = true; + state = CLOSED; // also break outer retry loop + break; + } + + // 'gotten' was modified to reflect the number of bytes actually + // received. Make sure we commit those later. (Don't commit them + // now, that would invalidate the buffer iterator sequence!) + tocommit += gotten; + LL_DEBUGS("LLProcess") << "filled " << gotten << " of " << toread + << " bytes from " << mDesc << LL_ENDL; + + // The parent end of this pipe is nonblocking. If we weren't even + // able to fill this buffer, don't loop to try to fill the next -- + // that won't change until the child writes more. Wait for next + // tick(). + if (gotten < toread) + { + // break outer retry loop too + state = EXHAUSTED; + break; + } + } + + // Don't forget to "commit" the data! + mStreambuf.commit(tocommit); + committed += tocommit; + + // state is changed from RETRY when we can't fill any one buffer + // of the mutable_buffer_sequence established by the current + // prepare() call -- whether due to error or not enough bytes. + // That is, if state is still RETRY, we've filled every physical + // buffer in the mutable_buffer_sequence. In that case, for all we + // know, the child might have still more data pending -- go for it! + } while (state == RETRY); + + // Once we recognize that the pipe is closed, make one more call to + // listener. The listener might be waiting for a particular substring + // to arrive, or a particular length of data or something. The event + // with "eof" == true announces that nothing further will arrive, so + // use it or lose it. + if (committed || state == CLOSED) + { + // If we actually received new data, publish it on our LLEventPump + // as advertised. Constrain it by mLimit. But show listener the + // actual accumulated buffer size, regardless of mLimit. + size_type datasize((std::min)(mLimit, size_type(mStreambuf.size()))); + mPump.post(LLSDMap + ("data", peek(0, datasize)) + ("len", LLSD::Integer(mStreambuf.size())) + ("slot", LLSD::Integer(mIndex)) + ("name", whichfile(mIndex)) + ("desc", mDesc) + ("eof", state == CLOSED)); + } + + return false; + } private: - std::string mDesc; - apr_file_t* mPipe; - LLProcess::FILESLOT mIndex; - LLTempBoundListener mConnection; - boost::asio::streambuf mStreambuf; - std::istream mStream; - LLEventStream mPump; - size_type mLimit; - bool mEOF; + std::string mDesc; + apr_file_t* mPipe; + LLProcess::FILESLOT mIndex; + LLTempBoundListener mConnection; + boost::asio::streambuf mStreambuf; + std::istream mStream; + LLEventStream mPump; + size_type mLimit; + bool mEOF; }; /***************************************************************************** @@ -482,72 +482,72 @@ private: /// internal use only struct LLProcessError: public LLException { - LLProcessError(const std::string& msg): LLException(msg) {} + LLProcessError(const std::string& msg): LLException(msg) {} }; LLProcessPtr LLProcess::create(const LLSDOrParams& params) { - try - { - return LLProcessPtr(new LLProcess(params)); - } - catch (const LLProcessError& e) - { - LL_WARNS("LLProcess") << e.what() << LL_ENDL; - - // If caller is requesting an event on process termination, send one - // indicating bad launch. This may prevent someone waiting forever for - // a termination post that can't arrive because the child never - // started. - if (params.postend.isProvided()) - { - LLEventPumps::instance().obtain(params.postend) - .post(LLSDMap - // no "id" - ("desc", getDesc(params)) - ("state", LLProcess::UNSTARTED) - // no "data" - ("string", e.what()) - ); - } - - return LLProcessPtr(); - } + try + { + return LLProcessPtr(new LLProcess(params)); + } + catch (const LLProcessError& e) + { + LL_WARNS("LLProcess") << e.what() << LL_ENDL; + + // If caller is requesting an event on process termination, send one + // indicating bad launch. This may prevent someone waiting forever for + // a termination post that can't arrive because the child never + // started. + if (params.postend.isProvided()) + { + LLEventPumps::instance().obtain(params.postend) + .post(LLSDMap + // no "id" + ("desc", getDesc(params)) + ("state", LLProcess::UNSTARTED) + // no "data" + ("string", e.what()) + ); + } + + return LLProcessPtr(); + } } /// Call an apr function returning apr_status_t. On failure, log warning and /// throw LLProcessError mentioning the function call that produced that /// result. #define chkapr(func) \ - if (ll_apr_warn_status(func)) \ - throw LLProcessError(#func " failed") + if (ll_apr_warn_status(func)) \ + throw LLProcessError(#func " failed") LLProcess::LLProcess(const LLSDOrParams& params): - mAutokill(params.autokill), - // Because 'autokill' originally meant both 'autokill' and 'attached', to - // preserve existing semantics, we promise that mAttached defaults to the - // same setting as mAutokill. - mAttached(params.attached.isProvided()? params.attached : params.autokill), + mAutokill(params.autokill), + // Because 'autokill' originally meant both 'autokill' and 'attached', to + // preserve existing semantics, we promise that mAttached defaults to the + // same setting as mAutokill. + mAttached(params.attached.isProvided()? params.attached : params.autokill), mPool(NULL), - mPipes(NSLOTS) + mPipes(NSLOTS) { - // Hmm, when you construct a ptr_vector with a size, it merely reserves - // space, it doesn't actually make it that big. Explicitly make it bigger. - // Because of ptr_vector's odd semantics, have to push_back(0) the right - // number of times! resize() wants to default-construct new BasePipe - // instances, which fails because it's pure virtual. But because of the - // constructor call, these push_back() calls should require no new - // allocation. - for (size_t i = 0; i < mPipes.capacity(); ++i) - mPipes.push_back(0); - - if (! params.validateBlock(true)) - { - LLTHROW(LLProcessError(STRINGIZE("not launched: failed parameter validation\n" - << LLSDNotationStreamer(params)))); - } - - mPostend = params.postend; + // Hmm, when you construct a ptr_vector with a size, it merely reserves + // space, it doesn't actually make it that big. Explicitly make it bigger. + // Because of ptr_vector's odd semantics, have to push_back(0) the right + // number of times! resize() wants to default-construct new BasePipe + // instances, which fails because it's pure virtual. But because of the + // constructor call, these push_back() calls should require no new + // allocation. + for (size_t i = 0; i < mPipes.capacity(); ++i) + mPipes.push_back(0); + + if (! params.validateBlock(true)) + { + LLTHROW(LLProcessError(STRINGIZE("not launched: failed parameter validation\n" + << LLSDNotationStreamer(params)))); + } + + mPostend = params.postend; apr_pool_create(&mPool, gAPRPoolp); if (!mPool) @@ -555,272 +555,272 @@ LLProcess::LLProcess(const LLSDOrParams& params): LLTHROW(LLProcessError(STRINGIZE("failed to create apr pool"))); } - apr_procattr_t *procattr = NULL; - chkapr(apr_procattr_create(&procattr, mPool)); - - // IQA-490, CHOP-900: On Windows, ask APR to jump through hoops to - // constrain the set of handles passed to the child process. Before we - // changed to APR, the Windows implementation of LLProcessLauncher called - // CreateProcess(bInheritHandles=FALSE), meaning to pass NO open handles - // to the child process. Now that we support pipes, though, we must allow - // apr_proc_create() to pass bInheritHandles=TRUE. But without taking - // special pains, that causes trouble in a number of ways, due to the fact - // that the viewer is constantly opening and closing files -- most of - // which CreateProcess() passes to every child process! + apr_procattr_t *procattr = NULL; + chkapr(apr_procattr_create(&procattr, mPool)); + + // IQA-490, CHOP-900: On Windows, ask APR to jump through hoops to + // constrain the set of handles passed to the child process. Before we + // changed to APR, the Windows implementation of LLProcessLauncher called + // CreateProcess(bInheritHandles=FALSE), meaning to pass NO open handles + // to the child process. Now that we support pipes, though, we must allow + // apr_proc_create() to pass bInheritHandles=TRUE. But without taking + // special pains, that causes trouble in a number of ways, due to the fact + // that the viewer is constantly opening and closing files -- most of + // which CreateProcess() passes to every child process! #if ! defined(APR_HAS_PROCATTR_CONSTRAIN_HANDLE_SET) - // Our special preprocessor symbol isn't even defined -- wrong APR - LL_WARNS("LLProcess") << "This version of APR lacks Linden " - << "apr_procattr_constrain_handle_set() extension" << LL_ENDL; + // Our special preprocessor symbol isn't even defined -- wrong APR + LL_WARNS("LLProcess") << "This version of APR lacks Linden " + << "apr_procattr_constrain_handle_set() extension" << LL_ENDL; #else - chkapr(apr_procattr_constrain_handle_set(procattr, 1)); + chkapr(apr_procattr_constrain_handle_set(procattr, 1)); #endif - // For which of stdin, stdout, stderr should we create a pipe to the - // child? In the viewer, there are only a couple viable - // apr_procattr_io_set() alternatives: inherit the viewer's own stdxxx - // handle (APR_NO_PIPE, e.g. for stdout, stderr), or create a pipe that's - // blocking on the child end but nonblocking at the viewer end - // (APR_CHILD_BLOCK). - // Other major options could include explicitly creating a single APR pipe - // and passing it as both stdout and stderr (apr_procattr_child_out_set(), - // apr_procattr_child_err_set()), or accepting a filename, opening it and - // passing that apr_file_t (simple <, >, 2> redirect emulation). - std::vector<apr_int32_t> select; - for (const FileParam& fparam : params.files) - { - // Every iteration, we're going to append an item to 'select'. At the - // top of the loop, its size() is, in effect, an index. Use that to - // pick a string description for messages. - std::string which(whichfile(FILESLOT(select.size()))); - if (fparam.type().empty()) // inherit our file descriptor - { - select.push_back(APR_NO_PIPE); - } - else if (fparam.type() == "pipe") // anonymous pipe - { - if (! fparam.name().empty()) - { - LL_WARNS("LLProcess") << "For " << params.executable() - << ": internal names for reusing pipes ('" - << fparam.name() << "' for " << which - << ") are not yet supported -- creating distinct pipe" - << LL_ENDL; - } - // The viewer can't block for anything: the parent end MUST be - // nonblocking. As the APR documentation itself points out, it - // makes very little sense to set nonblocking I/O for the child - // end of a pipe: only a specially-written child could deal with - // that. - select.push_back(APR_CHILD_BLOCK); - } - else - { - LLTHROW(LLProcessError(STRINGIZE("For " << params.executable() - << ": unsupported FileParam for " << which - << ": type='" << fparam.type() - << "', name='" << fparam.name() << "'"))); - } - } - // By default, pass APR_NO_PIPE for unspecified slots. - while (select.size() < NSLOTS) - { - select.push_back(APR_NO_PIPE); - } - chkapr(apr_procattr_io_set(procattr, select[STDIN], select[STDOUT], select[STDERR])); - - // Thumbs down on implicitly invoking the shell to invoke the child. From - // our point of view, the other major alternative to APR_PROGRAM_PATH - // would be APR_PROGRAM_ENV: still copy environment, but require full - // executable pathname. I don't see a downside to searching the PATH, - // though: if our caller wants (e.g.) a specific Python interpreter, s/he - // can still pass the full pathname. - chkapr(apr_procattr_cmdtype_set(procattr, APR_PROGRAM_PATH)); - // YES, do extra work if necessary to report child exec() failures back to - // parent process. - chkapr(apr_procattr_error_check_set(procattr, 1)); - // Do not start a non-autokill child in detached state. On Posix - // platforms, this setting attempts to daemonize the new child, closing - // std handles and the like, and that's a bit more detachment than we - // want. autokill=false just means not to implicitly kill the child when - // the parent terminates! -// chkapr(apr_procattr_detach_set(procattr, mAutokill? 0 : 1)); - - if (mAutokill) - { + // For which of stdin, stdout, stderr should we create a pipe to the + // child? In the viewer, there are only a couple viable + // apr_procattr_io_set() alternatives: inherit the viewer's own stdxxx + // handle (APR_NO_PIPE, e.g. for stdout, stderr), or create a pipe that's + // blocking on the child end but nonblocking at the viewer end + // (APR_CHILD_BLOCK). + // Other major options could include explicitly creating a single APR pipe + // and passing it as both stdout and stderr (apr_procattr_child_out_set(), + // apr_procattr_child_err_set()), or accepting a filename, opening it and + // passing that apr_file_t (simple <, >, 2> redirect emulation). + std::vector<apr_int32_t> select; + for (const FileParam& fparam : params.files) + { + // Every iteration, we're going to append an item to 'select'. At the + // top of the loop, its size() is, in effect, an index. Use that to + // pick a string description for messages. + std::string which(whichfile(FILESLOT(select.size()))); + if (fparam.type().empty()) // inherit our file descriptor + { + select.push_back(APR_NO_PIPE); + } + else if (fparam.type() == "pipe") // anonymous pipe + { + if (! fparam.name().empty()) + { + LL_WARNS("LLProcess") << "For " << params.executable() + << ": internal names for reusing pipes ('" + << fparam.name() << "' for " << which + << ") are not yet supported -- creating distinct pipe" + << LL_ENDL; + } + // The viewer can't block for anything: the parent end MUST be + // nonblocking. As the APR documentation itself points out, it + // makes very little sense to set nonblocking I/O for the child + // end of a pipe: only a specially-written child could deal with + // that. + select.push_back(APR_CHILD_BLOCK); + } + else + { + LLTHROW(LLProcessError(STRINGIZE("For " << params.executable() + << ": unsupported FileParam for " << which + << ": type='" << fparam.type() + << "', name='" << fparam.name() << "'"))); + } + } + // By default, pass APR_NO_PIPE for unspecified slots. + while (select.size() < NSLOTS) + { + select.push_back(APR_NO_PIPE); + } + chkapr(apr_procattr_io_set(procattr, select[STDIN], select[STDOUT], select[STDERR])); + + // Thumbs down on implicitly invoking the shell to invoke the child. From + // our point of view, the other major alternative to APR_PROGRAM_PATH + // would be APR_PROGRAM_ENV: still copy environment, but require full + // executable pathname. I don't see a downside to searching the PATH, + // though: if our caller wants (e.g.) a specific Python interpreter, s/he + // can still pass the full pathname. + chkapr(apr_procattr_cmdtype_set(procattr, APR_PROGRAM_PATH)); + // YES, do extra work if necessary to report child exec() failures back to + // parent process. + chkapr(apr_procattr_error_check_set(procattr, 1)); + // Do not start a non-autokill child in detached state. On Posix + // platforms, this setting attempts to daemonize the new child, closing + // std handles and the like, and that's a bit more detachment than we + // want. autokill=false just means not to implicitly kill the child when + // the parent terminates! +// chkapr(apr_procattr_detach_set(procattr, mAutokill? 0 : 1)); + + if (mAutokill) + { #if ! defined(APR_HAS_PROCATTR_AUTOKILL_SET) - // Our special preprocessor symbol isn't even defined -- wrong APR - LL_WARNS("LLProcess") << "This version of APR lacks Linden apr_procattr_autokill_set() extension" << LL_ENDL; + // Our special preprocessor symbol isn't even defined -- wrong APR + LL_WARNS("LLProcess") << "This version of APR lacks Linden apr_procattr_autokill_set() extension" << LL_ENDL; #elif ! APR_HAS_PROCATTR_AUTOKILL_SET - // Symbol is defined, but to 0: expect apr_procattr_autokill_set() to - // return APR_ENOTIMPL. + // Symbol is defined, but to 0: expect apr_procattr_autokill_set() to + // return APR_ENOTIMPL. #else // APR_HAS_PROCATTR_AUTOKILL_SET nonzero - ll_apr_warn_status(apr_procattr_autokill_set(procattr, 1)); + ll_apr_warn_status(apr_procattr_autokill_set(procattr, 1)); #endif - } - - // In preparation for calling apr_proc_create(), we collect a number of - // const char* pointers obtained from std::string::c_str(). Turns out - // LLInitParam::Block's helpers Optional, Mandatory, Multiple et al. - // guarantee that converting to the wrapped type (std::string in our - // case), e.g. by calling operator(), returns a reference to *the same - // instance* of the wrapped type that's stored in our Block subclass. - // That's important! We know 'params' persists throughout this method - // call; but without that guarantee, we'd have to assume that converting - // one of its members to std::string might return a different (temp) - // instance. Capturing the c_str() from a temporary std::string is Bad Bad - // Bad. But armed with this knowledge, when you see params.cwd().c_str(), - // grit your teeth and smile and carry on. - - if (params.cwd.isProvided()) - { - chkapr(apr_procattr_dir_set(procattr, params.cwd().c_str())); - } - - // create an argv vector for the child process - std::vector<const char*> argv; - - // Add the executable path. See above remarks about c_str(). - argv.push_back(params.executable().c_str()); - - // Add arguments. See above remarks about c_str(). - for (const std::string& arg : params.args) - { - argv.push_back(arg.c_str()); - } - - // terminate with a null pointer - argv.push_back(NULL); - - // Launch! The NULL would be the environment block, if we were passing - // one. Hand-expand chkapr() macro so we can fill in the actual command - // string instead of the variable names. - if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr, - mPool))) - { - LLTHROW(LLProcessError(STRINGIZE(params << " failed"))); - } - - // arrange to call status_callback() - apr_proc_other_child_register(&mProcess, &LLProcess::status_callback, this, mProcess.in, + } + + // In preparation for calling apr_proc_create(), we collect a number of + // const char* pointers obtained from std::string::c_str(). Turns out + // LLInitParam::Block's helpers Optional, Mandatory, Multiple et al. + // guarantee that converting to the wrapped type (std::string in our + // case), e.g. by calling operator(), returns a reference to *the same + // instance* of the wrapped type that's stored in our Block subclass. + // That's important! We know 'params' persists throughout this method + // call; but without that guarantee, we'd have to assume that converting + // one of its members to std::string might return a different (temp) + // instance. Capturing the c_str() from a temporary std::string is Bad Bad + // Bad. But armed with this knowledge, when you see params.cwd().c_str(), + // grit your teeth and smile and carry on. + + if (params.cwd.isProvided()) + { + chkapr(apr_procattr_dir_set(procattr, params.cwd().c_str())); + } + + // create an argv vector for the child process + std::vector<const char*> argv; + + // Add the executable path. See above remarks about c_str(). + argv.push_back(params.executable().c_str()); + + // Add arguments. See above remarks about c_str(). + for (const std::string& arg : params.args) + { + argv.push_back(arg.c_str()); + } + + // terminate with a null pointer + argv.push_back(NULL); + + // Launch! The NULL would be the environment block, if we were passing + // one. Hand-expand chkapr() macro so we can fill in the actual command + // string instead of the variable names. + if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr, + mPool))) + { + LLTHROW(LLProcessError(STRINGIZE(params << " failed"))); + } + + // arrange to call status_callback() + apr_proc_other_child_register(&mProcess, &LLProcess::status_callback, this, mProcess.in, mPool); - // and make sure we poll it once per "mainloop" tick - sProcessListener.addPoll(*this); - mStatus.mState = RUNNING; - - mDesc = STRINGIZE(getDesc(params) << " (" << mProcess.pid << ')'); - LL_INFOS("LLProcess") << mDesc << ": launched " << params << LL_ENDL; - - // Unless caller explicitly turned off autokill (child should persist), - // take steps to terminate the child. This is all suspenders-and-belt: in - // theory our destructor should kill an autokill child, but in practice - // that doesn't always work (e.g. VWR-21538). - if (mAutokill) - { + // and make sure we poll it once per "mainloop" tick + sProcessListener.addPoll(*this); + mStatus.mState = RUNNING; + + mDesc = STRINGIZE(getDesc(params) << " (" << mProcess.pid << ')'); + LL_INFOS("LLProcess") << mDesc << ": launched " << params << LL_ENDL; + + // Unless caller explicitly turned off autokill (child should persist), + // take steps to terminate the child. This is all suspenders-and-belt: in + // theory our destructor should kill an autokill child, but in practice + // that doesn't always work (e.g. VWR-21538). + if (mAutokill) + { /*==========================================================================*| - // NO: There may be an APR bug, not sure -- but at least on Mac, when - // gAPRPoolp is destroyed, OUR process receives SIGTERM! Apparently - // either our own PID is getting into the list of processes to kill() - // (unlikely), or somehow one of those PIDs is getting zeroed first, - // so that kill() sends SIGTERM to the whole process group -- this - // process included. I'd have to build and link with a debug version - // of APR to know for sure. It's too bad: this mechanism would be just - // right for dealing with static autokill LLProcessPtr variables, - // which aren't destroyed until after APR is no longer available. - - // Tie the lifespan of this child process to the lifespan of our APR - // pool: on destruction of the pool, forcibly kill the process. Tell - // APR to try SIGTERM and suspend 3 seconds. If that didn't work, use - // SIGKILL. - apr_pool_note_subprocess(gAPRPoolp, &mProcess, APR_KILL_AFTER_TIMEOUT); + // NO: There may be an APR bug, not sure -- but at least on Mac, when + // gAPRPoolp is destroyed, OUR process receives SIGTERM! Apparently + // either our own PID is getting into the list of processes to kill() + // (unlikely), or somehow one of those PIDs is getting zeroed first, + // so that kill() sends SIGTERM to the whole process group -- this + // process included. I'd have to build and link with a debug version + // of APR to know for sure. It's too bad: this mechanism would be just + // right for dealing with static autokill LLProcessPtr variables, + // which aren't destroyed until after APR is no longer available. + + // Tie the lifespan of this child process to the lifespan of our APR + // pool: on destruction of the pool, forcibly kill the process. Tell + // APR to try SIGTERM and suspend 3 seconds. If that didn't work, use + // SIGKILL. + apr_pool_note_subprocess(gAPRPoolp, &mProcess, APR_KILL_AFTER_TIMEOUT); |*==========================================================================*/ - // On Windows, associate the new child process with our Job Object. - autokill(); - } - - // Instantiate the proper pipe I/O machinery - // want to be able to point to apr_proc_t::in, out, err by index - typedef apr_file_t* apr_proc_t::*apr_proc_file_ptr; - static apr_proc_file_ptr members[] = - { &apr_proc_t::in, &apr_proc_t::out, &apr_proc_t::err }; - for (size_t i = 0; i < NSLOTS; ++i) - { - if (select[i] != APR_CHILD_BLOCK) - continue; - std::string desc(STRINGIZE(mDesc << ' ' << whichfile(FILESLOT(i)))); - apr_file_t* pipe(mProcess.*(members[i])); - if (i == STDIN) - { - mPipes.replace(i, new WritePipeImpl(desc, pipe)); - } - else - { - mPipes.replace(i, new ReadPipeImpl(desc, pipe, FILESLOT(i))); - } - // Removed temporaily for Xcode 7 build tests: error was: - // "error: expression with side effects will be evaluated despite - // being used as an operand to 'typeid' [-Werror,-Wpotentially-evaluated-expression]"" - //LL_DEBUGS("LLProcess") << "Instantiating " << typeid(mPipes[i]).name() - // << "('" << desc << "')" << LL_ENDL; - } + // On Windows, associate the new child process with our Job Object. + autokill(); + } + + // Instantiate the proper pipe I/O machinery + // want to be able to point to apr_proc_t::in, out, err by index + typedef apr_file_t* apr_proc_t::*apr_proc_file_ptr; + static apr_proc_file_ptr members[] = + { &apr_proc_t::in, &apr_proc_t::out, &apr_proc_t::err }; + for (size_t i = 0; i < NSLOTS; ++i) + { + if (select[i] != APR_CHILD_BLOCK) + continue; + std::string desc(STRINGIZE(mDesc << ' ' << whichfile(FILESLOT(i)))); + apr_file_t* pipe(mProcess.*(members[i])); + if (i == STDIN) + { + mPipes.replace(i, new WritePipeImpl(desc, pipe)); + } + else + { + mPipes.replace(i, new ReadPipeImpl(desc, pipe, FILESLOT(i))); + } + // Removed temporaily for Xcode 7 build tests: error was: + // "error: expression with side effects will be evaluated despite + // being used as an operand to 'typeid' [-Werror,-Wpotentially-evaluated-expression]"" + //LL_DEBUGS("LLProcess") << "Instantiating " << typeid(mPipes[i]).name() + // << "('" << desc << "')" << LL_ENDL; + } } // Helper to obtain a description string, given a Params block static std::string getDesc(const LLProcess::Params& params) { - // If caller specified a description string, by all means use it. - if (params.desc.isProvided()) - return params.desc; + // If caller specified a description string, by all means use it. + if (params.desc.isProvided()) + return params.desc; - // Caller didn't say. Use the executable name -- but use just the filename - // part. On Mac, for instance, full pathnames get cumbersome. - return LLProcess::basename(params.executable); + // Caller didn't say. Use the executable name -- but use just the filename + // part. On Mac, for instance, full pathnames get cumbersome. + return LLProcess::basename(params.executable); } //static std::string LLProcess::basename(const std::string& path) { - // If there are Linden utility functions to manipulate pathnames, I - // haven't found them -- and for this usage, Boost.Filesystem seems kind - // of heavyweight. - std::string::size_type delim = path.find_last_of("\\/"); - // If path contains no pathname delimiters, return the whole thing. - if (delim == std::string::npos) - return path; - - // Return just the part beyond the last delimiter. - return path.substr(delim + 1); + // If there are Linden utility functions to manipulate pathnames, I + // haven't found them -- and for this usage, Boost.Filesystem seems kind + // of heavyweight. + std::string::size_type delim = path.find_last_of("\\/"); + // If path contains no pathname delimiters, return the whole thing. + if (delim == std::string::npos) + return path; + + // Return just the part beyond the last delimiter. + return path.substr(delim + 1); } LLProcess::~LLProcess() { - // In the Linden viewer, there's at least one static LLProcessPtr. Its - // destructor will be called *after* ll_cleanup_apr(). In such a case, - // unregistering is pointless (and fatal!) -- and kill(), which also - // relies on APR, is impossible. - if (! gAPRPoolp) - return; - - // Only in state RUNNING are we registered for callback. In UNSTARTED we - // haven't yet registered. And since receiving the callback is the only - // way we detect child termination, we only change from state RUNNING at - // the same time we unregister. - if (mStatus.mState == RUNNING) - { - // We're still registered for a callback: unregister. Do it before - // we even issue the kill(): even if kill() somehow prompted an - // instantaneous callback (unlikely), this object is going away! Any - // information updated in this object by such a callback is no longer - // available to any consumer anyway. - apr_proc_other_child_unregister(this); - // One less LLProcess to poll for - sProcessListener.dropPoll(*this); - } - - if (mAttached) - { - kill("destructor"); - } + // In the Linden viewer, there's at least one static LLProcessPtr. Its + // destructor will be called *after* ll_cleanup_apr(). In such a case, + // unregistering is pointless (and fatal!) -- and kill(), which also + // relies on APR, is impossible. + if (! gAPRPoolp) + return; + + // Only in state RUNNING are we registered for callback. In UNSTARTED we + // haven't yet registered. And since receiving the callback is the only + // way we detect child termination, we only change from state RUNNING at + // the same time we unregister. + if (mStatus.mState == RUNNING) + { + // We're still registered for a callback: unregister. Do it before + // we even issue the kill(): even if kill() somehow prompted an + // instantaneous callback (unlikely), this object is going away! Any + // information updated in this object by such a callback is no longer + // available to any consumer anyway. + apr_proc_other_child_unregister(this); + // One less LLProcess to poll for + sProcessListener.dropPoll(*this); + } + + if (mAttached) + { + kill("destructor"); + } if (mPool) { @@ -831,330 +831,330 @@ LLProcess::~LLProcess() bool LLProcess::kill(const std::string& who) { - if (isRunning()) - { - LL_INFOS("LLProcess") << who << " killing " << mDesc << LL_ENDL; + if (isRunning()) + { + LL_INFOS("LLProcess") << who << " killing " << mDesc << LL_ENDL; #if LL_WINDOWS - int sig = -1; + int sig = -1; #else // Posix - int sig = SIGTERM; + int sig = SIGTERM; #endif - ll_apr_warn_status(apr_proc_kill(&mProcess, sig)); - } + ll_apr_warn_status(apr_proc_kill(&mProcess, sig)); + } - return ! isRunning(); + return ! isRunning(); } //static bool LLProcess::kill(const LLProcessPtr& p, const std::string& who) { - if (! p) - return true; // process dead! (was never running) - return p->kill(who); + if (! p) + return true; // process dead! (was never running) + return p->kill(who); } bool LLProcess::isRunning() const { - return getStatus().mState == RUNNING; + return getStatus().mState == RUNNING; } //static bool LLProcess::isRunning(const LLProcessPtr& p) { - if (! p) - return false; - return p->isRunning(); + if (! p) + return false; + return p->isRunning(); } LLProcess::Status LLProcess::getStatus() const { - return mStatus; + return mStatus; } //static LLProcess::Status LLProcess::getStatus(const LLProcessPtr& p) { - if (! p) - { - // default-constructed Status has mState == UNSTARTED - return Status(); - } - return p->getStatus(); + if (! p) + { + // default-constructed Status has mState == UNSTARTED + return Status(); + } + return p->getStatus(); } std::string LLProcess::getStatusString() const { - return getStatusString(getStatus()); + return getStatusString(getStatus()); } std::string LLProcess::getStatusString(const Status& status) const { - return getStatusString(mDesc, status); + return getStatusString(mDesc, status); } //static std::string LLProcess::getStatusString(const std::string& desc, const LLProcessPtr& p) { - if (! p) - { - // default-constructed Status has mState == UNSTARTED - return getStatusString(desc, Status()); - } - return desc + " " + p->getStatusString(); + if (! p) + { + // default-constructed Status has mState == UNSTARTED + return getStatusString(desc, Status()); + } + return desc + " " + p->getStatusString(); } //static std::string LLProcess::getStatusString(const std::string& desc, const Status& status) { - if (status.mState == UNSTARTED) - return desc + " was never launched"; + if (status.mState == UNSTARTED) + return desc + " was never launched"; - if (status.mState == RUNNING) - return desc + " running"; + if (status.mState == RUNNING) + return desc + " running"; - if (status.mState == EXITED) - return STRINGIZE(desc << " exited with code " << status.mData); + if (status.mState == EXITED) + return STRINGIZE(desc << " exited with code " << status.mData); - if (status.mState == KILLED) + if (status.mState == KILLED) #if LL_WINDOWS - return STRINGIZE(desc << " killed with exception " << std::hex << status.mData); + return STRINGIZE(desc << " killed with exception " << std::hex << status.mData); #else - return STRINGIZE(desc << " killed by signal " << status.mData - << " (" << apr_signal_description_get(status.mData) << ")"); + return STRINGIZE(desc << " killed by signal " << status.mData + << " (" << apr_signal_description_get(status.mData) << ")"); #endif - return STRINGIZE(desc << " in unknown state " << status.mState << " (" << status.mData << ")"); + return STRINGIZE(desc << " in unknown state " << status.mState << " (" << status.mData << ")"); } // Classic-C-style APR callback void LLProcess::status_callback(int reason, void* data, int status) { - // Our only role is to bounce this static method call back into object - // space. - static_cast<LLProcess*>(data)->handle_status(reason, status); + // Our only role is to bounce this static method call back into object + // space. + static_cast<LLProcess*>(data)->handle_status(reason, status); } #define tabent(symbol) { symbol, #symbol } static struct ReasonCode { - int code; - const char* name; + int code; + const char* name; } reasons[] = { - tabent(APR_OC_REASON_DEATH), - tabent(APR_OC_REASON_UNWRITABLE), - tabent(APR_OC_REASON_RESTART), - tabent(APR_OC_REASON_UNREGISTER), - tabent(APR_OC_REASON_LOST), - tabent(APR_OC_REASON_RUNNING) + tabent(APR_OC_REASON_DEATH), + tabent(APR_OC_REASON_UNWRITABLE), + tabent(APR_OC_REASON_RESTART), + tabent(APR_OC_REASON_UNREGISTER), + tabent(APR_OC_REASON_LOST), + tabent(APR_OC_REASON_RUNNING) }; #undef tabent // Object-oriented callback void LLProcess::handle_status(int reason, int status) { - { - // This odd appearance of LL_DEBUGS is just to bracket a lookup that will - // only be performed if in fact we're going to produce the log message. - LL_DEBUGS("LLProcess") << empty; - std::string reason_str; - for (const ReasonCode& rcp : reasons) - { - if (reason == rcp.code) - { - reason_str = rcp.name; - break; - } - } - if (reason_str.empty()) - { - reason_str = STRINGIZE("unknown reason " << reason); - } - LL_CONT << mDesc << ": handle_status(" << reason_str << ", " << status << ")" << LL_ENDL; - } - - if (! (reason == APR_OC_REASON_DEATH || reason == APR_OC_REASON_LOST)) - { - // We're only interested in the call when the child terminates. - return; - } - - // Somewhat oddly, APR requires that you explicitly unregister even when - // it already knows the child has terminated. We must pass the same 'data' - // pointer as for the register() call, which was our 'this'. - apr_proc_other_child_unregister(this); - // don't keep polling for a terminated process - sProcessListener.dropPoll(*this); - // We overload mStatus.mState to indicate whether the child is registered - // for APR callback: only RUNNING means registered. Track that we've - // unregistered. We know the child has terminated; might be EXITED or - // KILLED; refine below. - mStatus.mState = EXITED; - - // Make last-gasp calls for each of the ReadPipes we have on hand. Since - // they're listening on "mainloop", we can be sure they'll eventually - // collect all pending data from the child. But we want to be able to - // guarantee to our consumer that by the time we post on the "postend" - // LLEventPump, our ReadPipes are already buffering all the data there - // will ever be from the child. That lets the "postend" listener decide - // what to do with that final data. - for (size_t i = 0; i < mPipes.size(); ++i) - { - std::string error; - ReadPipeImpl* ppipe = getPipePtr<ReadPipeImpl>(error, FILESLOT(i)); - if (ppipe) - { - static LLSD trivial; - ppipe->tick(trivial); - } - } - -// wi->rv = apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT); - // It's just wrong to call apr_proc_wait() here. The only way APR knows to - // call us with APR_OC_REASON_DEATH is that it's already reaped this child - // process, so calling wait() will only produce "huh?" from the OS. We - // must rely on the status param passed in, which unfortunately comes - // straight from the OS wait() call, which means we have to decode it by - // hand. - mStatus = interpret_status(status); - LL_INFOS("LLProcess") << getStatusString() << LL_ENDL; - - // If caller requested notification on child termination, send it. - if (! mPostend.empty()) - { - LLEventPumps::instance().obtain(mPostend) - .post(LLSDMap - ("id", getProcessID()) - ("desc", mDesc) - ("state", mStatus.mState) - ("data", mStatus.mData) - ("string", getStatusString()) - ); - } + { + // This odd appearance of LL_DEBUGS is just to bracket a lookup that will + // only be performed if in fact we're going to produce the log message. + LL_DEBUGS("LLProcess") << empty; + std::string reason_str; + for (const ReasonCode& rcp : reasons) + { + if (reason == rcp.code) + { + reason_str = rcp.name; + break; + } + } + if (reason_str.empty()) + { + reason_str = STRINGIZE("unknown reason " << reason); + } + LL_CONT << mDesc << ": handle_status(" << reason_str << ", " << status << ")" << LL_ENDL; + } + + if (! (reason == APR_OC_REASON_DEATH || reason == APR_OC_REASON_LOST)) + { + // We're only interested in the call when the child terminates. + return; + } + + // Somewhat oddly, APR requires that you explicitly unregister even when + // it already knows the child has terminated. We must pass the same 'data' + // pointer as for the register() call, which was our 'this'. + apr_proc_other_child_unregister(this); + // don't keep polling for a terminated process + sProcessListener.dropPoll(*this); + // We overload mStatus.mState to indicate whether the child is registered + // for APR callback: only RUNNING means registered. Track that we've + // unregistered. We know the child has terminated; might be EXITED or + // KILLED; refine below. + mStatus.mState = EXITED; + + // Make last-gasp calls for each of the ReadPipes we have on hand. Since + // they're listening on "mainloop", we can be sure they'll eventually + // collect all pending data from the child. But we want to be able to + // guarantee to our consumer that by the time we post on the "postend" + // LLEventPump, our ReadPipes are already buffering all the data there + // will ever be from the child. That lets the "postend" listener decide + // what to do with that final data. + for (size_t i = 0; i < mPipes.size(); ++i) + { + std::string error; + ReadPipeImpl* ppipe = getPipePtr<ReadPipeImpl>(error, FILESLOT(i)); + if (ppipe) + { + static LLSD trivial; + ppipe->tick(trivial); + } + } + +// wi->rv = apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT); + // It's just wrong to call apr_proc_wait() here. The only way APR knows to + // call us with APR_OC_REASON_DEATH is that it's already reaped this child + // process, so calling wait() will only produce "huh?" from the OS. We + // must rely on the status param passed in, which unfortunately comes + // straight from the OS wait() call, which means we have to decode it by + // hand. + mStatus = interpret_status(status); + LL_INFOS("LLProcess") << getStatusString() << LL_ENDL; + + // If caller requested notification on child termination, send it. + if (! mPostend.empty()) + { + LLEventPumps::instance().obtain(mPostend) + .post(LLSDMap + ("id", getProcessID()) + ("desc", mDesc) + ("state", mStatus.mState) + ("data", mStatus.mData) + ("string", getStatusString()) + ); + } } LLProcess::id LLProcess::getProcessID() const { - return mProcess.pid; + return mProcess.pid; } LLProcess::handle LLProcess::getProcessHandle() const { #if LL_WINDOWS - return mProcess.hproc; + return mProcess.hproc; #else - return mProcess.pid; + return mProcess.pid; #endif } std::string LLProcess::getPipeName(FILESLOT) const { - // LLProcess::FileParam::type "npipe" is not yet implemented - return ""; + // LLProcess::FileParam::type "npipe" is not yet implemented + return ""; } template<class PIPETYPE> PIPETYPE* LLProcess::getPipePtr(std::string& error, FILESLOT slot) { - if (slot >= NSLOTS) - { - error = STRINGIZE(mDesc << " has no slot " << slot); - return NULL; - } - if (mPipes.is_null(slot)) - { - error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a monitored pipe"); - return NULL; - } - // Make sure we dynamic_cast in pointer domain so we can test, rather than - // accepting runtime's exception. - PIPETYPE* ppipe = dynamic_cast<PIPETYPE*>(&mPipes[slot]); - if (! ppipe) - { - error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a " << typeid(PIPETYPE).name()); - return NULL; - } - - error.clear(); - return ppipe; + if (slot >= NSLOTS) + { + error = STRINGIZE(mDesc << " has no slot " << slot); + return NULL; + } + if (mPipes.is_null(slot)) + { + error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a monitored pipe"); + return NULL; + } + // Make sure we dynamic_cast in pointer domain so we can test, rather than + // accepting runtime's exception. + PIPETYPE* ppipe = dynamic_cast<PIPETYPE*>(&mPipes[slot]); + if (! ppipe) + { + error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a " << typeid(PIPETYPE).name()); + return NULL; + } + + error.clear(); + return ppipe; } template <class PIPETYPE> PIPETYPE& LLProcess::getPipe(FILESLOT slot) { - std::string error; - PIPETYPE* wp = getPipePtr<PIPETYPE>(error, slot); - if (! wp) - { - LLTHROW(NoPipe(error)); - } - return *wp; + std::string error; + PIPETYPE* wp = getPipePtr<PIPETYPE>(error, slot); + if (! wp) + { + LLTHROW(NoPipe(error)); + } + return *wp; } template <class PIPETYPE> boost::optional<PIPETYPE&> LLProcess::getOptPipe(FILESLOT slot) { - std::string error; - PIPETYPE* wp = getPipePtr<PIPETYPE>(error, slot); - if (! wp) - { - LL_DEBUGS("LLProcess") << error << LL_ENDL; - return boost::optional<PIPETYPE&>(); - } - return *wp; + std::string error; + PIPETYPE* wp = getPipePtr<PIPETYPE>(error, slot); + if (! wp) + { + LL_DEBUGS("LLProcess") << error << LL_ENDL; + return boost::optional<PIPETYPE&>(); + } + return *wp; } LLProcess::WritePipe& LLProcess::getWritePipe(FILESLOT slot) { - return getPipe<WritePipe>(slot); + return getPipe<WritePipe>(slot); } boost::optional<LLProcess::WritePipe&> LLProcess::getOptWritePipe(FILESLOT slot) { - return getOptPipe<WritePipe>(slot); + return getOptPipe<WritePipe>(slot); } LLProcess::ReadPipe& LLProcess::getReadPipe(FILESLOT slot) { - return getPipe<ReadPipe>(slot); + return getPipe<ReadPipe>(slot); } boost::optional<LLProcess::ReadPipe&> LLProcess::getOptReadPipe(FILESLOT slot) { - return getOptPipe<ReadPipe>(slot); + return getOptPipe<ReadPipe>(slot); } //static std::string LLProcess::getline(std::istream& in) { - std::string line; - std::getline(in, line); - // Blur the distinction between "\r\n" and plain "\n". std::getline() will - // have eaten the "\n", but we could still end up with a trailing "\r". - std::string::size_type lastpos = line.find_last_not_of("\r"); - if (lastpos != std::string::npos) - { - // Found at least one character that's not a trailing '\r'. SKIP OVER - // IT and erase the rest of the line. - line.erase(lastpos+1); - } - return line; + std::string line; + std::getline(in, line); + // Blur the distinction between "\r\n" and plain "\n". std::getline() will + // have eaten the "\n", but we could still end up with a trailing "\r". + std::string::size_type lastpos = line.find_last_not_of("\r"); + if (lastpos != std::string::npos) + { + // Found at least one character that's not a trailing '\r'. SKIP OVER + // IT and erase the rest of the line. + line.erase(lastpos+1); + } + return line; } std::ostream& operator<<(std::ostream& out, const LLProcess::Params& params) { - if (params.cwd.isProvided()) - { - out << "cd " << LLStringUtil::quote(params.cwd) << ": "; - } - out << LLStringUtil::quote(params.executable); - for (const std::string& arg : params.args) - { - out << ' ' << LLStringUtil::quote(arg); - } - return out; + if (params.cwd.isProvided()) + { + out << "cd " << LLStringUtil::quote(params.cwd) << ": "; + } + out << LLStringUtil::quote(params.executable); + for (const std::string& arg : params.args) + { + out << ' ' << LLStringUtil::quote(arg); + } + return out; } /***************************************************************************** @@ -1166,68 +1166,68 @@ static std::string WindowsErrorString(const std::string& operation); void LLProcess::autokill() { - // hopefully now handled by apr_procattr_autokill_set() + // hopefully now handled by apr_procattr_autokill_set() } LLProcess::handle LLProcess::isRunning(handle h, const std::string& desc) { - // This direct Windows implementation is because we have no access to the - // apr_proc_t struct: we expect it's been destroyed. - if (! h) - return 0; - - DWORD waitresult = WaitForSingleObject(h, 0); - if(waitresult == WAIT_OBJECT_0) - { - // the process has completed. - if (! desc.empty()) - { - DWORD status = 0; - if (! GetExitCodeProcess(h, &status)) - { - LL_WARNS("LLProcess") << desc << " terminated, but " - << WindowsErrorString("GetExitCodeProcess()") << LL_ENDL; - } - { - LL_INFOS("LLProcess") << getStatusString(desc, interpret_status(status)) - << LL_ENDL; - } - } - CloseHandle(h); - return 0; - } - - return h; + // This direct Windows implementation is because we have no access to the + // apr_proc_t struct: we expect it's been destroyed. + if (! h) + return 0; + + DWORD waitresult = WaitForSingleObject(h, 0); + if(waitresult == WAIT_OBJECT_0) + { + // the process has completed. + if (! desc.empty()) + { + DWORD status = 0; + if (! GetExitCodeProcess(h, &status)) + { + LL_WARNS("LLProcess") << desc << " terminated, but " + << WindowsErrorString("GetExitCodeProcess()") << LL_ENDL; + } + { + LL_INFOS("LLProcess") << getStatusString(desc, interpret_status(status)) + << LL_ENDL; + } + } + CloseHandle(h); + return 0; + } + + return h; } static LLProcess::Status interpret_status(int status) { - LLProcess::Status result; - - // This bit of code is cribbed from apr/threadproc/win32/proc.c, a - // function (unfortunately static) called why_from_exit_code(): - /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how - * this class of failures was determined - */ - if ((status & 0xFFFF0000) == 0xC0000000) - { - result.mState = LLProcess::KILLED; - } - else - { - result.mState = LLProcess::EXITED; - } - result.mData = status; - - return result; + LLProcess::Status result; + + // This bit of code is cribbed from apr/threadproc/win32/proc.c, a + // function (unfortunately static) called why_from_exit_code(): + /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how + * this class of failures was determined + */ + if ((status & 0xFFFF0000) == 0xC0000000) + { + result.mState = LLProcess::KILLED; + } + else + { + result.mState = LLProcess::EXITED; + } + result.mData = status; + + return result; } /// GetLastError()/FormatMessage() boilerplate static std::string WindowsErrorString(const std::string& operation) { - auto result = GetLastError(); - return STRINGIZE(operation << " failed (" << result << "): " - << windows_message<std::string>(result)); + auto result = GetLastError(); + return STRINGIZE(operation << " failed (" << result << "): " + << windows_message<std::string>(result)); } /***************************************************************************** @@ -1242,117 +1242,117 @@ static std::string WindowsErrorString(const std::string& operation) void LLProcess::autokill() { - // What we ought to do here is to: - // 1. create a unique process group and run all autokill children in that - // group (see https://jira.secondlife.com/browse/SWAT-563); - // 2. figure out a way to intercept control when the viewer exits -- - // gracefully or not; - // 3. when the viewer exits, kill off the aforementioned process group. - - // It's point 2 that's troublesome. Although I've seen some signal- - // handling logic in the Posix viewer code, I haven't yet found any bit of - // code that's run no matter how the viewer exits (a try/finally for the - // whole process, as it were). + // What we ought to do here is to: + // 1. create a unique process group and run all autokill children in that + // group (see https://jira.secondlife.com/browse/SWAT-563); + // 2. figure out a way to intercept control when the viewer exits -- + // gracefully or not; + // 3. when the viewer exits, kill off the aforementioned process group. + + // It's point 2 that's troublesome. Although I've seen some signal- + // handling logic in the Posix viewer code, I haven't yet found any bit of + // code that's run no matter how the viewer exits (a try/finally for the + // whole process, as it were). } // Attempt to reap a process ID -- returns true if the process has exited and been reaped, false otherwise. static bool reap_pid(pid_t pid, LLProcess::Status* pstatus=NULL) { - LLProcess::Status dummy; - if (! pstatus) - { - // If caller doesn't want to see Status, give us a target anyway so we - // don't have to have a bunch of conditionals. - pstatus = &dummy; - } - - int status = 0; - pid_t wait_result = ::waitpid(pid, &status, WNOHANG); - if (wait_result == pid) - { - *pstatus = interpret_status(status); - return true; - } - if (wait_result == 0) - { - pstatus->mState = LLProcess::RUNNING; - pstatus->mData = 0; - return false; - } - - // Clear caller's Status block; caller must interpret UNSTARTED to mean - // "if this PID was ever valid, it no longer is." - *pstatus = LLProcess::Status(); - - // We've dealt with the success cases: we were able to reap the child - // (wait_result == pid) or it's still running (wait_result == 0). It may - // be that the child terminated but didn't hang around long enough for us - // to reap. In that case we still have no Status to report, but we can at - // least state that it's not running. - if (wait_result == -1 && errno == ECHILD) - { - // No such process -- this may mean we're ignoring SIGCHILD. - return true; - } - - // Uh, should never happen?! - LL_WARNS("LLProcess") << "LLProcess::reap_pid(): waitpid(" << pid << ") returned " - << wait_result << "; not meaningful?" << LL_ENDL; - // If caller is looping until this pid terminates, and if we can't find - // out, better to break the loop than to claim it's still running. - return true; + LLProcess::Status dummy; + if (! pstatus) + { + // If caller doesn't want to see Status, give us a target anyway so we + // don't have to have a bunch of conditionals. + pstatus = &dummy; + } + + int status = 0; + pid_t wait_result = ::waitpid(pid, &status, WNOHANG); + if (wait_result == pid) + { + *pstatus = interpret_status(status); + return true; + } + if (wait_result == 0) + { + pstatus->mState = LLProcess::RUNNING; + pstatus->mData = 0; + return false; + } + + // Clear caller's Status block; caller must interpret UNSTARTED to mean + // "if this PID was ever valid, it no longer is." + *pstatus = LLProcess::Status(); + + // We've dealt with the success cases: we were able to reap the child + // (wait_result == pid) or it's still running (wait_result == 0). It may + // be that the child terminated but didn't hang around long enough for us + // to reap. In that case we still have no Status to report, but we can at + // least state that it's not running. + if (wait_result == -1 && errno == ECHILD) + { + // No such process -- this may mean we're ignoring SIGCHILD. + return true; + } + + // Uh, should never happen?! + LL_WARNS("LLProcess") << "LLProcess::reap_pid(): waitpid(" << pid << ") returned " + << wait_result << "; not meaningful?" << LL_ENDL; + // If caller is looping until this pid terminates, and if we can't find + // out, better to break the loop than to claim it's still running. + return true; } LLProcess::id LLProcess::isRunning(id pid, const std::string& desc) { - // This direct Posix implementation is because we have no access to the - // apr_proc_t struct: we expect it's been destroyed. - if (! pid) - return 0; - - // Check whether the process has exited, and reap it if it has. - LLProcess::Status status; - if(reap_pid(pid, &status)) - { - // the process has exited. - if (! desc.empty()) - { - std::string statstr(desc + " apparently terminated: no status available"); - // We don't just pass UNSTARTED to getStatusString() because, in - // the context of reap_pid(), that state has special meaning. - if (status.mState != UNSTARTED) - { - statstr = getStatusString(desc, status); - } - LL_INFOS("LLProcess") << statstr << LL_ENDL; - } - return 0; - } - - return pid; + // This direct Posix implementation is because we have no access to the + // apr_proc_t struct: we expect it's been destroyed. + if (! pid) + return 0; + + // Check whether the process has exited, and reap it if it has. + LLProcess::Status status; + if(reap_pid(pid, &status)) + { + // the process has exited. + if (! desc.empty()) + { + std::string statstr(desc + " apparently terminated: no status available"); + // We don't just pass UNSTARTED to getStatusString() because, in + // the context of reap_pid(), that state has special meaning. + if (status.mState != UNSTARTED) + { + statstr = getStatusString(desc, status); + } + LL_INFOS("LLProcess") << statstr << LL_ENDL; + } + return 0; + } + + return pid; } static LLProcess::Status interpret_status(int status) { - LLProcess::Status result; - - if (WIFEXITED(status)) - { - result.mState = LLProcess::EXITED; - result.mData = WEXITSTATUS(status); - } - else if (WIFSIGNALED(status)) - { - result.mState = LLProcess::KILLED; - result.mData = WTERMSIG(status); - } - else // uh, shouldn't happen? - { - result.mState = LLProcess::EXITED; - result.mData = status; // someone else will have to decode - } - - return result; + LLProcess::Status result; + + if (WIFEXITED(status)) + { + result.mState = LLProcess::EXITED; + result.mData = WEXITSTATUS(status); + } + else if (WIFSIGNALED(status)) + { + result.mState = LLProcess::KILLED; + result.mData = WTERMSIG(status); + } + else // uh, shouldn't happen? + { + result.mState = LLProcess::EXITED; + result.mData = status; // someone else will have to decode + } + + return result; } #endif // Posix diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index c57821bf52..166da8f424 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -1,29 +1,29 @@ -/** +/** * @file llprocess.h * @brief Utility class for launching, terminating, and tracking child processes. * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #ifndef LL_LLPROCESS_H #define LL_LLPROCESS_H @@ -39,7 +39,7 @@ #include <iosfwd> // std::ostream #if LL_WINDOWS -#include "llwin32headerslean.h" // for HANDLE +#include "llwin32headerslean.h" // for HANDLE #elif LL_LINUX #if defined(Status) #undef Status @@ -71,503 +71,503 @@ typedef std::shared_ptr<LLProcess> LLProcessPtr; */ class LL_COMMON_API LLProcess: public boost::noncopyable { - LOG_CLASS(LLProcess); + LOG_CLASS(LLProcess); public: - /** - * Specify what to pass for each of child stdin, stdout, stderr. - * @see LLProcess::Params::files. - */ - struct FileParam: public LLInitParam::Block<FileParam> - { - /** - * type of file handle to pass to child process - * - * - "" (default): let the child inherit the same file handle used by - * this process. For instance, if passed as stdout, child stdout - * will be interleaved with stdout from this process. In this case, - * @a name is moot and should be left "". - * - * - "file": open an OS filesystem file with the specified @a name. - * <i>Not yet implemented.</i> - * - * - "pipe" or "tpipe" or "npipe": depends on @a name - * - * - @a name.empty(): construct an OS pipe used only for this slot - * of the forthcoming child process. - * - * - ! @a name.empty(): in a global registry, find or create (using - * the specified @a name) an OS pipe. The point of the (purely - * internal) @a name is that passing the same @a name in more than - * one slot for a given LLProcess -- or for slots in different - * LLProcess instances -- means the same pipe. For example, you - * might pass the same @a name value as both stdout and stderr to - * make the child process produce both on the same actual pipe. Or - * you might pass the same @a name as the stdout for one LLProcess - * and the stdin for another to connect the two child processes. - * Use LLProcess::getPipeName() to generate a unique name - * guaranteed not to already exist in the registry. <i>Not yet - * implemented.</i> - * - * The difference between "pipe", "tpipe" and "npipe" is as follows. - * - * - "pipe": direct LLProcess to monitor the parent end of the pipe, - * pumping nonblocking I/O every frame. The expectation (at least - * for stdout or stderr) is that the caller will listen for - * incoming data and consume it as it arrives. It's important not - * to neglect such a pipe, because it's buffered in memory. If you - * suspect the child may produce a great volume of output between - * frames, consider directing the child to write to a filesystem - * file instead, then read the file later. - * - * - "tpipe": do not engage LLProcess machinery to monitor the - * parent end of the pipe. A "tpipe" is used only to connect - * different child processes. As such, it makes little sense to - * pass an empty @a name. <i>Not yet implemented.</i> - * - * - "npipe": like "tpipe", but use an OS named pipe with a - * generated name. Note that @a name is the @em internal name of - * the pipe in our global registry -- it doesn't necessarily have - * anything to do with the pipe's name in the OS filesystem. Use - * LLProcess::getPipeName() to obtain the named pipe's OS - * filesystem name, e.g. to pass it as the @a name to another - * LLProcess instance using @a type "file". This supports usage - * like bash's <(subcommand...) or >(subcommand...) - * constructs. <i>Not yet implemented.</i> - * - * In all cases the open mode (read, write) is determined by the child - * slot you're filling. Child stdin means select the "read" end of a - * pipe, or open a filesystem file for reading; child stdout or stderr - * means select the "write" end of a pipe, or open a filesystem file - * for writing. - * - * Confusion such as passing the same pipe as the stdin of two - * processes (rather than stdout for one and stdin for the other) is - * explicitly permitted: it's up to the caller to construct meaningful - * LLProcess pipe graphs. - */ - Optional<std::string> type; - Optional<std::string> name; - - FileParam(const std::string& tp="", const std::string& nm=""): - type("type"), - name("name") - { - // If caller wants to specify values, use explicit assignment to - // set them rather than initialization. - if (! tp.empty()) type = tp; - if (! nm.empty()) name = nm; - } - }; - - /// Param block definition - struct Params: public LLInitParam::Block<Params> - { - Params(): - executable("executable"), - args("args"), - cwd("cwd"), - autokill("autokill", true), - attached("attached", true), - files("files"), - postend("postend"), - desc("desc") - {} - - /// pathname of executable - Mandatory<std::string> executable; - /** - * zero or more additional command-line arguments. Arguments are - * passed through as exactly as we can manage, whitespace and all. - * @note On Windows we manage this by implicitly double-quoting each - * argument while assembling the command line. - */ - Multiple<std::string> args; - /// current working directory, if need it changed - Optional<std::string> cwd; - /// implicitly kill child process on termination of parent, whether - /// voluntary or crash (default true) - Optional<bool> autokill; - /// implicitly kill process on destruction of LLProcess object - /// (default same as autokill) - /// - /// Originally, 'autokill' conflated two concepts: kill child process on - /// - destruction of its LLProcess object, and - /// - termination of parent process, voluntary or otherwise. - /// - /// It's useful to tease these apart. Some child processes are sent a - /// "clean up and terminate" message before the associated LLProcess - /// object is destroyed. A child process launched with attached=false - /// has an extra time window from the destruction of its LLProcess - /// until parent-process termination in which to perform its own - /// orderly shutdown, yet autokill=true still guarantees that we won't - /// accumulate orphan instances of such processes indefinitely. With - /// attached=true, if a child process cannot clean up between the - /// shutdown message and LLProcess destruction (presumably very soon - /// thereafter), it's forcibly killed anyway -- which can lead to - /// distressing user-visible crash indications. - /// - /// (The usefulness of attached=true with autokill=false is less - /// clear, but we don't prohibit that combination.) - Optional<bool> attached; - /** - * Up to three FileParam items: for child stdin, stdout, stderr. - * Passing two FileParam entries means default treatment for stderr, - * and so forth. - * - * @note LLInitParam::Block permits usage like this: - * @code - * LLProcess::Params params; - * ... - * params.files - * .add(LLProcess::FileParam()) // stdin - * .add(LLProcess::FileParam().type("pipe") // stdout - * .add(LLProcess::FileParam().type("file").name("error.log")); - * @endcode - * - * @note While it's theoretically plausible to pass additional open - * file handles to a child specifically written to expect them, our - * underlying implementation doesn't yet support that. - */ - Multiple<FileParam, AtMost<3> > files; - /** - * On child-process termination, if this LLProcess object still - * exists, post LLSD event to LLEventPump with specified name (default - * no event). Event contains at least: - * - * - "id" as obtained from getProcessID() - * - "desc" short string description of child (executable + pid) - * - "state" @c state enum value, from Status.mState - * - "data" if "state" is EXITED, exit code; if KILLED, on Posix, - * signal number - * - "string" English text describing "state" and "data" (e.g. "exited - * with code 0") - */ - Optional<std::string> postend; - /** - * Description of child process for logging purposes. It need not be - * unique; the logged description string will contain the PID as well. - * If this is omitted, a description will be derived from the - * executable name. - */ - Optional<std::string> desc; - }; - typedef LLSDParamAdapter<Params> LLSDOrParams; - - /** - * Factory accepting either plain LLSD::Map or Params block. - * MAY RETURN DEFAULT-CONSTRUCTED LLProcessPtr if params invalid! - */ - static LLProcessPtr create(const LLSDOrParams& params); - virtual ~LLProcess(); - - /// Is child process still running? - bool isRunning() const; - // static isRunning(LLProcessPtr), getStatus(LLProcessPtr), - // getStatusString(LLProcessPtr), kill(LLProcessPtr) handle the case in - // which the passed LLProcessPtr might be NULL (default-constructed). - static bool isRunning(const LLProcessPtr&); - - /** - * State of child process - */ - enum state - { - UNSTARTED, ///< initial value, invisible to consumer - RUNNING, ///< child process launched - EXITED, ///< child process terminated voluntarily - KILLED ///< child process terminated involuntarily - }; - - /** - * Status info - */ - struct Status - { - Status(): - mState(UNSTARTED), - mData(0) - {} - - state mState; ///< @see state - /** - * - for mState == EXITED: mData is exit() code - * - for mState == KILLED: mData is signal number (Posix) - * - otherwise: mData is undefined - */ - int mData; - }; - - /// Status query - Status getStatus() const; - static Status getStatus(const LLProcessPtr&); - /// English Status string query, for logging etc. - std::string getStatusString() const; - static std::string getStatusString(const std::string& desc, const LLProcessPtr&); - /// English Status string query for previously-captured Status - std::string getStatusString(const Status& status) const; - /// static English Status string query - static std::string getStatusString(const std::string& desc, const Status& status); - - // Attempt to kill the process -- returns true if the process is no longer running when it returns. - // Note that even if this returns false, the process may exit some time after it's called. - bool kill(const std::string& who=""); - static bool kill(const LLProcessPtr& p, const std::string& who=""); + /** + * Specify what to pass for each of child stdin, stdout, stderr. + * @see LLProcess::Params::files. + */ + struct FileParam: public LLInitParam::Block<FileParam> + { + /** + * type of file handle to pass to child process + * + * - "" (default): let the child inherit the same file handle used by + * this process. For instance, if passed as stdout, child stdout + * will be interleaved with stdout from this process. In this case, + * @a name is moot and should be left "". + * + * - "file": open an OS filesystem file with the specified @a name. + * <i>Not yet implemented.</i> + * + * - "pipe" or "tpipe" or "npipe": depends on @a name + * + * - @a name.empty(): construct an OS pipe used only for this slot + * of the forthcoming child process. + * + * - ! @a name.empty(): in a global registry, find or create (using + * the specified @a name) an OS pipe. The point of the (purely + * internal) @a name is that passing the same @a name in more than + * one slot for a given LLProcess -- or for slots in different + * LLProcess instances -- means the same pipe. For example, you + * might pass the same @a name value as both stdout and stderr to + * make the child process produce both on the same actual pipe. Or + * you might pass the same @a name as the stdout for one LLProcess + * and the stdin for another to connect the two child processes. + * Use LLProcess::getPipeName() to generate a unique name + * guaranteed not to already exist in the registry. <i>Not yet + * implemented.</i> + * + * The difference between "pipe", "tpipe" and "npipe" is as follows. + * + * - "pipe": direct LLProcess to monitor the parent end of the pipe, + * pumping nonblocking I/O every frame. The expectation (at least + * for stdout or stderr) is that the caller will listen for + * incoming data and consume it as it arrives. It's important not + * to neglect such a pipe, because it's buffered in memory. If you + * suspect the child may produce a great volume of output between + * frames, consider directing the child to write to a filesystem + * file instead, then read the file later. + * + * - "tpipe": do not engage LLProcess machinery to monitor the + * parent end of the pipe. A "tpipe" is used only to connect + * different child processes. As such, it makes little sense to + * pass an empty @a name. <i>Not yet implemented.</i> + * + * - "npipe": like "tpipe", but use an OS named pipe with a + * generated name. Note that @a name is the @em internal name of + * the pipe in our global registry -- it doesn't necessarily have + * anything to do with the pipe's name in the OS filesystem. Use + * LLProcess::getPipeName() to obtain the named pipe's OS + * filesystem name, e.g. to pass it as the @a name to another + * LLProcess instance using @a type "file". This supports usage + * like bash's <(subcommand...) or >(subcommand...) + * constructs. <i>Not yet implemented.</i> + * + * In all cases the open mode (read, write) is determined by the child + * slot you're filling. Child stdin means select the "read" end of a + * pipe, or open a filesystem file for reading; child stdout or stderr + * means select the "write" end of a pipe, or open a filesystem file + * for writing. + * + * Confusion such as passing the same pipe as the stdin of two + * processes (rather than stdout for one and stdin for the other) is + * explicitly permitted: it's up to the caller to construct meaningful + * LLProcess pipe graphs. + */ + Optional<std::string> type; + Optional<std::string> name; + + FileParam(const std::string& tp="", const std::string& nm=""): + type("type"), + name("name") + { + // If caller wants to specify values, use explicit assignment to + // set them rather than initialization. + if (! tp.empty()) type = tp; + if (! nm.empty()) name = nm; + } + }; + + /// Param block definition + struct Params: public LLInitParam::Block<Params> + { + Params(): + executable("executable"), + args("args"), + cwd("cwd"), + autokill("autokill", true), + attached("attached", true), + files("files"), + postend("postend"), + desc("desc") + {} + + /// pathname of executable + Mandatory<std::string> executable; + /** + * zero or more additional command-line arguments. Arguments are + * passed through as exactly as we can manage, whitespace and all. + * @note On Windows we manage this by implicitly double-quoting each + * argument while assembling the command line. + */ + Multiple<std::string> args; + /// current working directory, if need it changed + Optional<std::string> cwd; + /// implicitly kill child process on termination of parent, whether + /// voluntary or crash (default true) + Optional<bool> autokill; + /// implicitly kill process on destruction of LLProcess object + /// (default same as autokill) + /// + /// Originally, 'autokill' conflated two concepts: kill child process on + /// - destruction of its LLProcess object, and + /// - termination of parent process, voluntary or otherwise. + /// + /// It's useful to tease these apart. Some child processes are sent a + /// "clean up and terminate" message before the associated LLProcess + /// object is destroyed. A child process launched with attached=false + /// has an extra time window from the destruction of its LLProcess + /// until parent-process termination in which to perform its own + /// orderly shutdown, yet autokill=true still guarantees that we won't + /// accumulate orphan instances of such processes indefinitely. With + /// attached=true, if a child process cannot clean up between the + /// shutdown message and LLProcess destruction (presumably very soon + /// thereafter), it's forcibly killed anyway -- which can lead to + /// distressing user-visible crash indications. + /// + /// (The usefulness of attached=true with autokill=false is less + /// clear, but we don't prohibit that combination.) + Optional<bool> attached; + /** + * Up to three FileParam items: for child stdin, stdout, stderr. + * Passing two FileParam entries means default treatment for stderr, + * and so forth. + * + * @note LLInitParam::Block permits usage like this: + * @code + * LLProcess::Params params; + * ... + * params.files + * .add(LLProcess::FileParam()) // stdin + * .add(LLProcess::FileParam().type("pipe") // stdout + * .add(LLProcess::FileParam().type("file").name("error.log")); + * @endcode + * + * @note While it's theoretically plausible to pass additional open + * file handles to a child specifically written to expect them, our + * underlying implementation doesn't yet support that. + */ + Multiple<FileParam, AtMost<3> > files; + /** + * On child-process termination, if this LLProcess object still + * exists, post LLSD event to LLEventPump with specified name (default + * no event). Event contains at least: + * + * - "id" as obtained from getProcessID() + * - "desc" short string description of child (executable + pid) + * - "state" @c state enum value, from Status.mState + * - "data" if "state" is EXITED, exit code; if KILLED, on Posix, + * signal number + * - "string" English text describing "state" and "data" (e.g. "exited + * with code 0") + */ + Optional<std::string> postend; + /** + * Description of child process for logging purposes. It need not be + * unique; the logged description string will contain the PID as well. + * If this is omitted, a description will be derived from the + * executable name. + */ + Optional<std::string> desc; + }; + typedef LLSDParamAdapter<Params> LLSDOrParams; + + /** + * Factory accepting either plain LLSD::Map or Params block. + * MAY RETURN DEFAULT-CONSTRUCTED LLProcessPtr if params invalid! + */ + static LLProcessPtr create(const LLSDOrParams& params); + virtual ~LLProcess(); + + /// Is child process still running? + bool isRunning() const; + // static isRunning(LLProcessPtr), getStatus(LLProcessPtr), + // getStatusString(LLProcessPtr), kill(LLProcessPtr) handle the case in + // which the passed LLProcessPtr might be NULL (default-constructed). + static bool isRunning(const LLProcessPtr&); + + /** + * State of child process + */ + enum state + { + UNSTARTED, ///< initial value, invisible to consumer + RUNNING, ///< child process launched + EXITED, ///< child process terminated voluntarily + KILLED ///< child process terminated involuntarily + }; + + /** + * Status info + */ + struct Status + { + Status(): + mState(UNSTARTED), + mData(0) + {} + + state mState; ///< @see state + /** + * - for mState == EXITED: mData is exit() code + * - for mState == KILLED: mData is signal number (Posix) + * - otherwise: mData is undefined + */ + int mData; + }; + + /// Status query + Status getStatus() const; + static Status getStatus(const LLProcessPtr&); + /// English Status string query, for logging etc. + std::string getStatusString() const; + static std::string getStatusString(const std::string& desc, const LLProcessPtr&); + /// English Status string query for previously-captured Status + std::string getStatusString(const Status& status) const; + /// static English Status string query + static std::string getStatusString(const std::string& desc, const Status& status); + + // Attempt to kill the process -- returns true if the process is no longer running when it returns. + // Note that even if this returns false, the process may exit some time after it's called. + bool kill(const std::string& who=""); + static bool kill(const LLProcessPtr& p, const std::string& who=""); #if LL_WINDOWS - typedef int id; ///< as returned by getProcessID() - typedef HANDLE handle; ///< as returned by getProcessHandle() + typedef int id; ///< as returned by getProcessID() + typedef HANDLE handle; ///< as returned by getProcessHandle() #else - typedef pid_t id; - typedef pid_t handle; + typedef pid_t id; + typedef pid_t handle; #endif - /** - * Get an int-like id value. This is primarily intended for a human reader - * to differentiate processes. - */ - id getProcessID() const; - /** - * Get a "handle" of a kind that you might pass to platform-specific API - * functions to engage features not directly supported by LLProcess. - */ - handle getProcessHandle() const; - - /** - * Test if a process (@c handle obtained from getProcessHandle()) is still - * running. Return same nonzero @c handle value if still running, else - * zero, so you can test it like a bool. But if you want to update a - * stored variable as a side effect, you can write code like this: - * @code - * hchild = LLProcess::isRunning(hchild); - * @endcode - * @note This method is intended as a unit-test hook, not as the first of - * a whole set of operations supported on freestanding @c handle values. - * New functionality should be added as nonstatic members operating on - * the same data as getProcessHandle(). - * - * In particular, if child termination is detected by this static isRunning() - * rather than by nonstatic isRunning(), the LLProcess object won't be - * aware of the child's changed status and may encounter OS errors trying - * to obtain it. This static isRunning() is only intended for after the - * launching LLProcess object has been destroyed. - */ - static handle isRunning(handle, const std::string& desc=""); - - /// Provide symbolic access to child's file slots - enum FILESLOT { STDIN=0, STDOUT=1, STDERR=2, NSLOTS=3 }; - - /** - * For a pipe constructed with @a type "npipe", obtain the generated OS - * filesystem name for the specified pipe. Otherwise returns the empty - * string. @see LLProcess::FileParam::type - */ - std::string getPipeName(FILESLOT) const; - - /// base of ReadPipe, WritePipe - class LL_COMMON_API BasePipe - { - public: - virtual ~BasePipe() = 0; - - typedef std::size_t size_type; - static const size_type npos; - - /** - * Get accumulated buffer length. - * - * For WritePipe, is there still pending data to send to child? - * - * For ReadPipe, we often need to refrain from actually reading the - * std::istream returned by get_istream() until we've accumulated - * enough data to make it worthwhile. For instance, if we're expecting - * a number from the child, but the child happens to flush "12" before - * emitting "3\n", get_istream() >> myint could return 12 rather than - * 123! - */ - virtual size_type size() const = 0; - }; - - /// As returned by getWritePipe() or getOptWritePipe() - class WritePipe: public BasePipe - { - public: - /** - * Get ostream& on which to write to child's stdin. - * - * @usage - * @code - * myProcess->getWritePipe().get_ostream() << "Hello, child!" << std::endl; - * @endcode - */ - virtual std::ostream& get_ostream() = 0; - }; - - /// As returned by getReadPipe() or getOptReadPipe() - class ReadPipe: public BasePipe - { - public: - /** - * Get istream& on which to read from child's stdout or stderr. - * - * @usage - * @code - * std::string stuff; - * myProcess->getReadPipe().get_istream() >> stuff; - * @endcode - * - * You should be sure in advance that the ReadPipe in question can - * fill the request. @see getPump() - */ - virtual std::istream& get_istream() = 0; - - /** - * Like std::getline(get_istream(), line), but trims off trailing '\r' - * to make calling code less platform-sensitive. - */ - virtual std::string getline() = 0; - - /** - * Like get_istream().read(buffer, n), but returns std::string rather - * than requiring caller to construct a buffer, etc. - */ - virtual std::string read(size_type len) = 0; - - /** - * Peek at accumulated buffer data without consuming it. Optional - * parameters give you substr() functionality. - * - * @note You can discard buffer data using get_istream().ignore(n). - */ - virtual std::string peek(size_type offset=0, size_type len=npos) const = 0; - - /** - * Detect presence of a substring (or char) in accumulated buffer data - * without retrieving it. Optional offset allows you to search from - * specified position. - */ - template <typename SEEK> - bool contains(SEEK seek, size_type offset=0) const - { return find(seek, offset) != npos; } - - /** - * Search for a substring in accumulated buffer data without - * retrieving it. Returns size_type position at which found, or npos - * meaning not found. Optional offset allows you to search from - * specified position. - */ - virtual size_type find(const std::string& seek, size_type offset=0) const = 0; - - /** - * Search for a char in accumulated buffer data without retrieving it. - * Returns size_type position at which found, or npos meaning not - * found. Optional offset allows you to search from specified - * position. - */ - virtual size_type find(char seek, size_type offset=0) const = 0; - - /** - * Get LLEventPump& on which to listen for incoming data. The posted - * LLSD::Map event will contain: - * - * - "data" part of pending data; see setLimit() - * - "len" entire length of pending data, regardless of setLimit() - * - "slot" this ReadPipe's FILESLOT, e.g. LLProcess::STDOUT - * - "name" e.g. "stdout" - * - "desc" e.g. "SLPlugin (pid) stdout" - * - "eof" @c true means there no more data will arrive on this pipe, - * therefore no more events on this pump - * - * If the child sends "abc", and this ReadPipe posts "data"="abc", but - * you don't consume it by reading the std::istream returned by - * get_istream(), and the child next sends "def", ReadPipe will post - * "data"="abcdef". - */ - virtual LLEventPump& getPump() = 0; - - /** - * Set maximum length of buffer data that will be posted in the LLSD - * announcing arrival of new data from the child. If you call - * setLimit(5), and the child sends "abcdef", the LLSD event will - * contain "data"="abcde". However, you may still read the entire - * "abcdef" from get_istream(): this limit affects only the size of - * the data posted with the LLSD event. If you don't call this method, - * @em no data will be posted: the default is 0 bytes. - */ - virtual void setLimit(size_type limit) = 0; - - /** - * Query the current setLimit() limit. - */ - virtual size_type getLimit() const = 0; - }; - - /// Exception thrown by getWritePipe(), getReadPipe() if you didn't ask to - /// create a pipe at the corresponding FILESLOT. - struct NoPipe: public LLException - { - NoPipe(const std::string& what): LLException(what) {} - }; - - /** - * Get a reference to the (only) WritePipe for this LLProcess. @a slot, if - * specified, must be STDIN. Throws NoPipe if you did not request a "pipe" - * for child stdin. Use this method when you know how you created the - * LLProcess in hand. - */ - WritePipe& getWritePipe(FILESLOT slot=STDIN); - - /** - * Get a boost::optional<WritePipe&> to the (only) WritePipe for this - * LLProcess. @a slot, if specified, must be STDIN. The return value is - * empty if you did not request a "pipe" for child stdin. Use this method - * for inspecting an LLProcess you did not create. - */ - boost::optional<WritePipe&> getOptWritePipe(FILESLOT slot=STDIN); - - /** - * Get a reference to one of the ReadPipes for this LLProcess. @a slot, if - * specified, must be STDOUT or STDERR. Throws NoPipe if you did not - * request a "pipe" for child stdout or stderr. Use this method when you - * know how you created the LLProcess in hand. - */ - ReadPipe& getReadPipe(FILESLOT slot); - - /** - * Get a boost::optional<ReadPipe&> to one of the ReadPipes for this - * LLProcess. @a slot, if specified, must be STDOUT or STDERR. The return - * value is empty if you did not request a "pipe" for child stdout or - * stderr. Use this method for inspecting an LLProcess you did not create. - */ - boost::optional<ReadPipe&> getOptReadPipe(FILESLOT slot); - - /// little utilities that really should already be somewhere else in the - /// code base - static std::string basename(const std::string& path); - static std::string getline(std::istream&); + /** + * Get an int-like id value. This is primarily intended for a human reader + * to differentiate processes. + */ + id getProcessID() const; + /** + * Get a "handle" of a kind that you might pass to platform-specific API + * functions to engage features not directly supported by LLProcess. + */ + handle getProcessHandle() const; + + /** + * Test if a process (@c handle obtained from getProcessHandle()) is still + * running. Return same nonzero @c handle value if still running, else + * zero, so you can test it like a bool. But if you want to update a + * stored variable as a side effect, you can write code like this: + * @code + * hchild = LLProcess::isRunning(hchild); + * @endcode + * @note This method is intended as a unit-test hook, not as the first of + * a whole set of operations supported on freestanding @c handle values. + * New functionality should be added as nonstatic members operating on + * the same data as getProcessHandle(). + * + * In particular, if child termination is detected by this static isRunning() + * rather than by nonstatic isRunning(), the LLProcess object won't be + * aware of the child's changed status and may encounter OS errors trying + * to obtain it. This static isRunning() is only intended for after the + * launching LLProcess object has been destroyed. + */ + static handle isRunning(handle, const std::string& desc=""); + + /// Provide symbolic access to child's file slots + enum FILESLOT { STDIN=0, STDOUT=1, STDERR=2, NSLOTS=3 }; + + /** + * For a pipe constructed with @a type "npipe", obtain the generated OS + * filesystem name for the specified pipe. Otherwise returns the empty + * string. @see LLProcess::FileParam::type + */ + std::string getPipeName(FILESLOT) const; + + /// base of ReadPipe, WritePipe + class LL_COMMON_API BasePipe + { + public: + virtual ~BasePipe() = 0; + + typedef std::size_t size_type; + static const size_type npos; + + /** + * Get accumulated buffer length. + * + * For WritePipe, is there still pending data to send to child? + * + * For ReadPipe, we often need to refrain from actually reading the + * std::istream returned by get_istream() until we've accumulated + * enough data to make it worthwhile. For instance, if we're expecting + * a number from the child, but the child happens to flush "12" before + * emitting "3\n", get_istream() >> myint could return 12 rather than + * 123! + */ + virtual size_type size() const = 0; + }; + + /// As returned by getWritePipe() or getOptWritePipe() + class WritePipe: public BasePipe + { + public: + /** + * Get ostream& on which to write to child's stdin. + * + * @usage + * @code + * myProcess->getWritePipe().get_ostream() << "Hello, child!" << std::endl; + * @endcode + */ + virtual std::ostream& get_ostream() = 0; + }; + + /// As returned by getReadPipe() or getOptReadPipe() + class ReadPipe: public BasePipe + { + public: + /** + * Get istream& on which to read from child's stdout or stderr. + * + * @usage + * @code + * std::string stuff; + * myProcess->getReadPipe().get_istream() >> stuff; + * @endcode + * + * You should be sure in advance that the ReadPipe in question can + * fill the request. @see getPump() + */ + virtual std::istream& get_istream() = 0; + + /** + * Like std::getline(get_istream(), line), but trims off trailing '\r' + * to make calling code less platform-sensitive. + */ + virtual std::string getline() = 0; + + /** + * Like get_istream().read(buffer, n), but returns std::string rather + * than requiring caller to construct a buffer, etc. + */ + virtual std::string read(size_type len) = 0; + + /** + * Peek at accumulated buffer data without consuming it. Optional + * parameters give you substr() functionality. + * + * @note You can discard buffer data using get_istream().ignore(n). + */ + virtual std::string peek(size_type offset=0, size_type len=npos) const = 0; + + /** + * Detect presence of a substring (or char) in accumulated buffer data + * without retrieving it. Optional offset allows you to search from + * specified position. + */ + template <typename SEEK> + bool contains(SEEK seek, size_type offset=0) const + { return find(seek, offset) != npos; } + + /** + * Search for a substring in accumulated buffer data without + * retrieving it. Returns size_type position at which found, or npos + * meaning not found. Optional offset allows you to search from + * specified position. + */ + virtual size_type find(const std::string& seek, size_type offset=0) const = 0; + + /** + * Search for a char in accumulated buffer data without retrieving it. + * Returns size_type position at which found, or npos meaning not + * found. Optional offset allows you to search from specified + * position. + */ + virtual size_type find(char seek, size_type offset=0) const = 0; + + /** + * Get LLEventPump& on which to listen for incoming data. The posted + * LLSD::Map event will contain: + * + * - "data" part of pending data; see setLimit() + * - "len" entire length of pending data, regardless of setLimit() + * - "slot" this ReadPipe's FILESLOT, e.g. LLProcess::STDOUT + * - "name" e.g. "stdout" + * - "desc" e.g. "SLPlugin (pid) stdout" + * - "eof" @c true means there no more data will arrive on this pipe, + * therefore no more events on this pump + * + * If the child sends "abc", and this ReadPipe posts "data"="abc", but + * you don't consume it by reading the std::istream returned by + * get_istream(), and the child next sends "def", ReadPipe will post + * "data"="abcdef". + */ + virtual LLEventPump& getPump() = 0; + + /** + * Set maximum length of buffer data that will be posted in the LLSD + * announcing arrival of new data from the child. If you call + * setLimit(5), and the child sends "abcdef", the LLSD event will + * contain "data"="abcde". However, you may still read the entire + * "abcdef" from get_istream(): this limit affects only the size of + * the data posted with the LLSD event. If you don't call this method, + * @em no data will be posted: the default is 0 bytes. + */ + virtual void setLimit(size_type limit) = 0; + + /** + * Query the current setLimit() limit. + */ + virtual size_type getLimit() const = 0; + }; + + /// Exception thrown by getWritePipe(), getReadPipe() if you didn't ask to + /// create a pipe at the corresponding FILESLOT. + struct NoPipe: public LLException + { + NoPipe(const std::string& what): LLException(what) {} + }; + + /** + * Get a reference to the (only) WritePipe for this LLProcess. @a slot, if + * specified, must be STDIN. Throws NoPipe if you did not request a "pipe" + * for child stdin. Use this method when you know how you created the + * LLProcess in hand. + */ + WritePipe& getWritePipe(FILESLOT slot=STDIN); + + /** + * Get a boost::optional<WritePipe&> to the (only) WritePipe for this + * LLProcess. @a slot, if specified, must be STDIN. The return value is + * empty if you did not request a "pipe" for child stdin. Use this method + * for inspecting an LLProcess you did not create. + */ + boost::optional<WritePipe&> getOptWritePipe(FILESLOT slot=STDIN); + + /** + * Get a reference to one of the ReadPipes for this LLProcess. @a slot, if + * specified, must be STDOUT or STDERR. Throws NoPipe if you did not + * request a "pipe" for child stdout or stderr. Use this method when you + * know how you created the LLProcess in hand. + */ + ReadPipe& getReadPipe(FILESLOT slot); + + /** + * Get a boost::optional<ReadPipe&> to one of the ReadPipes for this + * LLProcess. @a slot, if specified, must be STDOUT or STDERR. The return + * value is empty if you did not request a "pipe" for child stdout or + * stderr. Use this method for inspecting an LLProcess you did not create. + */ + boost::optional<ReadPipe&> getOptReadPipe(FILESLOT slot); + + /// little utilities that really should already be somewhere else in the + /// code base + static std::string basename(const std::string& path); + static std::string getline(std::istream&); private: - /// constructor is private: use create() instead - LLProcess(const LLSDOrParams& params); - void autokill(); - // Classic-C-style APR callback - static void status_callback(int reason, void* data, int status); - // Object-oriented callback - void handle_status(int reason, int status); - // implementation for get[Opt][Read|Write]Pipe() - template <class PIPETYPE> - PIPETYPE& getPipe(FILESLOT slot); - template <class PIPETYPE> - boost::optional<PIPETYPE&> getOptPipe(FILESLOT slot); - template <class PIPETYPE> - PIPETYPE* getPipePtr(std::string& error, FILESLOT slot); - - std::string mDesc; - std::string mPostend; - apr_proc_t mProcess; - bool mAutokill, mAttached; - Status mStatus; - // explicitly want this ptr_vector to be able to store NULLs - typedef boost::ptr_vector< boost::nullable<BasePipe> > PipeVector; - PipeVector mPipes; + /// constructor is private: use create() instead + LLProcess(const LLSDOrParams& params); + void autokill(); + // Classic-C-style APR callback + static void status_callback(int reason, void* data, int status); + // Object-oriented callback + void handle_status(int reason, int status); + // implementation for get[Opt][Read|Write]Pipe() + template <class PIPETYPE> + PIPETYPE& getPipe(FILESLOT slot); + template <class PIPETYPE> + boost::optional<PIPETYPE&> getOptPipe(FILESLOT slot); + template <class PIPETYPE> + PIPETYPE* getPipePtr(std::string& error, FILESLOT slot); + + std::string mDesc; + std::string mPostend; + apr_proc_t mProcess; + bool mAutokill, mAttached; + Status mStatus; + // explicitly want this ptr_vector to be able to store NULLs + typedef boost::ptr_vector< boost::nullable<BasePipe> > PipeVector; + PipeVector mPipes; apr_pool_t* mPool; }; diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 28f8bc2b93..9d53b9be35 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocessor.cpp * @brief Code to figure out the processor. Originally by Benjamin Jurke. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,199 +34,199 @@ //#include <memory> #if LL_WINDOWS -# include "llwin32headerslean.h" -# define _interlockedbittestandset _renamed_interlockedbittestandset -# define _interlockedbittestandreset _renamed_interlockedbittestandreset -# include <intrin.h> -# undef _interlockedbittestandset -# undef _interlockedbittestandreset +# include "llwin32headerslean.h" +# define _interlockedbittestandset _renamed_interlockedbittestandset +# define _interlockedbittestandreset _renamed_interlockedbittestandreset +# include <intrin.h> +# undef _interlockedbittestandset +# undef _interlockedbittestandreset #endif #include "llsd.h" class LLProcessorInfoImpl; // foward declaration for the mImpl; -namespace +namespace { - enum cpu_info - { - eBrandName = 0, - eFrequency, - eVendor, - eStepping, - eFamily, - eExtendedFamily, - eModel, - eExtendedModel, - eType, - eBrandID, - eFamilyName - }; - - - const char* cpu_info_names[] = - { - "Processor Name", - "Frequency", - "Vendor", - "Stepping", - "Family", - "Extended Family", - "Model", - "Extended Model", - "Type", - "Brand ID", - "Family Name" - }; - - enum cpu_config - { - eMaxID, - eMaxExtID, - eCLFLUSHCacheLineSize, - eAPICPhysicalID, - eCacheLineSize, - eL2Associativity, - eCacheSizeK, - eFeatureBits, - eExtFeatureBits - }; - - const char* cpu_config_names[] = - { - "Max Supported CPUID level", - "Max Supported Ext. CPUID level", - "CLFLUSH cache line size", - "APIC Physical ID", - "Cache Line Size", - "L2 Associativity", - "Cache Size", - "Feature Bits", - "Ext. Feature Bits" - }; - - - - // *NOTE:Mani - this contains the elements we reference directly and extensions beyond the first 32. - // The rest of the names are referenced by bit maks returned from cpuid. - enum cpu_features - { - eSSE_Ext=25, - eSSE2_Ext=26, - - eSSE3_Features=32, - eMONTIOR_MWAIT=33, - eCPLDebugStore=34, - eThermalMonitor2=35, - eAltivec=36, + enum cpu_info + { + eBrandName = 0, + eFrequency, + eVendor, + eStepping, + eFamily, + eExtendedFamily, + eModel, + eExtendedModel, + eType, + eBrandID, + eFamilyName + }; + + + const char* cpu_info_names[] = + { + "Processor Name", + "Frequency", + "Vendor", + "Stepping", + "Family", + "Extended Family", + "Model", + "Extended Model", + "Type", + "Brand ID", + "Family Name" + }; + + enum cpu_config + { + eMaxID, + eMaxExtID, + eCLFLUSHCacheLineSize, + eAPICPhysicalID, + eCacheLineSize, + eL2Associativity, + eCacheSizeK, + eFeatureBits, + eExtFeatureBits + }; + + const char* cpu_config_names[] = + { + "Max Supported CPUID level", + "Max Supported Ext. CPUID level", + "CLFLUSH cache line size", + "APIC Physical ID", + "Cache Line Size", + "L2 Associativity", + "Cache Size", + "Feature Bits", + "Ext. Feature Bits" + }; + + + + // *NOTE:Mani - this contains the elements we reference directly and extensions beyond the first 32. + // The rest of the names are referenced by bit maks returned from cpuid. + enum cpu_features + { + eSSE_Ext=25, + eSSE2_Ext=26, + + eSSE3_Features=32, + eMONTIOR_MWAIT=33, + eCPLDebugStore=34, + eThermalMonitor2=35, + eAltivec=36, eSSE3S_Features = 37, eSSE4_1_Features = 38, eSSE4_2_Features = 39, eSSE4a_Features = 40, - }; - - const char* cpu_feature_names[] = - { - "x87 FPU On Chip", - "Virtual-8086 Mode Enhancement", - "Debugging Extensions", - "Page Size Extensions", - "Time Stamp Counter", - "RDMSR and WRMSR Support", - "Physical Address Extensions", - "Machine Check Exception", - "CMPXCHG8B Instruction", - "APIC On Chip", - "Unknown1", - "SYSENTER and SYSEXIT", - "Memory Type Range Registers", - "PTE Global Bit", - "Machine Check Architecture", - "Conditional Move/Compare Instruction", - "Page Attribute Table", - "Page Size Extension", - "Processor Serial Number", - "CFLUSH Extension", - "Unknown2", - "Debug Store", - "Thermal Monitor and Clock Ctrl", - "MMX Technology", - "FXSAVE/FXRSTOR", - "SSE Extensions", - "SSE2 Extensions", - "Self Snoop", - "Hyper-threading Technology", - "Thermal Monitor", - "Unknown4", - "Pend. Brk. EN.", // 31 End of FeatureInfo bits - - "SSE3 New Instructions", // 32 - "MONITOR/MWAIT", - "CPL Qualified Debug Store", - "Thermal Monitor 2", - - "Altivec", + }; + + const char* cpu_feature_names[] = + { + "x87 FPU On Chip", + "Virtual-8086 Mode Enhancement", + "Debugging Extensions", + "Page Size Extensions", + "Time Stamp Counter", + "RDMSR and WRMSR Support", + "Physical Address Extensions", + "Machine Check Exception", + "CMPXCHG8B Instruction", + "APIC On Chip", + "Unknown1", + "SYSENTER and SYSEXIT", + "Memory Type Range Registers", + "PTE Global Bit", + "Machine Check Architecture", + "Conditional Move/Compare Instruction", + "Page Attribute Table", + "Page Size Extension", + "Processor Serial Number", + "CFLUSH Extension", + "Unknown2", + "Debug Store", + "Thermal Monitor and Clock Ctrl", + "MMX Technology", + "FXSAVE/FXRSTOR", + "SSE Extensions", + "SSE2 Extensions", + "Self Snoop", + "Hyper-threading Technology", + "Thermal Monitor", + "Unknown4", + "Pend. Brk. EN.", // 31 End of FeatureInfo bits + + "SSE3 New Instructions", // 32 + "MONITOR/MWAIT", + "CPL Qualified Debug Store", + "Thermal Monitor 2", + + "Altivec", "SSE3S Instructions", "SSE4.1 Instructions", "SSE4.2 Instructions", "SSE4a Instructions", - }; - - std::string intel_CPUFamilyName(int composed_family) - { - switch(composed_family) - { - case 3: return "Intel i386"; - case 4: return "Intel i486"; - case 5: return "Intel Pentium"; - case 6: return "Intel Pentium Pro/2/3, Core"; - case 7: return "Intel Itanium (IA-64)"; - case 0xF: return "Intel Pentium 4"; - case 0x10: return "Intel Itanium 2 (IA-64)"; - } - return STRINGIZE("Intel <unknown 0x" << std::hex << composed_family << ">"); - } - - std::string amd_CPUFamilyName(int composed_family) - { + }; + + std::string intel_CPUFamilyName(int composed_family) + { + switch(composed_family) + { + case 3: return "Intel i386"; + case 4: return "Intel i486"; + case 5: return "Intel Pentium"; + case 6: return "Intel Pentium Pro/2/3, Core"; + case 7: return "Intel Itanium (IA-64)"; + case 0xF: return "Intel Pentium 4"; + case 0x10: return "Intel Itanium 2 (IA-64)"; + } + return STRINGIZE("Intel <unknown 0x" << std::hex << composed_family << ">"); + } + + std::string amd_CPUFamilyName(int composed_family) + { // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures // https://developer.amd.com/resources/developer-guides-manuals/ - switch(composed_family) - { - case 4: return "AMD 80486/5x86"; - case 5: return "AMD K5/K6"; - case 6: return "AMD K7"; - case 0xF: return "AMD K8"; - case 0x10: return "AMD K8L"; - case 0x12: return "AMD K10"; - case 0x14: return "AMD Bobcat"; - case 0x15: return "AMD Bulldozer"; - case 0x16: return "AMD Jaguar"; - case 0x17: return "AMD Zen/Zen+/Zen2"; - case 0x18: return "AMD Hygon Dhyana"; - case 0x19: return "AMD Zen 3"; - } - return STRINGIZE("AMD <unknown 0x" << std::hex << composed_family << ">"); - } - - std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family) - { - const char* intel_string = "GenuineIntel"; - const char* amd_string = "AuthenticAMD"; - if (LLStringUtil::startsWith(cpu_vendor, intel_string)) - { - U32 composed_family = family + ext_family; - return intel_CPUFamilyName(composed_family); - } - else if (LLStringUtil::startsWith(cpu_vendor, amd_string)) - { - U32 composed_family = (family == 0xF) - ? family + ext_family - : family; - return amd_CPUFamilyName(composed_family); - } - return STRINGIZE("Unrecognized CPU vendor <" << cpu_vendor << ">"); - } + switch(composed_family) + { + case 4: return "AMD 80486/5x86"; + case 5: return "AMD K5/K6"; + case 6: return "AMD K7"; + case 0xF: return "AMD K8"; + case 0x10: return "AMD K8L"; + case 0x12: return "AMD K10"; + case 0x14: return "AMD Bobcat"; + case 0x15: return "AMD Bulldozer"; + case 0x16: return "AMD Jaguar"; + case 0x17: return "AMD Zen/Zen+/Zen2"; + case 0x18: return "AMD Hygon Dhyana"; + case 0x19: return "AMD Zen 3"; + } + return STRINGIZE("AMD <unknown 0x" << std::hex << composed_family << ">"); + } + + std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family) + { + const char* intel_string = "GenuineIntel"; + const char* amd_string = "AuthenticAMD"; + if (LLStringUtil::startsWith(cpu_vendor, intel_string)) + { + U32 composed_family = family + ext_family; + return intel_CPUFamilyName(composed_family); + } + else if (LLStringUtil::startsWith(cpu_vendor, amd_string)) + { + U32 composed_family = (family == 0xF) + ? family + ext_family + : family; + return amd_CPUFamilyName(composed_family); + } + return STRINGIZE("Unrecognized CPU vendor <" << cpu_vendor << ">"); + } } // end unnamed namespace @@ -235,28 +235,28 @@ namespace class LLProcessorInfoImpl { public: - LLProcessorInfoImpl() - { - mProcessorInfo["info"] = LLSD::emptyMap(); - mProcessorInfo["config"] = LLSD::emptyMap(); - mProcessorInfo["extension"] = LLSD::emptyMap(); - } - virtual ~LLProcessorInfoImpl() {} - - F64 getCPUFrequency() const - { - return getInfo(eFrequency, 0).asReal(); - } - - bool hasSSE() const - { - return hasExtension(cpu_feature_names[eSSE_Ext]); - } - - bool hasSSE2() const - { - return hasExtension(cpu_feature_names[eSSE2_Ext]); - } + LLProcessorInfoImpl() + { + mProcessorInfo["info"] = LLSD::emptyMap(); + mProcessorInfo["config"] = LLSD::emptyMap(); + mProcessorInfo["extension"] = LLSD::emptyMap(); + } + virtual ~LLProcessorInfoImpl() {} + + F64 getCPUFrequency() const + { + return getInfo(eFrequency, 0).asReal(); + } + + bool hasSSE() const + { + return hasExtension(cpu_feature_names[eSSE_Ext]); + } + + bool hasSSE2() const + { + return hasExtension(cpu_feature_names[eSSE2_Ext]); + } bool hasSSE3() const { @@ -283,229 +283,229 @@ public: return hasExtension(cpu_feature_names[eSSE4a_Features]); } - bool hasAltivec() const - { - return hasExtension("Altivec"); - } - - std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unset family").asString(); } - std::string getCPUBrandName() const { return getInfo(eBrandName, "Unset brand").asString(); } - - // This is virtual to support a different linux format. - // *NOTE:Mani - I didn't want to screw up server use of this data... - virtual std::string getCPUFeatureDescription() const - { - std::ostringstream out; - out << std::endl << std::endl; - out << "// CPU General Information" << std::endl; - out << "//////////////////////////" << std::endl; - out << "Processor Name: " << getCPUBrandName() << std::endl; - out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl; - out << "Vendor: " << getInfo(eVendor, "Unset vendor").asString() << std::endl; - out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl; - out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl; - out << "Model: " << getInfo(eModel, 0) << std::endl; - out << "Extended model: " << getInfo(eExtendedModel, 0) << std::endl; - out << "Type: " << getInfo(eType, 0) << std::endl; - out << "Brand ID: " << getInfo(eBrandID, 0) << std::endl; - out << std::endl; - out << "// CPU Configuration" << std::endl; - out << "//////////////////////////" << std::endl; - - // Iterate through the dictionary of configuration options. - LLSD configs = mProcessorInfo["config"]; - for(LLSD::map_const_iterator cfgItr = configs.beginMap(); cfgItr != configs.endMap(); ++cfgItr) - { - out << cfgItr->first << " = " << cfgItr->second << std::endl; - } - out << std::endl; - - out << "// CPU Extensions" << std::endl; - out << "//////////////////////////" << std::endl; - - for(LLSD::map_const_iterator itr = mProcessorInfo["extension"].beginMap(); itr != mProcessorInfo["extension"].endMap(); ++itr) - { - out << " " << itr->first << std::endl; - } - return out.str(); - } + bool hasAltivec() const + { + return hasExtension("Altivec"); + } + + std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unset family").asString(); } + std::string getCPUBrandName() const { return getInfo(eBrandName, "Unset brand").asString(); } + + // This is virtual to support a different linux format. + // *NOTE:Mani - I didn't want to screw up server use of this data... + virtual std::string getCPUFeatureDescription() const + { + std::ostringstream out; + out << std::endl << std::endl; + out << "// CPU General Information" << std::endl; + out << "//////////////////////////" << std::endl; + out << "Processor Name: " << getCPUBrandName() << std::endl; + out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl; + out << "Vendor: " << getInfo(eVendor, "Unset vendor").asString() << std::endl; + out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl; + out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl; + out << "Model: " << getInfo(eModel, 0) << std::endl; + out << "Extended model: " << getInfo(eExtendedModel, 0) << std::endl; + out << "Type: " << getInfo(eType, 0) << std::endl; + out << "Brand ID: " << getInfo(eBrandID, 0) << std::endl; + out << std::endl; + out << "// CPU Configuration" << std::endl; + out << "//////////////////////////" << std::endl; + + // Iterate through the dictionary of configuration options. + LLSD configs = mProcessorInfo["config"]; + for(LLSD::map_const_iterator cfgItr = configs.beginMap(); cfgItr != configs.endMap(); ++cfgItr) + { + out << cfgItr->first << " = " << cfgItr->second << std::endl; + } + out << std::endl; + + out << "// CPU Extensions" << std::endl; + out << "//////////////////////////" << std::endl; + + for(LLSD::map_const_iterator itr = mProcessorInfo["extension"].beginMap(); itr != mProcessorInfo["extension"].endMap(); ++itr) + { + out << " " << itr->first << std::endl; + } + return out.str(); + } protected: - void setInfo(cpu_info info_type, const LLSD& value) - { - setInfo(cpu_info_names[info_type], value); - } + void setInfo(cpu_info info_type, const LLSD& value) + { + setInfo(cpu_info_names[info_type], value); + } LLSD getInfo(cpu_info info_type, const LLSD& defaultVal) const - { - return getInfo(cpu_info_names[info_type], defaultVal); - } - - void setConfig(cpu_config config_type, const LLSD& value) - { - setConfig(cpu_config_names[config_type], value); - } - LLSD getConfig(cpu_config config_type, const LLSD& defaultVal) const - { - return getConfig(cpu_config_names[config_type], defaultVal); - } - - void setExtension(const std::string& name) { mProcessorInfo["extension"][name] = "true"; } - bool hasExtension(const std::string& name) const - { - return mProcessorInfo["extension"].has(name); - } + { + return getInfo(cpu_info_names[info_type], defaultVal); + } + + void setConfig(cpu_config config_type, const LLSD& value) + { + setConfig(cpu_config_names[config_type], value); + } + LLSD getConfig(cpu_config config_type, const LLSD& defaultVal) const + { + return getConfig(cpu_config_names[config_type], defaultVal); + } + + void setExtension(const std::string& name) { mProcessorInfo["extension"][name] = "true"; } + bool hasExtension(const std::string& name) const + { + return mProcessorInfo["extension"].has(name); + } private: - void setInfo(const std::string& name, const LLSD& value) { mProcessorInfo["info"][name]=value; } - LLSD getInfo(const std::string& name, const LLSD& defaultVal) const - { - if(mProcessorInfo["info"].has(name)) - { - return mProcessorInfo["info"][name]; - } - return defaultVal; - } - void setConfig(const std::string& name, const LLSD& value) { mProcessorInfo["config"][name]=value; } - LLSD getConfig(const std::string& name, const LLSD& defaultVal) const - { - LLSD r = mProcessorInfo["config"].get(name); - return r.isDefined() ? r : defaultVal; - } + void setInfo(const std::string& name, const LLSD& value) { mProcessorInfo["info"][name]=value; } + LLSD getInfo(const std::string& name, const LLSD& defaultVal) const + { + if(mProcessorInfo["info"].has(name)) + { + return mProcessorInfo["info"][name]; + } + return defaultVal; + } + void setConfig(const std::string& name, const LLSD& value) { mProcessorInfo["config"][name]=value; } + LLSD getConfig(const std::string& name, const LLSD& defaultVal) const + { + LLSD r = mProcessorInfo["config"].get(name); + return r.isDefined() ? r : defaultVal; + } private: - LLSD mProcessorInfo; + LLSD mProcessorInfo; }; #ifdef LL_MSVC -// LL_MSVC and not LLWINDOWS because some of the following code +// LL_MSVC and not LLWINDOWS because some of the following code // uses the MSVC compiler intrinsics __cpuid() and __rdtsc(). // Delays for the specified amount of milliseconds static void _Delay(unsigned int ms) { - LARGE_INTEGER freq, c1, c2; - __int64 x; - - // Get High-Res Timer frequency - if (!QueryPerformanceFrequency(&freq)) - return; - - // Convert ms to High-Res Timer value - x = freq.QuadPart/1000*ms; - - // Get first snapshot of High-Res Timer value - QueryPerformanceCounter(&c1); - do - { - // Get second snapshot - QueryPerformanceCounter(&c2); - }while(c2.QuadPart-c1.QuadPart < x); - // Loop while (second-first < x) + LARGE_INTEGER freq, c1, c2; + __int64 x; + + // Get High-Res Timer frequency + if (!QueryPerformanceFrequency(&freq)) + return; + + // Convert ms to High-Res Timer value + x = freq.QuadPart/1000*ms; + + // Get first snapshot of High-Res Timer value + QueryPerformanceCounter(&c1); + do + { + // Get second snapshot + QueryPerformanceCounter(&c2); + }while(c2.QuadPart-c1.QuadPart < x); + // Loop while (second-first < x) } static F64 calculate_cpu_frequency(U32 measure_msecs) { - if(measure_msecs == 0) - { - return 0; - } - - // After that we declare some vars and check the frequency of the high - // resolution timer for the measure process. - // If there"s no high-res timer, we exit. - unsigned __int64 starttime, endtime, timedif, freq, start, end, dif; - if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq)) - { - return 0; - } - - // Now we can init the measure process. We set the process and thread priority - // to the highest available level (Realtime priority). Also we focus the - // first processor in the multiprocessor system. - HANDLE hProcess = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - unsigned long dwCurPriorityClass = GetPriorityClass(hProcess); - int iCurThreadPriority = GetThreadPriority(hThread); - DWORD_PTR dwProcessMask, dwSystemMask, dwNewMask = 1; - GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask); - - SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); - SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); - SetProcessAffinityMask(hProcess, dwNewMask); - - //// Now we call a CPUID to ensure, that all other prior called functions are - //// completed now (serialization) - //__asm cpuid - int cpu_info[4] = {-1}; - __cpuid(cpu_info, 0); - - // We ask the high-res timer for the start time - QueryPerformanceCounter((LARGE_INTEGER *) &starttime); - - // Then we get the current cpu clock and store it - start = __rdtsc(); - - // Now we wart for some msecs - _Delay(measure_msecs); - // Sleep(uiMeasureMSecs); - - // We ask for the end time - QueryPerformanceCounter((LARGE_INTEGER *) &endtime); - - // And also for the end cpu clock - end = __rdtsc(); - - // Now we can restore the default process and thread priorities - SetProcessAffinityMask(hProcess, dwProcessMask); - SetThreadPriority(hThread, iCurThreadPriority); - SetPriorityClass(hProcess, dwCurPriorityClass); - - // Then we calculate the time and clock differences - dif = end - start; - timedif = endtime - starttime; - - // And finally the frequency is the clock difference divided by the time - // difference. - F64 frequency = (F64)dif / (((F64)timedif) / freq); - - // At last we just return the frequency that is also stored in the call - // member var uqwFrequency - converted to MHz - return frequency / (F64)1000000; + if(measure_msecs == 0) + { + return 0; + } + + // After that we declare some vars and check the frequency of the high + // resolution timer for the measure process. + // If there"s no high-res timer, we exit. + unsigned __int64 starttime, endtime, timedif, freq, start, end, dif; + if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq)) + { + return 0; + } + + // Now we can init the measure process. We set the process and thread priority + // to the highest available level (Realtime priority). Also we focus the + // first processor in the multiprocessor system. + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + unsigned long dwCurPriorityClass = GetPriorityClass(hProcess); + int iCurThreadPriority = GetThreadPriority(hThread); + DWORD_PTR dwProcessMask, dwSystemMask, dwNewMask = 1; + GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask); + + SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + SetProcessAffinityMask(hProcess, dwNewMask); + + //// Now we call a CPUID to ensure, that all other prior called functions are + //// completed now (serialization) + //__asm cpuid + int cpu_info[4] = {-1}; + __cpuid(cpu_info, 0); + + // We ask the high-res timer for the start time + QueryPerformanceCounter((LARGE_INTEGER *) &starttime); + + // Then we get the current cpu clock and store it + start = __rdtsc(); + + // Now we wart for some msecs + _Delay(measure_msecs); + // Sleep(uiMeasureMSecs); + + // We ask for the end time + QueryPerformanceCounter((LARGE_INTEGER *) &endtime); + + // And also for the end cpu clock + end = __rdtsc(); + + // Now we can restore the default process and thread priorities + SetProcessAffinityMask(hProcess, dwProcessMask); + SetThreadPriority(hThread, iCurThreadPriority); + SetPriorityClass(hProcess, dwCurPriorityClass); + + // Then we calculate the time and clock differences + dif = end - start; + timedif = endtime - starttime; + + // And finally the frequency is the clock difference divided by the time + // difference. + F64 frequency = (F64)dif / (((F64)timedif) / freq); + + // At last we just return the frequency that is also stored in the call + // member var uqwFrequency - converted to MHz + return frequency / (F64)1000000; } // Windows implementation class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl { public: - LLProcessorInfoWindowsImpl() - { - getCPUIDInfo(); - setInfo(eFrequency, calculate_cpu_frequency(50)); - } + LLProcessorInfoWindowsImpl() + { + getCPUIDInfo(); + setInfo(eFrequency, calculate_cpu_frequency(50)); + } private: - void getCPUIDInfo() - { - // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx - - // __cpuid with an InfoType argument of 0 returns the number of - // valid Ids in cpu_info[0] and the CPU identification string in - // the other three array elements. The CPU identification string is - // not in linear order. The code below arranges the information - // in a human readable form. - int cpu_info[4] = {-1}; - __cpuid(cpu_info, 0); - unsigned int ids = (unsigned int)cpu_info[0]; - setConfig(eMaxID, (S32)ids); - - char cpu_vendor[0x20]; - memset(cpu_vendor, 0, sizeof(cpu_vendor)); - *((int*)cpu_vendor) = cpu_info[1]; - *((int*)(cpu_vendor+4)) = cpu_info[3]; - *((int*)(cpu_vendor+8)) = cpu_info[2]; - setInfo(eVendor, cpu_vendor); + void getCPUIDInfo() + { + // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx + + // __cpuid with an InfoType argument of 0 returns the number of + // valid Ids in cpu_info[0] and the CPU identification string in + // the other three array elements. The CPU identification string is + // not in linear order. The code below arranges the information + // in a human readable form. + int cpu_info[4] = {-1}; + __cpuid(cpu_info, 0); + unsigned int ids = (unsigned int)cpu_info[0]; + setConfig(eMaxID, (S32)ids); + + char cpu_vendor[0x20]; + memset(cpu_vendor, 0, sizeof(cpu_vendor)); + *((int*)cpu_vendor) = cpu_info[1]; + *((int*)(cpu_vendor+4)) = cpu_info[3]; + *((int*)(cpu_vendor+8)) = cpu_info[2]; + setInfo(eVendor, cpu_vendor); std::string cmp_vendor(cpu_vendor); bool is_amd = false; if (cmp_vendor == "AuthenticAMD") @@ -513,49 +513,49 @@ private: is_amd = true; } - // Get the information associated with each valid Id - for(unsigned int i=0; i<=ids; ++i) - { - __cpuid(cpu_info, i); - - // Interpret CPU feature information. - if (i == 1) - { - setInfo(eStepping, cpu_info[0] & 0xf); - setInfo(eModel, (cpu_info[0] >> 4) & 0xf); - int family = (cpu_info[0] >> 8) & 0xf; - setInfo(eFamily, family); - setInfo(eType, (cpu_info[0] >> 12) & 0x3); - setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf); - int ext_family = (cpu_info[0] >> 20) & 0xff; - setInfo(eExtendedFamily, ext_family); - setInfo(eBrandID, cpu_info[1] & 0xff); - - setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); - - setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); - setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); - - if(cpu_info[2] & 0x1) - { - setExtension(cpu_feature_names[eSSE3_Features]); - } - - if(cpu_info[2] & 0x8) - { + // Get the information associated with each valid Id + for(unsigned int i=0; i<=ids; ++i) + { + __cpuid(cpu_info, i); + + // Interpret CPU feature information. + if (i == 1) + { + setInfo(eStepping, cpu_info[0] & 0xf); + setInfo(eModel, (cpu_info[0] >> 4) & 0xf); + int family = (cpu_info[0] >> 8) & 0xf; + setInfo(eFamily, family); + setInfo(eType, (cpu_info[0] >> 12) & 0x3); + setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf); + int ext_family = (cpu_info[0] >> 20) & 0xff; + setInfo(eExtendedFamily, ext_family); + setInfo(eBrandID, cpu_info[1] & 0xff); + + setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); + + setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + + if(cpu_info[2] & 0x1) + { + setExtension(cpu_feature_names[eSSE3_Features]); + } + + if(cpu_info[2] & 0x8) + { // intel specific SSE3 suplements - setExtension(cpu_feature_names[eMONTIOR_MWAIT]); - } - - if(cpu_info[2] & 0x10) - { - setExtension(cpu_feature_names[eCPLDebugStore]); - } - - if(cpu_info[2] & 0x100) - { - setExtension(cpu_feature_names[eThermalMonitor2]); - } + setExtension(cpu_feature_names[eMONTIOR_MWAIT]); + } + + if(cpu_info[2] & 0x10) + { + setExtension(cpu_feature_names[eCPLDebugStore]); + } + + if(cpu_info[2] & 0x100) + { + setExtension(cpu_feature_names[eThermalMonitor2]); + } if (cpu_info[2] & 0x200) { @@ -572,32 +572,32 @@ private: setExtension(cpu_feature_names[eSSE4_2_Features]); } - unsigned int feature_info = (unsigned int) cpu_info[3]; - for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) - { - if(feature_info & bit) - { - setExtension(cpu_feature_names[index]); - } - } - } - } - - // Calling __cpuid with 0x80000000 as the InfoType argument - // gets the number of valid extended IDs. - __cpuid(cpu_info, 0x80000000); - unsigned int ext_ids = cpu_info[0]; - setConfig(eMaxExtID, 0); - - char cpu_brand_string[0x40]; - memset(cpu_brand_string, 0, sizeof(cpu_brand_string)); - - // Get the information associated with each extended ID. - for(unsigned int i=0x80000000; i<=ext_ids; ++i) - { - __cpuid(cpu_info, i); - - // Interpret CPU brand string and cache information. + unsigned int feature_info = (unsigned int) cpu_info[3]; + for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) + { + if(feature_info & bit) + { + setExtension(cpu_feature_names[index]); + } + } + } + } + + // Calling __cpuid with 0x80000000 as the InfoType argument + // gets the number of valid extended IDs. + __cpuid(cpu_info, 0x80000000); + unsigned int ext_ids = cpu_info[0]; + setConfig(eMaxExtID, 0); + + char cpu_brand_string[0x40]; + memset(cpu_brand_string, 0, sizeof(cpu_brand_string)); + + // Get the information associated with each extended ID. + for(unsigned int i=0x80000000; i<=ext_ids; ++i) + { + __cpuid(cpu_info, i); + + // Interpret CPU brand string and cache information. if (i == 0x80000001) { if (is_amd) @@ -609,21 +609,21 @@ private: { memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info)); } - else if (i == 0x80000003) - memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info)); - else if (i == 0x80000004) - { - memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info)); - setInfo(eBrandName, cpu_brand_string); - } - else if (i == 0x80000006) - { - setConfig(eCacheLineSize, cpu_info[2] & 0xff); - setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf); - setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff); - } - } - } + else if (i == 0x80000003) + memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info)); + else if (i == 0x80000004) + { + memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info)); + setInfo(eBrandName, cpu_brand_string); + } + else if (i == 0x80000006) + { + setConfig(eCacheLineSize, cpu_info[2] & 0xff); + setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf); + setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff); + } + } + } }; #elif LL_DARWIN @@ -634,126 +634,126 @@ private: class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl { public: - LLProcessorInfoDarwinImpl() - { - getCPUIDInfo(); - uint64_t frequency = getSysctlInt64("hw.cpufrequency"); - setInfo(eFrequency, (F64)frequency / (F64)1000000); - } + LLProcessorInfoDarwinImpl() + { + getCPUIDInfo(); + uint64_t frequency = getSysctlInt64("hw.cpufrequency"); + setInfo(eFrequency, (F64)frequency / (F64)1000000); + } - virtual ~LLProcessorInfoDarwinImpl() {} + virtual ~LLProcessorInfoDarwinImpl() {} private: - int getSysctlInt(const char* name) - { - int result = 0; - size_t len = sizeof(int); - int error = sysctlbyname(name, (void*)&result, &len, NULL, 0); - return error == -1 ? 0 : result; - } - - uint64_t getSysctlInt64(const char* name) - { - uint64_t value = 0; - size_t size = sizeof(value); - int result = sysctlbyname(name, (void*)&value, &size, NULL, 0); - if ( result == 0 ) - { - if ( size == sizeof( uint64_t ) ) - ; - else if ( size == sizeof( uint32_t ) ) - value = (uint64_t)(( uint32_t *)&value); - else if ( size == sizeof( uint16_t ) ) - value = (uint64_t)(( uint16_t *)&value); - else if ( size == sizeof( uint8_t ) ) - value = (uint64_t)(( uint8_t *)&value); - else - { - LL_WARNS() << "Unknown type returned from sysctl" << LL_ENDL; - } - } - - return result == -1 ? 0 : value; - } - - void getCPUIDInfo() - { - size_t len = 0; - - char cpu_brand_string[0x40]; - len = sizeof(cpu_brand_string); - memset(cpu_brand_string, 0, len); - sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0); - cpu_brand_string[0x3f] = 0; - setInfo(eBrandName, cpu_brand_string); - - char cpu_vendor[0x20]; - len = sizeof(cpu_vendor); - memset(cpu_vendor, 0, len); - sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0); - cpu_vendor[0x1f] = 0; - setInfo(eVendor, cpu_vendor); - - setInfo(eStepping, getSysctlInt("machdep.cpu.stepping")); - setInfo(eModel, getSysctlInt("machdep.cpu.model")); - int family = getSysctlInt("machdep.cpu.family"); - int ext_family = getSysctlInt("machdep.cpu.extfamily"); - setInfo(eFamily, family); - setInfo(eExtendedFamily, ext_family); - setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); - setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); - setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); - setInfo(eType, 0); // ? where to find this? - - //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); - //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); - setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); - setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); - setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); - - uint64_t feature_info = getSysctlInt64("machdep.cpu.feature_bits"); - S32 *feature_infos = (S32*)(&feature_info); - - setConfig(eFeatureBits, feature_infos[0]); - - for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) - { - if(feature_info & bit) - { - setExtension(cpu_feature_names[index]); - } - } - - // *NOTE:Mani - I didn't find any docs that assure me that machdep.cpu.feature_bits will always be - // The feature bits I think it is. Here's a test: + int getSysctlInt(const char* name) + { + int result = 0; + size_t len = sizeof(int); + int error = sysctlbyname(name, (void*)&result, &len, NULL, 0); + return error == -1 ? 0 : result; + } + + uint64_t getSysctlInt64(const char* name) + { + uint64_t value = 0; + size_t size = sizeof(value); + int result = sysctlbyname(name, (void*)&value, &size, NULL, 0); + if ( result == 0 ) + { + if ( size == sizeof( uint64_t ) ) + ; + else if ( size == sizeof( uint32_t ) ) + value = (uint64_t)(( uint32_t *)&value); + else if ( size == sizeof( uint16_t ) ) + value = (uint64_t)(( uint16_t *)&value); + else if ( size == sizeof( uint8_t ) ) + value = (uint64_t)(( uint8_t *)&value); + else + { + LL_WARNS() << "Unknown type returned from sysctl" << LL_ENDL; + } + } + + return result == -1 ? 0 : value; + } + + void getCPUIDInfo() + { + size_t len = 0; + + char cpu_brand_string[0x40]; + len = sizeof(cpu_brand_string); + memset(cpu_brand_string, 0, len); + sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0); + cpu_brand_string[0x3f] = 0; + setInfo(eBrandName, cpu_brand_string); + + char cpu_vendor[0x20]; + len = sizeof(cpu_vendor); + memset(cpu_vendor, 0, len); + sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0); + cpu_vendor[0x1f] = 0; + setInfo(eVendor, cpu_vendor); + + setInfo(eStepping, getSysctlInt("machdep.cpu.stepping")); + setInfo(eModel, getSysctlInt("machdep.cpu.model")); + int family = getSysctlInt("machdep.cpu.family"); + int ext_family = getSysctlInt("machdep.cpu.extfamily"); + setInfo(eFamily, family); + setInfo(eExtendedFamily, ext_family); + setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); + setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); + setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); + setInfo(eType, 0); // ? where to find this? + + //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); + setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); + setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); + + uint64_t feature_info = getSysctlInt64("machdep.cpu.feature_bits"); + S32 *feature_infos = (S32*)(&feature_info); + + setConfig(eFeatureBits, feature_infos[0]); + + for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) + { + if(feature_info & bit) + { + setExtension(cpu_feature_names[index]); + } + } + + // *NOTE:Mani - I didn't find any docs that assure me that machdep.cpu.feature_bits will always be + // The feature bits I think it is. Here's a test: #ifndef LL_RELEASE_FOR_DOWNLOAD - #if defined(__i386__) && defined(__PIC__) - /* %ebx may be the PIC register. */ - #define __cpuid(level, a, b, c, d) \ - __asm__ ("xchgl\t%%ebx, %1\n\t" \ - "cpuid\n\t" \ - "xchgl\t%%ebx, %1\n\t" \ - : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ - : "0" (level)) - #else - #define __cpuid(level, a, b, c, d) \ - __asm__ ("cpuid\n\t" \ - : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ - : "0" (level)) - #endif - - unsigned int eax, ebx, ecx, edx; - __cpuid(0x1, eax, ebx, ecx, edx); - if(feature_infos[0] != (S32)edx) - { - LL_WARNS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; - } -#endif // LL_RELEASE_FOR_DOWNLOAD - - - uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits"); - S32 *ext_feature_infos = (S32*)(&ext_feature_info); - setConfig(eExtFeatureBits, ext_feature_infos[0]); + #if defined(__i386__) && defined(__PIC__) + /* %ebx may be the PIC register. */ + #define __cpuid(level, a, b, c, d) \ + __asm__ ("xchgl\t%%ebx, %1\n\t" \ + "cpuid\n\t" \ + "xchgl\t%%ebx, %1\n\t" \ + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ + : "0" (level)) + #else + #define __cpuid(level, a, b, c, d) \ + __asm__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level)) + #endif + + unsigned int eax, ebx, ecx, edx; + __cpuid(0x1, eax, ebx, ecx, edx); + if(feature_infos[0] != (S32)edx) + { + LL_WARNS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; + } +#endif // LL_RELEASE_FOR_DOWNLOAD + + + uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits"); + S32 *ext_feature_infos = (S32*)(&ext_feature_info); + setConfig(eExtFeatureBits, ext_feature_infos[0]); char cpu_features[1024]; @@ -789,7 +789,7 @@ private: // Not supposed to happen? setExtension(cpu_feature_names[eSSE4a_Features]); } - } + } }; #elif LL_LINUX @@ -798,107 +798,107 @@ const char CPUINFO_FILE[] = "/proc/cpuinfo"; class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl { public: - LLProcessorInfoLinuxImpl() - { - get_proc_cpuinfo(); - } + LLProcessorInfoLinuxImpl() + { + get_proc_cpuinfo(); + } - virtual ~LLProcessorInfoLinuxImpl() {} + virtual ~LLProcessorInfoLinuxImpl() {} private: - void get_proc_cpuinfo() - { - std::map< std::string, std::string > cpuinfo; - LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); - if(cpuinfo_fp) - { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); - while(fgets(line, MAX_STRING, cpuinfo_fp)) - { - // /proc/cpuinfo on Linux looks like: - // name\t*: value\n - char* tabspot = strchr( line, '\t' ); - if (tabspot == NULL) - continue; - char* colspot = strchr( tabspot, ':' ); - if (colspot == NULL) - continue; - char* spacespot = strchr( colspot, ' ' ); - if (spacespot == NULL) - continue; - char* nlspot = strchr( line, '\n' ); - if (nlspot == NULL) - nlspot = line + strlen( line ); // Fallback to terminating NUL - std::string linename( line, tabspot ); - std::string llinename(linename); - LLStringUtil::toLower(llinename); - std::string lineval( spacespot + 1, nlspot ); - cpuinfo[ llinename ] = lineval; - } - fclose(cpuinfo_fp); - } + void get_proc_cpuinfo() + { + std::map< std::string, std::string > cpuinfo; + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo_fp) + { + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo_fp)) + { + // /proc/cpuinfo on Linux looks like: + // name\t*: value\n + char* tabspot = strchr( line, '\t' ); + if (tabspot == NULL) + continue; + char* colspot = strchr( tabspot, ':' ); + if (colspot == NULL) + continue; + char* spacespot = strchr( colspot, ' ' ); + if (spacespot == NULL) + continue; + char* nlspot = strchr( line, '\n' ); + if (nlspot == NULL) + nlspot = line + strlen( line ); // Fallback to terminating NUL + std::string linename( line, tabspot ); + std::string llinename(linename); + LLStringUtil::toLower(llinename); + std::string lineval( spacespot + 1, nlspot ); + cpuinfo[ llinename ] = lineval; + } + fclose(cpuinfo_fp); + } # if LL_X86 // *NOTE:Mani - eww, macros! srry. #define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \ - if (!cpuinfo[cpuinfo_id].empty()) \ - { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} + if (!cpuinfo[cpuinfo_id].empty()) \ + { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} #define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ - {\ - S32 result; \ - if (!cpuinfo[cpuinfo_id].empty() \ - && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ - { setInfo(llpi_id, result);} \ - } - - F64 mhz; - if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) - && 200.0 < mhz && mhz < 10000.0) - { - setInfo(eFrequency,(F64)(mhz)); - } - - LLPI_SET_INFO_STRING(eBrandName, "model name"); - LLPI_SET_INFO_STRING(eVendor, "vendor_id"); - - LLPI_SET_INFO_INT(eStepping, "stepping"); - LLPI_SET_INFO_INT(eModel, "model"); - - - S32 family; - if (!cpuinfo["cpu family"].empty() - && LLStringUtil::convertToS32(cpuinfo["cpu family"], family)) - { - setInfo(eFamily, family); - } - - setInfo(eFamilyName, compute_CPUFamilyName(cpuinfo["vendor_id"].c_str(), family, 0)); - - // setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); - // setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); - // setInfo(eType, 0); // ? where to find this? - - //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); - //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); - //setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); - //setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); - //setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); - - // Read extensions - std::string flags = " " + cpuinfo["flags"] + " "; - LLStringUtil::toLower(flags); - - if( flags.find( " sse " ) != std::string::npos ) - { - setExtension(cpu_feature_names[eSSE_Ext]); - } - - if( flags.find( " sse2 " ) != std::string::npos ) - { - setExtension(cpu_feature_names[eSSE2_Ext]); - } + {\ + S32 result; \ + if (!cpuinfo[cpuinfo_id].empty() \ + && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ + { setInfo(llpi_id, result);} \ + } + + F64 mhz; + if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) + && 200.0 < mhz && mhz < 10000.0) + { + setInfo(eFrequency,(F64)(mhz)); + } + + LLPI_SET_INFO_STRING(eBrandName, "model name"); + LLPI_SET_INFO_STRING(eVendor, "vendor_id"); + + LLPI_SET_INFO_INT(eStepping, "stepping"); + LLPI_SET_INFO_INT(eModel, "model"); + + + S32 family; + if (!cpuinfo["cpu family"].empty() + && LLStringUtil::convertToS32(cpuinfo["cpu family"], family)) + { + setInfo(eFamily, family); + } + + setInfo(eFamilyName, compute_CPUFamilyName(cpuinfo["vendor_id"].c_str(), family, 0)); + + // setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); + // setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); + // setInfo(eType, 0); // ? where to find this? + + //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + //setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); + //setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); + //setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); + + // Read extensions + std::string flags = " " + cpuinfo["flags"] + " "; + LLStringUtil::toLower(flags); + + if( flags.find( " sse " ) != std::string::npos ) + { + setExtension(cpu_feature_names[eSSE_Ext]); + } + + if( flags.find( " sse2 " ) != std::string::npos ) + { + setExtension(cpu_feature_names[eSSE2_Ext]); + } if (flags.find(" pni ") != std::string::npos) { @@ -924,36 +924,36 @@ private: { setExtension(cpu_feature_names[eSSE4a_Features]); } - + # endif // LL_X86 - } - - std::string getCPUFeatureDescription() const - { - std::ostringstream s; - - // *NOTE:Mani - This is for linux only. - LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); - if(cpuinfo) - { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); - while(fgets(line, MAX_STRING, cpuinfo)) - { - line[strlen(line)-1] = ' '; - s << line; - s << std::endl; - } - fclose(cpuinfo); - s << std::endl; - } - else - { - s << "Unable to collect processor information" << std::endl; - } - return s.str(); - } - + } + + std::string getCPUFeatureDescription() const + { + std::ostringstream s; + + // *NOTE:Mani - This is for linux only. + LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo) + { + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo)) + { + line[strlen(line)-1] = ' '; + s << line; + s << std::endl; + } + fclose(cpuinfo); + s << std::endl; + } + else + { + s << "Unable to collect processor information" << std::endl; + } + return s.str(); + } + }; @@ -963,20 +963,20 @@ private: // Interface definition LLProcessorInfo::LLProcessorInfo() : mImpl(NULL) { - // *NOTE:Mani - not thread safe. - if(!mImpl) - { + // *NOTE:Mani - not thread safe. + if(!mImpl) + { #ifdef LL_MSVC - static LLProcessorInfoWindowsImpl the_impl; - mImpl = &the_impl; + static LLProcessorInfoWindowsImpl the_impl; + mImpl = &the_impl; #elif LL_DARWIN - static LLProcessorInfoDarwinImpl the_impl; - mImpl = &the_impl; + static LLProcessorInfoDarwinImpl the_impl; + mImpl = &the_impl; #else - static LLProcessorInfoLinuxImpl the_impl; - mImpl = &the_impl; + static LLProcessorInfoLinuxImpl the_impl; + mImpl = &the_impl; #endif // LL_MSVC - } + } } diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 1a473ddc97..f8ccf686c8 100644 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -1,25 +1,25 @@ -/** +/** * @file llprocessor.h * @brief Code to figure out the processor. Originally by Benjamin Jurke. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,23 +48,23 @@ class LLProcessorInfoImpl; class LL_COMMON_API LLProcessorInfo { public: - LLProcessorInfo(); - ~LLProcessorInfo(); + LLProcessorInfo(); + ~LLProcessorInfo(); - F64MegahertzImplicit getCPUFrequency() const; - bool hasSSE() const; - bool hasSSE2() const; + F64MegahertzImplicit getCPUFrequency() const; + bool hasSSE() const; + bool hasSSE2() const; bool hasSSE3() const; bool hasSSE3S() const; bool hasSSE41() const; bool hasSSE42() const; bool hasSSE4a() const; - bool hasAltivec() const; - std::string getCPUFamilyName() const; - std::string getCPUBrandName() const; - std::string getCPUFeatureDescription() const; + bool hasAltivec() const; + std::string getCPUFamilyName() const; + std::string getCPUBrandName() const; + std::string getCPUFeatureDescription() const; private: - LLProcessorInfoImpl* mImpl; + LLProcessorInfoImpl* mImpl; }; #endif // LLPROCESSOR_H diff --git a/indra/llcommon/llprocinfo.cpp b/indra/llcommon/llprocinfo.cpp index c00f979b0b..69be00e14a 100644 --- a/indra/llcommon/llprocinfo.cpp +++ b/indra/llcommon/llprocinfo.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llprocinfo.cpp * @brief Process, cpu and resource usage information APIs. * @author monty@lindenlab.com @@ -30,7 +30,7 @@ #if LL_WINDOWS -#define PSAPI_VERSION 1 +#define PSAPI_VERSION 1 #include "windows.h" #include "psapi.h" @@ -38,7 +38,7 @@ #include <sys/resource.h> #include <mach/mach.h> - + #else #include <sys/time.h> @@ -52,42 +52,42 @@ void LLProcInfo::getCPUUsage(time_type & user_time, time_type & system_time) { #if LL_WINDOWS - HANDLE self(GetCurrentProcess()); // Does not have to be closed - FILETIME ft_dummy, ft_system, ft_user; - - GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); - ULARGE_INTEGER uli; - uli.u.LowPart = ft_system.dwLowDateTime; - uli.u.HighPart = ft_system.dwHighDateTime; - system_time = uli.QuadPart / U64L(10); // Convert to uS - uli.u.LowPart = ft_user.dwLowDateTime; - uli.u.HighPart = ft_user.dwHighDateTime; - user_time = uli.QuadPart / U64L(10); - + HANDLE self(GetCurrentProcess()); // Does not have to be closed + FILETIME ft_dummy, ft_system, ft_user; + + GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); + ULARGE_INTEGER uli; + uli.u.LowPart = ft_system.dwLowDateTime; + uli.u.HighPart = ft_system.dwHighDateTime; + system_time = uli.QuadPart / U64L(10); // Convert to uS + uli.u.LowPart = ft_user.dwLowDateTime; + uli.u.HighPart = ft_user.dwHighDateTime; + user_time = uli.QuadPart / U64L(10); + #elif LL_DARWIN - struct rusage usage; + struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) - { - user_time = system_time = time_type(0U); - return; - } - user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; - system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; + if (getrusage(RUSAGE_SELF, &usage)) + { + user_time = system_time = time_type(0U); + return; + } + user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; + system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; #else // Linux - struct rusage usage; + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + { + user_time = system_time = time_type(0U); + return; + } + user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; + system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; - if (getrusage(RUSAGE_SELF, &usage)) - { - user_time = system_time = time_type(0U); - return; - } - user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; - system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; - #endif // LL_WINDOWS/LL_DARWIN/Linux } diff --git a/indra/llcommon/llprocinfo.h b/indra/llcommon/llprocinfo.h index e78bcf490a..5955799812 100644 --- a/indra/llcommon/llprocinfo.h +++ b/indra/llcommon/llprocinfo.h @@ -1,4 +1,4 @@ -/** +/** * @file llprocinfo.h * @brief Interface to process/cpu/resource information services. * @author monty@lindenlab.com @@ -25,8 +25,8 @@ * $/LicenseInfo$ */ -#ifndef LL_PROCINFO_H -#define LL_PROCINFO_H +#ifndef LL_PROCINFO_H +#define LL_PROCINFO_H #include "linden_common.h" @@ -46,23 +46,23 @@ class LL_COMMON_API LLProcInfo { public: - /// Public types + /// Public types + + typedef U64 time_type; /// Relative microseconds - typedef U64 time_type; /// Relative microseconds - private: - LLProcInfo(); // Not defined - ~LLProcInfo(); // Not defined - LLProcInfo(const LLProcInfo &); // Not defined - void operator=(const LLProcInfo &); // Not defined + LLProcInfo(); // Not defined + ~LLProcInfo(); // Not defined + LLProcInfo(const LLProcInfo &); // Not defined + void operator=(const LLProcInfo &); // Not defined public: - /// Get accumulated system and user CPU time in - /// microseconds. Syscalls involved in every invocation. - /// - /// Threading: expected to be safe. - static void getCPUUsage(time_type & user_time, time_type & system_time); + /// Get accumulated system and user CPU time in + /// microseconds. Syscalls involved in every invocation. + /// + /// Threading: expected to be safe. + static void getCPUUsage(time_type & user_time, time_type & system_time); }; - -#endif // LL_PROCINFO_H + +#endif // LL_PROCINFO_H diff --git a/indra/llcommon/llptrto.cpp b/indra/llcommon/llptrto.cpp index b270291bd6..c4528a47a7 100644 --- a/indra/llcommon/llptrto.cpp +++ b/indra/llcommon/llptrto.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-08-20 * @brief Test for llptrto.h - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h index 9ef279fdbf..b57a1ee7f4 100644 --- a/indra/llcommon/llptrto.h +++ b/indra/llcommon/llptrto.h @@ -5,25 +5,25 @@ * @brief LLPtrTo<TARGET> is a template helper to pick either TARGET* or -- when * TARGET is a subclass of LLRefCount or LLThreadSafeRefCount -- * LLPointer<TARGET>. LLPtrTo<> chooses whichever pointer type is best. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 394212ee0d..aaf13ac796 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llqueuedthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,7 +29,7 @@ #include <chrono> #include "llstl.h" -#include "lltimer.h" // ms_sleep() +#include "lltimer.h" // ms_sleep() #include "llmutex.h" //============================================================================ @@ -46,75 +46,75 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool shou llassert(threaded); // not threaded implementation is deprecated mMainQueue = LL::WorkQueue::getInstance("mainloop"); - if (mThreaded) - { - if(should_pause) - { - pause() ; //call this before start the thread. - } + if (mThreaded) + { + if(should_pause) + { + pause() ; //call this before start the thread. + } - start(); - } + start(); + } } // MAIN THREAD LLQueuedThread::~LLQueuedThread() { - if (!mThreaded) - { - endThread(); - } - shutdown(); - // ~LLThread() will be called here + if (!mThreaded) + { + endThread(); + } + shutdown(); + // ~LLThread() will be called here } void LLQueuedThread::shutdown() { - setQuitting(); + setQuitting(); - unpause(); // MAIN THREAD - if (mThreaded) - { + unpause(); // MAIN THREAD + if (mThreaded) + { if (mRequestQueue.size() == 0) { mRequestQueue.close(); } - S32 timeout = 100; - for ( ; timeout>0; timeout--) - { - if (isStopped()) - { - break; - } - ms_sleep(100); - LLThread::yield(); - } - if (timeout == 0) - { - LL_WARNS() << "~LLQueuedThread (" << mName << ") timed out!" << LL_ENDL; - } - } - else - { - mStatus = STOPPED; - } - - QueuedRequest* req; - S32 active_count = 0; - while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) - { - if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS) - { - ++active_count; - req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest - } - req->deleteRequest(); - } - if (active_count) - { - LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL; - } + S32 timeout = 100; + for ( ; timeout>0; timeout--) + { + if (isStopped()) + { + break; + } + ms_sleep(100); + LLThread::yield(); + } + if (timeout == 0) + { + LL_WARNS() << "~LLQueuedThread (" << mName << ") timed out!" << LL_ENDL; + } + } + else + { + mStatus = STOPPED; + } + + QueuedRequest* req; + S32 active_count = 0; + while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) + { + if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS) + { + ++active_count; + req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest + } + req->deleteRequest(); + } + if (active_count) + { + LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL; + } mRequestQueue.close(); } @@ -126,23 +126,23 @@ void LLQueuedThread::shutdown() size_t LLQueuedThread::update(F32 max_time_ms) { LL_PROFILE_ZONE_SCOPED; - if (!mStarted) - { - if (!mThreaded) - { - startThread(); - mStarted = TRUE; - } - } - return updateQueue(max_time_ms); + if (!mStarted) + { + if (!mThreaded) + { + startThread(); + mStarted = TRUE; + } + } + return updateQueue(max_time_ms); } size_t LLQueuedThread::updateQueue(F32 max_time_ms) { LL_PROFILE_ZONE_SCOPED; - // Frame Update - if (mThreaded) - { + // Frame Update + if (mThreaded) + { // schedule a call to threadedUpdate for every call to updateQueue if (!isQuitting()) { @@ -156,29 +156,29 @@ size_t LLQueuedThread::updateQueue(F32 max_time_ms) ); } - if(getPending() > 0) - { - unpause(); - } - } - else - { + if(getPending() > 0) + { + unpause(); + } + } + else + { mRequestQueue.runFor(std::chrono::microseconds((int) (max_time_ms*1000.f))); threadedUpdate(); - } - return getPending(); + } + return getPending(); } void LLQueuedThread::incQueue() { - // Something has been added to the queue - if (!isPaused()) - { - if (mThreaded) - { - wake(); // Wake the thread up if necessary. - } - } + // Something has been added to the queue + if (!isPaused()) + { + if (mThreaded) + { + wake(); // Wake the thread up if necessary. + } + } } //virtual @@ -191,200 +191,200 @@ size_t LLQueuedThread::getPending() // MAIN thread void LLQueuedThread::waitOnPending() { - while(1) - { - update(0); - - if (mIdleThread) - { - break; - } - if (mThreaded) - { - yield(); - } - } - return; + while(1) + { + update(0); + + if (mIdleThread) + { + break; + } + if (mThreaded) + { + yield(); + } + } + return; } // MAIN thread void LLQueuedThread::printQueueStats() { U32 size = mRequestQueue.size(); - if (size > 0) - { - LL_INFOS() << llformat("Pending Requests:%d ", mRequestQueue.size()) << LL_ENDL; - } - else - { - LL_INFOS() << "Queued Thread Idle" << LL_ENDL; - } + if (size > 0) + { + LL_INFOS() << llformat("Pending Requests:%d ", mRequestQueue.size()) << LL_ENDL; + } + else + { + LL_INFOS() << "Queued Thread Idle" << LL_ENDL; + } } // MAIN thread LLQueuedThread::handle_t LLQueuedThread::generateHandle() { U32 res = ++mNextHandle; - return res; + return res; } // MAIN thread bool LLQueuedThread::addRequest(QueuedRequest* req) { LL_PROFILE_ZONE_SCOPED; - if (mStatus == QUITTING) - { - return false; - } - - lockData(); - req->setStatus(STATUS_QUEUED); + if (mStatus == QUITTING) + { + return false; + } + + lockData(); + req->setStatus(STATUS_QUEUED); mRequestHash.insert(req); #if _DEBUG -// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL; +// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL; #endif - unlockData(); + unlockData(); llassert(!mDataLock->isSelfLocked()); mRequestQueue.post([this, req]() { processRequest(req); }); - return true; + return true; } // MAIN thread bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete) { LL_PROFILE_ZONE_SCOPED; - llassert (handle != nullHandle()); - bool res = false; - bool waspaused = isPaused(); - bool done = false; - while(!done) - { - update(0); // unpauses - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (!req) - { - done = true; // request does not exist - } - else if (req->getStatus() == STATUS_COMPLETE) - { - res = true; - if (auto_complete) - { - mRequestHash.erase(handle); - req->deleteRequest(); -// check(); - } - done = true; - } - unlockData(); - - if (!done && mThreaded) - { - yield(); - } - } - if (waspaused) - { - pause(); - } - return res; + llassert (handle != nullHandle()); + bool res = false; + bool waspaused = isPaused(); + bool done = false; + while(!done) + { + update(0); // unpauses + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (!req) + { + done = true; // request does not exist + } + else if (req->getStatus() == STATUS_COMPLETE) + { + res = true; + if (auto_complete) + { + mRequestHash.erase(handle); + req->deleteRequest(); +// check(); + } + done = true; + } + unlockData(); + + if (!done && mThreaded) + { + yield(); + } + } + if (waspaused) + { + pause(); + } + return res; } // MAIN thread LLQueuedThread::QueuedRequest* LLQueuedThread::getRequest(handle_t handle) { - if (handle == nullHandle()) - { - return 0; - } - lockData(); - QueuedRequest* res = (QueuedRequest*)mRequestHash.find(handle); - unlockData(); - return res; + if (handle == nullHandle()) + { + return 0; + } + lockData(); + QueuedRequest* res = (QueuedRequest*)mRequestHash.find(handle); + unlockData(); + return res; } LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle) { - status_t res = STATUS_EXPIRED; - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - res = req->getStatus(); - } - unlockData(); - return res; + status_t res = STATUS_EXPIRED; + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + res = req->getStatus(); + } + unlockData(); + return res; } void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete) { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - req->setFlags(FLAG_ABORT | (autocomplete ? FLAG_AUTO_COMPLETE : 0)); - } - unlockData(); + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + req->setFlags(FLAG_ABORT | (autocomplete ? FLAG_AUTO_COMPLETE : 0)); + } + unlockData(); } // MAIN thread void LLQueuedThread::setFlags(handle_t handle, U32 flags) { - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - req->setFlags(flags); - } - unlockData(); + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + req->setFlags(flags); + } + unlockData(); } bool LLQueuedThread::completeRequest(handle_t handle) { LL_PROFILE_ZONE_SCOPED; - bool res = false; - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - llassert_always(req->getStatus() != STATUS_QUEUED); - llassert_always(req->getStatus() != STATUS_INPROGRESS); + bool res = false; + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + llassert_always(req->getStatus() != STATUS_QUEUED); + llassert_always(req->getStatus() != STATUS_INPROGRESS); #if _DEBUG -// LL_INFOS() << llformat("LLQueuedThread::Completed req [%08d]",handle) << LL_ENDL; +// LL_INFOS() << llformat("LLQueuedThread::Completed req [%08d]",handle) << LL_ENDL; #endif - mRequestHash.erase(handle); - req->deleteRequest(); -// check(); - res = true; - } - unlockData(); - return res; + mRequestHash.erase(handle); + req->deleteRequest(); +// check(); + res = true; + } + unlockData(); + return res; } bool LLQueuedThread::check() { #if 0 // not a reliable check once mNextHandle wraps, just for quick and dirty debugging - for (int i=0; i<REQUEST_HASH_SIZE; i++) - { - LLSimpleHashEntry<handle_t>* entry = mRequestHash.get_element_at_index(i); - while (entry) - { - if (entry->getHashKey() > mNextHandle) - { - LL_ERRS() << "Hash Error" << LL_ENDL; - return false; - } - entry = entry->getNextEntry(); - } - } + for (int i=0; i<REQUEST_HASH_SIZE; i++) + { + LLSimpleHashEntry<handle_t>* entry = mRequestHash.get_element_at_index(i); + while (entry) + { + if (entry->getHashKey() > mNextHandle) + { + LL_ERRS() << "Hash Error" << LL_ENDL; + return false; + } + entry = entry->getNextEntry(); + } + } #endif - return true; -} - + return true; +} + //============================================================================ // Runs on its OWN thread @@ -395,22 +395,22 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) mIdleThread = FALSE; //threadedUpdate(); - // Get next request from pool - lockData(); - - if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING)) - { + // Get next request from pool + lockData(); + + if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING)) + { LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qtpr - abort"); - req->setStatus(STATUS_ABORTED); - req->finishRequest(false); - if (req->getFlags() & FLAG_AUTO_COMPLETE) - { - mRequestHash.erase(req); - req->deleteRequest(); -// check(); - } + req->setStatus(STATUS_ABORTED); + req->finishRequest(false); + if (req->getFlags() & FLAG_AUTO_COMPLETE) + { + mRequestHash.erase(req); + req->deleteRequest(); +// check(); + } unlockData(); - } + } else { llassert_always(req->getStatus() == STATUS_QUEUED); @@ -426,7 +426,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) // safe to access req. if (req) { - // process request + // process request bool complete = req->processRequest(); if (complete) @@ -439,7 +439,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) { mRequestHash.erase(req); req->deleteRequest(); - // check(); + // check(); } unlockData(); } @@ -449,7 +449,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) //put back on queue and try again in 0.1ms lockData(); req->setStatus(STATUS_QUEUED); - + unlockData(); llassert(!mDataLock->isSelfLocked()); @@ -480,8 +480,8 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) if (LL::WorkQueue::TimePoint::clock::now() < retry_time) { auto sleep_time = std::chrono::duration_cast<std::chrono::milliseconds>(retry_time - LL::WorkQueue::TimePoint::clock::now()); - - if (sleep_time.count() > 0) + + if (sleep_time.count() > 0) { ms_sleep(sleep_time.count()); } @@ -489,7 +489,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) processRequest(req); }); #endif - + } } } @@ -500,48 +500,48 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) // virtual bool LLQueuedThread::runCondition() { - // mRunCondition must be locked here - if (mRequestQueue.size() == 0 && mIdleThread) - return false; - else - return true; + // mRunCondition must be locked here + if (mRequestQueue.size() == 0 && mIdleThread) + return false; + else + return true; } // virtual void LLQueuedThread::run() { - // call checPause() immediately so we don't try to do anything before the class is fully constructed - checkPause(); - startThread(); - mStarted = TRUE; - - - /*while (1) - { + // call checPause() immediately so we don't try to do anything before the class is fully constructed + checkPause(); + startThread(); + mStarted = TRUE; + + + /*while (1) + { LL_PROFILE_ZONE_SCOPED; - // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state. - checkPause(); - - mIdleThread = FALSE; + // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state. + checkPause(); - threadedUpdate(); - - auto pending_work = processNextRequest(); + mIdleThread = FALSE; - if (pending_work == 0) - { + threadedUpdate(); + + auto pending_work = processNextRequest(); + + if (pending_work == 0) + { //LL_PROFILE_ZONE_NAMED("LLQueuedThread - sleep"); - mIdleThread = TRUE; - //ms_sleep(1); - } - //LLThread::yield(); // thread should yield after each request - }*/ + mIdleThread = TRUE; + //ms_sleep(1); + } + //LLThread::yield(); // thread should yield after each request + }*/ mRequestQueue.runUntilClose(); endThread(); - LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL; + LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL; + - } // virtual @@ -562,15 +562,15 @@ void LLQueuedThread::threadedUpdate() //============================================================================ LLQueuedThread::QueuedRequest::QueuedRequest(LLQueuedThread::handle_t handle, U32 flags) : - LLSimpleHashEntry<LLQueuedThread::handle_t>(handle), - mStatus(STATUS_UNKNOWN), - mFlags(flags) + LLSimpleHashEntry<LLQueuedThread::handle_t>(handle), + mStatus(STATUS_UNKNOWN), + mFlags(flags) { } LLQueuedThread::QueuedRequest::~QueuedRequest() { - llassert_always(mStatus == STATUS_DELETE); + llassert_always(mStatus == STATUS_DELETE); } //virtual @@ -581,7 +581,7 @@ void LLQueuedThread::QueuedRequest::finishRequest(bool completed) //virtual void LLQueuedThread::QueuedRequest::deleteRequest() { - llassert_always(mStatus != STATUS_INPROGRESS); - setStatus(STATUS_DELETE); - delete this; + llassert_always(mStatus != STATUS_INPROGRESS); + setStatus(STATUS_DELETE); + delete this; } diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index 814dbc4c38..339299f081 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -1,25 +1,25 @@ -/** +/** * @file llqueuedthread.h * @brief * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,135 +44,135 @@ class LL_COMMON_API LLQueuedThread : public LLThread { - //------------------------------------------------------------------------ + //------------------------------------------------------------------------ public: - enum status_t { - STATUS_EXPIRED = -1, - STATUS_UNKNOWN = 0, - STATUS_QUEUED = 1, - STATUS_INPROGRESS = 2, - STATUS_COMPLETE = 3, - STATUS_ABORTED = 4, - STATUS_DELETE = 5 - }; - enum flags_t { - FLAG_AUTO_COMPLETE = 1, - FLAG_AUTO_DELETE = 2, // child-class dependent - FLAG_ABORT = 4 - }; - - typedef U32 handle_t; - - //------------------------------------------------------------------------ + enum status_t { + STATUS_EXPIRED = -1, + STATUS_UNKNOWN = 0, + STATUS_QUEUED = 1, + STATUS_INPROGRESS = 2, + STATUS_COMPLETE = 3, + STATUS_ABORTED = 4, + STATUS_DELETE = 5 + }; + enum flags_t { + FLAG_AUTO_COMPLETE = 1, + FLAG_AUTO_DELETE = 2, // child-class dependent + FLAG_ABORT = 4 + }; + + typedef U32 handle_t; + + //------------------------------------------------------------------------ public: - class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry<handle_t> - { - friend class LLQueuedThread; - - protected: - virtual ~QueuedRequest(); // use deleteRequest() - - public: - QueuedRequest(handle_t handle, U32 flags = 0); - - status_t getStatus() - { - return mStatus; - } - U32 getFlags() const - { - return mFlags; - } - - protected: - status_t setStatus(status_t newstatus) - { - status_t oldstatus = mStatus; - mStatus = newstatus; - return oldstatus; - } - void setFlags(U32 flags) - { - // NOTE: flags are |'d - mFlags |= flags; - } - - virtual bool processRequest() = 0; // Return true when request has completed - virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted - virtual void deleteRequest(); // Only method to delete a request - - protected: - LLAtomicBase<status_t> mStatus; - U32 mFlags; - }; - - //------------------------------------------------------------------------ - + class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry<handle_t> + { + friend class LLQueuedThread; + + protected: + virtual ~QueuedRequest(); // use deleteRequest() + + public: + QueuedRequest(handle_t handle, U32 flags = 0); + + status_t getStatus() + { + return mStatus; + } + U32 getFlags() const + { + return mFlags; + } + + protected: + status_t setStatus(status_t newstatus) + { + status_t oldstatus = mStatus; + mStatus = newstatus; + return oldstatus; + } + void setFlags(U32 flags) + { + // NOTE: flags are |'d + mFlags |= flags; + } + + virtual bool processRequest() = 0; // Return true when request has completed + virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted + virtual void deleteRequest(); // Only method to delete a request + + protected: + LLAtomicBase<status_t> mStatus; + U32 mFlags; + }; + + //------------------------------------------------------------------------ + public: - static handle_t nullHandle() { return handle_t(0); } - + static handle_t nullHandle() { return handle_t(0); } + public: - LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false); - virtual ~LLQueuedThread(); - virtual void shutdown(); - + LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false); + virtual ~LLQueuedThread(); + virtual void shutdown(); + private: - // No copy constructor or copy assignment - LLQueuedThread(const LLQueuedThread&); - LLQueuedThread& operator=(const LLQueuedThread&); + // No copy constructor or copy assignment + LLQueuedThread(const LLQueuedThread&); + LLQueuedThread& operator=(const LLQueuedThread&); - virtual bool runCondition(void); - virtual void run(void); - virtual void startThread(void); - virtual void endThread(void); - virtual void threadedUpdate(void); + virtual bool runCondition(void); + virtual void run(void); + virtual void startThread(void); + virtual void endThread(void); + virtual void threadedUpdate(void); protected: - handle_t generateHandle(); - bool addRequest(QueuedRequest* req); - void processRequest(QueuedRequest* req); - void incQueue(); + handle_t generateHandle(); + bool addRequest(QueuedRequest* req); + void processRequest(QueuedRequest* req); + void incQueue(); public: - bool waitForResult(handle_t handle, bool auto_complete = true); + bool waitForResult(handle_t handle, bool auto_complete = true); - virtual size_t update(F32 max_time_ms); - size_t updateQueue(F32 max_time_ms); + virtual size_t update(F32 max_time_ms); + size_t updateQueue(F32 max_time_ms); - void waitOnPending(); - void printQueueStats(); + void waitOnPending(); + void printQueueStats(); - virtual size_t getPending(); - bool getThreaded() { return mThreaded ? true : false; } + virtual size_t getPending(); + bool getThreaded() { return mThreaded ? true : false; } - // Request accessors - status_t getRequestStatus(handle_t handle); - void abortRequest(handle_t handle, bool autocomplete); - void setFlags(handle_t handle, U32 flags); - bool completeRequest(handle_t handle); - // This is public for support classes like LLWorkerThread, - // but generally the methods above should be used. - QueuedRequest* getRequest(handle_t handle); + // Request accessors + status_t getRequestStatus(handle_t handle); + void abortRequest(handle_t handle, bool autocomplete); + void setFlags(handle_t handle, U32 flags); + bool completeRequest(handle_t handle); + // This is public for support classes like LLWorkerThread, + // but generally the methods above should be used. + QueuedRequest* getRequest(handle_t handle); + + // debug (see source) + bool check(); - // debug (see source) - bool check(); - protected: - BOOL mThreaded; // if false, run on main thread and do updates during update() - BOOL mStarted; // required when mThreaded is false to call startThread() from update() - LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle - - //typedef std::set<QueuedRequest*, queued_request_less> request_queue_t; - //request_queue_t mRequestQueue; + BOOL mThreaded; // if false, run on main thread and do updates during update() + BOOL mStarted; // required when mThreaded is false to call startThread() from update() + LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle + + //typedef std::set<QueuedRequest*, queued_request_less> request_queue_t; + //request_queue_t mRequestQueue; LL::WorkQueue mRequestQueue; LL::WorkQueue::weak_t mMainQueue; - enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2 - typedef LLSimpleHash<handle_t, REQUEST_HASH_SIZE> request_hash_t; - request_hash_t mRequestHash; + enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2 + typedef LLSimpleHash<handle_t, REQUEST_HASH_SIZE> request_hash_t; + request_hash_t mRequestHash; - handle_t mNextHandle; + handle_t mNextHandle; }; #endif // LL_LLQUEUEDTHREAD_H diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index 0192111574..25d75af568 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llrand.cpp * @brief Global random generator. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -69,25 +69,25 @@ inline REAL ll_internal_random(); template <> inline F64 ll_internal_random<F64>() { - // *HACK: Through experimentation, we have found that dual core - // CPUs (or at least multi-threaded processes) seem to - // occasionally give an obviously incorrect random number -- like - // 5^15 or something. Sooooo, clamp it as described above. - F64 rv{ gRandomGenerator() }; - if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0); - return rv; + // *HACK: Through experimentation, we have found that dual core + // CPUs (or at least multi-threaded processes) seem to + // occasionally give an obviously incorrect random number -- like + // 5^15 or something. Sooooo, clamp it as described above. + F64 rv{ gRandomGenerator() }; + if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0); + return rv; } template <> inline F32 ll_internal_random<F32>() { - // *HACK: clamp the result as described above. - // Per Monty, it's important to clamp using the correct fmodf() rather - // than expanding to F64 for fmod() and then truncating back to F32. Prior - // to this change, we were getting sporadic ll_frand() == 1.0 results. - F32 rv{ narrow<F32>(gRandomGenerator()) }; - if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); - return rv; + // *HACK: clamp the result as described above. + // Per Monty, it's important to clamp using the correct fmodf() rather + // than expanding to F64 for fmod() and then truncating back to F32. Prior + // to this change, we were getting sporadic ll_frand() == 1.0 results. + F32 rv{ narrow<F32>(gRandomGenerator()) }; + if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); + return rv; } /*------------------------------ F64 aliases -------------------------------*/ @@ -98,7 +98,7 @@ inline F64 ll_internal_random_double() F64 ll_drand() { - return ll_internal_random_double(); + return ll_internal_random_double(); } /*------------------------------ F32 aliases -------------------------------*/ @@ -109,37 +109,37 @@ inline F32 ll_internal_random_float() F32 ll_frand() { - return ll_internal_random_float(); + return ll_internal_random_float(); } /*-------------------------- clamped random range --------------------------*/ S32 ll_rand() { - return ll_rand(RAND_MAX); + return ll_rand(RAND_MAX); } S32 ll_rand(S32 val) { - // The clamping rules are described above. - S32 rv = (S32)(ll_internal_random_double() * val); - if(rv == val) return 0; - return rv; + // The clamping rules are described above. + S32 rv = (S32)(ll_internal_random_double() * val); + if(rv == val) return 0; + return rv; } template <typename REAL> REAL ll_grand(REAL val) { - // The clamping rules are described above. - REAL rv = ll_internal_random<REAL>() * val; - if(val > 0) - { - if(rv >= val) return REAL(); - } - else - { - if(rv <= val) return REAL(); - } - return rv; + // The clamping rules are described above. + REAL rv = ll_internal_random<REAL>() * val; + if(val > 0) + { + if(rv >= val) return REAL(); + } + else + { + if(rv <= val) return REAL(); + } + return rv; } F32 ll_frand(F32 val) diff --git a/indra/llcommon/llrand.h b/indra/llcommon/llrand.h index ad317d5bf7..625ae0f5f4 100644 --- a/indra/llcommon/llrand.h +++ b/indra/llcommon/llrand.h @@ -1,25 +1,25 @@ -/** +/** * @file llrand.h * @brief Information, functions, and typedefs for randomness. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,18 +42,18 @@ * fairly trivial operations to try to limit compiler optimizations, * so these numbers are only good for relative comparisons. * - * usec/inter algorithm - * 0.21 boost::minstd_rand0 - * 0.039 boost:lagged_fibonacci19937 - * 0.036 boost:lagged_fibonacci607 - * 0.44 boost::hellekalek1995 - * 0.44 boost::ecuyer1988 - * 0.042 boost::rand48 - * 0.043 boost::mt11213b - * 0.028 stdlib random() - * 0.05 stdlib lrand48() - * 0.034 stdlib rand() - * 0.020 the old & lame LLRand + * usec/inter algorithm + * 0.21 boost::minstd_rand0 + * 0.039 boost:lagged_fibonacci19937 + * 0.036 boost:lagged_fibonacci607 + * 0.44 boost::hellekalek1995 + * 0.44 boost::ecuyer1988 + * 0.042 boost::rand48 + * 0.043 boost::mt11213b + * 0.028 stdlib random() + * 0.05 stdlib lrand48() + * 0.034 stdlib rand() + * 0.020 the old & lame LLRand */ /** @@ -100,13 +100,13 @@ F64 LL_COMMON_API ll_drand(F64 val); */ typedef boost::lagged_fibonacci607 LLRandLagFib607; -/**< +/**< * lengh of cycle: 2^32,000 * memory: 607*sizeof(double) (about 5K) */ typedef boost::lagged_fibonacci2281 LLRandLagFib2281; -/**< +/**< * lengh of cycle: 2^120,000 * memory: 2281*sizeof(double) (about 17K) */ diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 3da94e7a8d..6b546aac63 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llrefcount.cpp * @brief Base class for reference counted objects for use with LLPointer * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,26 +33,26 @@ const S32 gMaxRefCount = LL_REFCOUNT_FREE; LLRefCount::LLRefCount(const LLRefCount& other) -: mRef(0) +: mRef(0) { } LLRefCount& LLRefCount::operator=(const LLRefCount&) { - // do nothing, since ref count is specific to *this* reference - return *this; + // do nothing, since ref count is specific to *this* reference + return *this; } LLRefCount::LLRefCount() : - mRef(0) + mRef(0) { } LLRefCount::~LLRefCount() { - if (mRef != LL_REFCOUNT_FREE && mRef != 0) - { - LL_ERRS() << "deleting non-zero reference" << LL_ENDL; - } + if (mRef != LL_REFCOUNT_FREE && mRef != 0) + { + LL_ERRS() << "deleting non-zero reference" << LL_ENDL; + } } diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 15e7175fc8..33c9e956b1 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -1,25 +1,25 @@ -/** +/** * @file llrefcount.h * @brief Base class for reference counted objects for use with LLPointer * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,42 +44,42 @@ extern const S32 gMaxRefCount; class LL_COMMON_API LLRefCount { protected: - LLRefCount(const LLRefCount& other); - LLRefCount& operator=(const LLRefCount&); - virtual ~LLRefCount(); // use unref() - + LLRefCount(const LLRefCount& other); + LLRefCount& operator=(const LLRefCount&); + virtual ~LLRefCount(); // use unref() + public: - LLRefCount(); - - inline void ref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - mRef++; - llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak - } - - inline S32 unref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - llassert(mRef > 0); // ref count below 1, likely corrupted - if (0 == --mRef) - { - mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging - delete this; - return 0; - } - return mRef; - } - - //NOTE: when passing around a const LLRefCount object, this can return different results - // at different types, since mRef is mutable - S32 getNumRefs() const - { - return mRef; - } + LLRefCount(); + + inline void ref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + mRef++; + llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak + } + + inline S32 unref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + llassert(mRef > 0); // ref count below 1, likely corrupted + if (0 == --mRef) + { + mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging + delete this; + return 0; + } + return mRef; + } + + //NOTE: when passing around a const LLRefCount object, this can return different results + // at different types, since mRef is mutable + S32 getNumRefs() const + { + return mRef; + } private: - mutable S32 mRef; + mutable S32 mRef; }; @@ -90,50 +90,50 @@ private: class LL_COMMON_API LLThreadSafeRefCount { public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex + static void initThreadSafeRefCount(); // creates sMutex + static void cleanupThreadSafeRefCount(); // destroys sMutex private: - static LLMutex* sMutex; + static LLMutex* sMutex; protected: - virtual ~LLThreadSafeRefCount(); // use unref() + virtual ~LLThreadSafeRefCount(); // use unref() public: - LLThreadSafeRefCount(); - LLThreadSafeRefCount(const LLThreadSafeRefCount&); - LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) - { - mRef = 0; - return *this; - } - - void ref() - { - mRef++; - } - - void unref() - { - llassert(mRef >= 1); - if ((--mRef) == 0) - { - // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. - // It is technically possible for a vanilla pointer to mess this up, or another thread to - // jump in, find this object, create another smart pointer and end up dangling, but if - // the code is that bad and not thread-safe, it's trouble already. - delete this; - } - } - - S32 getNumRefs() const - { - const S32 currentVal = mRef.CurrentValue(); - return currentVal; - } + LLThreadSafeRefCount(); + LLThreadSafeRefCount(const LLThreadSafeRefCount&); + LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) + { + mRef = 0; + return *this; + } + + void ref() + { + mRef++; + } + + void unref() + { + llassert(mRef >= 1); + if ((--mRef) == 0) + { + // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. + // It is technically possible for a vanilla pointer to mess this up, or another thread to + // jump in, find this object, create another smart pointer and end up dangling, but if + // the code is that bad and not thread-safe, it's trouble already. + delete this; + } + } + + S32 getNumRefs() const + { + const S32 currentVal = mRef.CurrentValue(); + return currentVal; + } private: - LLAtomicS32 mRef; + LLAtomicS32 mRef; }; /** @@ -142,12 +142,12 @@ private: */ inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLThreadSafeRefCount* p) { - p->unref(); + p->unref(); } /** @@ -156,12 +156,12 @@ inline void intrusive_ptr_release(LLThreadSafeRefCount* p) */ inline void intrusive_ptr_add_ref(LLRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLRefCount* p) { - p->unref(); + p->unref(); } #endif diff --git a/indra/llcommon/llregex.h b/indra/llcommon/llregex.h index 2b7f5e47c2..18da304aee 100644 --- a/indra/llcommon/llregex.h +++ b/indra/llcommon/llregex.h @@ -1,24 +1,24 @@ -/** +/** * @file llregex.h * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2021, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,60 +30,60 @@ template <typename S, typename M, typename R> LL_COMMON_API bool ll_regex_match(const S& string, M& match, const R& regex) { - try - { - return boost::regex_match(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error matching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_match(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } template <typename S, typename R> LL_COMMON_API bool ll_regex_match(const S& string, const R& regex) { - try - { - return boost::regex_match(string, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error matching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_match(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } template <typename S, typename M, typename R> bool ll_regex_search(const S& string, M& match, const R& regex) { - try - { - return boost::regex_search(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error searching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_search(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } template <typename S, typename R> bool ll_regex_search(const S& string, const R& regex) { - try - { - return boost::regex_search(string, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error searching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_search(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } #endif // LLREGEX_H diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index e272d7a9b8..55dabd57a2 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -1,25 +1,25 @@ -/** +/** * @file llregistry.h * @brief template classes for registering name, value pairs in nested scopes, statically, etc. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,314 +35,314 @@ template <typename T> struct LLRegistryDefaultComparator { - bool operator()(const T& lhs, const T& rhs) const - { - using std::less; - return less<T>()(lhs, rhs); - } + bool operator()(const T& lhs, const T& rhs) const + { + using std::less; + return less<T>()(lhs, rhs); + } }; template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> > class LLRegistry { public: - typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; - typedef const KEY& ref_const_key_t; - typedef const VALUE& ref_const_value_t; - typedef const VALUE* ptr_const_value_t; - typedef VALUE* ptr_value_t; - - class Registrar - { - friend class LLRegistry<KEY, VALUE, COMPARATOR>; - public: - typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t; - - bool add(ref_const_key_t key, ref_const_value_t value) - { - if (mMap.insert(std::make_pair(key, value)).second == false) - { - LL_WARNS() << "Tried to register " << key << " but it was already registered!" << LL_ENDL; - return false; - } - return true; - } - - void remove(ref_const_key_t key) - { - mMap.erase(key); - } - - void replace(ref_const_key_t key, ref_const_value_t value) - { - mMap[key] = value; - } - - typename registry_map_t::const_iterator beginItems() const - { - return mMap.begin(); - } - - typename registry_map_t::const_iterator endItems() const - { - return mMap.end(); - } - - protected: - ptr_value_t getValue(ref_const_key_t key) - { - typename registry_map_t::iterator found_it = mMap.find(key); - if (found_it != mMap.end()) - { - return &(found_it->second); - } - return NULL; - } - - ptr_const_value_t getValue(ref_const_key_t key) const - { - typename registry_map_t::const_iterator found_it = mMap.find(key); - if (found_it != mMap.end()) - { - return &(found_it->second); - } - return NULL; - } - - // if the registry is used to store pointers, and null values are valid entries - // then use this function to check the existence of an entry - bool exists(ref_const_key_t key) const - { - return mMap.find(key) != mMap.end(); - } - - bool empty() const - { - return mMap.empty(); - } - - protected: - // use currentRegistrar() or defaultRegistrar() - Registrar() {} - ~Registrar() {} - - private: - registry_map_t mMap; - }; - - typedef typename std::list<Registrar*> scope_list_t; - typedef typename std::list<Registrar*>::iterator scope_list_iterator_t; - typedef typename std::list<Registrar*>::const_iterator scope_list_const_iterator_t; - - LLRegistry() - {} - - ~LLRegistry() {} - - ptr_value_t getValue(ref_const_key_t key) - { - for(Registrar* scope : mActiveScopes) - { - ptr_value_t valuep = scope->getValue(key); - if (valuep != NULL) return valuep; - } - return mDefaultRegistrar.getValue(key); - } - - ptr_const_value_t getValue(ref_const_key_t key) const - { - for(const Registrar* scope : mActiveScopes) - { - ptr_const_value_t valuep = scope->getValue(key); - if (valuep != NULL) return valuep; - } - return mDefaultRegistrar.getValue(key); - } - - bool exists(ref_const_key_t key) const - { - for(const Registrar* scope : mActiveScopes) - { - if (scope->exists(key)) return true; - } - - return mDefaultRegistrar.exists(key); - } - - bool empty() const - { - for(const Registrar* scope : mActiveScopes) - { - if (!scope->empty()) return false; - } - - return mDefaultRegistrar.empty(); - } - - - Registrar& defaultRegistrar() - { - return mDefaultRegistrar; - } - - const Registrar& defaultRegistrar() const - { - return mDefaultRegistrar; - } - - - Registrar& currentRegistrar() - { - if (!mActiveScopes.empty()) - { - return *mActiveScopes.front(); - } - - return mDefaultRegistrar; - } - - const Registrar& currentRegistrar() const - { - if (!mActiveScopes.empty()) - { - return *mActiveScopes.front(); - } - - return mDefaultRegistrar; - } + typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; + typedef const KEY& ref_const_key_t; + typedef const VALUE& ref_const_value_t; + typedef const VALUE* ptr_const_value_t; + typedef VALUE* ptr_value_t; + + class Registrar + { + friend class LLRegistry<KEY, VALUE, COMPARATOR>; + public: + typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t; + + bool add(ref_const_key_t key, ref_const_value_t value) + { + if (mMap.insert(std::make_pair(key, value)).second == false) + { + LL_WARNS() << "Tried to register " << key << " but it was already registered!" << LL_ENDL; + return false; + } + return true; + } + + void remove(ref_const_key_t key) + { + mMap.erase(key); + } + + void replace(ref_const_key_t key, ref_const_value_t value) + { + mMap[key] = value; + } + + typename registry_map_t::const_iterator beginItems() const + { + return mMap.begin(); + } + + typename registry_map_t::const_iterator endItems() const + { + return mMap.end(); + } + + protected: + ptr_value_t getValue(ref_const_key_t key) + { + typename registry_map_t::iterator found_it = mMap.find(key); + if (found_it != mMap.end()) + { + return &(found_it->second); + } + return NULL; + } + + ptr_const_value_t getValue(ref_const_key_t key) const + { + typename registry_map_t::const_iterator found_it = mMap.find(key); + if (found_it != mMap.end()) + { + return &(found_it->second); + } + return NULL; + } + + // if the registry is used to store pointers, and null values are valid entries + // then use this function to check the existence of an entry + bool exists(ref_const_key_t key) const + { + return mMap.find(key) != mMap.end(); + } + + bool empty() const + { + return mMap.empty(); + } + + protected: + // use currentRegistrar() or defaultRegistrar() + Registrar() {} + ~Registrar() {} + + private: + registry_map_t mMap; + }; + + typedef typename std::list<Registrar*> scope_list_t; + typedef typename std::list<Registrar*>::iterator scope_list_iterator_t; + typedef typename std::list<Registrar*>::const_iterator scope_list_const_iterator_t; + + LLRegistry() + {} + + ~LLRegistry() {} + + ptr_value_t getValue(ref_const_key_t key) + { + for(Registrar* scope : mActiveScopes) + { + ptr_value_t valuep = scope->getValue(key); + if (valuep != NULL) return valuep; + } + return mDefaultRegistrar.getValue(key); + } + + ptr_const_value_t getValue(ref_const_key_t key) const + { + for(const Registrar* scope : mActiveScopes) + { + ptr_const_value_t valuep = scope->getValue(key); + if (valuep != NULL) return valuep; + } + return mDefaultRegistrar.getValue(key); + } + + bool exists(ref_const_key_t key) const + { + for(const Registrar* scope : mActiveScopes) + { + if (scope->exists(key)) return true; + } + + return mDefaultRegistrar.exists(key); + } + + bool empty() const + { + for(const Registrar* scope : mActiveScopes) + { + if (!scope->empty()) return false; + } + + return mDefaultRegistrar.empty(); + } + + + Registrar& defaultRegistrar() + { + return mDefaultRegistrar; + } + + const Registrar& defaultRegistrar() const + { + return mDefaultRegistrar; + } + + + Registrar& currentRegistrar() + { + if (!mActiveScopes.empty()) + { + return *mActiveScopes.front(); + } + + return mDefaultRegistrar; + } + + const Registrar& currentRegistrar() const + { + if (!mActiveScopes.empty()) + { + return *mActiveScopes.front(); + } + + return mDefaultRegistrar; + } protected: - void addScope(Registrar* scope) - { - // newer scopes go up front - mActiveScopes.insert(mActiveScopes.begin(), scope); - } - - void removeScope(Registrar* scope) - { - // O(N) but should be near the beggining and N should be small and this is safer than storing iterators - scope_list_iterator_t iter = std::find(mActiveScopes.begin(), mActiveScopes.end(), scope); - if (iter != mActiveScopes.end()) - { - mActiveScopes.erase(iter); - } - } + void addScope(Registrar* scope) + { + // newer scopes go up front + mActiveScopes.insert(mActiveScopes.begin(), scope); + } + + void removeScope(Registrar* scope) + { + // O(N) but should be near the beggining and N should be small and this is safer than storing iterators + scope_list_iterator_t iter = std::find(mActiveScopes.begin(), mActiveScopes.end(), scope); + if (iter != mActiveScopes.end()) + { + mActiveScopes.erase(iter); + } + } private: - scope_list_t mActiveScopes; - Registrar mDefaultRegistrar; + scope_list_t mActiveScopes; + Registrar mDefaultRegistrar; }; template <typename KEY, typename VALUE, typename DERIVED_TYPE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> > class LLRegistrySingleton - : public LLRegistry<KEY, VALUE, COMPARATOR>, - public LLSingleton<DERIVED_TYPE> + : public LLRegistry<KEY, VALUE, COMPARATOR>, + public LLSingleton<DERIVED_TYPE> { - // This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton) - // because the concrete class is actually DERIVED_TYPE, not - // LLRegistrySingleton. So each concrete subclass needs - // LLSINGLETON(whatever) -- not this intermediate base class. + // This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton) + // because the concrete class is actually DERIVED_TYPE, not + // LLRegistrySingleton. So each concrete subclass needs + // LLSINGLETON(whatever) -- not this intermediate base class. public: - typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; - typedef const KEY& ref_const_key_t; - typedef const VALUE& ref_const_value_t; - typedef VALUE* ptr_value_t; - typedef const VALUE* ptr_const_value_t; - typedef LLSingleton<DERIVED_TYPE> singleton_t; - - class ScopedRegistrar : public registry_t::Registrar - { - public: - ScopedRegistrar(bool push_scope = true) - { - if (push_scope) - { - pushScope(); - } - } - - ~ScopedRegistrar() - { - if (singleton_t::instanceExists()) - { - popScope(); - } - } - - void pushScope() - { - singleton_t::instance().addScope(this); - } - - void popScope() - { - singleton_t::instance().removeScope(this); - } - - ptr_value_t getValueFromScope(ref_const_key_t key) - { - return getValue(key); - } - - ptr_const_value_t getValueFromScope(ref_const_key_t key) const - { - return getValue(key); - } - - private: - typename std::list<typename registry_t::Registrar*>::iterator mListIt; - }; - - class StaticRegistrar : public registry_t::Registrar - { - public: - virtual ~StaticRegistrar() {} - StaticRegistrar(ref_const_key_t key, ref_const_value_t value) - { - if (singleton_t::instance().exists(key)) - { - LL_ERRS() << "Duplicate registry entry under key \"" << key << "\"" << LL_ENDL; - } - singleton_t::instance().mStaticScope->add(key, value); - } - }; - - // convenience functions - typedef typename LLRegistry<KEY, VALUE, COMPARATOR>::Registrar& ref_registrar_t; - static ref_registrar_t currentRegistrar() - { - return singleton_t::instance().registry_t::currentRegistrar(); - } - - static ref_registrar_t defaultRegistrar() - { - return singleton_t::instance().registry_t::defaultRegistrar(); - } - - static ptr_value_t getValue(ref_const_key_t key) - { - return singleton_t::instance().registry_t::getValue(key); - } + typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; + typedef const KEY& ref_const_key_t; + typedef const VALUE& ref_const_value_t; + typedef VALUE* ptr_value_t; + typedef const VALUE* ptr_const_value_t; + typedef LLSingleton<DERIVED_TYPE> singleton_t; + + class ScopedRegistrar : public registry_t::Registrar + { + public: + ScopedRegistrar(bool push_scope = true) + { + if (push_scope) + { + pushScope(); + } + } + + ~ScopedRegistrar() + { + if (singleton_t::instanceExists()) + { + popScope(); + } + } + + void pushScope() + { + singleton_t::instance().addScope(this); + } + + void popScope() + { + singleton_t::instance().removeScope(this); + } + + ptr_value_t getValueFromScope(ref_const_key_t key) + { + return getValue(key); + } + + ptr_const_value_t getValueFromScope(ref_const_key_t key) const + { + return getValue(key); + } + + private: + typename std::list<typename registry_t::Registrar*>::iterator mListIt; + }; + + class StaticRegistrar : public registry_t::Registrar + { + public: + virtual ~StaticRegistrar() {} + StaticRegistrar(ref_const_key_t key, ref_const_value_t value) + { + if (singleton_t::instance().exists(key)) + { + LL_ERRS() << "Duplicate registry entry under key \"" << key << "\"" << LL_ENDL; + } + singleton_t::instance().mStaticScope->add(key, value); + } + }; + + // convenience functions + typedef typename LLRegistry<KEY, VALUE, COMPARATOR>::Registrar& ref_registrar_t; + static ref_registrar_t currentRegistrar() + { + return singleton_t::instance().registry_t::currentRegistrar(); + } + + static ref_registrar_t defaultRegistrar() + { + return singleton_t::instance().registry_t::defaultRegistrar(); + } + + static ptr_value_t getValue(ref_const_key_t key) + { + return singleton_t::instance().registry_t::getValue(key); + } protected: - // DERIVED_TYPE needs to derive from LLRegistrySingleton - LLRegistrySingleton() - : mStaticScope(NULL) - {} + // DERIVED_TYPE needs to derive from LLRegistrySingleton + LLRegistrySingleton() + : mStaticScope(NULL) + {} - virtual void initSingleton() - { - mStaticScope = new ScopedRegistrar(); - } + virtual void initSingleton() + { + mStaticScope = new ScopedRegistrar(); + } - virtual ~LLRegistrySingleton() - { - delete mStaticScope; - } + virtual ~LLRegistrySingleton() + { + delete mStaticScope; + } private: - ScopedRegistrar* mStaticScope; + ScopedRegistrar* mStaticScope; }; // helper macro for doing static registration diff --git a/indra/llcommon/llrun.cpp b/indra/llcommon/llrun.cpp index a3b3fccf4b..82005b16bc 100644 --- a/indra/llcommon/llrun.cpp +++ b/indra/llcommon/llrun.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llrun.cpp * @author Phoenix * @date 2006-02-16 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,136 +33,136 @@ static const LLRunner::run_handle_t INVALID_RUN_HANDLE = 0; -/** +/** * LLRunner */ LLRunner::LLRunner() : - mNextHandle(1) + mNextHandle(1) { } LLRunner::~LLRunner() { - mRunOnce.clear(); - mRunEvery.clear(); + mRunOnce.clear(); + mRunEvery.clear(); } size_t LLRunner::run() { - // We collect all of the runnables which should be run. Since the - // runnables are allowed to adjust the run list, we need to copy - // them into a temporary structure which then iterates over them - // to call out of this method into the runnables. - F64 now = LLFrameTimer::getTotalSeconds(); - run_list_t run_now; + // We collect all of the runnables which should be run. Since the + // runnables are allowed to adjust the run list, we need to copy + // them into a temporary structure which then iterates over them + // to call out of this method into the runnables. + F64 now = LLFrameTimer::getTotalSeconds(); + run_list_t run_now; - // Collect the run once. We erase the matching ones now because - // it's easier. If we find a reason to keep them around for a - // while, we can restructure this method. - LLRunner::run_list_t::iterator iter = mRunOnce.begin(); - for( ; iter != mRunOnce.end(); ) - { - if(now > (*iter).mNextRunAt) - { - run_now.push_back(*iter); - iter = mRunOnce.erase(iter); - } - else - { - ++iter; - } - } + // Collect the run once. We erase the matching ones now because + // it's easier. If we find a reason to keep them around for a + // while, we can restructure this method. + LLRunner::run_list_t::iterator iter = mRunOnce.begin(); + for( ; iter != mRunOnce.end(); ) + { + if(now > (*iter).mNextRunAt) + { + run_now.push_back(*iter); + iter = mRunOnce.erase(iter); + } + else + { + ++iter; + } + } - // Collect the ones that repeat. - iter = mRunEvery.begin(); - LLRunner::run_list_t::iterator end = mRunEvery.end(); - for( ; iter != end; ++iter ) - { - if(now > (*iter).mNextRunAt) - { - (*iter).mNextRunAt = now + (*iter).mIncrement; - run_now.push_back(*iter); - } - } + // Collect the ones that repeat. + iter = mRunEvery.begin(); + LLRunner::run_list_t::iterator end = mRunEvery.end(); + for( ; iter != end; ++iter ) + { + if(now > (*iter).mNextRunAt) + { + (*iter).mNextRunAt = now + (*iter).mIncrement; + run_now.push_back(*iter); + } + } - // Now, run them. - iter = run_now.begin(); - end = run_now.end(); - for( ; iter != end; ++iter ) - { - (*iter).mRunnable->run(this, (*iter).mHandle); - } - return run_now.size(); + // Now, run them. + iter = run_now.begin(); + end = run_now.end(); + for( ; iter != end; ++iter ) + { + (*iter).mRunnable->run(this, (*iter).mHandle); + } + return run_now.size(); } LLRunner::run_handle_t LLRunner::addRunnable( - run_ptr_t runnable, - ERunSchedule schedule, - F64 seconds) + run_ptr_t runnable, + ERunSchedule schedule, + F64 seconds) { - if(!runnable) return INVALID_RUN_HANDLE; - run_handle_t handle = mNextHandle++; - F64 next_run = LLFrameTimer::getTotalSeconds() + seconds; - LLRunInfo info(handle, runnable, schedule, next_run, seconds); - switch(schedule) - { - case RUN_IN: - // We could optimize this a bit by sorting this on entry. - mRunOnce.push_back(info); - break; - case RUN_EVERY: - mRunEvery.push_back(info); - break; - default: - handle = INVALID_RUN_HANDLE; - break; - } - return handle; + if(!runnable) return INVALID_RUN_HANDLE; + run_handle_t handle = mNextHandle++; + F64 next_run = LLFrameTimer::getTotalSeconds() + seconds; + LLRunInfo info(handle, runnable, schedule, next_run, seconds); + switch(schedule) + { + case RUN_IN: + // We could optimize this a bit by sorting this on entry. + mRunOnce.push_back(info); + break; + case RUN_EVERY: + mRunEvery.push_back(info); + break; + default: + handle = INVALID_RUN_HANDLE; + break; + } + return handle; } LLRunner::run_ptr_t LLRunner::removeRunnable(LLRunner::run_handle_t handle) { - LLRunner::run_ptr_t rv; - LLRunner::run_list_t::iterator iter = mRunOnce.begin(); - LLRunner::run_list_t::iterator end = mRunOnce.end(); - for( ; iter != end; ++iter) - { - if((*iter).mHandle == handle) - { - rv = (*iter).mRunnable; - mRunOnce.erase(iter); - return rv; - } - } + LLRunner::run_ptr_t rv; + LLRunner::run_list_t::iterator iter = mRunOnce.begin(); + LLRunner::run_list_t::iterator end = mRunOnce.end(); + for( ; iter != end; ++iter) + { + if((*iter).mHandle == handle) + { + rv = (*iter).mRunnable; + mRunOnce.erase(iter); + return rv; + } + } - iter = mRunEvery.begin(); - end = mRunEvery.end(); - for( ; iter != end; ++iter) - { - if((*iter).mHandle == handle) - { - rv = (*iter).mRunnable; - mRunEvery.erase(iter); - return rv; - } - } - return rv; + iter = mRunEvery.begin(); + end = mRunEvery.end(); + for( ; iter != end; ++iter) + { + if((*iter).mHandle == handle) + { + rv = (*iter).mRunnable; + mRunEvery.erase(iter); + return rv; + } + } + return rv; } -/** +/** * LLRunner::LLRunInfo */ LLRunner::LLRunInfo::LLRunInfo( - run_handle_t handle, - run_ptr_t runnable, - ERunSchedule schedule, - F64 next_run_after, - F64 increment) : - mHandle(handle), - mRunnable(runnable), - mSchedule(schedule), - mNextRunAt(next_run_after), - mIncrement(increment) + run_handle_t handle, + run_ptr_t runnable, + ERunSchedule schedule, + F64 next_run_after, + F64 increment) : + mHandle(handle), + mRunnable(runnable), + mSchedule(schedule), + mNextRunAt(next_run_after), + mIncrement(increment) { } diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index 42e3d9b47a..8061117ad5 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -1,4 +1,4 @@ -/** +/** * @file llrun.h * @author Phoenix * @date 2006-02-16 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,7 +34,7 @@ class LLRunnable; -/** +/** * @class LLRunner * @brief This class manages a set of LLRunnable objects. * @@ -45,96 +45,96 @@ class LLRunnable; class LL_COMMON_API LLRunner { public: - /** - * @brief The pointer to a runnable. - */ - typedef std::shared_ptr<LLRunnable> run_ptr_t; - - /** - * @brief The handle for use in the API. - */ - typedef S64 run_handle_t; - - /** - * @brief Constructor. - */ - LLRunner(); - - /** - * @brief Destructor. - */ - ~LLRunner(); - - /** - * @brief Enumeration which specifies when to run. - */ - enum ERunSchedule - { - // The runnable will run in N seconds - RUN_IN, - - // The run every N seconds - RUN_EVERY, - - // A count of the run types - RUN_SCHEDULE_COUNT - }; - - /** - * @brief Run the runnables which are scheduled to run - * - * @return Returns the number of runnables run. - */ - size_t run(); - - /** - * @brief Add a runnable to the run list. - * - * The handle of the runnable is unique to each addition. If the - * same runnable is added a second time with the same or different - * schedule, this method will return a new handle. - * @param runnable The runnable to run() on schedule. - * @param schedule Specifies the run schedule. - * @param seconds When to run the runnable as interpreted by schedule. - * @return Returns the handle to the runnable. handle == 0 means failure. - */ - run_handle_t addRunnable( - run_ptr_t runnable, - ERunSchedule schedule, - F64 seconds); - - /** - * @brief Remove the specified runnable. - * - * @param handle The handle of the runnable to remove. - * @return Returns the pointer to the runnable removed which may - * be empty. - */ - run_ptr_t removeRunnable(run_handle_t handle); + /** + * @brief The pointer to a runnable. + */ + typedef std::shared_ptr<LLRunnable> run_ptr_t; + + /** + * @brief The handle for use in the API. + */ + typedef S64 run_handle_t; + + /** + * @brief Constructor. + */ + LLRunner(); + + /** + * @brief Destructor. + */ + ~LLRunner(); + + /** + * @brief Enumeration which specifies when to run. + */ + enum ERunSchedule + { + // The runnable will run in N seconds + RUN_IN, + + // The run every N seconds + RUN_EVERY, + + // A count of the run types + RUN_SCHEDULE_COUNT + }; + + /** + * @brief Run the runnables which are scheduled to run + * + * @return Returns the number of runnables run. + */ + size_t run(); + + /** + * @brief Add a runnable to the run list. + * + * The handle of the runnable is unique to each addition. If the + * same runnable is added a second time with the same or different + * schedule, this method will return a new handle. + * @param runnable The runnable to run() on schedule. + * @param schedule Specifies the run schedule. + * @param seconds When to run the runnable as interpreted by schedule. + * @return Returns the handle to the runnable. handle == 0 means failure. + */ + run_handle_t addRunnable( + run_ptr_t runnable, + ERunSchedule schedule, + F64 seconds); + + /** + * @brief Remove the specified runnable. + * + * @param handle The handle of the runnable to remove. + * @return Returns the pointer to the runnable removed which may + * be empty. + */ + run_ptr_t removeRunnable(run_handle_t handle); protected: - struct LLRunInfo - { - run_handle_t mHandle; - run_ptr_t mRunnable; - ERunSchedule mSchedule; - F64 mNextRunAt; - F64 mIncrement; - LLRunInfo( - run_handle_t handle, - run_ptr_t runnable, - ERunSchedule schedule, - F64 next_run_at, - F64 increment); - }; - typedef std::vector<LLRunInfo> run_list_t; - run_list_t mRunOnce; - run_list_t mRunEvery; - run_handle_t mNextHandle; + struct LLRunInfo + { + run_handle_t mHandle; + run_ptr_t mRunnable; + ERunSchedule mSchedule; + F64 mNextRunAt; + F64 mIncrement; + LLRunInfo( + run_handle_t handle, + run_ptr_t runnable, + ERunSchedule schedule, + F64 next_run_at, + F64 increment); + }; + typedef std::vector<LLRunInfo> run_list_t; + run_list_t mRunOnce; + run_list_t mRunEvery; + run_handle_t mNextHandle; }; -/** +/** * @class LLRunnable * @brief Abstract base class for running some scheduled process. * @@ -146,17 +146,17 @@ protected: class LL_COMMON_API LLRunnable { public: - LLRunnable(); - virtual ~LLRunnable(); - - /** - * @brief Do the process. - * - * This method will be called from the LLRunner according to - * @param runner The Runner which call run(). - * @param handle The handle this run instance is run under. - */ - virtual void run(LLRunner* runner, S64 handle) = 0; + LLRunnable(); + virtual ~LLRunnable(); + + /** + * @brief Do the process. + * + * This method will be called from the LLRunner according to + * @param runner The Runner which call run(). + * @param handle The handle this run instance is run under. + */ + virtual void run(LLRunner* runner, S64 handle) = 0; }; #endif // LL_LLRUN_H diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h index 9550e6253e..1d7e4f8220 100644 --- a/indra/llcommon/llsafehandle.h +++ b/indra/llcommon/llsafehandle.h @@ -1,32 +1,32 @@ -/** +/** * @file llsafehandle.h * @brief Reference-counted object where Object() is valid, not NULL. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLSAFEHANDLE_H #define LLSAFEHANDLE_H -#include "llerror.h" // *TODO: consider eliminating this +#include "llerror.h" // *TODO: consider eliminating this #include "llsingleton.h" /*==========================================================================*| @@ -57,142 +57,142 @@ not ever affect subsequent computations. // when error checking occurs at a different granularity or in a different part of the code // than when referencing an object via a LLSafeHandle. -template <class Type> +template <class Type> class LLSafeHandle { public: - LLSafeHandle() : - mPointer(NULL) - { - } - - LLSafeHandle(Type* ptr) : - mPointer(NULL) - { - assign(ptr); - } - - LLSafeHandle(const LLSafeHandle<Type>& ptr) : - mPointer(NULL) - { - assign(ptr.mPointer); - } - - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template<typename Subclass> - LLSafeHandle(const LLSafeHandle<Subclass>& ptr) : - mPointer(NULL) - { - assign(ptr.get()); - } - - ~LLSafeHandle() - { - unref(); - } - - const Type* operator->() const { return nonNull(mPointer); } - Type* operator->() { return nonNull(mPointer); } - - Type* get() const { return mPointer; } - void clear() { assign(NULL); } - // we disallow these operations as they expose our null objects to direct manipulation - // and bypass the reference counting semantics - //const Type& operator*() const { return *nonNull(mPointer); } - //Type& operator*() { return *nonNull(mPointer); } - - operator BOOL() const { return mPointer != NULL; } - operator bool() const { return mPointer != NULL; } - bool operator!() const { return mPointer == NULL; } - bool isNull() const { return mPointer == NULL; } - bool notNull() const { return mPointer != NULL; } - - - operator Type*() const { return mPointer; } - operator const Type*() const { return mPointer; } - bool operator !=(Type* ptr) const { return (mPointer != ptr); } - bool operator ==(Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); } - - LLSafeHandle<Type>& operator =(Type* ptr) - { - assign(ptr); - return *this; - } - - LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr) - { - assign(ptr.mPointer); - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template<typename Subclass> - LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr) - { - assign(ptr.get()); - return *this; - } + LLSafeHandle() : + mPointer(NULL) + { + } + + LLSafeHandle(Type* ptr) : + mPointer(NULL) + { + assign(ptr); + } + + LLSafeHandle(const LLSafeHandle<Type>& ptr) : + mPointer(NULL) + { + assign(ptr.mPointer); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template<typename Subclass> + LLSafeHandle(const LLSafeHandle<Subclass>& ptr) : + mPointer(NULL) + { + assign(ptr.get()); + } + + ~LLSafeHandle() + { + unref(); + } + + const Type* operator->() const { return nonNull(mPointer); } + Type* operator->() { return nonNull(mPointer); } + + Type* get() const { return mPointer; } + void clear() { assign(NULL); } + // we disallow these operations as they expose our null objects to direct manipulation + // and bypass the reference counting semantics + //const Type& operator*() const { return *nonNull(mPointer); } + //Type& operator*() { return *nonNull(mPointer); } + + operator BOOL() const { return mPointer != NULL; } + operator bool() const { return mPointer != NULL; } + bool operator!() const { return mPointer == NULL; } + bool isNull() const { return mPointer == NULL; } + bool notNull() const { return mPointer != NULL; } + + + operator Type*() const { return mPointer; } + operator const Type*() const { return mPointer; } + bool operator !=(Type* ptr) const { return (mPointer != ptr); } + bool operator ==(Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); } + + LLSafeHandle<Type>& operator =(Type* ptr) + { + assign(ptr); + return *this; + } + + LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr) + { + assign(ptr.mPointer); + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template<typename Subclass> + LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr) + { + assign(ptr.get()); + return *this; + } protected: - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - Type *tempp = mPointer; - mPointer = NULL; - tempp->unref(); - if (mPointer != NULL) - { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; - unref(); - } - } - } - - void assign(Type* ptr) - { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - } - - // Define an LLSingleton whose sole purpose is to hold a "null instance" - // of the subject Type: the canonical instance to dereference if this - // LLSafeHandle actually holds a null pointer. We use LLSingleton - // specifically so that the "null instance" can be cleaned up at a well- - // defined time, specifically LLSingletonBase::deleteAll(). - // Of course, as with any LLSingleton, the "null instance" is only - // instantiated on demand -- in this case, if you actually try to - // dereference an LLSafeHandle containing null. - class NullInstanceHolder: public LLSingleton<NullInstanceHolder> - { - LLSINGLETON_EMPTY_CTOR(NullInstanceHolder); - ~NullInstanceHolder() {} - public: - Type mNullInstance; - }; - - static Type* nonNull(Type* ptr) - { - return ptr? ptr : &NullInstanceHolder::instance().mNullInstance; - } + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + Type *tempp = mPointer; + mPointer = NULL; + tempp->unref(); + if (mPointer != NULL) + { + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + unref(); + } + } + } + + void assign(Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = ptr; + ref(); + } + } + + // Define an LLSingleton whose sole purpose is to hold a "null instance" + // of the subject Type: the canonical instance to dereference if this + // LLSafeHandle actually holds a null pointer. We use LLSingleton + // specifically so that the "null instance" can be cleaned up at a well- + // defined time, specifically LLSingletonBase::deleteAll(). + // Of course, as with any LLSingleton, the "null instance" is only + // instantiated on demand -- in this case, if you actually try to + // dereference an LLSafeHandle containing null. + class NullInstanceHolder: public LLSingleton<NullInstanceHolder> + { + LLSINGLETON_EMPTY_CTOR(NullInstanceHolder); + ~NullInstanceHolder() {} + public: + Type mNullInstance; + }; + + static Type* nonNull(Type* ptr) + { + return ptr? ptr : &NullInstanceHolder::instance().mNullInstance; + } protected: - Type* mPointer; + Type* mPointer; }; #endif diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 590915e9d2..663ceac22b 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsd.cpp * @brief LLSD flexible data system * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -53,13 +53,13 @@ bool was_negative(size_t i) #endif #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace +namespace LLSDUnnamedNamespace #else -namespace +namespace #endif { - class ImplMap; - class ImplArray; + class ImplMap; + class ImplArray; } #ifdef NAME_UNNAMED_NAMESPACE @@ -70,740 +70,740 @@ namespace llsd { // statics -S32 sLLSDAllocationCount = 0; +S32 sLLSDAllocationCount = 0; S32 sLLSDNetObjects = 0; } // namespace llsd -#define ALLOC_LLSD_OBJECT { llsd::sLLSDNetObjects++; llsd::sLLSDAllocationCount++; } -#define FREE_LLSD_OBJECT { llsd::sLLSDNetObjects--; } +#define ALLOC_LLSD_OBJECT { llsd::sLLSDNetObjects++; llsd::sLLSDAllocationCount++; } +#define FREE_LLSD_OBJECT { llsd::sLLSDNetObjects--; } class LLSD::Impl - /**< This class is the abstract base class of the implementation of LLSD - It provides the reference counting implementation, and the default - implementation of most methods for most data types. It also serves - as a working implementation of the Undefined type. - - */ + /**< This class is the abstract base class of the implementation of LLSD + It provides the reference counting implementation, and the default + implementation of most methods for most data types. It also serves + as a working implementation of the Undefined type. + + */ { protected: - Impl(); - - enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF }; - Impl(StaticAllocationMarker); - ///< This constructor is used for static objects and causes the - // suppresses adjusting the debugging counters when they are - // finally initialized. - - virtual ~Impl(); - - bool shared() const { return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); } - - U32 mUseCount; + Impl(); + + enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF }; + Impl(StaticAllocationMarker); + ///< This constructor is used for static objects and causes the + // suppresses adjusting the debugging counters when they are + // finally initialized. + + virtual ~Impl(); + + bool shared() const { return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); } + + U32 mUseCount; public: - static void reset(Impl*& var, Impl* impl); - ///< safely set var to refer to the new impl (possibly shared) - - static Impl& safe( Impl*); - static const Impl& safe(const Impl*); - ///< since a NULL Impl* is used for undefined, this ensures there is - // always an object you call virtual member functions on - - virtual ImplMap& makeMap(Impl*& var); - virtual ImplArray& makeArray(Impl*& var); - ///< sure var is a modifiable, non-shared map or array - - virtual LLSD::Type type() const { return LLSD::TypeUndefined; } - - static void assignUndefined(LLSD::Impl*& var); - static void assign(LLSD::Impl*& var, const LLSD::Impl* other); - - virtual void assign(Impl*& var, LLSD::Boolean); - virtual void assign(Impl*& var, LLSD::Integer); - virtual void assign(Impl*& var, LLSD::Real); - virtual void assign(Impl*& var, const LLSD::String&); - virtual void assign(Impl*& var, const LLSD::UUID&); - virtual void assign(Impl*& var, const LLSD::Date&); - virtual void assign(Impl*& var, const LLSD::URI&); - virtual void assign(Impl*& var, const LLSD::Binary&); - ///< If the receiver is the right type and unshared, these are simple - // data assignments, othewise the default implementation handless - // constructing the proper Impl subclass - - virtual Boolean asBoolean() const { return false; } - virtual Integer asInteger() const { return 0; } - virtual Real asReal() const { return 0.0; } - virtual String asString() const { return std::string(); } - virtual UUID asUUID() const { return LLUUID(); } - virtual Date asDate() const { return LLDate(); } - virtual URI asURI() const { return LLURI(); } - virtual const Binary& asBinary() const { static const std::vector<U8> empty; return empty; } - - virtual const String& asStringRef() const { static const std::string empty; return empty; } - - virtual bool has(const String&) const { return false; } - virtual LLSD get(const String&) const { return LLSD(); } - virtual LLSD getKeys() const { return LLSD::emptyArray(); } - virtual void erase(const String&) { } - virtual const LLSD& ref(const String&) const{ return undef(); } - - virtual size_t size() const { return 0; } - virtual LLSD get(size_t) const { return LLSD(); } - virtual void erase(size_t) { } - virtual const LLSD& ref(size_t) const { return undef(); } - - virtual LLSD::map_const_iterator beginMap() const { return endMap(); } - virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); } - virtual LLSD::array_const_iterator beginArray() const { return endArray(); } - virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); } - - virtual void dumpStats() const; - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; - // Container subclasses contain LLSD objects, rather than directly - // containing Impl objects. This helper forwards through LLSD. - void calcStats(const LLSD& llsd, S32 type_counts[], S32 share_counts[]) const - { - safe(llsd.impl).calcStats(type_counts, share_counts); - } - - static const Impl& getImpl(const LLSD& llsd) { return safe(llsd.impl); } - static Impl& getImpl(LLSD& llsd) { return safe(llsd.impl); } - - static const LLSD& undef(); - - static U32 sAllocationCount; - static U32 sOutstandingCount; + static void reset(Impl*& var, Impl* impl); + ///< safely set var to refer to the new impl (possibly shared) + + static Impl& safe( Impl*); + static const Impl& safe(const Impl*); + ///< since a NULL Impl* is used for undefined, this ensures there is + // always an object you call virtual member functions on + + virtual ImplMap& makeMap(Impl*& var); + virtual ImplArray& makeArray(Impl*& var); + ///< sure var is a modifiable, non-shared map or array + + virtual LLSD::Type type() const { return LLSD::TypeUndefined; } + + static void assignUndefined(LLSD::Impl*& var); + static void assign(LLSD::Impl*& var, const LLSD::Impl* other); + + virtual void assign(Impl*& var, LLSD::Boolean); + virtual void assign(Impl*& var, LLSD::Integer); + virtual void assign(Impl*& var, LLSD::Real); + virtual void assign(Impl*& var, const LLSD::String&); + virtual void assign(Impl*& var, const LLSD::UUID&); + virtual void assign(Impl*& var, const LLSD::Date&); + virtual void assign(Impl*& var, const LLSD::URI&); + virtual void assign(Impl*& var, const LLSD::Binary&); + ///< If the receiver is the right type and unshared, these are simple + // data assignments, othewise the default implementation handless + // constructing the proper Impl subclass + + virtual Boolean asBoolean() const { return false; } + virtual Integer asInteger() const { return 0; } + virtual Real asReal() const { return 0.0; } + virtual String asString() const { return std::string(); } + virtual UUID asUUID() const { return LLUUID(); } + virtual Date asDate() const { return LLDate(); } + virtual URI asURI() const { return LLURI(); } + virtual const Binary& asBinary() const { static const std::vector<U8> empty; return empty; } + + virtual const String& asStringRef() const { static const std::string empty; return empty; } + + virtual bool has(const String&) const { return false; } + virtual LLSD get(const String&) const { return LLSD(); } + virtual LLSD getKeys() const { return LLSD::emptyArray(); } + virtual void erase(const String&) { } + virtual const LLSD& ref(const String&) const{ return undef(); } + + virtual size_t size() const { return 0; } + virtual LLSD get(size_t) const { return LLSD(); } + virtual void erase(size_t) { } + virtual const LLSD& ref(size_t) const { return undef(); } + + virtual LLSD::map_const_iterator beginMap() const { return endMap(); } + virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); } + virtual LLSD::array_const_iterator beginArray() const { return endArray(); } + virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); } + + virtual void dumpStats() const; + virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + // Container subclasses contain LLSD objects, rather than directly + // containing Impl objects. This helper forwards through LLSD. + void calcStats(const LLSD& llsd, S32 type_counts[], S32 share_counts[]) const + { + safe(llsd.impl).calcStats(type_counts, share_counts); + } + + static const Impl& getImpl(const LLSD& llsd) { return safe(llsd.impl); } + static Impl& getImpl(LLSD& llsd) { return safe(llsd.impl); } + + static const LLSD& undef(); + + static U32 sAllocationCount; + static U32 sOutstandingCount; }; #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace +namespace LLSDUnnamedNamespace #else -namespace +namespace #endif { - template<LLSD::Type T, class Data, class DataRef = 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 - // conversion functions and a constructor. - { - protected: - Data mValue; - - typedef ImplBase Base; - - public: - ImplBase(DataRef value) : mValue(value) { } - - virtual LLSD::Type type() const { return T; } - - using LLSD::Impl::assign; // Unhiding base class virtuals... - virtual void assign(LLSD::Impl*& var, DataRef value) { - if (shared()) - { - Impl::assign(var, value); - } - else - { - mValue = value; - } - } - }; - - - class ImplBoolean - : public ImplBase<LLSD::TypeBoolean, LLSD::Boolean> - { - public: - ImplBoolean(LLSD::Boolean v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const { return mValue; } - virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } - virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } - virtual LLSD::String asString() const; - }; - - LLSD::String ImplBoolean::asString() const - // *NOTE: The reason that false is not converted to "false" is - // because that would break roundtripping, - // e.g. LLSD(false).asString().asBoolean(). There are many - // reasons for wanting LLSD("false").asBoolean() == true, such - // as "everything else seems to work that way". - { return mValue ? "true" : ""; } - - - class ImplInteger - : public ImplBase<LLSD::TypeInteger, LLSD::Integer> - { - public: - ImplInteger(LLSD::Integer v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const { return mValue != 0; } - virtual LLSD::Integer asInteger() const { return mValue; } - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; - }; - - LLSD::String ImplInteger::asString() const - { return llformat("%d", mValue); } - - - class ImplReal - : public ImplBase<LLSD::TypeReal, LLSD::Real> - { - public: - ImplReal(LLSD::Real v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const; - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; - }; - - LLSD::Boolean ImplReal::asBoolean() const - { return !llisnan(mValue) && mValue != 0.0; } - - LLSD::Integer ImplReal::asInteger() const - { return !llisnan(mValue) ? (LLSD::Integer)mValue : 0; } - - LLSD::String ImplReal::asString() const - { return llformat("%lg", mValue); } - - - class ImplString - : public ImplBase<LLSD::TypeString, LLSD::String, const LLSD::String&> - { - public: - ImplString(const LLSD::String& v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); } - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const; - virtual LLSD::String asString() const { return mValue; } - virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } - virtual LLSD::Date asDate() const { return LLDate(mValue); } - virtual LLSD::URI asURI() const { return LLURI(mValue); } - virtual size_t size() const { return mValue.size(); } - virtual const LLSD::String& asStringRef() const { return mValue; } - }; - - LLSD::Integer ImplString::asInteger() const - { - // This must treat "1.23" not as an error, but as a number, which is - // then truncated down to an integer. Hence, this code doesn't call - // std::istringstream::operator>>(int&), which would not consume the - // ".23" portion. - - return (int)asReal(); - } - - LLSD::Real ImplString::asReal() const - { - F64 v = 0.0; - std::istringstream i_stream(mValue); - i_stream >> v; - - // we would probably like to ignore all trailing whitespace as - // well, but for now, simply eat the next character, and make - // sure we reached the end of the string. - // *NOTE: gcc 2.95 does not generate an eof() event on the - // stream operation above, so we manually get here to force it - // across platforms. - int c = i_stream.get(); - return ((EOF ==c) ? v : 0.0); - } - - - class ImplUUID - : public ImplBase<LLSD::TypeUUID, LLSD::UUID, const LLSD::UUID&> - { - public: - ImplUUID(const LLSD::UUID& v) : Base(v) { } - - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::UUID asUUID() const { return mValue; } - }; - - - class ImplDate - : public ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&> - { - public: - ImplDate(const LLSD::Date& v) - : ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>(v) - { } - - virtual LLSD::Integer asInteger() const - { - return (LLSD::Integer)(mValue.secondsSinceEpoch()); - } - virtual LLSD::Real asReal() const - { - return mValue.secondsSinceEpoch(); - } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::Date asDate() const { return mValue; } - }; - - - class ImplURI - : public ImplBase<LLSD::TypeURI, LLSD::URI, const LLSD::URI&> - { - public: - ImplURI(const LLSD::URI& v) : Base(v) { } - - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::URI asURI() const { return mValue; } - }; - - - class ImplBinary - : public ImplBase<LLSD::TypeBinary, LLSD::Binary, const LLSD::Binary&> - { - public: - ImplBinary(const LLSD::Binary& v) : Base(v) { } - - virtual const LLSD::Binary& asBinary() const{ return mValue; } - }; - - - class ImplMap : public LLSD::Impl - { - private: - typedef std::map<LLSD::String, LLSD> DataMap; - - DataMap mData; - - protected: - ImplMap(const DataMap& data) : mData(data) { } - - public: - ImplMap() { } - - virtual ImplMap& makeMap(LLSD::Impl*&); - - virtual LLSD::Type type() const { return LLSD::TypeMap; } - - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } - - virtual bool has(const LLSD::String&) const; - - using LLSD::Impl::get; // Unhiding get(size_t) - using LLSD::Impl::erase; // Unhiding erase(size_t) - using LLSD::Impl::ref; // Unhiding ref(size_t) - virtual LLSD get(const LLSD::String&) const; - virtual LLSD getKeys() const; - void insert(const LLSD::String& k, const LLSD& v); - virtual void erase(const LLSD::String&); - LLSD& ref(const LLSD::String&); - virtual const LLSD& ref(const LLSD::String&) const; - - virtual size_t size() const { return mData.size(); } - - LLSD::map_iterator beginMap() { return mData.begin(); } - LLSD::map_iterator endMap() { return mData.end(); } - virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); } - virtual LLSD::map_const_iterator endMap() const { return mData.end(); } - - virtual void dumpStats() const; - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; - }; - - ImplMap& ImplMap::makeMap(LLSD::Impl*& var) - { + template<LLSD::Type T, class Data, class DataRef = 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 + // conversion functions and a constructor. + { + protected: + Data mValue; + + typedef ImplBase Base; + + public: + ImplBase(DataRef value) : mValue(value) { } + + virtual LLSD::Type type() const { return T; } + + using LLSD::Impl::assign; // Unhiding base class virtuals... + virtual void assign(LLSD::Impl*& var, DataRef value) { + if (shared()) + { + Impl::assign(var, value); + } + else + { + mValue = value; + } + } + }; + + + class ImplBoolean + : public ImplBase<LLSD::TypeBoolean, LLSD::Boolean> + { + public: + ImplBoolean(LLSD::Boolean v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const { return mValue; } + virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } + virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } + virtual LLSD::String asString() const; + }; + + LLSD::String ImplBoolean::asString() const + // *NOTE: The reason that false is not converted to "false" is + // because that would break roundtripping, + // e.g. LLSD(false).asString().asBoolean(). There are many + // reasons for wanting LLSD("false").asBoolean() == true, such + // as "everything else seems to work that way". + { return mValue ? "true" : ""; } + + + class ImplInteger + : public ImplBase<LLSD::TypeInteger, LLSD::Integer> + { + public: + ImplInteger(LLSD::Integer v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const { return mValue != 0; } + virtual LLSD::Integer asInteger() const { return mValue; } + virtual LLSD::Real asReal() const { return mValue; } + virtual LLSD::String asString() const; + }; + + LLSD::String ImplInteger::asString() const + { return llformat("%d", mValue); } + + + class ImplReal + : public ImplBase<LLSD::TypeReal, LLSD::Real> + { + public: + ImplReal(LLSD::Real v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const; + virtual LLSD::Integer asInteger() const; + virtual LLSD::Real asReal() const { return mValue; } + virtual LLSD::String asString() const; + }; + + LLSD::Boolean ImplReal::asBoolean() const + { return !llisnan(mValue) && mValue != 0.0; } + + LLSD::Integer ImplReal::asInteger() const + { return !llisnan(mValue) ? (LLSD::Integer)mValue : 0; } + + LLSD::String ImplReal::asString() const + { return llformat("%lg", mValue); } + + + class ImplString + : public ImplBase<LLSD::TypeString, LLSD::String, const LLSD::String&> + { + public: + ImplString(const LLSD::String& v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); } + virtual LLSD::Integer asInteger() const; + virtual LLSD::Real asReal() const; + virtual LLSD::String asString() const { return mValue; } + virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } + virtual LLSD::Date asDate() const { return LLDate(mValue); } + virtual LLSD::URI asURI() const { return LLURI(mValue); } + virtual size_t size() const { return mValue.size(); } + virtual const LLSD::String& asStringRef() const { return mValue; } + }; + + LLSD::Integer ImplString::asInteger() const + { + // This must treat "1.23" not as an error, but as a number, which is + // then truncated down to an integer. Hence, this code doesn't call + // std::istringstream::operator>>(int&), which would not consume the + // ".23" portion. + + return (int)asReal(); + } + + LLSD::Real ImplString::asReal() const + { + F64 v = 0.0; + std::istringstream i_stream(mValue); + i_stream >> v; + + // we would probably like to ignore all trailing whitespace as + // well, but for now, simply eat the next character, and make + // sure we reached the end of the string. + // *NOTE: gcc 2.95 does not generate an eof() event on the + // stream operation above, so we manually get here to force it + // across platforms. + int c = i_stream.get(); + return ((EOF ==c) ? v : 0.0); + } + + + class ImplUUID + : public ImplBase<LLSD::TypeUUID, LLSD::UUID, const LLSD::UUID&> + { + public: + ImplUUID(const LLSD::UUID& v) : Base(v) { } + + virtual LLSD::String asString() const{ return mValue.asString(); } + virtual LLSD::UUID asUUID() const { return mValue; } + }; + + + class ImplDate + : public ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&> + { + public: + ImplDate(const LLSD::Date& v) + : ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>(v) + { } + + virtual LLSD::Integer asInteger() const + { + return (LLSD::Integer)(mValue.secondsSinceEpoch()); + } + virtual LLSD::Real asReal() const + { + return mValue.secondsSinceEpoch(); + } + virtual LLSD::String asString() const{ return mValue.asString(); } + virtual LLSD::Date asDate() const { return mValue; } + }; + + + class ImplURI + : public ImplBase<LLSD::TypeURI, LLSD::URI, const LLSD::URI&> + { + public: + ImplURI(const LLSD::URI& v) : Base(v) { } + + virtual LLSD::String asString() const{ return mValue.asString(); } + virtual LLSD::URI asURI() const { return mValue; } + }; + + + class ImplBinary + : public ImplBase<LLSD::TypeBinary, LLSD::Binary, const LLSD::Binary&> + { + public: + ImplBinary(const LLSD::Binary& v) : Base(v) { } + + virtual const LLSD::Binary& asBinary() const{ return mValue; } + }; + + + class ImplMap : public LLSD::Impl + { + private: + typedef std::map<LLSD::String, LLSD> DataMap; + + DataMap mData; + + protected: + ImplMap(const DataMap& data) : mData(data) { } + + public: + ImplMap() { } + + virtual ImplMap& makeMap(LLSD::Impl*&); + + virtual LLSD::Type type() const { return LLSD::TypeMap; } + + virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + + virtual bool has(const LLSD::String&) const; + + using LLSD::Impl::get; // Unhiding get(size_t) + using LLSD::Impl::erase; // Unhiding erase(size_t) + using LLSD::Impl::ref; // Unhiding ref(size_t) + virtual LLSD get(const LLSD::String&) const; + virtual LLSD getKeys() const; + void insert(const LLSD::String& k, const LLSD& v); + virtual void erase(const LLSD::String&); + LLSD& ref(const LLSD::String&); + virtual const LLSD& ref(const LLSD::String&) const; + + virtual size_t size() const { return mData.size(); } + + LLSD::map_iterator beginMap() { return mData.begin(); } + LLSD::map_iterator endMap() { return mData.end(); } + virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); } + virtual LLSD::map_const_iterator endMap() const { return mData.end(); } + + virtual void dumpStats() const; + virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + }; + + ImplMap& ImplMap::makeMap(LLSD::Impl*& var) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - if (shared()) - { - ImplMap* i = new ImplMap(mData); - Impl::assign(var, i); - return *i; - } - else - { - return *this; - } - } - - bool ImplMap::has(const LLSD::String& k) const - { + if (shared()) + { + ImplMap* i = new ImplMap(mData); + Impl::assign(var, i); + return *i; + } + else + { + return *this; + } + } + + bool ImplMap::has(const LLSD::String& k) const + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - DataMap::const_iterator i = mData.find(k); - return i != mData.end(); - } - - LLSD ImplMap::get(const LLSD::String& k) const - { + DataMap::const_iterator i = mData.find(k); + return i != mData.end(); + } + + LLSD ImplMap::get(const LLSD::String& k) const + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - DataMap::const_iterator i = mData.find(k); - return (i != mData.end()) ? i->second : LLSD(); - } + DataMap::const_iterator i = mData.find(k); + return (i != mData.end()) ? i->second : LLSD(); + } - LLSD ImplMap::getKeys() const - { + LLSD ImplMap::getKeys() const + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - LLSD keys = LLSD::emptyArray(); - DataMap::const_iterator iter = mData.begin(); - while (iter != mData.end()) - { - keys.append((*iter).first); - iter++; - } - return keys; - } - - void ImplMap::insert(const LLSD::String& k, const LLSD& v) - { + LLSD keys = LLSD::emptyArray(); + DataMap::const_iterator iter = mData.begin(); + while (iter != mData.end()) + { + keys.append((*iter).first); + iter++; + } + return keys; + } + + void ImplMap::insert(const LLSD::String& k, const LLSD& v) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - mData.insert(DataMap::value_type(k, v)); - } - - void ImplMap::erase(const LLSD::String& k) - { + mData.insert(DataMap::value_type(k, v)); + } + + void ImplMap::erase(const LLSD::String& k) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - mData.erase(k); - } - - LLSD& ImplMap::ref(const LLSD::String& k) - { - return mData[k]; - } - - const LLSD& ImplMap::ref(const LLSD::String& k) const - { - DataMap::const_iterator i = mData.lower_bound(k); - if (i == mData.end() || mData.key_comp()(k, i->first)) - { - return undef(); - } - - return i->second; - } - - void ImplMap::dumpStats() const - { - std::cout << "Map size: " << mData.size() << std::endl; - - std::cout << "LLSD Net Objects: " << llsd::sLLSDNetObjects << std::endl; - std::cout << "LLSD allocations: " << llsd::sLLSDAllocationCount << std::endl; - - std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl; - std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl; - - Impl::dumpStats(); - } - - void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const - { - LLSD::map_const_iterator iter = beginMap(); - while (iter != endMap()) - { - //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl; - Impl::calcStats((*iter).second, type_counts, share_counts); - iter++; - } - - // Add in the values for this map - Impl::calcStats(type_counts, share_counts); - } - - - class ImplArray : public LLSD::Impl - { - private: - typedef std::vector<LLSD> DataVector; - - DataVector mData; - - protected: - ImplArray(const DataVector& data) : mData(data) { } - - public: - ImplArray() { } - - virtual ImplArray& makeArray(Impl*&); - - virtual LLSD::Type type() const { return LLSD::TypeArray; } - - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } - - using LLSD::Impl::get; // Unhiding get(LLSD::String) - using LLSD::Impl::erase; // Unhiding erase(LLSD::String) - using LLSD::Impl::ref; // Unhiding ref(LLSD::String) - virtual size_t size() const; - virtual LLSD get(size_t) const; - void set(size_t, const LLSD&); - void insert(size_t, const LLSD&); - LLSD& append(const LLSD&); - virtual void erase(size_t); - LLSD& ref(size_t); - virtual const LLSD& ref(size_t) const; - - LLSD::array_iterator beginArray() { return mData.begin(); } - LLSD::array_iterator endArray() { return mData.end(); } - LLSD::reverse_array_iterator rbeginArray() { return mData.rbegin(); } - LLSD::reverse_array_iterator rendArray() { return mData.rend(); } - virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); } - virtual LLSD::array_const_iterator endArray() const { return mData.end(); } - - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; - }; - - ImplArray& ImplArray::makeArray(Impl*& var) - { - if (shared()) - { - ImplArray* i = new ImplArray(mData); - Impl::assign(var, i); - return *i; - } - else - { - return *this; - } - } - - size_t ImplArray::size() const { return mData.size(); } - - LLSD ImplArray::get(size_t i) const - { - NEGATIVE_RETURN(i, LLSD()); - DataVector::size_type index = i; - - return (index < mData.size()) ? mData[index] : LLSD(); - } - - void ImplArray::set(size_t i, const LLSD& v) - { - NEGATIVE_EXIT(i); - DataVector::size_type index = i; - - if (index >= mData.size()) - { - mData.resize(index + 1); - } - - mData[index] = v; - } - - void ImplArray::insert(size_t i, const LLSD& v) - { - NEGATIVE_EXIT(i); - DataVector::size_type index = i; - - if (index >= mData.size()) // tbd - sanity check limit for index ? - { - mData.resize(index + 1); - } - - mData.insert(mData.begin() + index, v); - } - - LLSD& ImplArray::append(const LLSD& v) - { - mData.push_back(v); - return mData.back(); - } - - void ImplArray::erase(size_t i) - { - NEGATIVE_EXIT(i); - DataVector::size_type index = i; - - if (index < mData.size()) - { - mData.erase(mData.begin() + index); - } - } - - LLSD& ImplArray::ref(size_t i) - { - DataVector::size_type index = was_negative(i)? 0 : i; - - if (index >= mData.size()) - { - mData.resize(index + 1); - } - - return mData[index]; - } - - const LLSD& ImplArray::ref(size_t i) const - { - NEGATIVE_RETURN(i, undef()); - DataVector::size_type index = i; - - if (index >= mData.size()) - { - return undef(); - } - - return mData[index]; - } - - void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const - { - LLSD::array_const_iterator iter = beginArray(); - while (iter != endArray()) - { // Add values for all items held in the array - Impl::calcStats((*iter), type_counts, share_counts); - iter++; - } - - // Add in the values for this array - Impl::calcStats(type_counts, share_counts); - } + mData.erase(k); + } + + LLSD& ImplMap::ref(const LLSD::String& k) + { + return mData[k]; + } + + const LLSD& ImplMap::ref(const LLSD::String& k) const + { + DataMap::const_iterator i = mData.lower_bound(k); + if (i == mData.end() || mData.key_comp()(k, i->first)) + { + return undef(); + } + + return i->second; + } + + void ImplMap::dumpStats() const + { + std::cout << "Map size: " << mData.size() << std::endl; + + std::cout << "LLSD Net Objects: " << llsd::sLLSDNetObjects << std::endl; + std::cout << "LLSD allocations: " << llsd::sLLSDAllocationCount << std::endl; + + std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl; + std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl; + + Impl::dumpStats(); + } + + void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const + { + LLSD::map_const_iterator iter = beginMap(); + while (iter != endMap()) + { + //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl; + Impl::calcStats((*iter).second, type_counts, share_counts); + iter++; + } + + // Add in the values for this map + Impl::calcStats(type_counts, share_counts); + } + + + class ImplArray : public LLSD::Impl + { + private: + typedef std::vector<LLSD> DataVector; + + DataVector mData; + + protected: + ImplArray(const DataVector& data) : mData(data) { } + + public: + ImplArray() { } + + virtual ImplArray& makeArray(Impl*&); + + virtual LLSD::Type type() const { return LLSD::TypeArray; } + + virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + + using LLSD::Impl::get; // Unhiding get(LLSD::String) + using LLSD::Impl::erase; // Unhiding erase(LLSD::String) + using LLSD::Impl::ref; // Unhiding ref(LLSD::String) + virtual size_t size() const; + virtual LLSD get(size_t) const; + void set(size_t, const LLSD&); + void insert(size_t, const LLSD&); + LLSD& append(const LLSD&); + virtual void erase(size_t); + LLSD& ref(size_t); + virtual const LLSD& ref(size_t) const; + + LLSD::array_iterator beginArray() { return mData.begin(); } + LLSD::array_iterator endArray() { return mData.end(); } + LLSD::reverse_array_iterator rbeginArray() { return mData.rbegin(); } + LLSD::reverse_array_iterator rendArray() { return mData.rend(); } + virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); } + virtual LLSD::array_const_iterator endArray() const { return mData.end(); } + + virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + }; + + ImplArray& ImplArray::makeArray(Impl*& var) + { + if (shared()) + { + ImplArray* i = new ImplArray(mData); + Impl::assign(var, i); + return *i; + } + else + { + return *this; + } + } + + size_t ImplArray::size() const { return mData.size(); } + + LLSD ImplArray::get(size_t i) const + { + NEGATIVE_RETURN(i, LLSD()); + DataVector::size_type index = i; + + return (index < mData.size()) ? mData[index] : LLSD(); + } + + void ImplArray::set(size_t i, const LLSD& v) + { + NEGATIVE_EXIT(i); + DataVector::size_type index = i; + + if (index >= mData.size()) + { + mData.resize(index + 1); + } + + mData[index] = v; + } + + void ImplArray::insert(size_t i, const LLSD& v) + { + NEGATIVE_EXIT(i); + DataVector::size_type index = i; + + if (index >= mData.size()) // tbd - sanity check limit for index ? + { + mData.resize(index + 1); + } + + mData.insert(mData.begin() + index, v); + } + + LLSD& ImplArray::append(const LLSD& v) + { + mData.push_back(v); + return mData.back(); + } + + void ImplArray::erase(size_t i) + { + NEGATIVE_EXIT(i); + DataVector::size_type index = i; + + if (index < mData.size()) + { + mData.erase(mData.begin() + index); + } + } + + LLSD& ImplArray::ref(size_t i) + { + DataVector::size_type index = was_negative(i)? 0 : i; + + if (index >= mData.size()) + { + mData.resize(index + 1); + } + + return mData[index]; + } + + const LLSD& ImplArray::ref(size_t i) const + { + NEGATIVE_RETURN(i, undef()); + DataVector::size_type index = i; + + if (index >= mData.size()) + { + return undef(); + } + + return mData[index]; + } + + void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const + { + LLSD::array_const_iterator iter = beginArray(); + while (iter != endArray()) + { // Add values for all items held in the array + Impl::calcStats((*iter), type_counts, share_counts); + iter++; + } + + // Add in the values for this array + Impl::calcStats(type_counts, share_counts); + } } LLSD::Impl::Impl() - : mUseCount(0) + : mUseCount(0) { - ++sAllocationCount; - ++sOutstandingCount; + ++sAllocationCount; + ++sOutstandingCount; } LLSD::Impl::Impl(StaticAllocationMarker) - : mUseCount(0) + : mUseCount(0) { } LLSD::Impl::~Impl() { - --sOutstandingCount; + --sOutstandingCount; } void LLSD::Impl::reset(Impl*& var, Impl* impl) { - if (impl && impl->mUseCount != STATIC_USAGE_COUNT) - { - ++impl->mUseCount; - } - if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0) - { - delete var; - } - var = impl; + if (impl && impl->mUseCount != STATIC_USAGE_COUNT) + { + ++impl->mUseCount; + } + if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0) + { + delete var; + } + var = impl; } LLSD::Impl& LLSD::Impl::safe(Impl* impl) { - static Impl theUndefined(STATIC_USAGE_COUNT); - return impl ? *impl : theUndefined; + static Impl theUndefined(STATIC_USAGE_COUNT); + return impl ? *impl : theUndefined; } const LLSD::Impl& LLSD::Impl::safe(const Impl* impl) { - static Impl theUndefined(STATIC_USAGE_COUNT); - return impl ? *impl : theUndefined; + static Impl theUndefined(STATIC_USAGE_COUNT); + return impl ? *impl : theUndefined; } ImplMap& LLSD::Impl::makeMap(Impl*& var) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - ImplMap* im = new ImplMap; - reset(var, im); - return *im; + ImplMap* im = new ImplMap; + reset(var, im); + return *im; } ImplArray& LLSD::Impl::makeArray(Impl*& var) { - ImplArray* ia = new ImplArray; - reset(var, ia); - return *ia; + ImplArray* ia = new ImplArray; + reset(var, ia); + return *ia; } void LLSD::Impl::assign(Impl*& var, const Impl* other) { - reset(var, const_cast<Impl*>(other)); + reset(var, const_cast<Impl*>(other)); } void LLSD::Impl::assignUndefined(Impl*& var) { - reset(var, 0); + reset(var, 0); } void LLSD::Impl::assign(Impl*& var, LLSD::Boolean v) { - reset(var, new ImplBoolean(v)); + reset(var, new ImplBoolean(v)); } void LLSD::Impl::assign(Impl*& var, LLSD::Integer v) { - reset(var, new ImplInteger(v)); + reset(var, new ImplInteger(v)); } void LLSD::Impl::assign(Impl*& var, LLSD::Real v) { - reset(var, new ImplReal(v)); + reset(var, new ImplReal(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::String& v) { - reset(var, new ImplString(v)); + reset(var, new ImplString(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::UUID& v) { - reset(var, new ImplUUID(v)); + reset(var, new ImplUUID(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::Date& v) { - reset(var, new ImplDate(v)); + reset(var, new ImplDate(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::URI& v) { - reset(var, new ImplURI(v)); + reset(var, new ImplURI(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::Binary& v) { - reset(var, new ImplBinary(v)); + reset(var, new ImplBinary(v)); } const LLSD& LLSD::Impl::undef() { - static const LLSD immutableUndefined; - return immutableUndefined; + static const LLSD immutableUndefined; + return immutableUndefined; } void LLSD::Impl::dumpStats() const { - S32 type_counts[LLSD::TypeLLSDNumTypes + 1]; - memset(&type_counts, 0, sizeof(type_counts)); - - S32 share_counts[LLSD::TypeLLSDNumTypes + 1]; - memset(&share_counts, 0, sizeof(share_counts)); - - // Add info from all the values this object has - calcStats(type_counts, share_counts); - - S32 type_index = LLSD::TypeLLSDTypeBegin; - while (type_index != LLSD::TypeLLSDTypeEnd) - { - std::cout << LLSD::typeString((LLSD::Type)type_index) << " type " - << type_counts[type_index] << " objects, " - << share_counts[type_index] << " shared" - << std::endl; - type_index++; - } + S32 type_counts[LLSD::TypeLLSDNumTypes + 1]; + memset(&type_counts, 0, sizeof(type_counts)); + + S32 share_counts[LLSD::TypeLLSDNumTypes + 1]; + memset(&share_counts, 0, sizeof(share_counts)); + + // Add info from all the values this object has + calcStats(type_counts, share_counts); + + S32 type_index = LLSD::TypeLLSDTypeBegin; + while (type_index != LLSD::TypeLLSDTypeEnd) + { + std::cout << LLSD::typeString((LLSD::Type)type_index) << " type " + << type_counts[type_index] << " objects, " + << share_counts[type_index] << " shared" + << std::endl; + type_index++; + } } void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const { - S32 tp = S32(type()); - if (0 <= tp && tp < LLSD::TypeLLSDNumTypes) - { - type_counts[tp]++; - if (shared()) - { - share_counts[tp]++; - } - } + S32 tp = S32(type()); + if (0 <= tp && tp < LLSD::TypeLLSDNumTypes) + { + type_counts[tp]++; + if (shared()) + { + share_counts[tp]++; + } + } } @@ -813,218 +813,218 @@ U32 LLSD::Impl::sOutstandingCount = 0; #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace +namespace LLSDUnnamedNamespace #else -namespace +namespace #endif { - inline LLSD::Impl& safe(LLSD::Impl* impl) - { return LLSD::Impl::safe(impl); } - - inline ImplMap& makeMap(LLSD::Impl*& var) - { return safe(var).makeMap(var); } - - inline ImplArray& makeArray(LLSD::Impl*& var) - { return safe(var).makeArray(var); } + inline LLSD::Impl& safe(LLSD::Impl* impl) + { return LLSD::Impl::safe(impl); } + + inline ImplMap& makeMap(LLSD::Impl*& var) + { return safe(var).makeMap(var); } + + inline ImplArray& makeArray(LLSD::Impl*& var) + { return safe(var).makeArray(var); } } -LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; } -LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); } +LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; } +LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); } LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); } -void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); } +void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); } -void LLSD::clear() { Impl::assignUndefined(impl); } +void LLSD::clear() { Impl::assignUndefined(impl); } -LLSD::Type LLSD::type() const { return safe(impl).type(); } +LLSD::Type LLSD::type() const { return safe(impl).type(); } // Scalar Constructors -LLSD::LLSD(Boolean v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(Integer v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(Real v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const UUID& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Boolean v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Integer v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Real v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const UUID& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } // Scalar Assignment -void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); } -void LLSD::assign(Integer v) { safe(impl).assign(impl, v); } -void LLSD::assign(Real v) { safe(impl).assign(impl, v); } -void LLSD::assign(const String& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const UUID& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const Date& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const URI& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const Binary& v) { safe(impl).assign(impl, v); } +void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); } +void LLSD::assign(Integer v) { safe(impl).assign(impl, v); } +void LLSD::assign(Real v) { safe(impl).assign(impl, v); } +void LLSD::assign(const String& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const UUID& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const Date& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const URI& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const Binary& v) { safe(impl).assign(impl, v); } // Scalar Accessors -LLSD::Boolean LLSD::asBoolean() const { return safe(impl).asBoolean(); } -LLSD::Integer LLSD::asInteger() const { return safe(impl).asInteger(); } -LLSD::Real LLSD::asReal() const { return safe(impl).asReal(); } -LLSD::String LLSD::asString() const { return safe(impl).asString(); } -LLSD::UUID LLSD::asUUID() const { return safe(impl).asUUID(); } -LLSD::Date LLSD::asDate() const { return safe(impl).asDate(); } -LLSD::URI LLSD::asURI() const { return safe(impl).asURI(); } -const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } +LLSD::Boolean LLSD::asBoolean() const { return safe(impl).asBoolean(); } +LLSD::Integer LLSD::asInteger() const { return safe(impl).asInteger(); } +LLSD::Real LLSD::asReal() const { return safe(impl).asReal(); } +LLSD::String LLSD::asString() const { return safe(impl).asString(); } +LLSD::UUID LLSD::asUUID() const { return safe(impl).asUUID(); } +LLSD::Date LLSD::asDate() const { return safe(impl).asDate(); } +LLSD::URI LLSD::asURI() const { return safe(impl).asURI(); } +const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); } // const char * helpers -LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } void LLSD::assign(const char* v) { - if(v) assign(std::string(v)); - else assign(std::string()); + if(v) assign(std::string(v)); + else assign(std::string()); } LLSD LLSD::emptyMap() { - LLSD v; - makeMap(v.impl); - return v; + LLSD v; + makeMap(v.impl); + return v; } -bool LLSD::has(const String& k) const { return safe(impl).has(k); } -LLSD LLSD::get(const String& k) const { return safe(impl).get(k); } -LLSD LLSD::getKeys() const { return safe(impl).getKeys(); } -void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); } +bool LLSD::has(const String& k) const { return safe(impl).has(k); } +LLSD LLSD::get(const String& k) const { return safe(impl).get(k); } +LLSD LLSD::getKeys() const { return safe(impl).getKeys(); } +void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); } LLSD& LLSD::with(const String& k, const LLSD& v) - { - makeMap(impl).insert(k, v); - return *this; - } -void LLSD::erase(const String& k) { makeMap(impl).erase(k); } + { + makeMap(impl).insert(k, v); + return *this; + } +void LLSD::erase(const String& k) { makeMap(impl).erase(k); } LLSD& LLSD::operator[](const String& k) -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return makeMap(impl).ref(k); + return makeMap(impl).ref(k); } const LLSD& LLSD::operator[](const String& k) const -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return safe(impl).ref(k); + return safe(impl).ref(k); } LLSD LLSD::emptyArray() { - LLSD v; - makeArray(v.impl); - return v; + LLSD v; + makeArray(v.impl); + return v; } -size_t LLSD::size() const { return safe(impl).size(); } - -LLSD LLSD::get(Integer i) const { return safe(impl).get(i); } +size_t LLSD::size() const { return safe(impl).size(); } + +LLSD LLSD::get(Integer i) const { return safe(impl).get(i); } void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); } void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); } LLSD& LLSD::with(Integer i, const LLSD& v) - { - makeArray(impl).insert(i, v); - return *this; - } -LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } -void LLSD::erase(Integer i) { makeArray(impl).erase(i); } + { + makeArray(impl).insert(i, v); + return *this; + } +LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } +void LLSD::erase(Integer i) { makeArray(impl).erase(i); } LLSD& LLSD::operator[](size_t i) -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return makeArray(impl).ref(i); + return makeArray(impl).ref(i); } const LLSD& LLSD::operator[](size_t i) const -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return safe(impl).ref(i); } static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat) { - // sStorage is used to hold the string representation of the llsd last - // passed into this function. If this function is never called (the - // normal case when not debugging), nothing is allocated. Otherwise - // sStorage will point to the result of the last call. This will actually - // be one leak, but since this is used only when running under the - // debugger, it should not be an issue. - static char *sStorage = NULL; - delete[] sStorage; - std::string out_string; - { - std::ostringstream out; - if (useXMLFormat) - out << LLSDXMLStreamer(llsd); - else - out << LLSDNotationStreamer(llsd); - out_string = out.str(); - } - auto len = out_string.length(); - sStorage = new char[len + 1]; - memcpy(sStorage, out_string.c_str(), len); - sStorage[len] = '\0'; - return sStorage; + // sStorage is used to hold the string representation of the llsd last + // passed into this function. If this function is never called (the + // normal case when not debugging), nothing is allocated. Otherwise + // sStorage will point to the result of the last call. This will actually + // be one leak, but since this is used only when running under the + // debugger, it should not be an issue. + static char *sStorage = NULL; + delete[] sStorage; + std::string out_string; + { + std::ostringstream out; + if (useXMLFormat) + out << LLSDXMLStreamer(llsd); + else + out << LLSDNotationStreamer(llsd); + out_string = out.str(); + } + auto len = out_string.length(); + sStorage = new char[len + 1]; + memcpy(sStorage, out_string.c_str(), len); + sStorage[len] = '\0'; + return sStorage; } /// Returns XML version of llsd -- only to be called from debugger const char *LLSD::dumpXML(const LLSD &llsd) { - return llsd_dump(llsd, true); + return llsd_dump(llsd, true); } /// Returns Notation version of llsd -- only to be called from debugger const char *LLSD::dump(const LLSD &llsd) { - return llsd_dump(llsd, false); + return llsd_dump(llsd, false); } -LLSD::map_iterator LLSD::beginMap() { return makeMap(impl).beginMap(); } -LLSD::map_iterator LLSD::endMap() { return makeMap(impl).endMap(); } -LLSD::map_const_iterator LLSD::beginMap() const { return safe(impl).beginMap(); } -LLSD::map_const_iterator LLSD::endMap() const { return safe(impl).endMap(); } +LLSD::map_iterator LLSD::beginMap() { return makeMap(impl).beginMap(); } +LLSD::map_iterator LLSD::endMap() { return makeMap(impl).endMap(); } +LLSD::map_const_iterator LLSD::beginMap() const { return safe(impl).beginMap(); } +LLSD::map_const_iterator LLSD::endMap() const { return safe(impl).endMap(); } -LLSD::array_iterator LLSD::beginArray() { return makeArray(impl).beginArray(); } -LLSD::array_iterator LLSD::endArray() { return makeArray(impl).endArray(); } -LLSD::array_const_iterator LLSD::beginArray() const{ return safe(impl).beginArray(); } -LLSD::array_const_iterator LLSD::endArray() const { return safe(impl).endArray(); } +LLSD::array_iterator LLSD::beginArray() { return makeArray(impl).beginArray(); } +LLSD::array_iterator LLSD::endArray() { return makeArray(impl).endArray(); } +LLSD::array_const_iterator LLSD::beginArray() const{ return safe(impl).beginArray(); } +LLSD::array_const_iterator LLSD::endArray() const { return safe(impl).endArray(); } -LLSD::reverse_array_iterator LLSD::rbeginArray() { return makeArray(impl).rbeginArray(); } -LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl).rendArray(); } +LLSD::reverse_array_iterator LLSD::rbeginArray() { return makeArray(impl).rbeginArray(); } +LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl).rendArray(); } namespace llsd { -U32 allocationCount() { return LLSD::Impl::sAllocationCount; } -U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; } +U32 allocationCount() { return LLSD::Impl::sAllocationCount; } +U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; } // Diagnostic dump of contents in an LLSD object -void dumpStats(const LLSD& llsd) { LLSD::Impl::getImpl(llsd).dumpStats(); } +void dumpStats(const LLSD& llsd) { LLSD::Impl::getImpl(llsd).dumpStats(); } } // namespace llsd // static -std::string LLSD::typeString(Type type) +std::string LLSD::typeString(Type type) { - static const char * sTypeNameArray[] = { - "Undefined", - "Boolean", - "Integer", - "Real", - "String", - "UUID", - "Date", - "URI", - "Binary", - "Map", - "Array" - }; - - if (0 <= type && type < LL_ARRAY_SIZE(sTypeNameArray)) - { - return sTypeNameArray[type]; - } - return STRINGIZE("** invalid type value " << type); + static const char * sTypeNameArray[] = { + "Undefined", + "Boolean", + "Integer", + "Real", + "String", + "UUID", + "Date", + "URI", + "Binary", + "Map", + "Array" + }; + + if (0 <= type && type < LL_ARRAY_SIZE(sTypeNameArray)) + { + return sTypeNameArray[type]; + } + return STRINGIZE("** invalid type value " << type); } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 8ed254919c..a5e735b561 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -1,25 +1,25 @@ -/** +/** * @file llsd.h * @brief LLSD flexible data system. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,450 +38,450 @@ #include "lluuid.h" /** - LLSD provides a flexible data system similar to the data facilities of - dynamic languages like Perl and Python. It is created to support exchange - of structured data between loosely coupled systems. (Here, "loosely coupled" - means not compiled together into the same module.) - - Data in such exchanges must be highly tolerant of changes on either side - such as: - - recompilation - - implementation in a different langauge - - addition of extra parameters - - execution of older versions (with fewer parameters) - - To this aim, the C++ API of LLSD strives to be very easy to use, and to - default to "the right thing" wherever possible. It is extremely tolerant - of errors and unexpected situations. - - The fundamental class is LLSD. LLSD is a value holding object. It holds - one value that is either undefined, one of the scalar types, or a map or an - array. LLSD objects have value semantics (copying them copies the value, - though it can be considered efficient, due to sharing), and mutable. - - Undefined is the singular value given to LLSD objects that are not - initialized with any data. It is also used as the return value for - operations that return an LLSD. - - The scalar data types are: - - Boolean - true or false - - Integer - a 32 bit signed integer - - Real - a 64 IEEE 754 floating point value - - UUID - a 128 unique value - - String - a sequence of zero or more Unicode chracters - - Date - an absolute point in time, UTC, - with resolution to the second - - URI - a String that is a URI - - Binary - a sequence of zero or more octets (unsigned bytes) - - A map is a dictionary mapping String keys to LLSD values. The keys are - unique within a map, and have only one value (though that value could be - an LLSD array). - - An array is a sequence of zero or more LLSD values. - - Thread Safety - - In general, these LLSD classes offer *less* safety than STL container - classes. Implementations prior to this one were unsafe even when - completely unrelated LLSD trees were in two threads due to reference - sharing of special 'undefined' values that participated in the reference - counting mechanism. - - The dereference-before-refcount and aggressive tree sharing also make - it impractical to share an LLSD across threads. A strategy of passing - ownership or a copy to another thread is still difficult due to a lack - of a cloning interface but it can be done with some care. - - One way of transferring ownership is as follows: - - void method(const LLSD input) { - ... - LLSD * xfer_tree = new LLSD(); - { - // Top-level values - (* xfer_tree)['label'] = "Some text"; - (* xfer_tree)['mode'] = APP_MODE_CONSTANT; - - // There will be a second-level - LLSD subtree(LLSD::emptyMap()); - (* xfer_tree)['subtree'] = subtree; - - // Do *not* copy from LLSD objects via LLSD - // intermediaries. Only use plain-old-data - // types as intermediaries to prevent reference - // sharing. - subtree['value1'] = input['value1'].asInteger(); - subtree['value2'] = input['value2'].asString(); - - // Close scope and drop 'subtree's reference. - // Only xfer_tree has a reference to the second - // level data. - } - ... - // Transfer the LLSD pointer to another thread. Ownership - // transfers, this thread no longer has a reference to any - // part of the xfer_tree and there's nothing to free or - // release here. Receiving thread does need to delete the - // pointer when it is done with the LLSD. Transfer - // mechanism must perform correct data ordering operations - // as dictated by architecture. - other_thread.sendMessageAndPointer("Take This", xfer_tree); - xfer_tree = NULL; - - - Avoid this pattern which provides half of a race condition: - - void method(const LLSD input) { - ... - LLSD xfer_tree(LLSD::emptyMap()); - xfer_tree['label'] = "Some text"; - xfer_tree['mode'] = APP_MODE_CONSTANT; - ... - other_thread.sendMessageAndPointer("Take This", xfer_tree); - - - @nosubgrouping + LLSD provides a flexible data system similar to the data facilities of + dynamic languages like Perl and Python. It is created to support exchange + of structured data between loosely coupled systems. (Here, "loosely coupled" + means not compiled together into the same module.) + + Data in such exchanges must be highly tolerant of changes on either side + such as: + - recompilation + - implementation in a different langauge + - addition of extra parameters + - execution of older versions (with fewer parameters) + + To this aim, the C++ API of LLSD strives to be very easy to use, and to + default to "the right thing" wherever possible. It is extremely tolerant + of errors and unexpected situations. + + The fundamental class is LLSD. LLSD is a value holding object. It holds + one value that is either undefined, one of the scalar types, or a map or an + array. LLSD objects have value semantics (copying them copies the value, + though it can be considered efficient, due to sharing), and mutable. + + Undefined is the singular value given to LLSD objects that are not + initialized with any data. It is also used as the return value for + operations that return an LLSD. + + The scalar data types are: + - Boolean - true or false + - Integer - a 32 bit signed integer + - Real - a 64 IEEE 754 floating point value + - UUID - a 128 unique value + - String - a sequence of zero or more Unicode chracters + - Date - an absolute point in time, UTC, + with resolution to the second + - URI - a String that is a URI + - Binary - a sequence of zero or more octets (unsigned bytes) + + A map is a dictionary mapping String keys to LLSD values. The keys are + unique within a map, and have only one value (though that value could be + an LLSD array). + + An array is a sequence of zero or more LLSD values. + + Thread Safety + + In general, these LLSD classes offer *less* safety than STL container + classes. Implementations prior to this one were unsafe even when + completely unrelated LLSD trees were in two threads due to reference + sharing of special 'undefined' values that participated in the reference + counting mechanism. + + The dereference-before-refcount and aggressive tree sharing also make + it impractical to share an LLSD across threads. A strategy of passing + ownership or a copy to another thread is still difficult due to a lack + of a cloning interface but it can be done with some care. + + One way of transferring ownership is as follows: + + void method(const LLSD input) { + ... + LLSD * xfer_tree = new LLSD(); + { + // Top-level values + (* xfer_tree)['label'] = "Some text"; + (* xfer_tree)['mode'] = APP_MODE_CONSTANT; + + // There will be a second-level + LLSD subtree(LLSD::emptyMap()); + (* xfer_tree)['subtree'] = subtree; + + // Do *not* copy from LLSD objects via LLSD + // intermediaries. Only use plain-old-data + // types as intermediaries to prevent reference + // sharing. + subtree['value1'] = input['value1'].asInteger(); + subtree['value2'] = input['value2'].asString(); + + // Close scope and drop 'subtree's reference. + // Only xfer_tree has a reference to the second + // level data. + } + ... + // Transfer the LLSD pointer to another thread. Ownership + // transfers, this thread no longer has a reference to any + // part of the xfer_tree and there's nothing to free or + // release here. Receiving thread does need to delete the + // pointer when it is done with the LLSD. Transfer + // mechanism must perform correct data ordering operations + // as dictated by architecture. + other_thread.sendMessageAndPointer("Take This", xfer_tree); + xfer_tree = NULL; + + + Avoid this pattern which provides half of a race condition: + + void method(const LLSD input) { + ... + LLSD xfer_tree(LLSD::emptyMap()); + xfer_tree['label'] = "Some text"; + xfer_tree['mode'] = APP_MODE_CONSTANT; + ... + other_thread.sendMessageAndPointer("Take This", xfer_tree); + + + @nosubgrouping */ // Normally undefined, used for diagnostics -//#define LLSD_DEBUG_INFO 1 +//#define LLSD_DEBUG_INFO 1 class LL_COMMON_API LLSD { public: - LLSD(); ///< initially Undefined - ~LLSD(); ///< this class may NOT be subclassed - - /** @name Copyable and Assignable */ - //@{ - LLSD(const LLSD&); - void assign(const LLSD& other); - LLSD& operator=(const LLSD& other) { assign(other); return *this; } - - //@} - - void clear(); ///< resets to Undefined - - - /** @name Scalar Types - The scalar types, and how they map onto C++ - */ - //@{ - typedef bool Boolean; - typedef S32 Integer; - typedef F64 Real; - typedef std::string String; - typedef LLUUID UUID; - typedef LLDate Date; - typedef LLURI URI; - typedef std::vector<U8> Binary; - //@} - - /** @name Scalar Constructors */ - //@{ - LLSD(Boolean); - LLSD(Integer); - LLSD(Real); - LLSD(const String&); - LLSD(const UUID&); - LLSD(const Date&); - LLSD(const URI&); - LLSD(const Binary&); - //@} - - /** @name Convenience Constructors */ - //@{ - // support construction from size_t et al. - template <typename VALUE, - typename std::enable_if<std::is_integral<VALUE>::value && - ! std::is_same<VALUE, Boolean>::value, - bool>::type = true> - LLSD(VALUE v): LLSD(Integer(narrow<VALUE>(v))) {} - // support construction from F32 et al. - template <typename VALUE, - typename std::enable_if<std::is_floating_point<VALUE>::value, - bool>::type = true> - LLSD(VALUE v): LLSD(Real(narrow<VALUE>(v))) {} - //@} - - /** @name Scalar Assignment */ - //@{ - void assign(Boolean); - void assign(Integer); - void assign(Real); - void assign(const String&); - void assign(const UUID&); - void assign(const Date&); - void assign(const URI&); - void assign(const Binary&); - - LLSD& operator=(Boolean v) { assign(v); return *this; } - LLSD& operator=(Integer v) { assign(v); return *this; } - LLSD& operator=(Real v) { assign(v); return *this; } - LLSD& operator=(const String& v) { assign(v); return *this; } - LLSD& operator=(const UUID& v) { assign(v); return *this; } - LLSD& operator=(const Date& v) { assign(v); return *this; } - LLSD& operator=(const URI& v) { assign(v); return *this; } - LLSD& operator=(const Binary& v) { assign(v); return *this; } - //@} - - /** - @name Scalar Accessors - @brief Fetch a scalar value, converting if needed and possible - - Conversion among the basic types, Boolean, Integer, Real and String, is - fully defined. Each type can be converted to another with a reasonable - interpretation. These conversions can be used as a convenience even - when you know the data is in one format, but you want it in another. Of - course, many of these conversions lose information. - - Note: These conversions are not the same as Perl's. In particular, when - converting a String to a Boolean, only the empty string converts to - false. Converting the String "0" to Boolean results in true. - - Conversion to and from UUID, Date, and URI is only defined to and from - String. Conversion is defined to be information preserving for valid - values of those types. These conversions can be used when one needs to - convert data to or from another system that cannot handle these types - natively, but can handle strings. - - Conversion to and from Binary isn't defined. - - Conversion of the Undefined value to any scalar type results in a - reasonable null or zero value for the type. - */ - //@{ - Boolean asBoolean() const; - Integer asInteger() const; - Real asReal() const; - String asString() const; - UUID asUUID() const; - Date asDate() const; - URI asURI() const; - const Binary& asBinary() const; - - // asStringRef on any non-string type will return a ref to an empty string. - const String& asStringRef() const; - - operator Boolean() const { return asBoolean(); } - operator Integer() const { return asInteger(); } - operator Real() const { return asReal(); } - operator String() const { return asString(); } - operator UUID() const { return asUUID(); } - operator Date() const { return asDate(); } - operator URI() const { return asURI(); } - operator Binary() const { return asBinary(); } - - // This is needed because most platforms do not automatically - // convert the boolean negation as a bool in an if statement. - bool operator!() const {return !asBoolean();} - //@} - - /** @name Character Pointer Helpers - These are helper routines to make working with char* as easy as - working with strings. - */ - //@{ - LLSD(const char*); - void assign(const char*); - LLSD& operator=(const char* v) { assign(v); return *this; } - //@} - - /** @name Map Values */ - //@{ - static LLSD emptyMap(); - - bool has(const String&) const; - LLSD get(const String&) const; - LLSD getKeys() const; // Return an LLSD array with keys as strings - void insert(const String&, const LLSD&); - void erase(const String&); - LLSD& with(const String&, const LLSD&); - - LLSD& operator[](const String&); - LLSD& operator[](const char* c) + LLSD(); ///< initially Undefined + ~LLSD(); ///< this class may NOT be subclassed + + /** @name Copyable and Assignable */ + //@{ + LLSD(const LLSD&); + void assign(const LLSD& other); + LLSD& operator=(const LLSD& other) { assign(other); return *this; } + + //@} + + void clear(); ///< resets to Undefined + + + /** @name Scalar Types + The scalar types, and how they map onto C++ + */ + //@{ + typedef bool Boolean; + typedef S32 Integer; + typedef F64 Real; + typedef std::string String; + typedef LLUUID UUID; + typedef LLDate Date; + typedef LLURI URI; + typedef std::vector<U8> Binary; + //@} + + /** @name Scalar Constructors */ + //@{ + LLSD(Boolean); + LLSD(Integer); + LLSD(Real); + LLSD(const String&); + LLSD(const UUID&); + LLSD(const Date&); + LLSD(const URI&); + LLSD(const Binary&); + //@} + + /** @name Convenience Constructors */ + //@{ + // support construction from size_t et al. + template <typename VALUE, + typename std::enable_if<std::is_integral<VALUE>::value && + ! std::is_same<VALUE, Boolean>::value, + bool>::type = true> + LLSD(VALUE v): LLSD(Integer(narrow<VALUE>(v))) {} + // support construction from F32 et al. + template <typename VALUE, + typename std::enable_if<std::is_floating_point<VALUE>::value, + bool>::type = true> + LLSD(VALUE v): LLSD(Real(narrow<VALUE>(v))) {} + //@} + + /** @name Scalar Assignment */ + //@{ + void assign(Boolean); + void assign(Integer); + void assign(Real); + void assign(const String&); + void assign(const UUID&); + void assign(const Date&); + void assign(const URI&); + void assign(const Binary&); + + LLSD& operator=(Boolean v) { assign(v); return *this; } + LLSD& operator=(Integer v) { assign(v); return *this; } + LLSD& operator=(Real v) { assign(v); return *this; } + LLSD& operator=(const String& v) { assign(v); return *this; } + LLSD& operator=(const UUID& v) { assign(v); return *this; } + LLSD& operator=(const Date& v) { assign(v); return *this; } + LLSD& operator=(const URI& v) { assign(v); return *this; } + LLSD& operator=(const Binary& v) { assign(v); return *this; } + //@} + + /** + @name Scalar Accessors + @brief Fetch a scalar value, converting if needed and possible + + Conversion among the basic types, Boolean, Integer, Real and String, is + fully defined. Each type can be converted to another with a reasonable + interpretation. These conversions can be used as a convenience even + when you know the data is in one format, but you want it in another. Of + course, many of these conversions lose information. + + Note: These conversions are not the same as Perl's. In particular, when + converting a String to a Boolean, only the empty string converts to + false. Converting the String "0" to Boolean results in true. + + Conversion to and from UUID, Date, and URI is only defined to and from + String. Conversion is defined to be information preserving for valid + values of those types. These conversions can be used when one needs to + convert data to or from another system that cannot handle these types + natively, but can handle strings. + + Conversion to and from Binary isn't defined. + + Conversion of the Undefined value to any scalar type results in a + reasonable null or zero value for the type. + */ + //@{ + Boolean asBoolean() const; + Integer asInteger() const; + Real asReal() const; + String asString() const; + UUID asUUID() const; + Date asDate() const; + URI asURI() const; + const Binary& asBinary() const; + + // asStringRef on any non-string type will return a ref to an empty string. + const String& asStringRef() const; + + operator Boolean() const { return asBoolean(); } + operator Integer() const { return asInteger(); } + operator Real() const { return asReal(); } + operator String() const { return asString(); } + operator UUID() const { return asUUID(); } + operator Date() const { return asDate(); } + operator URI() const { return asURI(); } + operator Binary() const { return asBinary(); } + + // This is needed because most platforms do not automatically + // convert the boolean negation as a bool in an if statement. + bool operator!() const {return !asBoolean();} + //@} + + /** @name Character Pointer Helpers + These are helper routines to make working with char* as easy as + working with strings. + */ + //@{ + LLSD(const char*); + void assign(const char*); + LLSD& operator=(const char* v) { assign(v); return *this; } + //@} + + /** @name Map Values */ + //@{ + static LLSD emptyMap(); + + bool has(const String&) const; + LLSD get(const String&) const; + LLSD getKeys() const; // Return an LLSD array with keys as strings + void insert(const String&, const LLSD&); + void erase(const String&); + LLSD& with(const String&, const LLSD&); + + LLSD& operator[](const String&); + LLSD& operator[](const char* c) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return (*this)[String(c)]; } - const LLSD& operator[](const String&) const; - const LLSD& operator[](const char* c) const + const LLSD& operator[](const String&) const; + const LLSD& operator[](const char* c) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return (*this)[String(c)]; } - //@} - - /** @name Array Values */ - //@{ - static LLSD emptyArray(); - - LLSD get(Integer) const; - void set(Integer, const LLSD&); - void insert(Integer, const LLSD&); - LLSD& append(const LLSD&); - void erase(Integer); - LLSD& with(Integer, const LLSD&); - - // accept size_t so we can index relative to size() - const LLSD& operator[](size_t) const; - LLSD& operator[](size_t); - // template overloads to support int literals, U32 et al. - template <typename IDX, - typename std::enable_if<std::is_convertible<IDX, size_t>::value, - bool>::type = true> - const LLSD& operator[](IDX i) const { return (*this)[size_t(i)]; } - template <typename IDX, - typename std::enable_if<std::is_convertible<IDX, size_t>::value, - bool>::type = true> - LLSD& operator[](IDX i) { return (*this)[size_t(i)]; } - //@} - - /** @name Iterators */ - //@{ - size_t size() const; - - typedef std::map<String, LLSD>::iterator map_iterator; - typedef std::map<String, LLSD>::const_iterator map_const_iterator; - - map_iterator beginMap(); - map_iterator endMap(); - map_const_iterator beginMap() const; - map_const_iterator endMap() const; - - typedef std::vector<LLSD>::iterator array_iterator; - typedef std::vector<LLSD>::const_iterator array_const_iterator; - typedef std::vector<LLSD>::reverse_iterator reverse_array_iterator; - - array_iterator beginArray(); - array_iterator endArray(); - array_const_iterator beginArray() const; - array_const_iterator endArray() const; - - reverse_array_iterator rbeginArray(); - reverse_array_iterator rendArray(); - //@} - - /** @name Type Testing */ - //@{ - enum Type { - TypeUndefined = 0, - TypeBoolean, - TypeInteger, - TypeReal, - TypeString, - TypeUUID, - TypeDate, - TypeURI, - TypeBinary, - TypeMap, - TypeArray, - TypeLLSDTypeEnd, - TypeLLSDTypeBegin = TypeUndefined, - TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin) - }; - - Type type() const; - - bool isUndefined() const { return type() == TypeUndefined; } - bool isDefined() const { return type() != TypeUndefined; } - bool isBoolean() const { return type() == TypeBoolean; } - bool isInteger() const { return type() == TypeInteger; } - bool isReal() const { return type() == TypeReal; } - bool isString() const { return type() == TypeString; } - bool isUUID() const { return type() == TypeUUID; } - bool isDate() const { return type() == TypeDate; } - bool isURI() const { return type() == TypeURI; } - bool isBinary() const { return type() == TypeBinary; } - bool isMap() const { return type() == TypeMap; } - bool isArray() const { return type() == TypeArray; } - //@} - - /** @name Automatic Cast Protection - These are not implemented on purpose. Without them, C++ can perform - some conversions that are clearly not what the programmer intended. - - If you get a linker error about these being missing, you have made - mistake in your code. DO NOT IMPLEMENT THESE FUNCTIONS as a fix. - - All of these problems stem from trying to support char* in LLSD or in - std::string. There are too many automatic casts that will lead to - using an arbitrary pointer or scalar type to std::string. - */ - //@{ - LLSD(const void*); ///< construct from aribrary pointers - void assign(const void*); ///< assign from arbitrary pointers - LLSD& operator=(const void*); ///< assign from arbitrary pointers - - bool has(Integer) const; ///< has() only works for Maps - //@} - - /** @name Implementation */ - //@{ + //@} + + /** @name Array Values */ + //@{ + static LLSD emptyArray(); + + LLSD get(Integer) const; + void set(Integer, const LLSD&); + void insert(Integer, const LLSD&); + LLSD& append(const LLSD&); + void erase(Integer); + LLSD& with(Integer, const LLSD&); + + // accept size_t so we can index relative to size() + const LLSD& operator[](size_t) const; + LLSD& operator[](size_t); + // template overloads to support int literals, U32 et al. + template <typename IDX, + typename std::enable_if<std::is_convertible<IDX, size_t>::value, + bool>::type = true> + const LLSD& operator[](IDX i) const { return (*this)[size_t(i)]; } + template <typename IDX, + typename std::enable_if<std::is_convertible<IDX, size_t>::value, + bool>::type = true> + LLSD& operator[](IDX i) { return (*this)[size_t(i)]; } + //@} + + /** @name Iterators */ + //@{ + size_t size() const; + + typedef std::map<String, LLSD>::iterator map_iterator; + typedef std::map<String, LLSD>::const_iterator map_const_iterator; + + map_iterator beginMap(); + map_iterator endMap(); + map_const_iterator beginMap() const; + map_const_iterator endMap() const; + + typedef std::vector<LLSD>::iterator array_iterator; + typedef std::vector<LLSD>::const_iterator array_const_iterator; + typedef std::vector<LLSD>::reverse_iterator reverse_array_iterator; + + array_iterator beginArray(); + array_iterator endArray(); + array_const_iterator beginArray() const; + array_const_iterator endArray() const; + + reverse_array_iterator rbeginArray(); + reverse_array_iterator rendArray(); + //@} + + /** @name Type Testing */ + //@{ + enum Type { + TypeUndefined = 0, + TypeBoolean, + TypeInteger, + TypeReal, + TypeString, + TypeUUID, + TypeDate, + TypeURI, + TypeBinary, + TypeMap, + TypeArray, + TypeLLSDTypeEnd, + TypeLLSDTypeBegin = TypeUndefined, + TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin) + }; + + Type type() const; + + bool isUndefined() const { return type() == TypeUndefined; } + bool isDefined() const { return type() != TypeUndefined; } + bool isBoolean() const { return type() == TypeBoolean; } + bool isInteger() const { return type() == TypeInteger; } + bool isReal() const { return type() == TypeReal; } + bool isString() const { return type() == TypeString; } + bool isUUID() const { return type() == TypeUUID; } + bool isDate() const { return type() == TypeDate; } + bool isURI() const { return type() == TypeURI; } + bool isBinary() const { return type() == TypeBinary; } + bool isMap() const { return type() == TypeMap; } + bool isArray() const { return type() == TypeArray; } + //@} + + /** @name Automatic Cast Protection + These are not implemented on purpose. Without them, C++ can perform + some conversions that are clearly not what the programmer intended. + + If you get a linker error about these being missing, you have made + mistake in your code. DO NOT IMPLEMENT THESE FUNCTIONS as a fix. + + All of these problems stem from trying to support char* in LLSD or in + std::string. There are too many automatic casts that will lead to + using an arbitrary pointer or scalar type to std::string. + */ + //@{ + LLSD(const void*); ///< construct from aribrary pointers + void assign(const void*); ///< assign from arbitrary pointers + LLSD& operator=(const void*); ///< assign from arbitrary pointers + + bool has(Integer) const; ///< has() only works for Maps + //@} + + /** @name Implementation */ + //@{ public: - class Impl; + class Impl; private: - Impl* impl; - friend class LLSD::Impl; - //@} + Impl* impl; + friend class LLSD::Impl; + //@} private: - /** @name Debugging Interface */ - //@{ - /// Returns XML version of llsd -- only to be called from debugger - static const char *dumpXML(const LLSD &llsd); + /** @name Debugging Interface */ + //@{ + /// Returns XML version of llsd -- only to be called from debugger + static const char *dumpXML(const LLSD &llsd); - /// Returns Notation version of llsd -- only to be called from debugger - static const char *dump(const LLSD &llsd); - //@} + /// Returns Notation version of llsd -- only to be called from debugger + static const char *dump(const LLSD &llsd); + //@} public: - static std::string typeString(Type type); // Return human-readable type as a string + static std::string typeString(Type type); // Return human-readable type as a string }; struct llsd_select_bool { - LLSD::Boolean operator()(const LLSD& sd) const - { - return sd.asBoolean(); - } + LLSD::Boolean operator()(const LLSD& sd) const + { + return sd.asBoolean(); + } }; struct llsd_select_integer { - LLSD::Integer operator()(const LLSD& sd) const - { - return sd.asInteger(); - } + LLSD::Integer operator()(const LLSD& sd) const + { + return sd.asInteger(); + } }; struct llsd_select_real { - LLSD::Real operator()(const LLSD& sd) const - { - return sd.asReal(); - } + LLSD::Real operator()(const LLSD& sd) const + { + return sd.asReal(); + } }; struct llsd_select_float { - F32 operator()(const LLSD& sd) const - { - return (F32)sd.asReal(); - } + F32 operator()(const LLSD& sd) const + { + return (F32)sd.asReal(); + } }; struct llsd_select_uuid { - LLSD::UUID operator()(const LLSD& sd) const - { - return sd.asUUID(); - } + LLSD::UUID operator()(const LLSD& sd) const + { + return sd.asUUID(); + } }; struct llsd_select_string { - LLSD::String operator()(const LLSD& sd) const - { - return sd.asString(); - } + LLSD::String operator()(const LLSD& sd) const + { + return sd.asString(); + } }; LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); @@ -492,30 +492,30 @@ namespace llsd #ifdef LLSD_DEBUG_INFO /** @name Unit Testing Interface */ //@{ - LL_COMMON_API void dumpStats(const LLSD&); ///< Output information on object and usage - - /// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED - /// ENVIRONMENT. - /// - /// These counts track LLSD::Impl (hidden) objects. - LL_COMMON_API U32 allocationCount(); ///< how many Impls have been made - LL_COMMON_API U32 outstandingCount(); ///< how many Impls are still alive - - /// These counts track LLSD (public) objects. - LL_COMMON_API extern S32 sLLSDAllocationCount; ///< Number of LLSD objects ever created - LL_COMMON_API extern S32 sLLSDNetObjects; ///< Number of LLSD objects that exist + LL_COMMON_API void dumpStats(const LLSD&); ///< Output information on object and usage + + /// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED + /// ENVIRONMENT. + /// + /// These counts track LLSD::Impl (hidden) objects. + LL_COMMON_API U32 allocationCount(); ///< how many Impls have been made + LL_COMMON_API U32 outstandingCount(); ///< how many Impls are still alive + + /// These counts track LLSD (public) objects. + LL_COMMON_API extern S32 sLLSDAllocationCount; ///< Number of LLSD objects ever created + LL_COMMON_API extern S32 sLLSDNetObjects; ///< Number of LLSD objects that exist #endif //@} } // namespace llsd /** QUESTIONS & TO DOS - - Would Binary be more convenient as unsigned char* buffer semantics? - - Should Binary be convertible to/from String, and if so how? - - as UTF8 encoded strings (making not like UUID<->String) - - as Base64 or Base96 encoded (making like UUID<->String) - - Conversions to std::string and LLUUID do not result in easy assignment - to std::string, std::string or LLUUID due to non-unique conversion paths + - Would Binary be more convenient as unsigned char* buffer semantics? + - Should Binary be convertible to/from String, and if so how? + - as UTF8 encoded strings (making not like UUID<->String) + - as Base64 or Base96 encoded (making like UUID<->String) + - Conversions to std::string and LLUUID do not result in easy assignment + to std::string, std::string or LLUUID due to non-unique conversion paths */ #endif // LL_LLSD_NEW_H diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp index 8caaaee534..bb2b8681f7 100644 --- a/indra/llcommon/llsdjson.cpp +++ b/indra/llcommon/llsdjson.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsdjson.cpp * @brief LLSD flexible data system * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2015, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h index e56cf03b45..79bf2c56fa 100644 --- a/indra/llcommon/llsdjson.h +++ b/indra/llcommon/llsdjson.h @@ -1,25 +1,25 @@ -/** +/** * @file llsdjson.cpp * @brief LLSD flexible data system * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2015, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,10 +36,10 @@ #include "llsd.h" #include "json/value.h" -/// Convert a parsed JSON structure into LLSD maintaining member names and +/// Convert a parsed JSON structure into LLSD maintaining member names and /// array indexes. /// JSON/JavaScript types are converted as follows: -/// +/// /// JSON Type | LLSD Type /// --------------+-------------- /// null | undefined @@ -50,14 +50,14 @@ /// boolean | LLSD::Boolean /// array | LLSD::Array /// object | LLSD::Map -/// +/// /// For maps and arrays child entries will be converted and added to the structure. /// Order is preserved for an array but not for objects. LLSD LlsdFromJson(const Json::Value &val); -/// Convert an LLSD object into Parsed JSON object maintaining member names and +/// Convert an LLSD object into Parsed JSON object maintaining member names and /// array indexs. -/// +/// /// Types are converted as follows: /// LLSD Type | JSON Type /// --------------+---------------- @@ -71,7 +71,7 @@ LLSD LlsdFromJson(const Json::Value &val); /// TypeUUID | string /// TypeMap | object /// TypeArray | array -/// TypeBinary | unsupported +/// TypeBinary | unsupported Json::Value LlsdToJson(const LLSD &val); #endif // LL_LLSDJSON_H diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 30f49b27ea..b981be4d0a 100644 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llsdparam.cpp - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,9 +32,9 @@ #include "llsdutil.h" #include "boost/bind.hpp" -static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; -static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; -static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; +static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; static const LLSD NO_VALUE_MARKER; // @@ -43,95 +43,95 @@ static const LLSD NO_VALUE_MARKER; LLParamSDParser::LLParamSDParser() : Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) { - using boost::bind; - - if (sReadFuncs.empty()) - { - registerParserFuncs<LLInitParam::Flag>(readFlag, &LLParamSDParser::writeFlag); - registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>); - registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param); - registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); - registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>); - registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>); - registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>); - registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>); - registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>); - registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>); - registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>); - } + using boost::bind; + + if (sReadFuncs.empty()) + { + registerParserFuncs<LLInitParam::Flag>(readFlag, &LLParamSDParser::writeFlag); + registerParserFuncs<S32>(readS32, &LLParamSDParser::writeTypedValue<S32>); + registerParserFuncs<U32>(readU32, &LLParamSDParser::writeU32Param); + registerParserFuncs<F32>(readF32, &LLParamSDParser::writeTypedValue<F32>); + registerParserFuncs<F64>(readF64, &LLParamSDParser::writeTypedValue<F64>); + registerParserFuncs<bool>(readBool, &LLParamSDParser::writeTypedValue<bool>); + registerParserFuncs<std::string>(readString, &LLParamSDParser::writeTypedValue<std::string>); + registerParserFuncs<LLUUID>(readUUID, &LLParamSDParser::writeTypedValue<LLUUID>); + registerParserFuncs<LLDate>(readDate, &LLParamSDParser::writeTypedValue<LLDate>); + registerParserFuncs<LLURI>(readURI, &LLParamSDParser::writeTypedValue<LLURI>); + registerParserFuncs<LLSD>(readSD, &LLParamSDParser::writeTypedValue<LLSD>); + } } // special case handling of U32 due to ambiguous LLSD::assign overload bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) { - LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); - if (!sdparser.mWriteRootSD) return false; - - parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - sd_to_write.assign((S32)*((const U32*)val_ptr)); - - return true; + LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); + if (!sdparser.mWriteRootSD) return false; + + parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + sd_to_write.assign((S32)*((const U32*)val_ptr)); + + return true; } bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) { - LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); - if (!sdparser.mWriteRootSD) return false; + LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); + if (!sdparser.mWriteRootSD) return false; - parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - return true; + return true; } void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack) { - mCurReadSD = &sd; - block.submitValue(name_stack, *this); + mCurReadSD = &sd; + block.submitValue(name_stack, *this); } void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent) { - mCurReadSD = NULL; - mNameStack.clear(); - setParseSilently(silent); + mCurReadSD = NULL; + mNameStack.clear(); + setParseSilently(silent); - LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); - //readSDValues(sd, block); + LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); + //readSDValues(sd, block); } void LLParamSDParser::writeSDImpl(LLSD& sd, const LLInitParam::BaseBlock& block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block) { - mNameStack.clear(); - mWriteRootSD = &sd; + mNameStack.clear(); + mWriteRootSD = &sd; - name_stack_t name_stack; - block.serializeBlock(*this, name_stack, rules, diff_block); + name_stack_t name_stack; + block.serializeBlock(*this, name_stack, rules, diff_block); } /*virtual*/ std::string LLParamSDParser::getCurrentElementName() { - std::string full_name = "sd"; - for (name_stack_t::value_type& stack_pair : mNameStack) - { - full_name += llformat("[%s]", stack_pair.first.c_str()); - } + std::string full_name = "sd"; + for (name_stack_t::value_type& stack_pair : mNameStack) + { + full_name += llformat("[%s]", stack_pair.first.c_str()); + } - return full_name; + return full_name; } bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - return self.mCurReadSD == &NO_VALUE_MARKER; + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + return self.mCurReadSD == &NO_VALUE_MARKER; } bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); *((S32*)val_ptr) = self.mCurReadSD->asInteger(); return true; @@ -139,7 +139,7 @@ bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); *((U32*)val_ptr) = self.mCurReadSD->asInteger(); return true; @@ -147,7 +147,7 @@ bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); *((F32*)val_ptr) = self.mCurReadSD->asReal(); return true; @@ -155,7 +155,7 @@ bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); *((F64*)val_ptr) = self.mCurReadSD->asReal(); return true; @@ -163,7 +163,7 @@ bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); *((bool*)val_ptr) = self.mCurReadSD->asBoolean(); return true; @@ -171,170 +171,170 @@ bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) bool LLParamSDParser::readString(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - *((std::string*)val_ptr) = self.mCurReadSD->asString(); + *((std::string*)val_ptr) = self.mCurReadSD->asString(); return true; } bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - *((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); + *((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); return true; } bool LLParamSDParser::readDate(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - *((LLDate*)val_ptr) = self.mCurReadSD->asDate(); + *((LLDate*)val_ptr) = self.mCurReadSD->asDate(); return true; } bool LLParamSDParser::readURI(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - *((LLURI*)val_ptr) = self.mCurReadSD->asURI(); + *((LLURI*)val_ptr) = self.mCurReadSD->asURI(); return true; } bool LLParamSDParser::readSD(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); + LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - *((LLSD*)val_ptr) = *self.mCurReadSD; + *((LLSD*)val_ptr) = *self.mCurReadSD; return true; } // static LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range) { - LLSD* sd_to_write = &input; - - for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; - it != name_stack_range.second; - ++it) - { - bool new_traversal = it->second; - - LLSD* child_sd; - if (it->first.empty()) - { - child_sd = sd_to_write; - if (child_sd->isUndefined()) - { - *child_sd = LLSD::emptyArray(); - } - if (new_traversal) - { - // write to new element at end - sd_to_write = &(*child_sd)[child_sd->size()]; - } - else - { - // write to last of existing elements, or first element if empty - sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; - } - } - else - { - sd_to_write = &(*sd_to_write)[it->first]; - } - it->second = false; - } - - return *sd_to_write; + LLSD* sd_to_write = &input; + + for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; + it != name_stack_range.second; + ++it) + { + bool new_traversal = it->second; + + LLSD* child_sd; + if (it->first.empty()) + { + child_sd = sd_to_write; + if (child_sd->isUndefined()) + { + *child_sd = LLSD::emptyArray(); + } + if (new_traversal) + { + // write to new element at end + sd_to_write = &(*child_sd)[child_sd->size()]; + } + else + { + // write to last of existing elements, or first element if empty + sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; + } + } + else + { + sd_to_write = &(*sd_to_write)[it->first]; + } + it->second = false; + } + + return *sd_to_write; } //static void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack) { - if (sd.isMap()) - { - for (LLSD::map_const_iterator it = sd.beginMap(); - it != sd.endMap(); - ++it) - { - stack.push_back(make_pair(it->first, true)); - readSDValues(cb, it->second, stack); - stack.pop_back(); - } - } - else if (sd.isArray()) - { - for (LLSD::array_const_iterator it = sd.beginArray(); - it != sd.endArray(); - ++it) - { - stack.push_back(make_pair(std::string(), true)); - readSDValues(cb, *it, stack); - stack.pop_back(); - } - } - else if (sd.isUndefined()) - { - if (!cb.empty()) - { - cb(NO_VALUE_MARKER, stack); - } - } - else - { - if (!cb.empty()) - { - cb(sd, stack); - } - } + if (sd.isMap()) + { + for (LLSD::map_const_iterator it = sd.beginMap(); + it != sd.endMap(); + ++it) + { + stack.push_back(make_pair(it->first, true)); + readSDValues(cb, it->second, stack); + stack.pop_back(); + } + } + else if (sd.isArray()) + { + for (LLSD::array_const_iterator it = sd.beginArray(); + it != sd.endArray(); + ++it) + { + stack.push_back(make_pair(std::string(), true)); + readSDValues(cb, *it, stack); + stack.pop_back(); + } + } + else if (sd.isUndefined()) + { + if (!cb.empty()) + { + cb(NO_VALUE_MARKER, stack); + } + } + else + { + if (!cb.empty()) + { + cb(sd, stack); + } + } } //static void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) { - LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); - readSDValues(cb, sd, stack); + LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); + readSDValues(cb, sd, stack); } namespace LLInitParam { - // LLSD specialization - // block param interface - bool ParamValue<LLSD, NOT_BLOCK>::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name) - { - if (name_stack.first == name_stack.second - && p.readValue<LLSD>(mValue)) - { - return true; - } - - LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); - - LLSD::String string; - - if (p.readValue<LLSD::String>(string)) - { - sd = string; - return true; - } - return false; - } - - //static - void ParamValue<LLSD, NOT_BLOCK>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) - { - p.writeValue<LLSD::String>(sd.asString(), name_stack); - } - - bool ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const - { - // attempt to write LLSD out directly - if (!p.writeValue<LLSD>(mValue, name_stack_range)) - { - // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) - LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack_range); - } - return true; - } + // LLSD specialization + // block param interface + bool ParamValue<LLSD, NOT_BLOCK>::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name) + { + if (name_stack.first == name_stack.second + && p.readValue<LLSD>(mValue)) + { + return true; + } + + LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); + + LLSD::String string; + + if (p.readValue<LLSD::String>(string)) + { + sd = string; + return true; + } + return false; + } + + //static + void ParamValue<LLSD, NOT_BLOCK>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) + { + p.writeValue<LLSD::String>(sd.asString(), name_stack); + } + + bool ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const + { + // attempt to write LLSD out directly + if (!p.writeValue<LLSD>(mValue, name_stack_range)) + { + // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) + LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack_range); + } + return true; + } } diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h index 82a623a8a0..21ebb9a258 100644 --- a/indra/llcommon/llsdparam.h +++ b/indra/llcommon/llsdparam.h @@ -1,26 +1,26 @@ -/** +/** * @file llsdparam.h - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,79 +34,79 @@ struct LL_COMMON_API LLParamSDParserUtilities { - static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); + static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); - typedef boost::function<void (const LLSD&, LLInitParam::Parser::name_stack_t&)> read_sd_cb_t; - static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); - static void readSDValues(read_sd_cb_t cb, const LLSD& sd); + typedef boost::function<void (const LLSD&, LLInitParam::Parser::name_stack_t&)> read_sd_cb_t; + static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); + static void readSDValues(read_sd_cb_t cb, const LLSD& sd); }; -class LL_COMMON_API LLParamSDParser -: public LLInitParam::Parser +class LL_COMMON_API LLParamSDParser +: public LLInitParam::Parser { LOG_CLASS(LLParamSDParser); typedef LLInitParam::Parser parser_t; public: - LLParamSDParser(); - void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); - template<typename BLOCK> - void writeSD(LLSD& sd, - const BLOCK& block, - const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), - const LLInitParam::BaseBlock* diff_block = NULL) - { - if (!diff_block - && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) - { - diff_block = &LLInitParam::defaultValue<BLOCK>(); - } - writeSDImpl(sd, block, rules, diff_block); - } - - /*virtual*/ std::string getCurrentElementName(); - /*virtual*/ std::string getCurrentFileName(){ return LLStringUtil::null; } + LLParamSDParser(); + void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); + template<typename BLOCK> + void writeSD(LLSD& sd, + const BLOCK& block, + const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), + const LLInitParam::BaseBlock* diff_block = NULL) + { + if (!diff_block + && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) + { + diff_block = &LLInitParam::defaultValue<BLOCK>(); + } + writeSDImpl(sd, block, rules, diff_block); + } + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ std::string getCurrentFileName(){ return LLStringUtil::null; } private: - void writeSDImpl(LLSD& sd, - const LLInitParam::BaseBlock& block, - const LLInitParam::predicate_rule_t, - const LLInitParam::BaseBlock* diff_block); - - void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); - - template<typename T> - static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) - { - LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); - if (!sdparser.mWriteRootSD) return false; - - LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - - sd_to_write.assign(*((const T*)val_ptr)); - return true; - } - - static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - - static bool readFlag(Parser& parser, void* val_ptr); - static bool readS32(Parser& parser, void* val_ptr); - static bool readU32(Parser& parser, void* val_ptr); - static bool readF32(Parser& parser, void* val_ptr); - static bool readF64(Parser& parser, void* val_ptr); - static bool readBool(Parser& parser, void* val_ptr); - static bool readString(Parser& parser, void* val_ptr); - static bool readUUID(Parser& parser, void* val_ptr); - static bool readDate(Parser& parser, void* val_ptr); - static bool readURI(Parser& parser, void* val_ptr); - static bool readSD(Parser& parser, void* val_ptr); - - Parser::name_stack_t mNameStack; - const LLSD* mCurReadSD; - LLSD* mWriteRootSD; + void writeSDImpl(LLSD& sd, + const LLInitParam::BaseBlock& block, + const LLInitParam::predicate_rule_t, + const LLInitParam::BaseBlock* diff_block); + + void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); + + template<typename T> + static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) + { + LLParamSDParser& sdparser = static_cast<LLParamSDParser&>(parser); + if (!sdparser.mWriteRootSD) return false; + + LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + + sd_to_write.assign(*((const T*)val_ptr)); + return true; + } + + static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); + static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); + + static bool readFlag(Parser& parser, void* val_ptr); + static bool readS32(Parser& parser, void* val_ptr); + static bool readU32(Parser& parser, void* val_ptr); + static bool readF32(Parser& parser, void* val_ptr); + static bool readF64(Parser& parser, void* val_ptr); + static bool readBool(Parser& parser, void* val_ptr); + static bool readString(Parser& parser, void* val_ptr); + static bool readUUID(Parser& parser, void* val_ptr); + static bool readDate(Parser& parser, void* val_ptr); + static bool readURI(Parser& parser, void* val_ptr); + static bool readSD(Parser& parser, void* val_ptr); + + Parser::name_stack_t mNameStack; + const LLSD* mCurReadSD; + LLSD* mWriteRootSD; }; @@ -114,29 +114,29 @@ template<typename T> class LLSDParamAdapter : public T { public: - LLSDParamAdapter() {} - LLSDParamAdapter(const LLSD& sd) - { + LLSDParamAdapter() {} + LLSDParamAdapter(const LLSD& sd) + { LL_PROFILE_ZONE_SCOPED; - LLParamSDParser parser; - // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it - bool parse_silently = true; - parser.readSD(sd, *this, parse_silently); - } - - operator LLSD() const - { - LLParamSDParser parser; - LLSD sd; - parser.writeSD(sd, *this); - return sd; - } - - LLSDParamAdapter(const T& val) - : T(val) - { - T::operator=(val); - } + LLParamSDParser parser; + // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it + bool parse_silently = true; + parser.readSD(sd, *this, parse_silently); + } + + operator LLSD() const + { + LLParamSDParser parser; + LLSD sd; + parser.writeSD(sd, *this); + return sd; + } + + LLSDParamAdapter(const T& val) + : T(val) + { + T::operator=(val); + } }; #endif // LL_LLSDPARAM_H diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 76171f2dfd..d5af31a28e 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize.cpp * @author Phoenix * @date 2006-03-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -88,42 +88,42 @@ S32 parse_using(std::istream& istr, LLSD& data, size_t max_bytes, S32 max_depth= // static void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, - LLSDFormatter::EFormatterOptions options) + LLSDFormatter::EFormatterOptions options) { - LLPointer<LLSDFormatter> f = NULL; - - switch (type) - { - case LLSD_BINARY: - str << "<? " << LLSD_BINARY_HEADER << " ?>\n"; - f = new LLSDBinaryFormatter; - break; - - case LLSD_XML: - str << "<? " << LLSD_XML_HEADER << " ?>\n"; - f = new LLSDXMLFormatter; - break; - - case LLSD_NOTATION: - str << "<? " << LLSD_NOTATION_HEADER << " ?>\n"; - f = new LLSDNotationFormatter; - break; - - default: - LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; - } - - if (f.notNull()) - { - f->format(sd, str, options); - } + LLPointer<LLSDFormatter> f = NULL; + + switch (type) + { + case LLSD_BINARY: + str << "<? " << LLSD_BINARY_HEADER << " ?>\n"; + f = new LLSDBinaryFormatter; + break; + + case LLSD_XML: + str << "<? " << LLSD_XML_HEADER << " ?>\n"; + f = new LLSDXMLFormatter; + break; + + case LLSD_NOTATION: + str << "<? " << LLSD_NOTATION_HEADER << " ?>\n"; + f = new LLSDNotationFormatter; + break; + + default: + LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; + } + + if (f.notNull()) + { + f->format(sd, str, options); + } } // static bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes) { - char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ - bool fail_if_not_legacy = false; + char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ + bool fail_if_not_legacy = false; /* * Get the first line before anything. Don't read more than max_bytes: @@ -132,125 +132,125 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes) * sizeof(hdr_buf), get() will read no more than sizeof(hdr_buf)-2. */ llssize max_hdr_read = MAX_HDR_LEN; - if (max_bytes != LLSDSerialize::SIZE_UNLIMITED) - { + if (max_bytes != LLSDSerialize::SIZE_UNLIMITED) + { max_hdr_read = llmin(max_bytes + 1, max_hdr_read); - } + } str.get(hdr_buf, max_hdr_read, '\n'); - auto inbuf = str.gcount(); - - // https://en.cppreference.com/w/cpp/io/basic_istream/get - // When the get() above sees the specified delimiter '\n', it stops there - // without pulling it from the stream. If it turns out that the stream - // does NOT contain a header, and the content includes meaningful '\n', - // it's important to pull that into hdr_buf too. - if (inbuf < max_bytes && str.get(hdr_buf[inbuf])) - { - // got the delimiting '\n' - ++inbuf; - // None of the following requires that hdr_buf contain a final '\0' - // byte. We could store one if needed, since even the incremented - // inbuf won't exceed sizeof(hdr_buf)-1, but there's no need. - } - std::string header{ hdr_buf, static_cast<std::string::size_type>(inbuf) }; - if (str.fail()) - { - str.clear(); - fail_if_not_legacy = true; - } - - if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ - { // Create a LLSD XML parser, and parse the first chunk read above. - LLSDXMLParser x; - x.parsePart(hdr_buf, inbuf); // Parse the first part that was already read - auto parsed = x.parse(str, sd, max_bytes - inbuf); // Parse the rest of it - // Formally we should probably check (parsed != PARSE_FAILURE && - // parsed > 0), but since PARSE_FAILURE is -1, this suffices. - return (parsed > 0); - } - - if (fail_if_not_legacy) - { - LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL; - return false; - } - - /* - * Remove the newline chars - */ - std::string::size_type lastchar = header.find_last_not_of("\r\n"); - if (lastchar != std::string::npos) - { - // It's important that find_last_not_of() returns size_type, which is - // why lastchar explicitly declares the type above. erase(size_type) - // erases from that offset to the end of the string, whereas - // erase(iterator) erases only a single character. - header.erase(lastchar+1); - } - - // trim off the <? ... ?> header syntax - auto start = header.find_first_not_of("<? "); - if (start != std::string::npos) - { - auto end = header.find_first_of(" ?", start); - if (end != std::string::npos) - { - header = header.substr(start, end - start); - ws(str); - } - } - /* - * Create the parser as appropriate - */ - if (0 == LLStringUtil::compareInsensitive(header, LLSD_BINARY_HEADER)) - { - return (parse_using<LLSDBinaryParser>(str, sd, max_bytes-inbuf) > 0); - } - else if (0 == LLStringUtil::compareInsensitive(header, LLSD_XML_HEADER)) - { - return (parse_using<LLSDXMLParser>(str, sd, max_bytes-inbuf) > 0); - } - else if (0 == LLStringUtil::compareInsensitive(header, LLSD_NOTATION_HEADER)) - { - return (parse_using<LLSDNotationParser>(str, sd, max_bytes-inbuf) > 0); - } - else // no header we recognize - { - LLPointer<LLSDParser> p; - if (inbuf && hdr_buf[0] == '<') - { - // looks like XML - LL_DEBUGS() << "deserialize request with no header, assuming XML" << LL_ENDL; - p = new LLSDXMLParser; - } - else - { - // assume notation - LL_DEBUGS() << "deserialize request with no header, assuming notation" << LL_ENDL; - p = new LLSDNotationParser; - } - // Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that - // data to whatever remains in 'str'. - LLMemoryStreamBuf already(reinterpret_cast<const U8*>(hdr_buf), inbuf); - cat_streambuf prebuff(&already, str.rdbuf()); - std::istream prepend(&prebuff); + auto inbuf = str.gcount(); + + // https://en.cppreference.com/w/cpp/io/basic_istream/get + // When the get() above sees the specified delimiter '\n', it stops there + // without pulling it from the stream. If it turns out that the stream + // does NOT contain a header, and the content includes meaningful '\n', + // it's important to pull that into hdr_buf too. + if (inbuf < max_bytes && str.get(hdr_buf[inbuf])) + { + // got the delimiting '\n' + ++inbuf; + // None of the following requires that hdr_buf contain a final '\0' + // byte. We could store one if needed, since even the incremented + // inbuf won't exceed sizeof(hdr_buf)-1, but there's no need. + } + std::string header{ hdr_buf, static_cast<std::string::size_type>(inbuf) }; + if (str.fail()) + { + str.clear(); + fail_if_not_legacy = true; + } + + if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ + { // Create a LLSD XML parser, and parse the first chunk read above. + LLSDXMLParser x; + x.parsePart(hdr_buf, inbuf); // Parse the first part that was already read + auto parsed = x.parse(str, sd, max_bytes - inbuf); // Parse the rest of it + // Formally we should probably check (parsed != PARSE_FAILURE && + // parsed > 0), but since PARSE_FAILURE is -1, this suffices. + return (parsed > 0); + } + + if (fail_if_not_legacy) + { + LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL; + return false; + } + + /* + * Remove the newline chars + */ + std::string::size_type lastchar = header.find_last_not_of("\r\n"); + if (lastchar != std::string::npos) + { + // It's important that find_last_not_of() returns size_type, which is + // why lastchar explicitly declares the type above. erase(size_type) + // erases from that offset to the end of the string, whereas + // erase(iterator) erases only a single character. + header.erase(lastchar+1); + } + + // trim off the <? ... ?> header syntax + auto start = header.find_first_not_of("<? "); + if (start != std::string::npos) + { + auto end = header.find_first_of(" ?", start); + if (end != std::string::npos) + { + header = header.substr(start, end - start); + ws(str); + } + } + /* + * Create the parser as appropriate + */ + if (0 == LLStringUtil::compareInsensitive(header, LLSD_BINARY_HEADER)) + { + return (parse_using<LLSDBinaryParser>(str, sd, max_bytes-inbuf) > 0); + } + else if (0 == LLStringUtil::compareInsensitive(header, LLSD_XML_HEADER)) + { + return (parse_using<LLSDXMLParser>(str, sd, max_bytes-inbuf) > 0); + } + else if (0 == LLStringUtil::compareInsensitive(header, LLSD_NOTATION_HEADER)) + { + return (parse_using<LLSDNotationParser>(str, sd, max_bytes-inbuf) > 0); + } + else // no header we recognize + { + LLPointer<LLSDParser> p; + if (inbuf && hdr_buf[0] == '<') + { + // looks like XML + LL_DEBUGS() << "deserialize request with no header, assuming XML" << LL_ENDL; + p = new LLSDXMLParser; + } + else + { + // assume notation + LL_DEBUGS() << "deserialize request with no header, assuming notation" << LL_ENDL; + p = new LLSDNotationParser; + } + // Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that + // data to whatever remains in 'str'. + LLMemoryStreamBuf already(reinterpret_cast<const U8*>(hdr_buf), inbuf); + cat_streambuf prebuff(&already, str.rdbuf()); + std::istream prepend(&prebuff); #if 1 - return (p->parse(prepend, sd, max_bytes) > 0); + return (p->parse(prepend, sd, max_bytes) > 0); #else - // debugging the reconstituted 'prepend' stream - // allocate a buffer that we hope is big enough for the whole thing - std::vector<char> wholemsg((max_bytes == size_t(SIZE_UNLIMITED))? 1024 : max_bytes); - prepend.read(wholemsg.data(), std::min(max_bytes, wholemsg.size())); - LLMemoryStream replay(reinterpret_cast<const U8*>(wholemsg.data()), prepend.gcount()); - auto success{ p->parse(replay, sd, prepend.gcount()) > 0 }; - { - LL_DEBUGS() << (success? "parsed: $$" : "failed: '") - << std::string(wholemsg.data(), llmin(prepend.gcount(), 100)) << "$$" - << LL_ENDL; - } - return success; + // debugging the reconstituted 'prepend' stream + // allocate a buffer that we hope is big enough for the whole thing + std::vector<char> wholemsg((max_bytes == size_t(SIZE_UNLIMITED))? 1024 : max_bytes); + prepend.read(wholemsg.data(), std::min(max_bytes, wholemsg.size())); + LLMemoryStream replay(reinterpret_cast<const U8*>(wholemsg.data()), prepend.gcount()); + auto success{ p->parse(replay, sd, prepend.gcount()) > 0 }; + { + LL_DEBUGS() << (success? "parsed: $$" : "failed: '") + << std::string(wholemsg.data(), llmin(prepend.gcount(), 100)) << "$$" + << LL_ENDL; + } + return success; #endif - } + } } /** @@ -268,32 +268,32 @@ F64 ll_ntohd(F64 netlonglong) { return netlonglong; } // operation. U64 ll_htonll(U64 hostlonglong) { - return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) | - ((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32)); + return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) | + ((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32)); } U64 ll_ntohll(U64 netlonglong) { - return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) | - ((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32)); + return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) | + ((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32)); } union LLEndianSwapper { - F64 d; - U64 i; + F64 d; + U64 i; }; F64 ll_htond(F64 hostdouble) { - LLEndianSwapper tmp; - tmp.d = hostdouble; - tmp.i = ll_htonll(tmp.i); - return tmp.d; + LLEndianSwapper tmp; + tmp.d = hostdouble; + tmp.i = ll_htonll(tmp.i); + return tmp.d; } F64 ll_ntohd(F64 netdouble) { - LLEndianSwapper tmp; - tmp.d = netdouble; - tmp.i = ll_ntohll(tmp.i); - return tmp.d; + LLEndianSwapper tmp; + tmp.d = netdouble; + tmp.i = ll_ntohll(tmp.i); + return tmp.d; } #endif @@ -313,7 +313,7 @@ F64 ll_ntohd(F64 netdouble) llssize deserialize_string(std::istream& istr, std::string& value, llssize max_bytes); /** - * @brief Parse a delimited string. + * @brief Parse a delimited string. * * @param istr The stream to read from, with the delimiter already popped. * @param value [out] The string which was found. @@ -336,9 +336,9 @@ llssize deserialize_string_delim(std::istream& istr, std::string& value, char d) * PARSE_FAILURE (-1) on failure. */ llssize deserialize_string_raw( - std::istream& istr, - std::string& value, - llssize max_bytes); + std::istream& istr, + std::string& value, + llssize max_bytes); /** * @brief helper method for dealing with the different notation boolean format. @@ -351,10 +351,10 @@ llssize deserialize_string_raw( * PARSE_FAILURE (-1) on failure. */ llssize deserialize_boolean( - std::istream& istr, - LLSD& data, - const std::string& compare, - bool value); + std::istream& istr, + LLSD& data, + const std::string& compare, + bool value); /** * @brief Do notation escaping of a string to an ostream. @@ -379,7 +379,7 @@ static const char BINARY_FALSE_SERIAL = '0'; * LLSDParser */ LLSDParser::LLSDParser() - : mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false) + : mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false) { } @@ -389,75 +389,75 @@ LLSDParser::~LLSDParser() S32 LLSDParser::parse(std::istream& istr, LLSD& data, llssize max_bytes, S32 max_depth) { - mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true; - mMaxBytesLeft = max_bytes; - return doParse(istr, data, max_depth); + mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true; + mMaxBytesLeft = max_bytes; + return doParse(istr, data, max_depth); } // Parse using routine to get() lines, faster than parse() S32 LLSDParser::parseLines(std::istream& istr, LLSD& data) { - mCheckLimits = false; - mParseLines = true; - return doParse(istr, data); + mCheckLimits = false; + mParseLines = true; + return doParse(istr, data); } int LLSDParser::get(std::istream& istr) const { - if(mCheckLimits) --mMaxBytesLeft; - return istr.get(); + if(mCheckLimits) --mMaxBytesLeft; + return istr.get(); } std::istream& LLSDParser::get( - std::istream& istr, - char* s, - std::streamsize n, - char delim) const + std::istream& istr, + char* s, + std::streamsize n, + char delim) const { - istr.get(s, n, delim); - if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); - return istr; + istr.get(s, n, delim); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; } std::istream& LLSDParser::get( - std::istream& istr, - std::streambuf& sb, - char delim) const + std::istream& istr, + std::streambuf& sb, + char delim) const { - istr.get(sb, delim); - if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); - return istr; + istr.get(sb, delim); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; } std::istream& LLSDParser::ignore(std::istream& istr) const { - istr.ignore(); - if(mCheckLimits) --mMaxBytesLeft; - return istr; + istr.ignore(); + if(mCheckLimits) --mMaxBytesLeft; + return istr; } std::istream& LLSDParser::putback(std::istream& istr, char c) const { - istr.putback(c); - if(mCheckLimits) ++mMaxBytesLeft; - return istr; + istr.putback(c); + if(mCheckLimits) ++mMaxBytesLeft; + return istr; } std::istream& LLSDParser::read( - std::istream& istr, - char* s, - std::streamsize n) const + std::istream& istr, + char* s, + std::streamsize n) const { - istr.read(s, n); - if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); - return istr; + istr.read(s, n); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; } void LLSDParser::account(llssize bytes) const { - if(mCheckLimits) mMaxBytesLeft -= bytes; + if(mCheckLimits) mMaxBytesLeft -= bytes; } @@ -466,7 +466,7 @@ void LLSDParser::account(llssize bytes) const */ LLSDNotationParser::LLSDNotationParser() { -} +} // virtual LLSDNotationParser::~LLSDNotationParser() @@ -475,463 +475,463 @@ LLSDNotationParser::~LLSDNotationParser() // virtual S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // map: { string:object, string:object } - // array: [ object, object, object ] - // undef: ! - // boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE - // integer: i#### - // real: r#### - // uuid: u#### - // string: "g'day" | 'have a "nice" day' | s(size)"raw data" - // uri: l"escaped" - // date: d"YYYY-MM-DDTHH:MM:SS.FFZ" - // binary: b##"ff3120ab1" | b(size)"raw data" - char c; - c = istr.peek(); - if (max_depth == 0) - { - return PARSE_FAILURE; - } - while(isspace(c)) - { - // pop the whitespace. - c = get(istr); - c = istr.peek(); - continue; - } - if(!istr.good()) - { - return 0; - } - S32 parse_count = 1; - switch(c) - { - case '{': - { - S32 child_count = parseMap(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading map." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '[': - { - S32 child_count = parseArray(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading array." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '!': - c = get(istr); - data.clear(); - break; - - case '0': - c = get(istr); - data = false; - break; - - case 'F': - case 'f': - ignore(istr); - c = istr.peek(); - if(isalpha(c)) - { - auto cnt = deserialize_boolean( - istr, - data, - NOTATION_FALSE_SERIAL, - false); - if(PARSE_FAILURE == cnt) parse_count = cnt; - else account(cnt); - } - else - { - data = false; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - case '1': - c = get(istr); - data = true; - break; - - case 'T': - case 't': - ignore(istr); - c = istr.peek(); - if(isalpha(c)) - { - auto cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); - if(PARSE_FAILURE == cnt) parse_count = cnt; - else account(cnt); - } - else - { - data = true; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - case 'i': - { - c = get(istr); - S32 integer = 0; - istr >> integer; - data = integer; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading integer." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'r': - { - c = get(istr); - F64 real = 0.0; - istr >> real; - data = real; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading real." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'u': - { - c = get(istr); - LLUUID id; - istr >> id; - data = id; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading uuid." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '\"': - case '\'': - case 's': - if(!parseString(istr, data)) - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading string." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - case 'l': - { - c = get(istr); // pop the 'l' - c = get(istr); // pop the delimiter - std::string str; - auto cnt = deserialize_string_delim(istr, str, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = LLURI(str); - account(cnt); - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading link." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'd': - { - c = get(istr); // pop the 'd' - c = get(istr); // pop the delimiter - std::string str; - auto cnt = deserialize_string_delim(istr, str, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = LLDate(str); - account(cnt); - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading date." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'b': - if(!parseBinary(istr, data)) - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading data." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - default: - parse_count = PARSE_FAILURE; - LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) - << ")" << LL_ENDL; - break; - } - if(PARSE_FAILURE == parse_count) - { - data.clear(); - } - return parse_count; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // map: { string:object, string:object } + // array: [ object, object, object ] + // undef: ! + // boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE + // integer: i#### + // real: r#### + // uuid: u#### + // string: "g'day" | 'have a "nice" day' | s(size)"raw data" + // uri: l"escaped" + // date: d"YYYY-MM-DDTHH:MM:SS.FFZ" + // binary: b##"ff3120ab1" | b(size)"raw data" + char c; + c = istr.peek(); + if (max_depth == 0) + { + return PARSE_FAILURE; + } + while(isspace(c)) + { + // pop the whitespace. + c = get(istr); + c = istr.peek(); + continue; + } + if(!istr.good()) + { + return 0; + } + S32 parse_count = 1; + switch(c) + { + case '{': + { + S32 child_count = parseMap(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading map." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '[': + { + S32 child_count = parseArray(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading array." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '!': + c = get(istr); + data.clear(); + break; + + case '0': + c = get(istr); + data = false; + break; + + case 'F': + case 'f': + ignore(istr); + c = istr.peek(); + if(isalpha(c)) + { + auto cnt = deserialize_boolean( + istr, + data, + NOTATION_FALSE_SERIAL, + false); + if(PARSE_FAILURE == cnt) parse_count = cnt; + else account(cnt); + } + else + { + data = false; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + case '1': + c = get(istr); + data = true; + break; + + case 'T': + case 't': + ignore(istr); + c = istr.peek(); + if(isalpha(c)) + { + auto cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); + if(PARSE_FAILURE == cnt) parse_count = cnt; + else account(cnt); + } + else + { + data = true; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + case 'i': + { + c = get(istr); + S32 integer = 0; + istr >> integer; + data = integer; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading integer." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'r': + { + c = get(istr); + F64 real = 0.0; + istr >> real; + data = real; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading real." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'u': + { + c = get(istr); + LLUUID id; + istr >> id; + data = id; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading uuid." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '\"': + case '\'': + case 's': + if(!parseString(istr, data)) + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading string." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + case 'l': + { + c = get(istr); // pop the 'l' + c = get(istr); // pop the delimiter + std::string str; + auto cnt = deserialize_string_delim(istr, str, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = LLURI(str); + account(cnt); + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading link." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'd': + { + c = get(istr); // pop the 'd' + c = get(istr); // pop the delimiter + std::string str; + auto cnt = deserialize_string_delim(istr, str, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = LLDate(str); + account(cnt); + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading date." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'b': + if(!parseBinary(istr, data)) + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading data." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + default: + parse_count = PARSE_FAILURE; + LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) + << ")" << LL_ENDL; + break; + } + if(PARSE_FAILURE == parse_count) + { + data.clear(); + } + return parse_count; } S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // map: { string:object, string:object } - map = LLSD::emptyMap(); - S32 parse_count = 0; - char c = get(istr); - if(c == '{') - { - // eat commas, white - bool found_name = false; - std::string name; - c = get(istr); - while(c != '}' && istr.good()) - { - if(!found_name) - { - if((c == '\"') || (c == '\'') || (c == 's')) - { - putback(istr, c); - found_name = true; - auto count = deserialize_string(istr, name, mMaxBytesLeft); - if(PARSE_FAILURE == count) return PARSE_FAILURE; - account(count); - } - c = get(istr); - } - else - { - if(isspace(c) || (c == ':')) - { - c = get(istr); - continue; - } - putback(istr, c); - LLSD child; - S32 count = doParse(istr, child, max_depth); - if(count > 0) - { - // There must be a value for every key, thus - // child_count must be greater than 0. - parse_count += count; - map.insert(name, child); - } - else - { - return PARSE_FAILURE; - } - found_name = false; - c = get(istr); - } - } - if(c != '}') - { - map.clear(); - return PARSE_FAILURE; - } - } - return parse_count; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // map: { string:object, string:object } + map = LLSD::emptyMap(); + S32 parse_count = 0; + char c = get(istr); + if(c == '{') + { + // eat commas, white + bool found_name = false; + std::string name; + c = get(istr); + while(c != '}' && istr.good()) + { + if(!found_name) + { + if((c == '\"') || (c == '\'') || (c == 's')) + { + putback(istr, c); + found_name = true; + auto count = deserialize_string(istr, name, mMaxBytesLeft); + if(PARSE_FAILURE == count) return PARSE_FAILURE; + account(count); + } + c = get(istr); + } + else + { + if(isspace(c) || (c == ':')) + { + c = get(istr); + continue; + } + putback(istr, c); + LLSD child; + S32 count = doParse(istr, child, max_depth); + if(count > 0) + { + // There must be a value for every key, thus + // child_count must be greater than 0. + parse_count += count; + map.insert(name, child); + } + else + { + return PARSE_FAILURE; + } + found_name = false; + c = get(istr); + } + } + if(c != '}') + { + map.clear(); + return PARSE_FAILURE; + } + } + return parse_count; } S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // array: [ object, object, object ] - array = LLSD::emptyArray(); - S32 parse_count = 0; - char c = get(istr); - if(c == '[') - { - // eat commas, white - c = get(istr); - while((c != ']') && istr.good()) - { - LLSD child; - if(isspace(c) || (c == ',')) - { - c = get(istr); - continue; - } - putback(istr, c); - S32 count = doParse(istr, child, max_depth); - if(PARSE_FAILURE == count) - { - return PARSE_FAILURE; - } - else - { - parse_count += count; - array.append(child); - } - c = get(istr); - } - if(c != ']') - { - return PARSE_FAILURE; - } - } - return parse_count; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // array: [ object, object, object ] + array = LLSD::emptyArray(); + S32 parse_count = 0; + char c = get(istr); + if(c == '[') + { + // eat commas, white + c = get(istr); + while((c != ']') && istr.good()) + { + LLSD child; + if(isspace(c) || (c == ',')) + { + c = get(istr); + continue; + } + putback(istr, c); + S32 count = doParse(istr, child, max_depth); + if(PARSE_FAILURE == count) + { + return PARSE_FAILURE; + } + else + { + parse_count += count; + array.append(child); + } + c = get(istr); + } + if(c != ']') + { + return PARSE_FAILURE; + } + } + return parse_count; } bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - std::string value; - auto count = deserialize_string(istr, value, mMaxBytesLeft); - if(PARSE_FAILURE == count) return false; - account(count); - data = value; - return true; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + std::string value; + auto count = deserialize_string(istr, value, mMaxBytesLeft); + if(PARSE_FAILURE == count) return false; + account(count); + data = value; + return true; } bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // binary: b##"ff3120ab1" - // or: b(len)"..." - - // I want to manually control those values here to make sure the - // parser doesn't break when someone changes a constant somewhere - // else. - const U32 BINARY_BUFFER_SIZE = 256; - const U32 STREAM_GET_COUNT = 255; - - // need to read the base out. - char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ - get(istr, buf, STREAM_GET_COUNT, '"'); - char c = get(istr); - if(c != '"') return false; - if(0 == strncmp("b(", buf, 2)) - { - // We probably have a valid raw binary stream. determine - // the size, and read it. - auto len = strtol(buf + 2, NULL, 0); - if(mCheckLimits && (len > mMaxBytesLeft)) return false; - std::vector<U8> value; - if(len) - { - value.resize(len); - account(fullread(istr, (char *)&value[0], len)); - } - c = get(istr); // strip off the trailing double-quote - data = value; - } - else if(0 == strncmp("b64", buf, 3)) - { - // *FIX: A bit inefficient, but works for now. To make the - // format better, I would need to add a hint into the - // serialization format that indicated how long it was. - std::stringstream coded_stream; - get(istr, *(coded_stream.rdbuf()), '\"'); - c = get(istr); - std::string encoded(coded_stream.str()); - S32 len = apr_base64_decode_len(encoded.c_str()); - std::vector<U8> value; - if(len) - { - value.resize(len); - len = apr_base64_decode_binary(&value[0], encoded.c_str()); - value.resize(len); - } - data = value; - } - else if(0 == strncmp("b16", buf, 3)) - { - // yay, base 16. We pop the next character which is either a - // double quote or base 16 data. If it's a double quote, we're - // done parsing. If it's not, put the data back, and read the - // stream until the next double quote. - char* read; /*Flawfinder: ignore*/ - U8 byte; - U8 byte_buffer[BINARY_BUFFER_SIZE]; - U8* write; - std::vector<U8> value; - c = get(istr); - while(c != '"') - { - putback(istr, c); - read = buf; - write = byte_buffer; - get(istr, buf, STREAM_GET_COUNT, '"'); - c = get(istr); - while(*read != '\0') /*Flawfinder: ignore*/ - { - byte = hex_as_nybble(*read++); - byte = byte << 4; - byte |= hex_as_nybble(*read++); - *write++ = byte; - } - // copy the data out of the byte buffer - value.insert(value.end(), byte_buffer, write); - } - data = value; - } - else - { - return false; - } - return true; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // binary: b##"ff3120ab1" + // or: b(len)"..." + + // I want to manually control those values here to make sure the + // parser doesn't break when someone changes a constant somewhere + // else. + const U32 BINARY_BUFFER_SIZE = 256; + const U32 STREAM_GET_COUNT = 255; + + // need to read the base out. + char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ + get(istr, buf, STREAM_GET_COUNT, '"'); + char c = get(istr); + if(c != '"') return false; + if(0 == strncmp("b(", buf, 2)) + { + // We probably have a valid raw binary stream. determine + // the size, and read it. + auto len = strtol(buf + 2, NULL, 0); + if(mCheckLimits && (len > mMaxBytesLeft)) return false; + std::vector<U8> value; + if(len) + { + value.resize(len); + account(fullread(istr, (char *)&value[0], len)); + } + c = get(istr); // strip off the trailing double-quote + data = value; + } + else if(0 == strncmp("b64", buf, 3)) + { + // *FIX: A bit inefficient, but works for now. To make the + // format better, I would need to add a hint into the + // serialization format that indicated how long it was. + std::stringstream coded_stream; + get(istr, *(coded_stream.rdbuf()), '\"'); + c = get(istr); + std::string encoded(coded_stream.str()); + S32 len = apr_base64_decode_len(encoded.c_str()); + std::vector<U8> value; + if(len) + { + value.resize(len); + len = apr_base64_decode_binary(&value[0], encoded.c_str()); + value.resize(len); + } + data = value; + } + else if(0 == strncmp("b16", buf, 3)) + { + // yay, base 16. We pop the next character which is either a + // double quote or base 16 data. If it's a double quote, we're + // done parsing. If it's not, put the data back, and read the + // stream until the next double quote. + char* read; /*Flawfinder: ignore*/ + U8 byte; + U8 byte_buffer[BINARY_BUFFER_SIZE]; + U8* write; + std::vector<U8> value; + c = get(istr); + while(c != '"') + { + putback(istr, c); + read = buf; + write = byte_buffer; + get(istr, buf, STREAM_GET_COUNT, '"'); + c = get(istr); + while(*read != '\0') /*Flawfinder: ignore*/ + { + byte = hex_as_nybble(*read++); + byte = byte << 4; + byte |= hex_as_nybble(*read++); + *write++ = byte; + } + // copy the data out of the byte buffer + value.insert(value.end(), byte_buffer, write); + } + data = value; + } + else + { + return false; + } + return true; } @@ -950,7 +950,7 @@ LLSDBinaryParser::~LLSDBinaryParser() // virtual S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD /** * Undefined: '!'<br> * Boolean: '1' for true '0' for false<br> @@ -967,332 +967,332 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con * map keys are serialized as s + 4 byte integer size + string or in the * notation format. */ - char c; - c = get(istr); - if(!istr.good()) - { - return 0; - } - if (max_depth == 0) - { - return PARSE_FAILURE; - } - S32 parse_count = 1; - switch(c) - { - case '{': - { - S32 child_count = parseMap(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '[': - { - S32 child_count = parseArray(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '!': - data.clear(); - break; - - case '0': - data = false; - break; - - case '1': - data = true; - break; - - case 'i': - { - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - data = (S32)ntohl(value_nbo); - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL; - } - break; - } - - case 'r': - { - F64 real_nbo = 0.0; - read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ - data = ll_ntohd(real_nbo); - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL; - } - break; - } - - case 'u': - { - LLUUID id; - read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ - data = id; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL; - } - break; - } - - case '\'': - case '"': - { - std::string value; - auto cnt = deserialize_string_delim(istr, value, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = value; - account(cnt); - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string." - << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 's': - { - std::string value; - if(parseString(istr, value)) - { - data = value; - } - else - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'l': - { - std::string value; - if(parseString(istr, value)) - { - data = LLURI(value); - } - else - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'd': - { - F64 real = 0.0; - read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ - data = LLDate(real); - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'b': - { - // We probably have a valid raw binary stream. determine - // the size, and read it. - U32 size_nbo = 0; - read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(size_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) - { - parse_count = PARSE_FAILURE; - } - else - { - std::vector<U8> value; - if(size > 0) - { - value.resize(size); - account(fullread(istr, (char*)&value[0], size)); - } - data = value; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - default: - parse_count = PARSE_FAILURE; - LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) - << ")" << LL_ENDL; - break; - } - if(PARSE_FAILURE == parse_count) - { - data.clear(); - } - return parse_count; + char c; + c = get(istr); + if(!istr.good()) + { + return 0; + } + if (max_depth == 0) + { + return PARSE_FAILURE; + } + S32 parse_count = 1; + switch(c) + { + case '{': + { + S32 child_count = parseMap(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '[': + { + S32 child_count = parseArray(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '!': + data.clear(); + break; + + case '0': + data = false; + break; + + case '1': + data = true; + break; + + case 'i': + { + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + data = (S32)ntohl(value_nbo); + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL; + } + break; + } + + case 'r': + { + F64 real_nbo = 0.0; + read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ + data = ll_ntohd(real_nbo); + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL; + } + break; + } + + case 'u': + { + LLUUID id; + read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ + data = id; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL; + } + break; + } + + case '\'': + case '"': + { + std::string value; + auto cnt = deserialize_string_delim(istr, value, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = value; + account(cnt); + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string." + << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 's': + { + std::string value; + if(parseString(istr, value)) + { + data = value; + } + else + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'l': + { + std::string value; + if(parseString(istr, value)) + { + data = LLURI(value); + } + else + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'd': + { + F64 real = 0.0; + read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ + data = LLDate(real); + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'b': + { + // We probably have a valid raw binary stream. determine + // the size, and read it. + U32 size_nbo = 0; + read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(size_nbo); + if(mCheckLimits && (size > mMaxBytesLeft)) + { + parse_count = PARSE_FAILURE; + } + else + { + std::vector<U8> value; + if(size > 0) + { + value.resize(size); + account(fullread(istr, (char*)&value[0], size)); + } + data = value; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + default: + parse_count = PARSE_FAILURE; + LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) + << ")" << LL_ENDL; + break; + } + if(PARSE_FAILURE == parse_count) + { + data.clear(); + } + return parse_count; } S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const { - map = LLSD::emptyMap(); - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - S32 parse_count = 0; - S32 count = 0; - char c = get(istr); - while(c != '}' && (count < size) && istr.good()) - { - std::string name; - switch(c) - { - case 'k': - if(!parseString(istr, name)) - { - return PARSE_FAILURE; - } - break; - case '\'': - case '"': - { - auto cnt = deserialize_string_delim(istr, name, c); - if(PARSE_FAILURE == cnt) return PARSE_FAILURE; - account(cnt); - break; - } - } - LLSD child; - S32 child_count = doParse(istr, child, max_depth); - if(child_count > 0) - { - // There must be a value for every key, thus child_count - // must be greater than 0. - parse_count += child_count; - map.insert(name, child); - } - else - { - return PARSE_FAILURE; - } - ++count; - c = get(istr); - } - if((c != '}') || (count < size)) - { - // Make sure it is correctly terminated and we parsed as many - // as were said to be there. - return PARSE_FAILURE; - } - return parse_count; + map = LLSD::emptyMap(); + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(value_nbo); + S32 parse_count = 0; + S32 count = 0; + char c = get(istr); + while(c != '}' && (count < size) && istr.good()) + { + std::string name; + switch(c) + { + case 'k': + if(!parseString(istr, name)) + { + return PARSE_FAILURE; + } + break; + case '\'': + case '"': + { + auto cnt = deserialize_string_delim(istr, name, c); + if(PARSE_FAILURE == cnt) return PARSE_FAILURE; + account(cnt); + break; + } + } + LLSD child; + S32 child_count = doParse(istr, child, max_depth); + if(child_count > 0) + { + // There must be a value for every key, thus child_count + // must be greater than 0. + parse_count += child_count; + map.insert(name, child); + } + else + { + return PARSE_FAILURE; + } + ++count; + c = get(istr); + } + if((c != '}') || (count < size)) + { + // Make sure it is correctly terminated and we parsed as many + // as were said to be there. + return PARSE_FAILURE; + } + return parse_count; } S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const { - array = LLSD::emptyArray(); - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - - // *FIX: This would be a good place to reserve some space in the - // array... - - S32 parse_count = 0; - S32 count = 0; - char c = istr.peek(); - while((c != ']') && (count < size) && istr.good()) - { - LLSD child; - S32 child_count = doParse(istr, child, max_depth); - if(PARSE_FAILURE == child_count) - { - return PARSE_FAILURE; - } - if(child_count) - { - parse_count += child_count; - array.append(child); - } - ++count; - c = istr.peek(); - } - c = get(istr); - if((c != ']') || (count < size)) - { - // Make sure it is correctly terminated and we parsed as many - // as were said to be there. - return PARSE_FAILURE; - } - return parse_count; + array = LLSD::emptyArray(); + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(value_nbo); + + // *FIX: This would be a good place to reserve some space in the + // array... + + S32 parse_count = 0; + S32 count = 0; + char c = istr.peek(); + while((c != ']') && (count < size) && istr.good()) + { + LLSD child; + S32 child_count = doParse(istr, child, max_depth); + if(PARSE_FAILURE == child_count) + { + return PARSE_FAILURE; + } + if(child_count) + { + parse_count += child_count; + array.append(child); + } + ++count; + c = istr.peek(); + } + c = get(istr); + if((c != ']') || (count < size)) + { + // Make sure it is correctly terminated and we parsed as many + // as were said to be there. + return PARSE_FAILURE; + } + return parse_count; } bool LLSDBinaryParser::parseString( - std::istream& istr, - std::string& value) const + std::istream& istr, + std::string& value) const { - // *FIX: This is memory inefficient. - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) return false; - if(size < 0) return false; - std::vector<char> buf; - if(size) - { - buf.resize(size); - account(fullread(istr, &buf[0], size)); - value.assign(buf.begin(), buf.end()); - } - return true; + // *FIX: This is memory inefficient. + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(value_nbo); + if(mCheckLimits && (size > mMaxBytesLeft)) return false; + if(size < 0) return false; + std::vector<char> buf; + if(size) + { + buf.resize(size); + account(fullread(istr, &buf[0], size)); + value.assign(buf.begin(), buf.end()); + } + return true; } @@ -1312,12 +1312,12 @@ LLSDFormatter::~LLSDFormatter() void LLSDFormatter::boolalpha(bool alpha) { - mBoolAlpha = alpha; + mBoolAlpha = alpha; } void LLSDFormatter::realFormat(const std::string& format) { - mRealFormat = format; + mRealFormat = format; } S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr) const @@ -1333,8 +1333,8 @@ S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr, EFormatterOption void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const { - std::string buffer = llformat(mRealFormat.c_str(), real); - ostr << buffer; + std::string buffer = llformat(mRealFormat.c_str(), real); + ostr << buffer; } /** @@ -1353,174 +1353,174 @@ LLSDNotationFormatter::~LLSDNotationFormatter() // static std::string LLSDNotationFormatter::escapeString(const std::string& in) { - std::ostringstream ostr; - serialize_string(in, ostr); - return ostr.str(); + std::ostringstream ostr; + serialize_string(in, ostr); + return ostr.str(); } S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, - EFormatterOptions options, U32 level) const + EFormatterOptions options, U32 level) const { - S32 format_count = 1; - std::string pre; - std::string post; - - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - for (U32 i = 0; i < level; i++) - { - pre += " "; - } - post = "\n"; - } - - switch(data.type()) - { - case LLSD::TypeMap: - { - if (0 != level) ostr << post << pre; - ostr << "{"; - std::string inner_pre; - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - inner_pre = pre + " "; - } - - bool need_comma = false; - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - if(need_comma) ostr << ","; - need_comma = true; - ostr << post << inner_pre << '\''; - serialize_string((*iter).first, ostr); - ostr << "':"; - format_count += format_impl((*iter).second, ostr, options, level + 2); - } - ostr << post << pre << "}"; - break; - } - - case LLSD::TypeArray: - { - ostr << post << pre << "["; - bool need_comma = false; - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - if(need_comma) ostr << ","; - need_comma = true; - format_count += format_impl(*iter, ostr, options, level + 1); - } - ostr << "]"; - break; - } - - case LLSD::TypeUndefined: - ostr << "!"; - break; - - case LLSD::TypeBoolean: - if(mBoolAlpha || + S32 format_count = 1; + std::string pre; + std::string post; + + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + for (U32 i = 0; i < level; i++) + { + pre += " "; + } + post = "\n"; + } + + switch(data.type()) + { + case LLSD::TypeMap: + { + if (0 != level) ostr << post << pre; + ostr << "{"; + std::string inner_pre; + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + inner_pre = pre + " "; + } + + bool need_comma = false; + LLSD::map_const_iterator iter = data.beginMap(); + LLSD::map_const_iterator end = data.endMap(); + for(; iter != end; ++iter) + { + if(need_comma) ostr << ","; + need_comma = true; + ostr << post << inner_pre << '\''; + serialize_string((*iter).first, ostr); + ostr << "':"; + format_count += format_impl((*iter).second, ostr, options, level + 2); + } + ostr << post << pre << "}"; + break; + } + + case LLSD::TypeArray: + { + ostr << post << pre << "["; + bool need_comma = false; + LLSD::array_const_iterator iter = data.beginArray(); + LLSD::array_const_iterator end = data.endArray(); + for(; iter != end; ++iter) + { + if(need_comma) ostr << ","; + need_comma = true; + format_count += format_impl(*iter, ostr, options, level + 1); + } + ostr << "]"; + break; + } + + case LLSD::TypeUndefined: + ostr << "!"; + break; + + case LLSD::TypeBoolean: + if(mBoolAlpha || #if( LL_WINDOWS || __GNUC__ > 2) - (ostr.flags() & std::ios::boolalpha) + (ostr.flags() & std::ios::boolalpha) #else - (ostr.flags() & 0x0100) + (ostr.flags() & 0x0100) #endif - ) - { - ostr << (data.asBoolean() - ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL); - } - else - { - ostr << (data.asBoolean() ? 1 : 0); - } - break; - - case LLSD::TypeInteger: - ostr << "i" << data.asInteger(); - break; - - case LLSD::TypeReal: - ostr << "r"; - if(mRealFormat.empty()) - { - ostr << data.asReal(); - } - else - { - formatReal(data.asReal(), ostr); - } - break; - - case LLSD::TypeUUID: - ostr << "u" << data.asUUID(); - break; - - case LLSD::TypeString: - ostr << '\''; - serialize_string(data.asStringRef(), ostr); - ostr << '\''; - break; - - case LLSD::TypeDate: - ostr << "d\"" << data.asDate() << "\""; - break; - - case LLSD::TypeURI: - ostr << "l\""; - serialize_string(data.asString(), ostr); - ostr << "\""; - break; - - case LLSD::TypeBinary: - { - // *FIX: memory inefficient. - const std::vector<U8>& buffer = data.asBinary(); - if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) - { - ostr << "b16\""; - if (! buffer.empty()) - { - std::ios_base::fmtflags old_flags = ostr.flags(); - ostr.setf( std::ios::hex, std::ios::basefield ); - // It shouldn't strictly matter whether the emitted hex digits - // are uppercase; LLSDNotationParser handles either; but as of - // 2020-05-13, Python's llbase.llsd requires uppercase hex. - ostr << std::uppercase; - auto oldfill(ostr.fill('0')); - auto oldwidth(ostr.width()); - for (size_t i = 0; i < buffer.size(); i++) - { - // have to restate setw() before every conversion - ostr << std::setw(2) << (int) buffer[i]; - } - ostr.width(oldwidth); - ostr.fill(oldfill); - ostr.flags(old_flags); - } - } - else // ! OPTIONS_PRETTY_BINARY - { - ostr << "b(" << buffer.size() << ")\""; - if (! buffer.empty()) - { - ostr.write((const char*)&buffer[0], buffer.size()); - } - } - ostr << "\""; - break; - } - - default: - // *NOTE: This should never happen. - ostr << "!"; - break; - } - return format_count; + ) + { + ostr << (data.asBoolean() + ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL); + } + else + { + ostr << (data.asBoolean() ? 1 : 0); + } + break; + + case LLSD::TypeInteger: + ostr << "i" << data.asInteger(); + break; + + case LLSD::TypeReal: + ostr << "r"; + if(mRealFormat.empty()) + { + ostr << data.asReal(); + } + else + { + formatReal(data.asReal(), ostr); + } + break; + + case LLSD::TypeUUID: + ostr << "u" << data.asUUID(); + break; + + case LLSD::TypeString: + ostr << '\''; + serialize_string(data.asStringRef(), ostr); + ostr << '\''; + break; + + case LLSD::TypeDate: + ostr << "d\"" << data.asDate() << "\""; + break; + + case LLSD::TypeURI: + ostr << "l\""; + serialize_string(data.asString(), ostr); + ostr << "\""; + break; + + case LLSD::TypeBinary: + { + // *FIX: memory inefficient. + const std::vector<U8>& buffer = data.asBinary(); + if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) + { + ostr << "b16\""; + if (! buffer.empty()) + { + std::ios_base::fmtflags old_flags = ostr.flags(); + ostr.setf( std::ios::hex, std::ios::basefield ); + // It shouldn't strictly matter whether the emitted hex digits + // are uppercase; LLSDNotationParser handles either; but as of + // 2020-05-13, Python's llbase.llsd requires uppercase hex. + ostr << std::uppercase; + auto oldfill(ostr.fill('0')); + auto oldwidth(ostr.width()); + for (size_t i = 0; i < buffer.size(); i++) + { + // have to restate setw() before every conversion + ostr << std::setw(2) << (int) buffer[i]; + } + ostr.width(oldwidth); + ostr.fill(oldfill); + ostr.flags(old_flags); + } + } + else // ! OPTIONS_PRETTY_BINARY + { + ostr << "b(" << buffer.size() << ")\""; + if (! buffer.empty()) + { + ostr.write((const char*)&buffer[0], buffer.size()); + } + } + ostr << "\""; + break; + } + + default: + // *NOTE: This should never happen. + ostr << "!"; + break; + } + return format_count; } /** @@ -1538,119 +1538,119 @@ LLSDBinaryFormatter::~LLSDBinaryFormatter() // virtual S32 LLSDBinaryFormatter::format_impl(const LLSD& data, std::ostream& ostr, - EFormatterOptions options, U32 level) const + EFormatterOptions options, U32 level) const { - S32 format_count = 1; - switch(data.type()) - { - case LLSD::TypeMap: - { - ostr.put('{'); - U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - ostr.put('k'); - formatString((*iter).first, ostr); - format_count += format_impl((*iter).second, ostr, options, level+1); - } - ostr.put('}'); - break; - } - - case LLSD::TypeArray: - { - ostr.put('['); - U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - format_count += format_impl(*iter, ostr, options, level+1); - } - ostr.put(']'); - break; - } - - case LLSD::TypeUndefined: - ostr.put('!'); - break; - - case LLSD::TypeBoolean: - if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL); - else ostr.put(BINARY_FALSE_SERIAL); - break; - - case LLSD::TypeInteger: - { - ostr.put('i'); - U32 value_nbo = htonl(data.asInteger()); - ostr.write((const char*)(&value_nbo), sizeof(U32)); - break; - } - - case LLSD::TypeReal: - { - ostr.put('r'); - F64 value_nbo = ll_htond(data.asReal()); - ostr.write((const char*)(&value_nbo), sizeof(F64)); - break; - } - - case LLSD::TypeUUID: - { - ostr.put('u'); - LLUUID temp = data.asUUID(); - ostr.write((const char*)(&(temp.mData)), UUID_BYTES); - break; - } - - case LLSD::TypeString: - ostr.put('s'); - formatString(data.asStringRef(), ostr); - break; - - case LLSD::TypeDate: - { - ostr.put('d'); - F64 value = data.asReal(); - ostr.write((const char*)(&value), sizeof(F64)); - break; - } - - case LLSD::TypeURI: - ostr.put('l'); - formatString(data.asString(), ostr); - break; - - case LLSD::TypeBinary: - { - ostr.put('b'); - const std::vector<U8>& buffer = data.asBinary(); - U32 size_nbo = htonl(buffer.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); - break; - } - - default: - // *NOTE: This should never happen. - ostr.put('!'); - break; - } - return format_count; + S32 format_count = 1; + switch(data.type()) + { + case LLSD::TypeMap: + { + ostr.put('{'); + U32 size_nbo = htonl(data.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + LLSD::map_const_iterator iter = data.beginMap(); + LLSD::map_const_iterator end = data.endMap(); + for(; iter != end; ++iter) + { + ostr.put('k'); + formatString((*iter).first, ostr); + format_count += format_impl((*iter).second, ostr, options, level+1); + } + ostr.put('}'); + break; + } + + case LLSD::TypeArray: + { + ostr.put('['); + U32 size_nbo = htonl(data.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + LLSD::array_const_iterator iter = data.beginArray(); + LLSD::array_const_iterator end = data.endArray(); + for(; iter != end; ++iter) + { + format_count += format_impl(*iter, ostr, options, level+1); + } + ostr.put(']'); + break; + } + + case LLSD::TypeUndefined: + ostr.put('!'); + break; + + case LLSD::TypeBoolean: + if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL); + else ostr.put(BINARY_FALSE_SERIAL); + break; + + case LLSD::TypeInteger: + { + ostr.put('i'); + U32 value_nbo = htonl(data.asInteger()); + ostr.write((const char*)(&value_nbo), sizeof(U32)); + break; + } + + case LLSD::TypeReal: + { + ostr.put('r'); + F64 value_nbo = ll_htond(data.asReal()); + ostr.write((const char*)(&value_nbo), sizeof(F64)); + break; + } + + case LLSD::TypeUUID: + { + ostr.put('u'); + LLUUID temp = data.asUUID(); + ostr.write((const char*)(&(temp.mData)), UUID_BYTES); + break; + } + + case LLSD::TypeString: + ostr.put('s'); + formatString(data.asStringRef(), ostr); + break; + + case LLSD::TypeDate: + { + ostr.put('d'); + F64 value = data.asReal(); + ostr.write((const char*)(&value), sizeof(F64)); + break; + } + + case LLSD::TypeURI: + ostr.put('l'); + formatString(data.asString(), ostr); + break; + + case LLSD::TypeBinary: + { + ostr.put('b'); + const std::vector<U8>& buffer = data.asBinary(); + U32 size_nbo = htonl(buffer.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); + break; + } + + default: + // *NOTE: This should never happen. + ostr.put('!'); + break; + } + return format_count; } void LLSDBinaryFormatter::formatString( - const std::string& string, - std::ostream& ostr) const + const std::string& string, + std::ostream& ostr) const { - U32 size_nbo = htonl(string.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - ostr.write(string.c_str(), string.size()); + U32 size_nbo = htonl(string.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + ostr.write(string.c_str(), string.size()); } /** @@ -1658,491 +1658,491 @@ void LLSDBinaryFormatter::formatString( */ llssize deserialize_string(std::istream& istr, std::string& value, llssize max_bytes) { - int c = istr.get(); - if(istr.fail()) - { - // No data in stream, bail out but mention the character we - // grabbed. - return LLSDParser::PARSE_FAILURE; - } - - llssize rv = LLSDParser::PARSE_FAILURE; - switch(c) - { - case '\'': - case '"': - rv = deserialize_string_delim(istr, value, c); - break; - case 's': - // technically, less than max_bytes, but this is just meant to - // catch egregious protocol errors. parse errors will be - // caught in the case of incorrect counts. - rv = deserialize_string_raw(istr, value, max_bytes); - break; - default: - break; - } - if(LLSDParser::PARSE_FAILURE == rv) return rv; - return rv + 1; // account for the character grabbed at the top. + int c = istr.get(); + if(istr.fail()) + { + // No data in stream, bail out but mention the character we + // grabbed. + return LLSDParser::PARSE_FAILURE; + } + + llssize rv = LLSDParser::PARSE_FAILURE; + switch(c) + { + case '\'': + case '"': + rv = deserialize_string_delim(istr, value, c); + break; + case 's': + // technically, less than max_bytes, but this is just meant to + // catch egregious protocol errors. parse errors will be + // caught in the case of incorrect counts. + rv = deserialize_string_raw(istr, value, max_bytes); + break; + default: + break; + } + if(LLSDParser::PARSE_FAILURE == rv) return rv; + return rv + 1; // account for the character grabbed at the top. } llssize deserialize_string_delim( - std::istream& istr, - std::string& value, - char delim) + std::istream& istr, + std::string& value, + char delim) { - std::ostringstream write_buffer; - bool found_escape = false; - bool found_hex = false; - bool found_digit = false; - U8 byte = 0; - llssize count = 0; - - while (true) - { - int next_byte = istr.get(); - ++count; - - if(istr.fail()) - { - // If our stream is empty, break out - value = write_buffer.str(); - return LLSDParser::PARSE_FAILURE; - } - - char next_char = (char)next_byte; // Now that we know it's not EOF - - if(found_escape) - { - // next character(s) is a special sequence. - if(found_hex) - { - if(found_digit) - { - found_digit = false; - found_hex = false; - found_escape = false; - byte = byte << 4; - byte |= hex_as_nybble(next_char); - write_buffer << byte; - byte = 0; - } - else - { - // next character is the first nybble of - // - found_digit = true; - byte = hex_as_nybble(next_char); - } - } - else if(next_char == 'x') - { - found_hex = true; - } - else - { - switch(next_char) - { - case 'a': - write_buffer << '\a'; - break; - case 'b': - write_buffer << '\b'; - break; - case 'f': - write_buffer << '\f'; - break; - case 'n': - write_buffer << '\n'; - break; - case 'r': - write_buffer << '\r'; - break; - case 't': - write_buffer << '\t'; - break; - case 'v': - write_buffer << '\v'; - break; - default: - write_buffer << next_char; - break; - } - found_escape = false; - } - } - else if(next_char == '\\') - { - found_escape = true; - } - else if(next_char == delim) - { - break; - } - else - { - write_buffer << next_char; - } - } - - value = write_buffer.str(); - return count; + std::ostringstream write_buffer; + bool found_escape = false; + bool found_hex = false; + bool found_digit = false; + U8 byte = 0; + llssize count = 0; + + while (true) + { + int next_byte = istr.get(); + ++count; + + if(istr.fail()) + { + // If our stream is empty, break out + value = write_buffer.str(); + return LLSDParser::PARSE_FAILURE; + } + + char next_char = (char)next_byte; // Now that we know it's not EOF + + if(found_escape) + { + // next character(s) is a special sequence. + if(found_hex) + { + if(found_digit) + { + found_digit = false; + found_hex = false; + found_escape = false; + byte = byte << 4; + byte |= hex_as_nybble(next_char); + write_buffer << byte; + byte = 0; + } + else + { + // next character is the first nybble of + // + found_digit = true; + byte = hex_as_nybble(next_char); + } + } + else if(next_char == 'x') + { + found_hex = true; + } + else + { + switch(next_char) + { + case 'a': + write_buffer << '\a'; + break; + case 'b': + write_buffer << '\b'; + break; + case 'f': + write_buffer << '\f'; + break; + case 'n': + write_buffer << '\n'; + break; + case 'r': + write_buffer << '\r'; + break; + case 't': + write_buffer << '\t'; + break; + case 'v': + write_buffer << '\v'; + break; + default: + write_buffer << next_char; + break; + } + found_escape = false; + } + } + else if(next_char == '\\') + { + found_escape = true; + } + else if(next_char == delim) + { + break; + } + else + { + write_buffer << next_char; + } + } + + value = write_buffer.str(); + return count; } llssize deserialize_string_raw( - std::istream& istr, - std::string& value, - llssize max_bytes) + std::istream& istr, + std::string& value, + llssize max_bytes) { - llssize count = 0; - const S32 BUF_LEN = 20; - char buf[BUF_LEN]; /* Flawfinder: ignore */ - istr.get(buf, BUF_LEN - 1, ')'); - count += istr.gcount(); - int c = istr.get(); - c = istr.get(); - count += 2; - if(((c == '"') || (c == '\'')) && (buf[0] == '(')) - { - // We probably have a valid raw string. determine - // the size, and read it. - // *FIX: This is memory inefficient. - auto len = strtol(buf + 1, NULL, 0); - if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; - std::vector<char> buf; - if(len) - { - buf.resize(len); - count += fullread(istr, (char *)&buf[0], len); - value.assign(buf.begin(), buf.end()); - } - c = istr.get(); - ++count; - if(!((c == '"') || (c == '\''))) - { - return LLSDParser::PARSE_FAILURE; - } - } - else - { - return LLSDParser::PARSE_FAILURE; - } - return count; + llssize count = 0; + const S32 BUF_LEN = 20; + char buf[BUF_LEN]; /* Flawfinder: ignore */ + istr.get(buf, BUF_LEN - 1, ')'); + count += istr.gcount(); + int c = istr.get(); + c = istr.get(); + count += 2; + if(((c == '"') || (c == '\'')) && (buf[0] == '(')) + { + // We probably have a valid raw string. determine + // the size, and read it. + // *FIX: This is memory inefficient. + auto len = strtol(buf + 1, NULL, 0); + if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; + std::vector<char> buf; + if(len) + { + buf.resize(len); + count += fullread(istr, (char *)&buf[0], len); + value.assign(buf.begin(), buf.end()); + } + c = istr.get(); + ++count; + if(!((c == '"') || (c == '\''))) + { + return LLSDParser::PARSE_FAILURE; + } + } + else + { + return LLSDParser::PARSE_FAILURE; + } + return count; } static const char* NOTATION_STRING_CHARACTERS[256] = { - "\\x00", // 0 - "\\x01", // 1 - "\\x02", // 2 - "\\x03", // 3 - "\\x04", // 4 - "\\x05", // 5 - "\\x06", // 6 - "\\a", // 7 - "\\b", // 8 - "\\t", // 9 - "\\n", // 10 - "\\v", // 11 - "\\f", // 12 - "\\r", // 13 - "\\x0e", // 14 - "\\x0f", // 15 - "\\x10", // 16 - "\\x11", // 17 - "\\x12", // 18 - "\\x13", // 19 - "\\x14", // 20 - "\\x15", // 21 - "\\x16", // 22 - "\\x17", // 23 - "\\x18", // 24 - "\\x19", // 25 - "\\x1a", // 26 - "\\x1b", // 27 - "\\x1c", // 28 - "\\x1d", // 29 - "\\x1e", // 30 - "\\x1f", // 31 - " ", // 32 - "!", // 33 - "\"", // 34 - "#", // 35 - "$", // 36 - "%", // 37 - "&", // 38 - "\\'", // 39 - "(", // 40 - ")", // 41 - "*", // 42 - "+", // 43 - ",", // 44 - "-", // 45 - ".", // 46 - "/", // 47 - "0", // 48 - "1", // 49 - "2", // 50 - "3", // 51 - "4", // 52 - "5", // 53 - "6", // 54 - "7", // 55 - "8", // 56 - "9", // 57 - ":", // 58 - ";", // 59 - "<", // 60 - "=", // 61 - ">", // 62 - "?", // 63 - "@", // 64 - "A", // 65 - "B", // 66 - "C", // 67 - "D", // 68 - "E", // 69 - "F", // 70 - "G", // 71 - "H", // 72 - "I", // 73 - "J", // 74 - "K", // 75 - "L", // 76 - "M", // 77 - "N", // 78 - "O", // 79 - "P", // 80 - "Q", // 81 - "R", // 82 - "S", // 83 - "T", // 84 - "U", // 85 - "V", // 86 - "W", // 87 - "X", // 88 - "Y", // 89 - "Z", // 90 - "[", // 91 - "\\\\", // 92 - "]", // 93 - "^", // 94 - "_", // 95 - "`", // 96 - "a", // 97 - "b", // 98 - "c", // 99 - "d", // 100 - "e", // 101 - "f", // 102 - "g", // 103 - "h", // 104 - "i", // 105 - "j", // 106 - "k", // 107 - "l", // 108 - "m", // 109 - "n", // 110 - "o", // 111 - "p", // 112 - "q", // 113 - "r", // 114 - "s", // 115 - "t", // 116 - "u", // 117 - "v", // 118 - "w", // 119 - "x", // 120 - "y", // 121 - "z", // 122 - "{", // 123 - "|", // 124 - "}", // 125 - "~", // 126 - "\\x7f", // 127 - "\\x80", // 128 - "\\x81", // 129 - "\\x82", // 130 - "\\x83", // 131 - "\\x84", // 132 - "\\x85", // 133 - "\\x86", // 134 - "\\x87", // 135 - "\\x88", // 136 - "\\x89", // 137 - "\\x8a", // 138 - "\\x8b", // 139 - "\\x8c", // 140 - "\\x8d", // 141 - "\\x8e", // 142 - "\\x8f", // 143 - "\\x90", // 144 - "\\x91", // 145 - "\\x92", // 146 - "\\x93", // 147 - "\\x94", // 148 - "\\x95", // 149 - "\\x96", // 150 - "\\x97", // 151 - "\\x98", // 152 - "\\x99", // 153 - "\\x9a", // 154 - "\\x9b", // 155 - "\\x9c", // 156 - "\\x9d", // 157 - "\\x9e", // 158 - "\\x9f", // 159 - "\\xa0", // 160 - "\\xa1", // 161 - "\\xa2", // 162 - "\\xa3", // 163 - "\\xa4", // 164 - "\\xa5", // 165 - "\\xa6", // 166 - "\\xa7", // 167 - "\\xa8", // 168 - "\\xa9", // 169 - "\\xaa", // 170 - "\\xab", // 171 - "\\xac", // 172 - "\\xad", // 173 - "\\xae", // 174 - "\\xaf", // 175 - "\\xb0", // 176 - "\\xb1", // 177 - "\\xb2", // 178 - "\\xb3", // 179 - "\\xb4", // 180 - "\\xb5", // 181 - "\\xb6", // 182 - "\\xb7", // 183 - "\\xb8", // 184 - "\\xb9", // 185 - "\\xba", // 186 - "\\xbb", // 187 - "\\xbc", // 188 - "\\xbd", // 189 - "\\xbe", // 190 - "\\xbf", // 191 - "\\xc0", // 192 - "\\xc1", // 193 - "\\xc2", // 194 - "\\xc3", // 195 - "\\xc4", // 196 - "\\xc5", // 197 - "\\xc6", // 198 - "\\xc7", // 199 - "\\xc8", // 200 - "\\xc9", // 201 - "\\xca", // 202 - "\\xcb", // 203 - "\\xcc", // 204 - "\\xcd", // 205 - "\\xce", // 206 - "\\xcf", // 207 - "\\xd0", // 208 - "\\xd1", // 209 - "\\xd2", // 210 - "\\xd3", // 211 - "\\xd4", // 212 - "\\xd5", // 213 - "\\xd6", // 214 - "\\xd7", // 215 - "\\xd8", // 216 - "\\xd9", // 217 - "\\xda", // 218 - "\\xdb", // 219 - "\\xdc", // 220 - "\\xdd", // 221 - "\\xde", // 222 - "\\xdf", // 223 - "\\xe0", // 224 - "\\xe1", // 225 - "\\xe2", // 226 - "\\xe3", // 227 - "\\xe4", // 228 - "\\xe5", // 229 - "\\xe6", // 230 - "\\xe7", // 231 - "\\xe8", // 232 - "\\xe9", // 233 - "\\xea", // 234 - "\\xeb", // 235 - "\\xec", // 236 - "\\xed", // 237 - "\\xee", // 238 - "\\xef", // 239 - "\\xf0", // 240 - "\\xf1", // 241 - "\\xf2", // 242 - "\\xf3", // 243 - "\\xf4", // 244 - "\\xf5", // 245 - "\\xf6", // 246 - "\\xf7", // 247 - "\\xf8", // 248 - "\\xf9", // 249 - "\\xfa", // 250 - "\\xfb", // 251 - "\\xfc", // 252 - "\\xfd", // 253 - "\\xfe", // 254 - "\\xff" // 255 + "\\x00", // 0 + "\\x01", // 1 + "\\x02", // 2 + "\\x03", // 3 + "\\x04", // 4 + "\\x05", // 5 + "\\x06", // 6 + "\\a", // 7 + "\\b", // 8 + "\\t", // 9 + "\\n", // 10 + "\\v", // 11 + "\\f", // 12 + "\\r", // 13 + "\\x0e", // 14 + "\\x0f", // 15 + "\\x10", // 16 + "\\x11", // 17 + "\\x12", // 18 + "\\x13", // 19 + "\\x14", // 20 + "\\x15", // 21 + "\\x16", // 22 + "\\x17", // 23 + "\\x18", // 24 + "\\x19", // 25 + "\\x1a", // 26 + "\\x1b", // 27 + "\\x1c", // 28 + "\\x1d", // 29 + "\\x1e", // 30 + "\\x1f", // 31 + " ", // 32 + "!", // 33 + "\"", // 34 + "#", // 35 + "$", // 36 + "%", // 37 + "&", // 38 + "\\'", // 39 + "(", // 40 + ")", // 41 + "*", // 42 + "+", // 43 + ",", // 44 + "-", // 45 + ".", // 46 + "/", // 47 + "0", // 48 + "1", // 49 + "2", // 50 + "3", // 51 + "4", // 52 + "5", // 53 + "6", // 54 + "7", // 55 + "8", // 56 + "9", // 57 + ":", // 58 + ";", // 59 + "<", // 60 + "=", // 61 + ">", // 62 + "?", // 63 + "@", // 64 + "A", // 65 + "B", // 66 + "C", // 67 + "D", // 68 + "E", // 69 + "F", // 70 + "G", // 71 + "H", // 72 + "I", // 73 + "J", // 74 + "K", // 75 + "L", // 76 + "M", // 77 + "N", // 78 + "O", // 79 + "P", // 80 + "Q", // 81 + "R", // 82 + "S", // 83 + "T", // 84 + "U", // 85 + "V", // 86 + "W", // 87 + "X", // 88 + "Y", // 89 + "Z", // 90 + "[", // 91 + "\\\\", // 92 + "]", // 93 + "^", // 94 + "_", // 95 + "`", // 96 + "a", // 97 + "b", // 98 + "c", // 99 + "d", // 100 + "e", // 101 + "f", // 102 + "g", // 103 + "h", // 104 + "i", // 105 + "j", // 106 + "k", // 107 + "l", // 108 + "m", // 109 + "n", // 110 + "o", // 111 + "p", // 112 + "q", // 113 + "r", // 114 + "s", // 115 + "t", // 116 + "u", // 117 + "v", // 118 + "w", // 119 + "x", // 120 + "y", // 121 + "z", // 122 + "{", // 123 + "|", // 124 + "}", // 125 + "~", // 126 + "\\x7f", // 127 + "\\x80", // 128 + "\\x81", // 129 + "\\x82", // 130 + "\\x83", // 131 + "\\x84", // 132 + "\\x85", // 133 + "\\x86", // 134 + "\\x87", // 135 + "\\x88", // 136 + "\\x89", // 137 + "\\x8a", // 138 + "\\x8b", // 139 + "\\x8c", // 140 + "\\x8d", // 141 + "\\x8e", // 142 + "\\x8f", // 143 + "\\x90", // 144 + "\\x91", // 145 + "\\x92", // 146 + "\\x93", // 147 + "\\x94", // 148 + "\\x95", // 149 + "\\x96", // 150 + "\\x97", // 151 + "\\x98", // 152 + "\\x99", // 153 + "\\x9a", // 154 + "\\x9b", // 155 + "\\x9c", // 156 + "\\x9d", // 157 + "\\x9e", // 158 + "\\x9f", // 159 + "\\xa0", // 160 + "\\xa1", // 161 + "\\xa2", // 162 + "\\xa3", // 163 + "\\xa4", // 164 + "\\xa5", // 165 + "\\xa6", // 166 + "\\xa7", // 167 + "\\xa8", // 168 + "\\xa9", // 169 + "\\xaa", // 170 + "\\xab", // 171 + "\\xac", // 172 + "\\xad", // 173 + "\\xae", // 174 + "\\xaf", // 175 + "\\xb0", // 176 + "\\xb1", // 177 + "\\xb2", // 178 + "\\xb3", // 179 + "\\xb4", // 180 + "\\xb5", // 181 + "\\xb6", // 182 + "\\xb7", // 183 + "\\xb8", // 184 + "\\xb9", // 185 + "\\xba", // 186 + "\\xbb", // 187 + "\\xbc", // 188 + "\\xbd", // 189 + "\\xbe", // 190 + "\\xbf", // 191 + "\\xc0", // 192 + "\\xc1", // 193 + "\\xc2", // 194 + "\\xc3", // 195 + "\\xc4", // 196 + "\\xc5", // 197 + "\\xc6", // 198 + "\\xc7", // 199 + "\\xc8", // 200 + "\\xc9", // 201 + "\\xca", // 202 + "\\xcb", // 203 + "\\xcc", // 204 + "\\xcd", // 205 + "\\xce", // 206 + "\\xcf", // 207 + "\\xd0", // 208 + "\\xd1", // 209 + "\\xd2", // 210 + "\\xd3", // 211 + "\\xd4", // 212 + "\\xd5", // 213 + "\\xd6", // 214 + "\\xd7", // 215 + "\\xd8", // 216 + "\\xd9", // 217 + "\\xda", // 218 + "\\xdb", // 219 + "\\xdc", // 220 + "\\xdd", // 221 + "\\xde", // 222 + "\\xdf", // 223 + "\\xe0", // 224 + "\\xe1", // 225 + "\\xe2", // 226 + "\\xe3", // 227 + "\\xe4", // 228 + "\\xe5", // 229 + "\\xe6", // 230 + "\\xe7", // 231 + "\\xe8", // 232 + "\\xe9", // 233 + "\\xea", // 234 + "\\xeb", // 235 + "\\xec", // 236 + "\\xed", // 237 + "\\xee", // 238 + "\\xef", // 239 + "\\xf0", // 240 + "\\xf1", // 241 + "\\xf2", // 242 + "\\xf3", // 243 + "\\xf4", // 244 + "\\xf5", // 245 + "\\xf6", // 246 + "\\xf7", // 247 + "\\xf8", // 248 + "\\xf9", // 249 + "\\xfa", // 250 + "\\xfb", // 251 + "\\xfc", // 252 + "\\xfd", // 253 + "\\xfe", // 254 + "\\xff" // 255 }; void serialize_string(const std::string& value, std::ostream& str) { - std::string::const_iterator it = value.begin(); - std::string::const_iterator end = value.end(); - U8 c; - for(; it != end; ++it) - { - c = (U8)(*it); - str << NOTATION_STRING_CHARACTERS[c]; - } + std::string::const_iterator it = value.begin(); + std::string::const_iterator end = value.end(); + U8 c; + for(; it != end; ++it) + { + c = (U8)(*it); + str << NOTATION_STRING_CHARACTERS[c]; + } } llssize deserialize_boolean( - std::istream& istr, - LLSD& data, - const std::string& compare, - bool value) + std::istream& istr, + LLSD& data, + const std::string& compare, + bool value) { - // - // this method is a little goofy, because it gets the stream at - // the point where the t or f has already been - // consumed. Basically, parse for a patch to the string passed in - // starting at index 1. If it's a match: - // * assign data to value - // * return the number of bytes read - // otherwise: - // * set data to LLSD::null - // * return LLSDParser::PARSE_FAILURE (-1) - // - llssize bytes_read = 0; - std::string::size_type ii = 0; - char c = istr.peek(); - while((++ii < compare.size()) - && (tolower(c) == (int)compare[ii]) - && istr.good()) - { - istr.ignore(); - ++bytes_read; - c = istr.peek(); - } - if(compare.size() != ii) - { - data.clear(); - return LLSDParser::PARSE_FAILURE; - } - data = value; - return bytes_read; + // + // this method is a little goofy, because it gets the stream at + // the point where the t or f has already been + // consumed. Basically, parse for a patch to the string passed in + // starting at index 1. If it's a match: + // * assign data to value + // * return the number of bytes read + // otherwise: + // * set data to LLSD::null + // * return LLSDParser::PARSE_FAILURE (-1) + // + llssize bytes_read = 0; + std::string::size_type ii = 0; + char c = istr.peek(); + while((++ii < compare.size()) + && (tolower(c) == (int)compare[ii]) + && istr.good()) + { + istr.ignore(); + ++bytes_read; + c = istr.peek(); + } + if(compare.size() != ii) + { + data.clear(); + return LLSDParser::PARSE_FAILURE; + } + data = value; + return bytes_read; } std::ostream& operator<<(std::ostream& s, const LLSD& llsd) { - s << LLSDNotationStreamer(llsd); - return s; + s << LLSDNotationStreamer(llsd); + return s; } @@ -2151,89 +2151,89 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd) //return a string containing gzipped bytes of binary serialized LLSD // VERY inefficient -- creates several copies of LLSD block in memory std::string zip_llsd(LLSD& data) -{ - std::stringstream llsd_strm; - - LLSDSerialize::toBinary(data, llsd_strm); - - const U32 CHUNK = 65536; - - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - - S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); - if (ret != Z_OK) - { - LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; - return std::string(); - } - - std::string source = llsd_strm.str(); - - U8 out[CHUNK]; - - strm.avail_in = narrow<size_t>(source.size()); - strm.next_in = (U8*) source.data(); - U8* output = NULL; - - U32 cur_size = 0; - - U32 have = 0; - - do - { - strm.avail_out = CHUNK; - strm.next_out = out; - - ret = deflate(&strm, Z_FINISH); - if (ret == Z_OK || ret == Z_STREAM_END) - { //copy result into output - if (strm.avail_out >= CHUNK) - { - deflateEnd(&strm); - if(output) - free(output); - LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; - return std::string(); - } - - have = CHUNK-strm.avail_out; - U8* new_output = (U8*) realloc(output, cur_size+have); - if (new_output == NULL) - { - LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; - deflateEnd(&strm); - if (output) - { - free(output); - } - return std::string(); - } - output = new_output; - memcpy(output+cur_size, out, have); - cur_size += have; - } - else - { - deflateEnd(&strm); - if(output) - free(output); - LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; - return std::string(); - } - } - while (ret == Z_OK); - - std::string::size_type size = cur_size; - - std::string result((char*) output, size); - deflateEnd(&strm); - if(output) - free(output); - - return result; +{ + std::stringstream llsd_strm; + + LLSDSerialize::toBinary(data, llsd_strm); + + const U32 CHUNK = 65536; + + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); + if (ret != Z_OK) + { + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; + return std::string(); + } + + std::string source = llsd_strm.str(); + + U8 out[CHUNK]; + + strm.avail_in = narrow<size_t>(source.size()); + strm.next_in = (U8*) source.data(); + U8* output = NULL; + + U32 cur_size = 0; + + U32 have = 0; + + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + + ret = deflate(&strm, Z_FINISH); + if (ret == Z_OK || ret == Z_STREAM_END) + { //copy result into output + if (strm.avail_out >= CHUNK) + { + deflateEnd(&strm); + if(output) + free(output); + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; + return std::string(); + } + + have = CHUNK-strm.avail_out; + U8* new_output = (U8*) realloc(output, cur_size+have); + if (new_output == NULL) + { + LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + deflateEnd(&strm); + if (output) + { + free(output); + } + return std::string(); + } + output = new_output; + memcpy(output+cur_size, out, have); + cur_size += have; + } + else + { + deflateEnd(&strm); + if(output) + free(output); + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; + return std::string(); + } + } + while (ret == Z_OK); + + std::string::size_type size = cur_size; + + std::string result((char*) output, size); + deflateEnd(&strm); + if(output) + free(output); + + return result; } //decompress a block of LLSD from provided istream @@ -2241,230 +2241,230 @@ std::string zip_llsd(LLSD& data) // and deserializes from that copy using LLSDSerialize LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size) { - std::unique_ptr<U8[]> in = std::unique_ptr<U8[]>(new(std::nothrow) U8[size]); - if (!in) - { - return ZR_MEM_ERROR; - } - is.read((char*) in.get(), size); - - return unzip_llsd(data, in.get(), size); + std::unique_ptr<U8[]> in = std::unique_ptr<U8[]>(new(std::nothrow) U8[size]); + if (!in) + { + return ZR_MEM_ERROR; + } + is.read((char*) in.get(), size); + + return unzip_llsd(data, in.get(), size); } LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size) { - U8* result = NULL; - llssize cur_size = 0; - z_stream strm; - - constexpr U32 CHUNK = 1024 * 512; - - static thread_local std::unique_ptr<U8[]> out; - if (!out) - { - out = std::unique_ptr<U8[]>(new(std::nothrow) U8[CHUNK]); - } - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = size; - strm.next_in = const_cast<U8*>(in); - - S32 ret = inflateInit(&strm); - - do - { - strm.avail_out = CHUNK; - strm.next_out = out.get(); - ret = inflate(&strm, Z_NO_FLUSH); - switch (ret) - { - case Z_NEED_DICT: - case Z_DATA_ERROR: - { - inflateEnd(&strm); - free(result); - return ZR_DATA_ERROR; - } - case Z_STREAM_ERROR: - case Z_BUF_ERROR: - { - inflateEnd(&strm); - free(result); - return ZR_BUFFER_ERROR; - } - - case Z_MEM_ERROR: - { - inflateEnd(&strm); - free(result); - return ZR_MEM_ERROR; - } - } - - U32 have = CHUNK-strm.avail_out; - - U8* new_result = (U8*)realloc(result, cur_size + have); - if (new_result == NULL) - { - inflateEnd(&strm); - if (result) - { - free(result); - } - return ZR_MEM_ERROR; - } - result = new_result; - memcpy(result+cur_size, out.get(), have); - cur_size += have; - - } while (ret == Z_OK && ret != Z_STREAM_END); - - inflateEnd(&strm); - - if (ret != Z_STREAM_END) - { - free(result); - return ZR_DATA_ERROR; - } - - //result now points to the decompressed LLSD block - { - char* result_ptr = strip_deprecated_header((char*)result, cur_size); - - boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size); - - if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH)) - { - free(result); - return ZR_PARSE_ERROR; - } - } - - free(result); - return ZR_OK; + U8* result = NULL; + llssize cur_size = 0; + z_stream strm; + + constexpr U32 CHUNK = 1024 * 512; + + static thread_local std::unique_ptr<U8[]> out; + if (!out) + { + out = std::unique_ptr<U8[]>(new(std::nothrow) U8[CHUNK]); + } + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = const_cast<U8*>(in); + + S32 ret = inflateInit(&strm); + + do + { + strm.avail_out = CHUNK; + strm.next_out = out.get(); + ret = inflate(&strm, Z_NO_FLUSH); + switch (ret) + { + case Z_NEED_DICT: + case Z_DATA_ERROR: + { + inflateEnd(&strm); + free(result); + return ZR_DATA_ERROR; + } + case Z_STREAM_ERROR: + case Z_BUF_ERROR: + { + inflateEnd(&strm); + free(result); + return ZR_BUFFER_ERROR; + } + + case Z_MEM_ERROR: + { + inflateEnd(&strm); + free(result); + return ZR_MEM_ERROR; + } + } + + U32 have = CHUNK-strm.avail_out; + + U8* new_result = (U8*)realloc(result, cur_size + have); + if (new_result == NULL) + { + inflateEnd(&strm); + if (result) + { + free(result); + } + return ZR_MEM_ERROR; + } + result = new_result; + memcpy(result+cur_size, out.get(), have); + cur_size += have; + + } while (ret == Z_OK && ret != Z_STREAM_END); + + inflateEnd(&strm); + + if (ret != Z_STREAM_END) + { + free(result); + return ZR_DATA_ERROR; + } + + //result now points to the decompressed LLSD block + { + char* result_ptr = strip_deprecated_header((char*)result, cur_size); + + boost::iostreams::stream<boost::iostreams::array_source> istrm(result_ptr, cur_size); + + if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH)) + { + free(result); + return ZR_PARSE_ERROR; + } + } + + free(result); + return ZR_OK; } //This unzip function will only work with a gzip header and trailer - while the contents //of the actual compressed data is the same for either format (gzip vs zlib ), the headers //and trailers are different for the formats. U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size ) { - if (size == 0) - { - LL_WARNS() << "No data to unzip." << LL_ENDL; - return NULL; - } - - U8* result = NULL; - U32 cur_size = 0; - z_stream strm; - - const U32 CHUNK = 0x4000; - - U8 *in = new(std::nothrow) U8[size]; - if (in == NULL) - { - LL_WARNS() << "Memory allocation failure." << LL_ENDL; - return NULL; - } - is.read((char*) in, size); - - U8 out[CHUNK]; - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = size; - strm.next_in = in; - - - S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP ); - do - { - strm.avail_out = CHUNK; - strm.next_out = out; - ret = inflate(&strm, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR) - { - inflateEnd(&strm); - free(result); - delete [] in; - valid = false; - } - - switch (ret) - { - case Z_NEED_DICT: - ret = Z_DATA_ERROR; - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&strm); - free(result); - delete [] in; - valid = false; - break; - } - - U32 have = CHUNK-strm.avail_out; - - U8* new_result = (U8*) realloc(result, cur_size + have); - if (new_result == NULL) - { - LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size - << " bytes; requested " << cur_size + have - << " bytes; total syze: ." << size << " bytes." - << LL_ENDL; - inflateEnd(&strm); - if (result) - { - free(result); - } - delete[] in; - valid = false; - return NULL; - } - result = new_result; - memcpy(result+cur_size, out, have); - cur_size += have; - - } while (ret == Z_OK); - - inflateEnd(&strm); - delete [] in; - - if (ret != Z_STREAM_END) - { - free(result); - valid = false; - return NULL; - } - - //result now points to the decompressed LLSD block - { - outsize= cur_size; - valid = true; - } - - return result; + if (size == 0) + { + LL_WARNS() << "No data to unzip." << LL_ENDL; + return NULL; + } + + U8* result = NULL; + U32 cur_size = 0; + z_stream strm; + + const U32 CHUNK = 0x4000; + + U8 *in = new(std::nothrow) U8[size]; + if (in == NULL) + { + LL_WARNS() << "Memory allocation failure." << LL_ENDL; + return NULL; + } + is.read((char*) in, size); + + U8 out[CHUNK]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = in; + + + S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP ); + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR) + { + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + } + + switch (ret) + { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + break; + } + + U32 have = CHUNK-strm.avail_out; + + U8* new_result = (U8*) realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size + << " bytes; requested " << cur_size + have + << " bytes; total syze: ." << size << " bytes." + << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete[] in; + valid = false; + return NULL; + } + result = new_result; + memcpy(result+cur_size, out, have); + cur_size += have; + + } while (ret == Z_OK); + + inflateEnd(&strm); + delete [] in; + + if (ret != Z_STREAM_END) + { + free(result); + valid = false; + return NULL; + } + + //result now points to the decompressed LLSD block + { + outsize= cur_size; + valid = true; + } + + return result; } char* strip_deprecated_header(char* in, llssize& cur_size, llssize* header_size) { - const char* deprecated_header = "<? LLSD/Binary ?>"; - constexpr size_t deprecated_header_size = 17; - - if (cur_size > deprecated_header_size - && memcmp(in, deprecated_header, deprecated_header_size) == 0) - { - in = in + deprecated_header_size; - cur_size = cur_size - deprecated_header_size; - if (header_size) - { - *header_size = deprecated_header_size + 1; - } - } - - return in; + const char* deprecated_header = "<? LLSD/Binary ?>"; + constexpr size_t deprecated_header_size = 17; + + if (cur_size > deprecated_header_size + && memcmp(in, deprecated_header, deprecated_header_size) == 0) + { + in = in + deprecated_header_size; + cur_size = cur_size - deprecated_header_size; + if (header_size) + { + *header_size = deprecated_header_size + 1; + } + } + + return in; } diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 676b7bfd6a..12dd3c96ec 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize.h * @author Phoenix * @date 2006-02-26 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,574 +34,574 @@ #include "llrefcount.h" #include "llsd.h" -/** +/** * @class LLSDParser * @brief Abstract base class for LLSD parsers. */ class LL_COMMON_API LLSDParser : public LLRefCount { protected: - /** - * @brief Destructor - */ - virtual ~LLSDParser(); + /** + * @brief Destructor + */ + virtual ~LLSDParser(); public: - /** - * @brief Anonymous enum to indicate parsing failure. - */ - enum - { - PARSE_FAILURE = -1 - }; - - /** - * @brief Constructor - */ - LLSDParser(); - - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_bytes The maximum number of bytes that will be in - * the stream. Pass in LLSDSerialize::SIZE_UNLIMITED (-1) to set no - * byte limit. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - S32 parse(std::istream& istr, LLSD& data, llssize max_bytes, S32 max_depth = -1); - - /** Like parse(), but uses a different call (istream.getline()) to read by lines - * This API is better suited for XML, where the parse cannot tell - * where the document actually ends. - */ - S32 parseLines(std::istream& istr, LLSD& data); - - /** - * @brief Resets the parser so parse() or parseLines() can be called again for another <llsd> chunk. - */ - void reset() { doReset(); }; + /** + * @brief Anonymous enum to indicate parsing failure. + */ + enum + { + PARSE_FAILURE = -1 + }; + + /** + * @brief Constructor + */ + LLSDParser(); + + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_bytes The maximum number of bytes that will be in + * the stream. Pass in LLSDSerialize::SIZE_UNLIMITED (-1) to set no + * byte limit. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + S32 parse(std::istream& istr, LLSD& data, llssize max_bytes, S32 max_depth = -1); + + /** Like parse(), but uses a different call (istream.getline()) to read by lines + * This API is better suited for XML, where the parse cannot tell + * where the document actually ends. + */ + S32 parseLines(std::istream& istr, LLSD& data); + + /** + * @brief Resets the parser so parse() or parseLines() can be called again for another <llsd> chunk. + */ + void reset() { doReset(); }; protected: - /** - * @brief Pure virtual base for doing the parse. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const = 0; - - /** - * @brief Virtual default function for resetting the parser - */ - virtual void doReset() {}; - - /* @name Simple istream helper methods - * - * These helper methods exist to help correctly use the - * mMaxBytesLeft without really thinking about it for most simple - * operations. Use of the streamtools in llstreamtools.h will - * require custom wrapping. - */ - //@{ - /** - * @brief get a byte off the stream - * - * @param istr The istream to work with. - * @return returns the next character. - */ - int get(std::istream& istr) const; - - /** - * @brief get several bytes off the stream into a buffer. - * - * @param istr The istream to work with. - * @param s The buffer to get into - * @param n Extract maximum of n-1 bytes and null temrinate. - * @param delim Delimiter to get until found. - * @return Returns istr. - */ - std::istream& get( - std::istream& istr, - char* s, - std::streamsize n, - char delim) const; - - /** - * @brief get several bytes off the stream into a streambuf - * - * @param istr The istream to work with. - * @param sb The streambuf to read into - * @param delim Delimiter to get until found. - * @return Returns istr. - */ - std::istream& get( - std::istream& istr, - std::streambuf& sb, - char delim) const; - - /** - * @brief ignore the next byte on the istream - * - * @param istr The istream to work with. - * @return Returns istr. - */ - std::istream& ignore(std::istream& istr) const; - - /** - * @brief put the last character retrieved back on the stream - * - * @param istr The istream to work with. - * @param c The character to put back - * @return Returns istr. - */ - std::istream& putback(std::istream& istr, char c) const; - - /** - * @brief read a block of n characters into a buffer - * - * @param istr The istream to work with. - * @param s The buffer to read into - * @param n The number of bytes to read. - * @return Returns istr. - */ - std::istream& read(std::istream& istr, char* s, std::streamsize n) const; - //@} + /** + * @brief Pure virtual base for doing the parse. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const = 0; + + /** + * @brief Virtual default function for resetting the parser + */ + virtual void doReset() {}; + + /* @name Simple istream helper methods + * + * These helper methods exist to help correctly use the + * mMaxBytesLeft without really thinking about it for most simple + * operations. Use of the streamtools in llstreamtools.h will + * require custom wrapping. + */ + //@{ + /** + * @brief get a byte off the stream + * + * @param istr The istream to work with. + * @return returns the next character. + */ + int get(std::istream& istr) const; + + /** + * @brief get several bytes off the stream into a buffer. + * + * @param istr The istream to work with. + * @param s The buffer to get into + * @param n Extract maximum of n-1 bytes and null temrinate. + * @param delim Delimiter to get until found. + * @return Returns istr. + */ + std::istream& get( + std::istream& istr, + char* s, + std::streamsize n, + char delim) const; + + /** + * @brief get several bytes off the stream into a streambuf + * + * @param istr The istream to work with. + * @param sb The streambuf to read into + * @param delim Delimiter to get until found. + * @return Returns istr. + */ + std::istream& get( + std::istream& istr, + std::streambuf& sb, + char delim) const; + + /** + * @brief ignore the next byte on the istream + * + * @param istr The istream to work with. + * @return Returns istr. + */ + std::istream& ignore(std::istream& istr) const; + + /** + * @brief put the last character retrieved back on the stream + * + * @param istr The istream to work with. + * @param c The character to put back + * @return Returns istr. + */ + std::istream& putback(std::istream& istr, char c) const; + + /** + * @brief read a block of n characters into a buffer + * + * @param istr The istream to work with. + * @param s The buffer to read into + * @param n The number of bytes to read. + * @return Returns istr. + */ + std::istream& read(std::istream& istr, char* s, std::streamsize n) const; + //@} protected: - /** - * @brief Accunt for bytes read outside of the istream helpers. - * - * Conceptually const since it only modifies mutable members. - * @param bytes The number of bytes read. - */ - void account(llssize bytes) const; + /** + * @brief Accunt for bytes read outside of the istream helpers. + * + * Conceptually const since it only modifies mutable members. + * @param bytes The number of bytes read. + */ + void account(llssize bytes) const; protected: - /** - * @brief boolean to set if byte counts should be checked during parsing. - */ - bool mCheckLimits; - - /** - * @brief The maximum number of bytes left to be parsed. - */ - mutable llssize mMaxBytesLeft; - - /** - * @brief Use line-based reading to get text - */ - bool mParseLines; + /** + * @brief boolean to set if byte counts should be checked during parsing. + */ + bool mCheckLimits; + + /** + * @brief The maximum number of bytes left to be parsed. + */ + mutable llssize mMaxBytesLeft; + + /** + * @brief Use line-based reading to get text + */ + bool mParseLines; }; -/** +/** * @class LLSDNotationParser * @brief Parser which handles the original notation format for LLSD. */ class LL_COMMON_API LLSDNotationParser : public LLSDParser { protected: - /** - * @brief Destructor - */ - virtual ~LLSDNotationParser(); + /** + * @brief Destructor + */ + virtual ~LLSDNotationParser(); public: - /** - * @brief Constructor - */ - LLSDNotationParser(); + /** + * @brief Constructor + */ + LLSDNotationParser(); protected: - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. Undefined on failure. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. Undefined on failure. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; private: - /** - * @brief Parse a map from the istream - * - * @param istr The input stream. - * @param map The map to add the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; - - /** - * @brief Parse an array from the istream. - * - * @param istr The input stream. - * @param array The array to append the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; - - /** - * @brief Parse a string from the istream and assign it to data. - * - * @param istr The input stream. - * @param data[out] The data to assign. - * @return Retuns true if a complete string was parsed. - */ - bool parseString(std::istream& istr, LLSD& data) const; - - /** - * @brief Parse binary data from the stream. - * - * @param istr The input stream. - * @param data[out] The data to assign. - * @return Retuns true if a complete blob was parsed. - */ - bool parseBinary(std::istream& istr, LLSD& data) const; + /** + * @brief Parse a map from the istream + * + * @param istr The input stream. + * @param map The map to add the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; + + /** + * @brief Parse an array from the istream. + * + * @param istr The input stream. + * @param array The array to append the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; + + /** + * @brief Parse a string from the istream and assign it to data. + * + * @param istr The input stream. + * @param data[out] The data to assign. + * @return Retuns true if a complete string was parsed. + */ + bool parseString(std::istream& istr, LLSD& data) const; + + /** + * @brief Parse binary data from the stream. + * + * @param istr The input stream. + * @param data[out] The data to assign. + * @return Retuns true if a complete blob was parsed. + */ + bool parseBinary(std::istream& istr, LLSD& data) const; }; -/** +/** * @class LLSDXMLParser * @brief Parser which handles XML format LLSD. */ class LL_COMMON_API LLSDXMLParser : public LLSDParser { protected: - /** - * @brief Destructor - */ - virtual ~LLSDXMLParser(); + /** + * @brief Destructor + */ + virtual ~LLSDXMLParser(); public: - /** - * @brief Constructor - */ - LLSDXMLParser(bool emit_errors=true); + /** + * @brief Constructor + */ + LLSDXMLParser(bool emit_errors=true); protected: - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; - - /** - * @brief Virtual default function for resetting the parser - */ - virtual void doReset(); + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; + + /** + * @brief Virtual default function for resetting the parser + */ + virtual void doReset(); private: - class Impl; - Impl& impl; + class Impl; + Impl& impl; - void parsePart(const char* buf, llssize len); - friend class LLSDSerialize; + void parsePart(const char* buf, llssize len); + friend class LLSDSerialize; }; -/** +/** * @class LLSDBinaryParser * @brief Parser which handles binary formatted LLSD. */ class LL_COMMON_API LLSDBinaryParser : public LLSDParser { protected: - /** - * @brief Destructor - */ - virtual ~LLSDBinaryParser(); + /** + * @brief Destructor + */ + virtual ~LLSDBinaryParser(); public: - /** - * @brief Constructor - */ - LLSDBinaryParser(); + /** + * @brief Constructor + */ + LLSDBinaryParser(); protected: - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns -1 on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns -1 on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; private: - /** - * @brief Parse a map from the istream - * - * @param istr The input stream. - * @param map The map to add the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; - - /** - * @brief Parse an array from the istream. - * - * @param istr The input stream. - * @param array The array to append the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; - - /** - * @brief Parse a string from the istream and assign it to data. - * - * @param istr The input stream. - * @param value[out] The string to assign. - * @return Retuns true if a complete string was parsed. - */ - bool parseString(std::istream& istr, std::string& value) const; + /** + * @brief Parse a map from the istream + * + * @param istr The input stream. + * @param map The map to add the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; + + /** + * @brief Parse an array from the istream. + * + * @param istr The input stream. + * @param array The array to append the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; + + /** + * @brief Parse a string from the istream and assign it to data. + * + * @param istr The input stream. + * @param value[out] The string to assign. + * @return Retuns true if a complete string was parsed. + */ + bool parseString(std::istream& istr, std::string& value) const; }; -/** +/** * @class LLSDFormatter * @brief Abstract base class for formatting LLSD. */ class LL_COMMON_API LLSDFormatter : public LLRefCount { protected: - /** - * @brief Destructor - */ - virtual ~LLSDFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDFormatter(); public: - /** - * Options for output - */ - typedef enum e_formatter_options_type - { - OPTIONS_NONE = 0, - OPTIONS_PRETTY = 1, - OPTIONS_PRETTY_BINARY = 2 - } EFormatterOptions; - - /** - * @brief Constructor - */ - LLSDFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); - - /** - * @brief Set the boolean serialization format. - * - * @param alpha Serializes boolean as alpha if true. - */ - void boolalpha(bool alpha); - - /** - * @brief Set the real format - * - * By default, the formatter will use default double serialization - * which is frequently frustrating for many applications. You can - * set the precision on the stream independently, but that still - * might not work depending on the value. - * EXAMPLES:<br> - * %.2f<br> - * @param format A format string which follows the printf format - * rules. Specify an empty string to return to default formatting. - */ - void realFormat(const std::string& format); - - /** - * @brief Call this method to format an LLSD to a stream with options as - * set by the constructor. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format(const LLSD& data, std::ostream& ostr) const; - - /** - * @brief Call this method to format an LLSD to a stream, passing options - * explicitly. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @param options OPTIONS_NONE to emit LLSD::Binary as raw bytes - * @return Returns The number of LLSD objects formatted out - */ - virtual S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const; + /** + * Options for output + */ + typedef enum e_formatter_options_type + { + OPTIONS_NONE = 0, + OPTIONS_PRETTY = 1, + OPTIONS_PRETTY_BINARY = 2 + } EFormatterOptions; + + /** + * @brief Constructor + */ + LLSDFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); + + /** + * @brief Set the boolean serialization format. + * + * @param alpha Serializes boolean as alpha if true. + */ + void boolalpha(bool alpha); + + /** + * @brief Set the real format + * + * By default, the formatter will use default double serialization + * which is frequently frustrating for many applications. You can + * set the precision on the stream independently, but that still + * might not work depending on the value. + * EXAMPLES:<br> + * %.2f<br> + * @param format A format string which follows the printf format + * rules. Specify an empty string to return to default formatting. + */ + void realFormat(const std::string& format); + + /** + * @brief Call this method to format an LLSD to a stream with options as + * set by the constructor. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format(const LLSD& data, std::ostream& ostr) const; + + /** + * @brief Call this method to format an LLSD to a stream, passing options + * explicitly. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @param options OPTIONS_NONE to emit LLSD::Binary as raw bytes + * @return Returns The number of LLSD objects formatted out + */ + virtual S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const; protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - virtual S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const = 0; - - /** - * @brief Helper method which appropriately obeys the real format. - * - * @param real The real value to format. - * @param ostr The destination stream for the data. - */ - void formatReal(LLSD::Real real, std::ostream& ostr) const; - - bool mBoolAlpha; - std::string mRealFormat; - EFormatterOptions mOptions; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + virtual S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const = 0; + + /** + * @brief Helper method which appropriately obeys the real format. + * + * @param real The real value to format. + * @param ostr The destination stream for the data. + */ + void formatReal(LLSD::Real real, std::ostream& ostr) const; + + bool mBoolAlpha; + std::string mRealFormat; + EFormatterOptions mOptions; }; -/** +/** * @class LLSDNotationFormatter * @brief Formatter which outputs the original notation format for LLSD. */ class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter { protected: - /** - * @brief Destructor - */ - virtual ~LLSDNotationFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDNotationFormatter(); public: - /** - * @brief Constructor - */ - LLSDNotationFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); - - /** - * @brief Helper static method to return a notation escaped string - * - * This method will return the notation escaped string, but not - * the surrounding serialization identifiers such as a double or - * single quote. It will be up to the caller to embed those as - * appropriate. - * @param in The raw, unescaped string. - * @return Returns an escaped string appropriate for serialization. - */ - static std::string escapeString(const std::string& in); + /** + * @brief Constructor + */ + LLSDNotationFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); + + /** + * @brief Helper static method to return a notation escaped string + * + * This method will return the notation escaped string, but not + * the surrounding serialization identifiers such as a double or + * single quote. It will be up to the caller to embed those as + * appropriate. + * @param in The raw, unescaped string. + * @return Returns an escaped string appropriate for serialization. + */ + static std::string escapeString(const std::string& in); protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const override; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; }; -/** +/** * @class LLSDXMLFormatter * @brief Formatter which outputs the LLSD as XML. */ class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter { protected: - /** - * @brief Destructor - */ - virtual ~LLSDXMLFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDXMLFormatter(); public: - /** - * @brief Constructor - */ - LLSDXMLFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); - - /** - * @brief Helper static method to return an xml escaped string - * - * @param in A valid UTF-8 string. - * @return Returns an escaped string appropriate for serialization. - */ - static std::string escapeString(const std::string& in); - - /** - * @brief Call this method to format an LLSD to a stream. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const override; - - // also pull down base-class format() method that isn't overridden - using LLSDFormatter::format; + /** + * @brief Constructor + */ + LLSDXMLFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); + + /** + * @brief Helper static method to return an xml escaped string + * + * @param in A valid UTF-8 string. + * @return Returns an escaped string appropriate for serialization. + */ + static std::string escapeString(const std::string& in); + + /** + * @brief Call this method to format an LLSD to a stream. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const override; + + // also pull down base-class format() method that isn't overridden + using LLSDFormatter::format; protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const override; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; }; -/** +/** * @class LLSDBinaryFormatter * @brief Formatter which outputs the LLSD as a binary notation format. * @@ -628,42 +628,42 @@ protected: class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter { protected: - /** - * @brief Destructor - */ - virtual ~LLSDBinaryFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDBinaryFormatter(); public: - /** - * @brief Constructor - */ - LLSDBinaryFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); + /** + * @brief Constructor + */ + LLSDBinaryFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const override; - - /** - * @brief Helper method to serialize strings - * - * This method serializes a network byte order size and the raw - * string contents. - * @param string The string to write. - * @param ostr The destination stream for the data. - */ - void formatString(const std::string& string, std::ostream& ostr) const; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; + + /** + * @brief Helper method to serialize strings + * + * This method serializes a network byte order size and the raw + * string contents. + * @param string The string to write. + * @param ostr The destination stream for the data. + */ + void formatString(const std::string& string, std::ostream& ostr) const; }; -/** +/** * @class LLSDNotationStreamFormatter * @brief Formatter which is specialized for use on streams which * outputs the original notation format for LLSD. @@ -674,7 +674,7 @@ protected: * LLSD sd;<br> * sd["foo"] = "bar";<br> * std::stringstream params;<br> - * params << "[{'version':i1}," << LLSDOStreamer<LLSDNotationFormatter>(sd) + * params << "[{'version':i1}," << LLSDOStreamer<LLSDNotationFormatter>(sd) * << "]"; * </code> * @@ -687,165 +687,165 @@ template <class Formatter> class LLSDOStreamer { public: - /** - * @brief Constructor - */ - LLSDOStreamer(const LLSD& data, - LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY) : - mSD(data), mOptions(options) {} - - /** - * @brief Stream operator. - * - * Use this inline during construction during a stream operation. - * @param str The destination stream for serialized output. - * @param The formatter which will output it's LLSD. - * @return Returns the stream passed in after streaming mSD. - */ - friend std::ostream& operator<<( - std::ostream& out, - const LLSDOStreamer<Formatter>& streamer) - { - LLPointer<Formatter> f = new Formatter; - f->format(streamer.mSD, out, streamer.mOptions); - return out; - } + /** + * @brief Constructor + */ + LLSDOStreamer(const LLSD& data, + LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY) : + mSD(data), mOptions(options) {} + + /** + * @brief Stream operator. + * + * Use this inline during construction during a stream operation. + * @param str The destination stream for serialized output. + * @param The formatter which will output it's LLSD. + * @return Returns the stream passed in after streaming mSD. + */ + friend std::ostream& operator<<( + std::ostream& out, + const LLSDOStreamer<Formatter>& streamer) + { + LLPointer<Formatter> f = new Formatter; + f->format(streamer.mSD, out, streamer.mOptions); + return out; + } protected: - LLSD mSD; - LLSDFormatter::EFormatterOptions mOptions; + LLSD mSD; + LLSDFormatter::EFormatterOptions mOptions; }; -typedef LLSDOStreamer<LLSDNotationFormatter> LLSDNotationStreamer; -typedef LLSDOStreamer<LLSDXMLFormatter> LLSDXMLStreamer; +typedef LLSDOStreamer<LLSDNotationFormatter> LLSDNotationStreamer; +typedef LLSDOStreamer<LLSDXMLFormatter> LLSDXMLStreamer; -/** +/** * @class LLSDSerialize * @brief Serializer / deserializer for the various LLSD formats */ class LL_COMMON_API LLSDSerialize { public: - enum ELLSD_Serialize - { + enum ELLSD_Serialize + { LLSD_BINARY, LLSD_XML, LLSD_NOTATION - }; - - /** - * @brief anonymouse enumeration for useful max_bytes constants. - */ - enum - { - // Setting an unlimited size is discouraged and should only be - // used when reading cin or another stream source which does - // not provide access to size. - SIZE_UNLIMITED = -1, - }; - - /* - * Generic in/outs - */ - static void serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize, - LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY); - - /** - * @brief Examine a stream, and parse 1 sd object out based on contents. - * - * @param sd [out] The data found on the stream - * @param str The incoming stream - * @param max_bytes the maximum number of bytes to parse - * @return Returns true if the stream appears to contain valid data - */ - static bool deserialize(LLSD& sd, std::istream& str, llssize max_bytes); - - /* - * Notation Methods - */ - static S32 toNotation(const LLSD& sd, std::ostream& str) - { - LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); - } - static S32 toPrettyNotation(const LLSD& sd, std::ostream& str) - { - LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); - } - static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) - { - LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; - return f->format(sd, str, - LLSDFormatter::EFormatterOptions(LLSDFormatter::OPTIONS_PRETTY | - LLSDFormatter::OPTIONS_PRETTY_BINARY)); - } - static S32 fromNotation(LLSD& sd, std::istream& str, llssize max_bytes) - { - LLPointer<LLSDNotationParser> p = new LLSDNotationParser; - return p->parse(str, sd, max_bytes); - } - static LLSD fromNotation(std::istream& str, llssize max_bytes) - { - LLPointer<LLSDNotationParser> p = new LLSDNotationParser; - LLSD sd; - (void)p->parse(str, sd, max_bytes); - return sd; - } - - /* - * XML Methods - */ - static S32 toXML(const LLSD& sd, std::ostream& str) - { - LLPointer<LLSDXMLFormatter> f = new LLSDXMLFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); - } - static S32 toPrettyXML(const LLSD& sd, std::ostream& str) - { - LLPointer<LLSDXMLFormatter> f = new LLSDXMLFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); - } - - static S32 fromXMLEmbedded(LLSD& sd, std::istream& str, bool emit_errors=true) - { - // no need for max_bytes since xml formatting is not - // subvertable by bad sizes. - LLPointer<LLSDXMLParser> p = new LLSDXMLParser(emit_errors); - return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED); - } - // Line oriented parser, 30% faster than fromXML(), but can - // only be used when you know you have the complete XML - // document available in the stream. - static S32 fromXMLDocument(LLSD& sd, std::istream& str, bool emit_errors=true) - { - LLPointer<LLSDXMLParser> p = new LLSDXMLParser(emit_errors); - return p->parseLines(str, sd); - } - static S32 fromXML(LLSD& sd, std::istream& str, bool emit_errors=true) - { - return fromXMLEmbedded(sd, str, emit_errors); -// return fromXMLDocument(sd, str, emit_errors); - } - - /* - * Binary Methods - */ - static S32 toBinary(const LLSD& sd, std::ostream& str) - { - LLPointer<LLSDBinaryFormatter> f = new LLSDBinaryFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); - } - static S32 fromBinary(LLSD& sd, std::istream& str, llssize max_bytes, S32 max_depth = -1) - { - LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser; - return p->parse(str, sd, max_bytes, max_depth); - } - static LLSD fromBinary(std::istream& str, llssize max_bytes, S32 max_depth = -1) - { - LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser; - LLSD sd; - (void)p->parse(str, sd, max_bytes, max_depth); - return sd; - } + }; + + /** + * @brief anonymouse enumeration for useful max_bytes constants. + */ + enum + { + // Setting an unlimited size is discouraged and should only be + // used when reading cin or another stream source which does + // not provide access to size. + SIZE_UNLIMITED = -1, + }; + + /* + * Generic in/outs + */ + static void serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize, + LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY); + + /** + * @brief Examine a stream, and parse 1 sd object out based on contents. + * + * @param sd [out] The data found on the stream + * @param str The incoming stream + * @param max_bytes the maximum number of bytes to parse + * @return Returns true if the stream appears to contain valid data + */ + static bool deserialize(LLSD& sd, std::istream& str, llssize max_bytes); + + /* + * Notation Methods + */ + static S32 toNotation(const LLSD& sd, std::ostream& str) + { + LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); + } + static S32 toPrettyNotation(const LLSD& sd, std::ostream& str) + { + LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); + } + static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) + { + LLPointer<LLSDNotationFormatter> f = new LLSDNotationFormatter; + return f->format(sd, str, + LLSDFormatter::EFormatterOptions(LLSDFormatter::OPTIONS_PRETTY | + LLSDFormatter::OPTIONS_PRETTY_BINARY)); + } + static S32 fromNotation(LLSD& sd, std::istream& str, llssize max_bytes) + { + LLPointer<LLSDNotationParser> p = new LLSDNotationParser; + return p->parse(str, sd, max_bytes); + } + static LLSD fromNotation(std::istream& str, llssize max_bytes) + { + LLPointer<LLSDNotationParser> p = new LLSDNotationParser; + LLSD sd; + (void)p->parse(str, sd, max_bytes); + return sd; + } + + /* + * XML Methods + */ + static S32 toXML(const LLSD& sd, std::ostream& str) + { + LLPointer<LLSDXMLFormatter> f = new LLSDXMLFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); + } + static S32 toPrettyXML(const LLSD& sd, std::ostream& str) + { + LLPointer<LLSDXMLFormatter> f = new LLSDXMLFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); + } + + static S32 fromXMLEmbedded(LLSD& sd, std::istream& str, bool emit_errors=true) + { + // no need for max_bytes since xml formatting is not + // subvertable by bad sizes. + LLPointer<LLSDXMLParser> p = new LLSDXMLParser(emit_errors); + return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED); + } + // Line oriented parser, 30% faster than fromXML(), but can + // only be used when you know you have the complete XML + // document available in the stream. + static S32 fromXMLDocument(LLSD& sd, std::istream& str, bool emit_errors=true) + { + LLPointer<LLSDXMLParser> p = new LLSDXMLParser(emit_errors); + return p->parseLines(str, sd); + } + static S32 fromXML(LLSD& sd, std::istream& str, bool emit_errors=true) + { + return fromXMLEmbedded(sd, str, emit_errors); +// return fromXMLDocument(sd, str, emit_errors); + } + + /* + * Binary Methods + */ + static S32 toBinary(const LLSD& sd, std::ostream& str) + { + LLPointer<LLSDBinaryFormatter> f = new LLSDBinaryFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); + } + static S32 fromBinary(LLSD& sd, std::istream& str, llssize max_bytes, S32 max_depth = -1) + { + LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser; + return p->parse(str, sd, max_bytes, max_depth); + } + static LLSD fromBinary(std::istream& str, llssize max_bytes, S32 max_depth = -1) + { + LLPointer<LLSDBinaryParser> p = new LLSDBinaryParser; + LLSD sd; + (void)p->parse(str, sd, max_bytes, max_depth); + return sd; + } }; class LL_COMMON_API LLUZipHelper : public LLRefCount @@ -858,12 +858,12 @@ public: ZR_SIZE_ERROR, ZR_DATA_ERROR, ZR_PARSE_ERROR, - ZR_BUFFER_ERROR, - ZR_VERSION_ERROR + ZR_BUFFER_ERROR, + ZR_VERSION_ERROR } EZipRresult; // return OK or reason for failure static EZipRresult unzip_llsd(LLSD& data, std::istream& is, S32 size); - static EZipRresult unzip_llsd(LLSD& data, const U8* in, S32 size); + static EZipRresult unzip_llsd(LLSD& data, const U8* in, S32 size); }; //dirty little zip functions -- yell at davep diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index db61f4ae41..88cbb3b984 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsdserialize_xml.cpp * @brief XML parsers and formatters for LLSD * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -58,195 +58,195 @@ LLSDXMLFormatter::~LLSDXMLFormatter() // virtual S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, - EFormatterOptions options) const + EFormatterOptions options) const { - std::streamsize old_precision = ostr.precision(25); - - std::string post; - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - post = "\n"; - } - ostr << "<llsd>" << post; - S32 rv = format_impl(data, ostr, options, 1); - ostr << "</llsd>\n"; - - ostr.precision(old_precision); - return rv; + std::streamsize old_precision = ostr.precision(25); + + std::string post; + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + post = "\n"; + } + ostr << "<llsd>" << post; + S32 rv = format_impl(data, ostr, options, 1); + ostr << "</llsd>\n"; + + ostr.precision(old_precision); + return rv; } S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, - EFormatterOptions options, U32 level) const + EFormatterOptions options, U32 level) const { - S32 format_count = 1; - std::string pre; - std::string post; - - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - for (U32 i = 0; i < level; i++) - { - pre += " "; - } - post = "\n"; - } - - switch(data.type()) - { - case LLSD::TypeMap: - if(0 == data.size()) - { - ostr << pre << "<map />" << post; - } - else - { - ostr << pre << "<map>" << post; - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post; - format_count += format_impl((*iter).second, ostr, options, level + 1); - } - ostr << pre << "</map>" << post; - } - break; - - case LLSD::TypeArray: - if(0 == data.size()) - { - ostr << pre << "<array />" << post; - } - else - { - ostr << pre << "<array>" << post; - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - format_count += format_impl(*iter, ostr, options, level + 1); - } - ostr << pre << "</array>" << post; - } - break; - - case LLSD::TypeUndefined: - ostr << pre << "<undef />" << post; - break; - - case LLSD::TypeBoolean: - ostr << pre << "<boolean>"; - if(mBoolAlpha || - (ostr.flags() & std::ios::boolalpha) - ) - { - ostr << (data.asBoolean() ? "true" : "false"); - } - else - { - ostr << (data.asBoolean() ? 1 : 0); - } - ostr << "</boolean>" << post; - break; - - case LLSD::TypeInteger: - ostr << pre << "<integer>" << data.asInteger() << "</integer>" << post; - break; - - case LLSD::TypeReal: - ostr << pre << "<real>"; - if(mRealFormat.empty()) - { - ostr << data.asReal(); - } - else - { - formatReal(data.asReal(), ostr); - } - ostr << "</real>" << post; - break; - - case LLSD::TypeUUID: - if(data.asUUID().isNull()) ostr << pre << "<uuid />" << post; - else ostr << pre << "<uuid>" << data.asUUID() << "</uuid>" << post; - break; - - case LLSD::TypeString: - if(data.asStringRef().empty()) ostr << pre << "<string />" << post; - else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post; - break; - - case LLSD::TypeDate: - ostr << pre << "<date>" << data.asDate() << "</date>" << post; - break; - - case LLSD::TypeURI: - ostr << pre << "<uri>" << escapeString(data.asString()) << "</uri>" << post; - break; - - case LLSD::TypeBinary: - { - const LLSD::Binary& buffer = data.asBinary(); - if(buffer.empty()) - { - ostr << pre << "<binary />" << post; - } - else - { - // *FIX: memory inefficient. - // *TODO: convert to use LLBase64 - ostr << pre << "<binary encoding=\"base64\">"; - int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(buffer.size())); - char* b64_buffer = new char[b64_buffer_length]; - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - &buffer[0], - narrow<size_t>(buffer.size())); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; - ostr << "</binary>" << post; - } - break; - } - default: - // *NOTE: This should never happen. - ostr << pre << "<undef />" << post; - break; - } - return format_count; + S32 format_count = 1; + std::string pre; + std::string post; + + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + for (U32 i = 0; i < level; i++) + { + pre += " "; + } + post = "\n"; + } + + switch(data.type()) + { + case LLSD::TypeMap: + if(0 == data.size()) + { + ostr << pre << "<map />" << post; + } + else + { + ostr << pre << "<map>" << post; + LLSD::map_const_iterator iter = data.beginMap(); + LLSD::map_const_iterator end = data.endMap(); + for(; iter != end; ++iter) + { + ostr << pre << "<key>" << escapeString((*iter).first) << "</key>" << post; + format_count += format_impl((*iter).second, ostr, options, level + 1); + } + ostr << pre << "</map>" << post; + } + break; + + case LLSD::TypeArray: + if(0 == data.size()) + { + ostr << pre << "<array />" << post; + } + else + { + ostr << pre << "<array>" << post; + LLSD::array_const_iterator iter = data.beginArray(); + LLSD::array_const_iterator end = data.endArray(); + for(; iter != end; ++iter) + { + format_count += format_impl(*iter, ostr, options, level + 1); + } + ostr << pre << "</array>" << post; + } + break; + + case LLSD::TypeUndefined: + ostr << pre << "<undef />" << post; + break; + + case LLSD::TypeBoolean: + ostr << pre << "<boolean>"; + if(mBoolAlpha || + (ostr.flags() & std::ios::boolalpha) + ) + { + ostr << (data.asBoolean() ? "true" : "false"); + } + else + { + ostr << (data.asBoolean() ? 1 : 0); + } + ostr << "</boolean>" << post; + break; + + case LLSD::TypeInteger: + ostr << pre << "<integer>" << data.asInteger() << "</integer>" << post; + break; + + case LLSD::TypeReal: + ostr << pre << "<real>"; + if(mRealFormat.empty()) + { + ostr << data.asReal(); + } + else + { + formatReal(data.asReal(), ostr); + } + ostr << "</real>" << post; + break; + + case LLSD::TypeUUID: + if(data.asUUID().isNull()) ostr << pre << "<uuid />" << post; + else ostr << pre << "<uuid>" << data.asUUID() << "</uuid>" << post; + break; + + case LLSD::TypeString: + if(data.asStringRef().empty()) ostr << pre << "<string />" << post; + else ostr << pre << "<string>" << escapeString(data.asStringRef()) <<"</string>" << post; + break; + + case LLSD::TypeDate: + ostr << pre << "<date>" << data.asDate() << "</date>" << post; + break; + + case LLSD::TypeURI: + ostr << pre << "<uri>" << escapeString(data.asString()) << "</uri>" << post; + break; + + case LLSD::TypeBinary: + { + const LLSD::Binary& buffer = data.asBinary(); + if(buffer.empty()) + { + ostr << pre << "<binary />" << post; + } + else + { + // *FIX: memory inefficient. + // *TODO: convert to use LLBase64 + ostr << pre << "<binary encoding=\"base64\">"; + int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(buffer.size())); + char* b64_buffer = new char[b64_buffer_length]; + b64_buffer_length = apr_base64_encode_binary( + b64_buffer, + &buffer[0], + narrow<size_t>(buffer.size())); + ostr.write(b64_buffer, b64_buffer_length - 1); + delete[] b64_buffer; + ostr << "</binary>" << post; + } + break; + } + default: + // *NOTE: This should never happen. + ostr << pre << "<undef />" << post; + break; + } + return format_count; } // static std::string LLSDXMLFormatter::escapeString(const std::string& in) { - std::ostringstream out; - std::string::const_iterator it = in.begin(); - std::string::const_iterator end = in.end(); - for(; it != end; ++it) - { - switch((*it)) - { - case '<': - out << "<"; - break; - case '>': - out << ">"; - break; - case '&': - out << "&"; - break; - case '\'': - out << "'"; - break; - case '"': - out << """; - break; - default: - out << (*it); - break; - } - } - return out.str(); + std::ostringstream out; + std::string::const_iterator it = in.begin(); + std::string::const_iterator end = in.end(); + for(; it != end; ++it) + { + switch((*it)) + { + case '<': + out << "<"; + break; + case '>': + out << ">"; + break; + case '&': + out << "&"; + break; + case '\'': + out << "'"; + break; + case '"': + out << """; + break; + default: + out << (*it); + break; + } + } + return out.str(); } @@ -254,161 +254,161 @@ std::string LLSDXMLFormatter::escapeString(const std::string& in) class LLSDXMLParser::Impl { public: - Impl(bool emit_errors); - ~Impl(); - - S32 parse(std::istream& input, LLSD& data); - S32 parseLines(std::istream& input, LLSD& data); + Impl(bool emit_errors); + ~Impl(); + + S32 parse(std::istream& input, LLSD& data); + S32 parseLines(std::istream& input, LLSD& data); - void parsePart(const char *buf, llssize len); - - void reset(); + void parsePart(const char *buf, llssize len); + + void reset(); private: - void startElementHandler(const XML_Char* name, const XML_Char** attributes); - void endElementHandler(const XML_Char* name); - void characterDataHandler(const XML_Char* data, int length); - - static void sStartElementHandler( - void* userData, const XML_Char* name, const XML_Char** attributes); - static void sEndElementHandler( - void* userData, const XML_Char* name); - static void sCharacterDataHandler( - void* userData, const XML_Char* data, int length); - - void startSkipping(); - - enum Element { - ELEMENT_LLSD, - ELEMENT_UNDEF, - ELEMENT_BOOL, - ELEMENT_INTEGER, - ELEMENT_REAL, - ELEMENT_STRING, - ELEMENT_UUID, - ELEMENT_DATE, - ELEMENT_URI, - ELEMENT_BINARY, - ELEMENT_MAP, - ELEMENT_ARRAY, - ELEMENT_KEY, - ELEMENT_UNKNOWN - }; - static Element readElement(const XML_Char* name); - - static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs); - - bool mEmitErrors; - - XML_Parser mParser; - - LLSD mResult; - S32 mParseCount; - - bool mInLLSDElement; // true if we're on LLSD - bool mGracefullStop; // true if we found the </llsd - - typedef std::deque<LLSD*> LLSDRefStack; - LLSDRefStack mStack; - - int mDepth; - bool mSkipping; - int mSkipThrough; - - std::string mCurrentKey; // Current XML <tag> - std::string mCurrentContent; // String data between <tag> and </tag> + void startElementHandler(const XML_Char* name, const XML_Char** attributes); + void endElementHandler(const XML_Char* name); + void characterDataHandler(const XML_Char* data, int length); + + static void sStartElementHandler( + void* userData, const XML_Char* name, const XML_Char** attributes); + static void sEndElementHandler( + void* userData, const XML_Char* name); + static void sCharacterDataHandler( + void* userData, const XML_Char* data, int length); + + void startSkipping(); + + enum Element { + ELEMENT_LLSD, + ELEMENT_UNDEF, + ELEMENT_BOOL, + ELEMENT_INTEGER, + ELEMENT_REAL, + ELEMENT_STRING, + ELEMENT_UUID, + ELEMENT_DATE, + ELEMENT_URI, + ELEMENT_BINARY, + ELEMENT_MAP, + ELEMENT_ARRAY, + ELEMENT_KEY, + ELEMENT_UNKNOWN + }; + static Element readElement(const XML_Char* name); + + static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs); + + bool mEmitErrors; + + XML_Parser mParser; + + LLSD mResult; + S32 mParseCount; + + bool mInLLSDElement; // true if we're on LLSD + bool mGracefullStop; // true if we found the </llsd + + typedef std::deque<LLSD*> LLSDRefStack; + LLSDRefStack mStack; + + int mDepth; + bool mSkipping; + int mSkipThrough; + + std::string mCurrentKey; // Current XML <tag> + std::string mCurrentContent; // String data between <tag> and </tag> }; LLSDXMLParser::Impl::Impl(bool emit_errors) - : mEmitErrors(emit_errors) + : mEmitErrors(emit_errors) { - mParser = XML_ParserCreate(NULL); - reset(); + mParser = XML_ParserCreate(NULL); + reset(); } LLSDXMLParser::Impl::~Impl() { - XML_ParserFree(mParser); + XML_ParserFree(mParser); } inline bool is_eol(char c) { - return (c == '\n' || c == '\r'); + return (c == '\n' || c == '\r'); } void clear_eol(std::istream& input) { - char c = input.peek(); - while (input.good() && is_eol(c)) - { - input.get(c); - c = input.peek(); - } + char c = input.peek(); + while (input.good() && is_eol(c)) + { + input.get(c); + c = input.peek(); + } } static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize) { - unsigned count = 0; - while (count < bufsize && input.good()) - { - char c = input.get(); - buf[count++] = c; - if (is_eol(c)) - break; - } - return count; + unsigned count = 0; + while (count < bufsize && input.good()) + { + char c = input.get(); + buf[count++] = c; + if (is_eol(c)) + break; + } + return count; } S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) { - XML_Status status; - - static const int BUFFER_SIZE = 1024; - void* buffer = NULL; - int count = 0; - while (input.good() && !input.eof()) - { - buffer = XML_GetBuffer(mParser, BUFFER_SIZE); - - /* - * If we happened to end our last buffer right at the end of the llsd, but the - * stream is still going we will get a null buffer here. Check for mGracefullStop. - */ - if (!buffer) - { - break; - } - count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); - if (!count) - { - break; - } - status = XML_ParseBuffer(mParser, count, false); - - if (status == XML_STATUS_ERROR) - { - break; - } - } - - // *FIX.: This code is buggy - if the stream was empty or not - // good, there is not buffer to parse, both the call to - // XML_ParseBuffer and the buffer manipulations are illegal - // futhermore, it isn't clear that the expat buffer semantics are - // preserved - - status = XML_ParseBuffer(mParser, 0, true); - if (status == XML_STATUS_ERROR && !mGracefullStop) - { - if (buffer) - { - ((char*) buffer)[count ? count - 1 : 0] = '\0'; + XML_Status status; + + static const int BUFFER_SIZE = 1024; + void* buffer = NULL; + int count = 0; + while (input.good() && !input.eof()) + { + buffer = XML_GetBuffer(mParser, BUFFER_SIZE); + + /* + * If we happened to end our last buffer right at the end of the llsd, but the + * stream is still going we will get a null buffer here. Check for mGracefullStop. + */ + if (!buffer) + { + break; + } + count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); + if (!count) + { + break; + } + status = XML_ParseBuffer(mParser, count, false); + + if (status == XML_STATUS_ERROR) + { + break; + } + } + + // *FIX.: This code is buggy - if the stream was empty or not + // good, there is not buffer to parse, both the call to + // XML_ParseBuffer and the buffer manipulations are illegal + // futhermore, it isn't clear that the expat buffer semantics are + // preserved + + status = XML_ParseBuffer(mParser, 0, true); + if (status == XML_STATUS_ERROR && !mGracefullStop) + { + if (buffer) + { + ((char*) buffer)[count ? count - 1 : 0] = '\0'; if (mEmitErrors) { LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*)buffer << LL_ENDL; } - } + } else { if (mEmitErrors) @@ -416,159 +416,159 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR, null buffer" << LL_ENDL; } } - data = LLSD(); - return LLSDParser::PARSE_FAILURE; - } + data = LLSD(); + return LLSDParser::PARSE_FAILURE; + } - clear_eol(input); - data = mResult; - return mParseCount; + clear_eol(input); + data = mResult; + return mParseCount; } S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data) { - XML_Status status = XML_STATUS_OK; - - data = LLSD(); - - static const int BUFFER_SIZE = 1024; - - //static char last_buffer[ BUFFER_SIZE ]; - //std::streamsize last_num_read; - - // Must get rid of any leading \n, otherwise the stream gets into an error/eof state - clear_eol(input); - - while( !mGracefullStop - && input.good() - && !input.eof()) - { - void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE); - /* - * If we happened to end our last buffer right at the end of the llsd, but the - * stream is still going we will get a null buffer here. Check for mGracefullStop. - * -- I don't think this is actually true - zero 2008-05-09 - */ - if (!buffer) - { - break; - } - - // Get one line - input.getline((char*)buffer, BUFFER_SIZE); - std::streamsize num_read = input.gcount(); - - //memcpy( last_buffer, buffer, num_read ); - //last_num_read = num_read; - - if ( num_read > 0 ) - { - if (!input.good() ) - { // Clear state that's set when we run out of buffer - input.clear(); - } - - // Re-insert with the \n that was absorbed by getline() - char * text = (char *) buffer; - if ( text[num_read - 1] == 0) - { - text[num_read - 1] = '\n'; - } - } - - status = XML_ParseBuffer(mParser, (int)num_read, false); - if (status == XML_STATUS_ERROR) - { - break; - } - } - - if (status != XML_STATUS_ERROR - && !mGracefullStop) - { // Parse last bit - status = XML_ParseBuffer(mParser, 0, true); - } - - if (status == XML_STATUS_ERROR - && !mGracefullStop) - { - if (mEmitErrors) - { - LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL; - } - return LLSDParser::PARSE_FAILURE; - } - - clear_eol(input); - data = mResult; - return mParseCount; + XML_Status status = XML_STATUS_OK; + + data = LLSD(); + + static const int BUFFER_SIZE = 1024; + + //static char last_buffer[ BUFFER_SIZE ]; + //std::streamsize last_num_read; + + // Must get rid of any leading \n, otherwise the stream gets into an error/eof state + clear_eol(input); + + while( !mGracefullStop + && input.good() + && !input.eof()) + { + void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE); + /* + * If we happened to end our last buffer right at the end of the llsd, but the + * stream is still going we will get a null buffer here. Check for mGracefullStop. + * -- I don't think this is actually true - zero 2008-05-09 + */ + if (!buffer) + { + break; + } + + // Get one line + input.getline((char*)buffer, BUFFER_SIZE); + std::streamsize num_read = input.gcount(); + + //memcpy( last_buffer, buffer, num_read ); + //last_num_read = num_read; + + if ( num_read > 0 ) + { + if (!input.good() ) + { // Clear state that's set when we run out of buffer + input.clear(); + } + + // Re-insert with the \n that was absorbed by getline() + char * text = (char *) buffer; + if ( text[num_read - 1] == 0) + { + text[num_read - 1] = '\n'; + } + } + + status = XML_ParseBuffer(mParser, (int)num_read, false); + if (status == XML_STATUS_ERROR) + { + break; + } + } + + if (status != XML_STATUS_ERROR + && !mGracefullStop) + { // Parse last bit + status = XML_ParseBuffer(mParser, 0, true); + } + + if (status == XML_STATUS_ERROR + && !mGracefullStop) + { + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL; + } + return LLSDParser::PARSE_FAILURE; + } + + clear_eol(input); + data = mResult; + return mParseCount; } void LLSDXMLParser::Impl::reset() { - mResult.clear(); - mParseCount = 0; - - mInLLSDElement = false; - mDepth = 0; - - mGracefullStop = false; - - mStack.clear(); - - mSkipping = false; - - mCurrentKey.clear(); - - XML_ParserReset(mParser, "utf-8"); - XML_SetUserData(mParser, this); - XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler); - XML_SetCharacterDataHandler(mParser, sCharacterDataHandler); + mResult.clear(); + mParseCount = 0; + + mInLLSDElement = false; + mDepth = 0; + + mGracefullStop = false; + + mStack.clear(); + + mSkipping = false; + + mCurrentKey.clear(); + + XML_ParserReset(mParser, "utf-8"); + XML_SetUserData(mParser, this); + XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler); + XML_SetCharacterDataHandler(mParser, sCharacterDataHandler); } void LLSDXMLParser::Impl::startSkipping() { - mSkipping = true; - mSkipThrough = mDepth; + mSkipping = true; + mSkipThrough = mDepth; } const XML_Char* LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs) { - while (NULL != pairs && NULL != *pairs) - { - if(0 == strcmp(name, *pairs)) - { - return *(pairs + 1); - } - pairs += 2; - } - return NULL; + while (NULL != pairs && NULL != *pairs) + { + if(0 == strcmp(name, *pairs)) + { + return *(pairs + 1); + } + pairs += 2; + } + return NULL; } void LLSDXMLParser::Impl::parsePart(const char* buf, llssize len) { - if ( buf != NULL - && len > 0 ) - { - XML_Status status = XML_Parse(mParser, buf, len, false); - if (status == XML_STATUS_ERROR) - { - LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL; - } - } + if ( buf != NULL + && len > 0 ) + { + XML_Status status = XML_Parse(mParser, buf, len, false); + if (status == XML_STATUS_ERROR) + { + LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL; + } + } } // Performance testing code -//#define XML_PARSER_PERFORMANCE_TESTS +//#define XML_PARSER_PERFORMANCE_TESTS #ifdef XML_PARSER_PERFORMANCE_TESTS extern U64 totalTime(); -U64 readElementTime = 0; +U64 readElementTime = 0; U64 startElementTime = 0; U64 endElementTime = 0; U64 charDataTime = 0; @@ -577,333 +577,333 @@ U64 parseTime = 0; class XML_Timer { public: - XML_Timer( U64 * sum ) : mSum( sum ) - { - mStart = totalTime(); - } - ~XML_Timer() - { - *mSum += (totalTime() - mStart); - } - - U64 * mSum; - U64 mStart; + XML_Timer( U64 * sum ) : mSum( sum ) + { + mStart = totalTime(); + } + ~XML_Timer() + { + *mSum += (totalTime() - mStart); + } + + U64 * mSum; + U64 mStart; }; #endif // XML_PARSER_PERFORMANCE_TESTS void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &startElementTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS - - ++mDepth; - if (mSkipping) - { - return; - } - - Element element = readElement(name); - - mCurrentContent.clear(); - - switch (element) - { - case ELEMENT_LLSD: - if (mInLLSDElement) { return startSkipping(); } - mInLLSDElement = true; - return; - - case ELEMENT_KEY: - if (mStack.empty() || !(mStack.back()->isMap())) - { - return startSkipping(); - } - return; - - case ELEMENT_BINARY: - { - const XML_Char* encoding = findAttribute("encoding", attributes); - if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); } - break; - } - - default: - // all rest are values, fall through - ; - } - - - if (!mInLLSDElement) { return startSkipping(); } - - if (mStack.empty()) - { - mStack.push_back(&mResult); - } - else if (mStack.back()->isMap()) - { - if (mCurrentKey.empty()) { return startSkipping(); } - - LLSD& map = *mStack.back(); - LLSD& newElement = map[mCurrentKey]; - mStack.push_back(&newElement); - - mCurrentKey.clear(); - } - else if (mStack.back()->isArray()) - { - LLSD& array = *mStack.back(); - array.append(LLSD()); - LLSD& newElement = array[array.size()-1]; - mStack.push_back(&newElement); - } - else { - // improperly nested value in a non-structure - return startSkipping(); - } - - ++mParseCount; - switch (element) - { - case ELEMENT_MAP: - *mStack.back() = LLSD::emptyMap(); - break; - - case ELEMENT_ARRAY: - *mStack.back() = LLSD::emptyArray(); - break; - - default: - // all the other values will be set in the end element handler - ; - } + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &startElementTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS + + ++mDepth; + if (mSkipping) + { + return; + } + + Element element = readElement(name); + + mCurrentContent.clear(); + + switch (element) + { + case ELEMENT_LLSD: + if (mInLLSDElement) { return startSkipping(); } + mInLLSDElement = true; + return; + + case ELEMENT_KEY: + if (mStack.empty() || !(mStack.back()->isMap())) + { + return startSkipping(); + } + return; + + case ELEMENT_BINARY: + { + const XML_Char* encoding = findAttribute("encoding", attributes); + if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); } + break; + } + + default: + // all rest are values, fall through + ; + } + + + if (!mInLLSDElement) { return startSkipping(); } + + if (mStack.empty()) + { + mStack.push_back(&mResult); + } + else if (mStack.back()->isMap()) + { + if (mCurrentKey.empty()) { return startSkipping(); } + + LLSD& map = *mStack.back(); + LLSD& newElement = map[mCurrentKey]; + mStack.push_back(&newElement); + + mCurrentKey.clear(); + } + else if (mStack.back()->isArray()) + { + LLSD& array = *mStack.back(); + array.append(LLSD()); + LLSD& newElement = array[array.size()-1]; + mStack.push_back(&newElement); + } + else { + // improperly nested value in a non-structure + return startSkipping(); + } + + ++mParseCount; + switch (element) + { + case ELEMENT_MAP: + *mStack.back() = LLSD::emptyMap(); + break; + + case ELEMENT_ARRAY: + *mStack.back() = LLSD::emptyArray(); + break; + + default: + // all the other values will be set in the end element handler + ; + } } void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &endElementTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS - - --mDepth; - if (mSkipping) - { - if (mDepth < mSkipThrough) - { - mSkipping = false; - } - return; - } - - Element element = readElement(name); - - switch (element) - { - case ELEMENT_LLSD: - if (mInLLSDElement) - { - mInLLSDElement = false; - mGracefullStop = true; - XML_StopParser(mParser, false); - } - return; - - case ELEMENT_KEY: - mCurrentKey = mCurrentContent; - return; - - default: - // all rest are values, fall through - ; - } - - if (!mInLLSDElement) { return; } - - LLSD& value = *mStack.back(); - mStack.pop_back(); - - switch (element) - { - case ELEMENT_UNDEF: - value.clear(); - break; - - case ELEMENT_BOOL: - value = (mCurrentContent == "true" || mCurrentContent == "1"); - break; - - case ELEMENT_INTEGER: - { - S32 i; - // sscanf okay here with different locales - ints don't change for different locale settings like floats do. - if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 ) - { // See if sscanf works - it's faster - value = i; - } - else - { - value = LLSD(mCurrentContent).asInteger(); - } - } - break; - - case ELEMENT_REAL: - { - value = LLSD(mCurrentContent).asReal(); - // removed since this breaks when locale has decimal separator that isn't '.' - // investigated changing local to something compatible each time but deemed higher - // risk that just using LLSD.asReal() each time. - //F64 r; - //if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 ) - //{ // See if sscanf works - it's faster - // value = r; - //} - //else - //{ - // value = LLSD(mCurrentContent).asReal(); - //} - } - break; - - case ELEMENT_STRING: - value = mCurrentContent; - break; - - case ELEMENT_UUID: - value = LLSD(mCurrentContent).asUUID(); - break; - - case ELEMENT_DATE: - value = LLSD(mCurrentContent).asDate(); - break; - - case ELEMENT_URI: - value = LLSD(mCurrentContent).asURI(); - break; - - case ELEMENT_BINARY: - { - // Regex is expensive, but only fix for whitespace in base64, - // created by python and other non-linden systems - DEV-39358 - // Fortunately we have very little binary passing now, - // so performance impact shold be negligible. + poppy 2009-09-04 - boost::regex r; - r.assign("\\s"); - std::string stripped = boost::regex_replace(mCurrentContent, r, ""); - S32 len = apr_base64_decode_len(stripped.c_str()); - std::vector<U8> data; - data.resize(len); - len = apr_base64_decode_binary(&data[0], stripped.c_str()); - data.resize(len); - value = data; - break; - } - - case ELEMENT_UNKNOWN: - value.clear(); - break; - - default: - // other values, map and array, have already been set - break; - } - - mCurrentContent.clear(); + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &endElementTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS + + --mDepth; + if (mSkipping) + { + if (mDepth < mSkipThrough) + { + mSkipping = false; + } + return; + } + + Element element = readElement(name); + + switch (element) + { + case ELEMENT_LLSD: + if (mInLLSDElement) + { + mInLLSDElement = false; + mGracefullStop = true; + XML_StopParser(mParser, false); + } + return; + + case ELEMENT_KEY: + mCurrentKey = mCurrentContent; + return; + + default: + // all rest are values, fall through + ; + } + + if (!mInLLSDElement) { return; } + + LLSD& value = *mStack.back(); + mStack.pop_back(); + + switch (element) + { + case ELEMENT_UNDEF: + value.clear(); + break; + + case ELEMENT_BOOL: + value = (mCurrentContent == "true" || mCurrentContent == "1"); + break; + + case ELEMENT_INTEGER: + { + S32 i; + // sscanf okay here with different locales - ints don't change for different locale settings like floats do. + if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 ) + { // See if sscanf works - it's faster + value = i; + } + else + { + value = LLSD(mCurrentContent).asInteger(); + } + } + break; + + case ELEMENT_REAL: + { + value = LLSD(mCurrentContent).asReal(); + // removed since this breaks when locale has decimal separator that isn't '.' + // investigated changing local to something compatible each time but deemed higher + // risk that just using LLSD.asReal() each time. + //F64 r; + //if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 ) + //{ // See if sscanf works - it's faster + // value = r; + //} + //else + //{ + // value = LLSD(mCurrentContent).asReal(); + //} + } + break; + + case ELEMENT_STRING: + value = mCurrentContent; + break; + + case ELEMENT_UUID: + value = LLSD(mCurrentContent).asUUID(); + break; + + case ELEMENT_DATE: + value = LLSD(mCurrentContent).asDate(); + break; + + case ELEMENT_URI: + value = LLSD(mCurrentContent).asURI(); + break; + + case ELEMENT_BINARY: + { + // Regex is expensive, but only fix for whitespace in base64, + // created by python and other non-linden systems - DEV-39358 + // Fortunately we have very little binary passing now, + // so performance impact shold be negligible. + poppy 2009-09-04 + boost::regex r; + r.assign("\\s"); + std::string stripped = boost::regex_replace(mCurrentContent, r, ""); + S32 len = apr_base64_decode_len(stripped.c_str()); + std::vector<U8> data; + data.resize(len); + len = apr_base64_decode_binary(&data[0], stripped.c_str()); + data.resize(len); + value = data; + break; + } + + case ELEMENT_UNKNOWN: + value.clear(); + break; + + default: + // other values, map and array, have already been set + break; + } + + mCurrentContent.clear(); } void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &charDataTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &charDataTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS - mCurrentContent.append(data, length); + mCurrentContent.append(data, length); } void LLSDXMLParser::Impl::sStartElementHandler( - void* userData, const XML_Char* name, const XML_Char** attributes) + void* userData, const XML_Char* name, const XML_Char** attributes) { - ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes); + ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes); } void LLSDXMLParser::Impl::sEndElementHandler( - void* userData, const XML_Char* name) + void* userData, const XML_Char* name) { - ((LLSDXMLParser::Impl*)userData)->endElementHandler(name); + ((LLSDXMLParser::Impl*)userData)->endElementHandler(name); } void LLSDXMLParser::Impl::sCharacterDataHandler( - void* userData, const XML_Char* data, int length) + void* userData, const XML_Char* data, int length) { - ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length); + ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length); } /* - This code is time critical - - This is a sample of tag occurances of text in simstate file with ~8000 objects. - A tag pair (<key>something</key>) counts is counted as two: - - key - 2680178 - real - 1818362 - integer - 906078 - array - 295682 - map - 191818 - uuid - 177903 - binary - 175748 - string - 53482 - undef - 40353 - boolean - 33874 - llsd - 16332 - uri - 38 - date - 1 + This code is time critical + + This is a sample of tag occurances of text in simstate file with ~8000 objects. + A tag pair (<key>something</key>) counts is counted as two: + + key - 2680178 + real - 1818362 + integer - 906078 + array - 295682 + map - 191818 + uuid - 177903 + binary - 175748 + string - 53482 + undef - 40353 + boolean - 33874 + llsd - 16332 + uri - 38 + date - 1 */ LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &readElementTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS - - XML_Char c = *name; - switch (c) - { - case 'k': - if (strcmp(name, "key") == 0) { return ELEMENT_KEY; } - break; - case 'r': - if (strcmp(name, "real") == 0) { return ELEMENT_REAL; } - break; - case 'i': - if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; } - break; - case 'a': - if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; } - break; - case 'm': - if (strcmp(name, "map") == 0) { return ELEMENT_MAP; } - break; - case 'u': - if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; } - if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; } - if (strcmp(name, "uri") == 0) { return ELEMENT_URI; } - break; - case 'b': - if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; } - if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; } - break; - case 's': - if (strcmp(name, "string") == 0) { return ELEMENT_STRING; } - break; - case 'l': - if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; } - break; - case 'd': - if (strcmp(name, "date") == 0) { return ELEMENT_DATE; } - break; - } - return ELEMENT_UNKNOWN; + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &readElementTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS + + XML_Char c = *name; + switch (c) + { + case 'k': + if (strcmp(name, "key") == 0) { return ELEMENT_KEY; } + break; + case 'r': + if (strcmp(name, "real") == 0) { return ELEMENT_REAL; } + break; + case 'i': + if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; } + break; + case 'a': + if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; } + break; + case 'm': + if (strcmp(name, "map") == 0) { return ELEMENT_MAP; } + break; + case 'u': + if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; } + if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; } + if (strcmp(name, "uri") == 0) { return ELEMENT_URI; } + break; + case 'b': + if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; } + if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; } + break; + case 's': + if (strcmp(name, "string") == 0) { return ELEMENT_STRING; } + break; + case 'l': + if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; } + break; + case 'd': + if (strcmp(name, "date") == 0) { return ELEMENT_DATE; } + break; + } + return ELEMENT_UNKNOWN; } @@ -919,34 +919,34 @@ LLSDXMLParser::LLSDXMLParser(bool emit_errors /* = true */) : impl(* new Impl(em LLSDXMLParser::~LLSDXMLParser() { - delete &impl; + delete &impl; } void LLSDXMLParser::parsePart(const char *buf, llssize len) { - impl.parsePart(buf, len); + impl.parsePart(buf, len); } // virtual S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &parseTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &parseTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS - if (mParseLines) - { - // Use line-based reading (faster code) - return impl.parseLines(input, data); - } + if (mParseLines) + { + // Use line-based reading (faster code) + return impl.parseLines(input, data); + } - return impl.parse(input, data); + return impl.parse(input, data); } -// virtual +// virtual void LLSDXMLParser::doReset() { - impl.reset(); + impl.reset(); } diff --git a/indra/llcommon/llsdserialize_xml.h b/indra/llcommon/llsdserialize_xml.h index dcc5f3d3c7..6c1a74c0e3 100644 --- a/indra/llcommon/llsdserialize_xml.h +++ b/indra/llcommon/llsdserialize_xml.h @@ -1,25 +1,25 @@ -/** +/** * @file llsdserialize_xml.h * @brief XML parsers and formatters for LLSD * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index e98fc0285a..efce458117 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdutil.cpp * @author Phoenix * @date 2006-05-24 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,12 +32,12 @@ #include <sstream> #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> // for htonl +# define WIN32_LEAN_AND_MEAN +# include <winsock2.h> // for htonl #elif LL_LINUX -# include <netinet/in.h> +# include <netinet/in.h> #elif LL_DARWIN -# include <arpa/inet.h> +# include <arpa/inet.h> #endif #include "llsdserialize.h" @@ -51,152 +51,152 @@ // U32 LLSD ll_sd_from_U32(const U32 val) { - std::vector<U8> v; - U32 net_order = htonl(val); + std::vector<U8> v; + U32 net_order = htonl(val); - v.resize(4); - memcpy(&(v[0]), &net_order, 4); /* Flawfinder: ignore */ + v.resize(4); + memcpy(&(v[0]), &net_order, 4); /* Flawfinder: ignore */ - return LLSD(v); + return LLSD(v); } U32 ll_U32_from_sd(const LLSD& sd) { - U32 ret; - std::vector<U8> v = sd.asBinary(); - if (v.size() < 4) - { - return 0; - } - memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ - ret = ntohl(ret); - return ret; + U32 ret; + std::vector<U8> v = sd.asBinary(); + if (v.size() < 4) + { + return 0; + } + memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ + ret = ntohl(ret); + return ret; } //U64 LLSD ll_sd_from_U64(const U64 val) { - std::vector<U8> v; - U32 high, low; + std::vector<U8> v; + U32 high, low; - high = (U32)(val >> 32); - low = (U32)val; - high = htonl(high); - low = htonl(low); + high = (U32)(val >> 32); + low = (U32)val; + high = htonl(high); + low = htonl(low); - v.resize(8); - memcpy(&(v[0]), &high, 4); /* Flawfinder: ignore */ - memcpy(&(v[4]), &low, 4); /* Flawfinder: ignore */ + v.resize(8); + memcpy(&(v[0]), &high, 4); /* Flawfinder: ignore */ + memcpy(&(v[4]), &low, 4); /* Flawfinder: ignore */ - return LLSD(v); + return LLSD(v); } U64 ll_U64_from_sd(const LLSD& sd) { - U32 high, low; - std::vector<U8> v = sd.asBinary(); + U32 high, low; + std::vector<U8> v = sd.asBinary(); - if (v.size() < 8) - { - return 0; - } + if (v.size() < 8) + { + return 0; + } - memcpy(&high, &(v[0]), 4); /* Flawfinder: ignore */ - memcpy(&low, &(v[4]), 4); /* Flawfinder: ignore */ - high = ntohl(high); - low = ntohl(low); + memcpy(&high, &(v[0]), 4); /* Flawfinder: ignore */ + memcpy(&low, &(v[4]), 4); /* Flawfinder: ignore */ + high = ntohl(high); + low = ntohl(low); - return ((U64)high) << 32 | low; + return ((U64)high) << 32 | low; } // IP Address (stored in net order in a U32, so don't need swizzling) LLSD ll_sd_from_ipaddr(const U32 val) { - std::vector<U8> v; + std::vector<U8> v; - v.resize(4); - memcpy(&(v[0]), &val, 4); /* Flawfinder: ignore */ + v.resize(4); + memcpy(&(v[0]), &val, 4); /* Flawfinder: ignore */ - return LLSD(v); + return LLSD(v); } U32 ll_ipaddr_from_sd(const LLSD& sd) { - U32 ret; - std::vector<U8> v = sd.asBinary(); - if (v.size() < 4) - { - return 0; - } - memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ - return ret; + U32 ret; + std::vector<U8> v = sd.asBinary(); + if (v.size() < 4) + { + return 0; + } + memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ + return ret; } // Converts an LLSD binary to an LLSD string LLSD ll_string_from_binary(const LLSD& sd) { - std::vector<U8> value = sd.asBinary(); - std::string str; - str.resize(value.size()); - memcpy(&str[0], &value[0], value.size()); - return str; + std::vector<U8> value = sd.asBinary(); + std::string str; + str.resize(value.size()); + memcpy(&str[0], &value[0], value.size()); + return str; } // Converts an LLSD string to an LLSD binary LLSD ll_binary_from_string(const LLSD& sd) { - std::vector<U8> binary_value; + std::vector<U8> binary_value; - std::string string_value = sd.asString(); - for (const U8 c : string_value) - { - binary_value.push_back(c); - } + std::string string_value = sd.asString(); + for (const U8 c : string_value) + { + binary_value.push_back(c); + } - binary_value.push_back('\0'); + binary_value.push_back('\0'); - return binary_value; + return binary_value; } char* ll_print_sd(const LLSD& sd) { - const U32 bufferSize = 10 * 1024; - static char buffer[bufferSize]; - std::ostringstream stream; - //stream.rdbuf()->pubsetbuf(buffer, bufferSize); - stream << LLSDOStreamer<LLSDXMLFormatter>(sd); - stream << std::ends; - strncpy(buffer, stream.str().c_str(), bufferSize); - buffer[bufferSize - 1] = '\0'; - return buffer; + const U32 bufferSize = 10 * 1024; + static char buffer[bufferSize]; + std::ostringstream stream; + //stream.rdbuf()->pubsetbuf(buffer, bufferSize); + stream << LLSDOStreamer<LLSDXMLFormatter>(sd); + stream << std::ends; + strncpy(buffer, stream.str().c_str(), bufferSize); + buffer[bufferSize - 1] = '\0'; + return buffer; } char* ll_pretty_print_sd_ptr(const LLSD* sd) { - if (sd) - { - return ll_pretty_print_sd(*sd); - } - return NULL; + if (sd) + { + return ll_pretty_print_sd(*sd); + } + return NULL; } char* ll_pretty_print_sd(const LLSD& sd) { - const U32 bufferSize = 100 * 1024; - static char buffer[bufferSize]; - std::ostringstream stream; - //stream.rdbuf()->pubsetbuf(buffer, bufferSize); - stream << LLSDOStreamer<LLSDXMLFormatter>(sd, LLSDFormatter::OPTIONS_PRETTY); - stream << std::ends; - strncpy(buffer, stream.str().c_str(), bufferSize); - buffer[bufferSize - 1] = '\0'; - return buffer; + const U32 bufferSize = 100 * 1024; + static char buffer[bufferSize]; + std::ostringstream stream; + //stream.rdbuf()->pubsetbuf(buffer, bufferSize); + stream << LLSDOStreamer<LLSDXMLFormatter>(sd, LLSDFormatter::OPTIONS_PRETTY); + stream << std::ends; + strncpy(buffer, stream.str().c_str(), bufferSize); + buffer[bufferSize - 1] = '\0'; + return buffer; } std::string ll_stream_notation_sd(const LLSD& sd) { - std::ostringstream stream; - stream << LLSDOStreamer<LLSDNotationFormatter>(sd); + std::ostringstream stream; + stream << LLSDOStreamer<LLSDNotationFormatter>(sd); return stream.str(); } @@ -210,121 +210,121 @@ std::string ll_stream_notation_sd(const LLSD& sd) //of the same value. Ordering of arrays matters //Otherwise, returns true BOOL compare_llsd_with_template( - const LLSD& llsd_to_test, - const LLSD& template_llsd, - LLSD& resultant_llsd) + const LLSD& llsd_to_test, + const LLSD& template_llsd, + LLSD& resultant_llsd) { LL_PROFILE_ZONE_SCOPED - if ( - llsd_to_test.isUndefined() && - template_llsd.isDefined() ) - { - resultant_llsd = template_llsd; - return TRUE; - } - else if ( llsd_to_test.type() != template_llsd.type() ) - { - resultant_llsd = LLSD(); - return FALSE; - } - - if ( llsd_to_test.isArray() ) - { - //they are both arrays - //we loop over all the items in the template - //verifying that the to_test has a subset (in the same order) - //any shortcoming in the testing_llsd are just taken - //to be the rest of the template - LLSD data; - LLSD::array_const_iterator test_iter; - LLSD::array_const_iterator template_iter; - - resultant_llsd = LLSD::emptyArray(); - test_iter = llsd_to_test.beginArray(); - - for ( - template_iter = template_llsd.beginArray(); - (template_iter != template_llsd.endArray() && - test_iter != llsd_to_test.endArray()); - ++template_iter) - { - if ( !compare_llsd_with_template( - *test_iter, - *template_iter, - data) ) - { - resultant_llsd = LLSD(); - return FALSE; - } - else - { - resultant_llsd.append(data); - } - - ++test_iter; - } - - //so either the test or the template ended - //we do another loop now to the end of the template - //grabbing the default values - for (; - template_iter != template_llsd.endArray(); - ++template_iter) - { - resultant_llsd.append(*template_iter); - } - } - else if ( llsd_to_test.isMap() ) - { - //now we loop over the keys of the two maps - //any excess is taken from the template - //excess is ignored in the test - LLSD value; - LLSD::map_const_iterator template_iter; - - resultant_llsd = LLSD::emptyMap(); - for ( - template_iter = template_llsd.beginMap(); - template_iter != template_llsd.endMap(); - ++template_iter) - { - if ( llsd_to_test.has(template_iter->first) ) - { - //the test LLSD has the same key - if ( !compare_llsd_with_template( - llsd_to_test[template_iter->first], - template_iter->second, - value) ) - { - resultant_llsd = LLSD(); - return FALSE; - } - else - { - resultant_llsd[template_iter->first] = value; - } - } - else - { - //test llsd doesn't have it...take the - //template as default value - resultant_llsd[template_iter->first] = - template_iter->second; - } - } - } - else - { - //of same type...take the test llsd's value - resultant_llsd = llsd_to_test; - } - - - return TRUE; + if ( + llsd_to_test.isUndefined() && + template_llsd.isDefined() ) + { + resultant_llsd = template_llsd; + return TRUE; + } + else if ( llsd_to_test.type() != template_llsd.type() ) + { + resultant_llsd = LLSD(); + return FALSE; + } + + if ( llsd_to_test.isArray() ) + { + //they are both arrays + //we loop over all the items in the template + //verifying that the to_test has a subset (in the same order) + //any shortcoming in the testing_llsd are just taken + //to be the rest of the template + LLSD data; + LLSD::array_const_iterator test_iter; + LLSD::array_const_iterator template_iter; + + resultant_llsd = LLSD::emptyArray(); + test_iter = llsd_to_test.beginArray(); + + for ( + template_iter = template_llsd.beginArray(); + (template_iter != template_llsd.endArray() && + test_iter != llsd_to_test.endArray()); + ++template_iter) + { + if ( !compare_llsd_with_template( + *test_iter, + *template_iter, + data) ) + { + resultant_llsd = LLSD(); + return FALSE; + } + else + { + resultant_llsd.append(data); + } + + ++test_iter; + } + + //so either the test or the template ended + //we do another loop now to the end of the template + //grabbing the default values + for (; + template_iter != template_llsd.endArray(); + ++template_iter) + { + resultant_llsd.append(*template_iter); + } + } + else if ( llsd_to_test.isMap() ) + { + //now we loop over the keys of the two maps + //any excess is taken from the template + //excess is ignored in the test + LLSD value; + LLSD::map_const_iterator template_iter; + + resultant_llsd = LLSD::emptyMap(); + for ( + template_iter = template_llsd.beginMap(); + template_iter != template_llsd.endMap(); + ++template_iter) + { + if ( llsd_to_test.has(template_iter->first) ) + { + //the test LLSD has the same key + if ( !compare_llsd_with_template( + llsd_to_test[template_iter->first], + template_iter->second, + value) ) + { + resultant_llsd = LLSD(); + return FALSE; + } + else + { + resultant_llsd[template_iter->first] = value; + } + } + else + { + //test llsd doesn't have it...take the + //template as default value + resultant_llsd[template_iter->first] = + template_iter->second; + } + } + } + else + { + //of same type...take the test llsd's value + resultant_llsd = llsd_to_test; + } + + + return TRUE; } -// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// filter_llsd_with_template() is a direct clone (copy-n-paste) of // compare_llsd_with_template with the following differences: // (1) bool vs BOOL return types // (2) A map with the key value "*" is a special value and maps any key in the @@ -333,171 +333,171 @@ BOOL compare_llsd_with_template( // for *all* the elements of the test array. If the template array is of // different size, compare_llsd_with_template() semantics apply. bool filter_llsd_with_template( - const LLSD & llsd_to_test, - const LLSD & template_llsd, - LLSD & resultant_llsd) + const LLSD & llsd_to_test, + const LLSD & template_llsd, + LLSD & resultant_llsd) { LL_PROFILE_ZONE_SCOPED - if (llsd_to_test.isUndefined() && template_llsd.isDefined()) - { - resultant_llsd = template_llsd; - return true; - } - else if (llsd_to_test.type() != template_llsd.type()) - { - resultant_llsd = LLSD(); - return false; - } - - if (llsd_to_test.isArray()) - { - //they are both arrays - //we loop over all the items in the template - //verifying that the to_test has a subset (in the same order) - //any shortcoming in the testing_llsd are just taken - //to be the rest of the template - LLSD data; - LLSD::array_const_iterator test_iter; - LLSD::array_const_iterator template_iter; - - resultant_llsd = LLSD::emptyArray(); - test_iter = llsd_to_test.beginArray(); - - if (1 == template_llsd.size()) - { - // If the template has a single item, treat it as - // the template for *all* items in the test LLSD. - template_iter = template_llsd.beginArray(); - - for (; test_iter != llsd_to_test.endArray(); ++test_iter) - { - if (! filter_llsd_with_template(*test_iter, *template_iter, data)) - { - resultant_llsd = LLSD(); - return false; - } - else - { - resultant_llsd.append(data); - } - } - } - else - { - // Traditional compare_llsd_with_template matching - - for (template_iter = template_llsd.beginArray(); - template_iter != template_llsd.endArray() && - test_iter != llsd_to_test.endArray(); - ++template_iter, ++test_iter) - { - if (! filter_llsd_with_template(*test_iter, *template_iter, data)) - { - resultant_llsd = LLSD(); - return false; - } - else - { - resultant_llsd.append(data); - } - } - - //so either the test or the template ended - //we do another loop now to the end of the template - //grabbing the default values - for (; - template_iter != template_llsd.endArray(); - ++template_iter) - { - resultant_llsd.append(*template_iter); - } - } - } - else if (llsd_to_test.isMap()) - { - resultant_llsd = LLSD::emptyMap(); - - //now we loop over the keys of the two maps - //any excess is taken from the template - //excess is ignored in the test - - // Special tag for wildcarded LLSD map key templates - const LLSD::String wildcard_tag("*"); - - const bool template_has_wildcard = template_llsd.has(wildcard_tag); - LLSD wildcard_value; - LLSD value; - - const LLSD::map_const_iterator template_iter_end(template_llsd.endMap()); - for (LLSD::map_const_iterator template_iter(template_llsd.beginMap()); - template_iter_end != template_iter; - ++template_iter) - { - if (wildcard_tag == template_iter->first) - { - wildcard_value = template_iter->second; - } - else if (llsd_to_test.has(template_iter->first)) - { - //the test LLSD has the same key - if (! filter_llsd_with_template(llsd_to_test[template_iter->first], - template_iter->second, - value)) - { - resultant_llsd = LLSD(); - return false; - } - else - { - resultant_llsd[template_iter->first] = value; - } - } - else if (! template_has_wildcard) - { - // test llsd doesn't have it...take the - // template as default value - resultant_llsd[template_iter->first] = template_iter->second; - } - } - if (template_has_wildcard) - { - LLSD sub_value; - LLSD::map_const_iterator test_iter; - - for (test_iter = llsd_to_test.beginMap(); - test_iter != llsd_to_test.endMap(); - ++test_iter) - { - if (resultant_llsd.has(test_iter->first)) - { - // Final value has test key, assume more specific - // template matched and we shouldn't modify it again. - continue; - } - else if (! filter_llsd_with_template(test_iter->second, - wildcard_value, - sub_value)) - { - // Test value doesn't match wildcarded template - resultant_llsd = LLSD(); - return false; - } - else - { - // Test value matches template, add the actuals. - resultant_llsd[test_iter->first] = sub_value; - } - } - } - } - else - { - //of same type...take the test llsd's value - resultant_llsd = llsd_to_test; - } - - return true; + if (llsd_to_test.isUndefined() && template_llsd.isDefined()) + { + resultant_llsd = template_llsd; + return true; + } + else if (llsd_to_test.type() != template_llsd.type()) + { + resultant_llsd = LLSD(); + return false; + } + + if (llsd_to_test.isArray()) + { + //they are both arrays + //we loop over all the items in the template + //verifying that the to_test has a subset (in the same order) + //any shortcoming in the testing_llsd are just taken + //to be the rest of the template + LLSD data; + LLSD::array_const_iterator test_iter; + LLSD::array_const_iterator template_iter; + + resultant_llsd = LLSD::emptyArray(); + test_iter = llsd_to_test.beginArray(); + + if (1 == template_llsd.size()) + { + // If the template has a single item, treat it as + // the template for *all* items in the test LLSD. + template_iter = template_llsd.beginArray(); + + for (; test_iter != llsd_to_test.endArray(); ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + } + else + { + // Traditional compare_llsd_with_template matching + + for (template_iter = template_llsd.beginArray(); + template_iter != template_llsd.endArray() && + test_iter != llsd_to_test.endArray(); + ++template_iter, ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + + //so either the test or the template ended + //we do another loop now to the end of the template + //grabbing the default values + for (; + template_iter != template_llsd.endArray(); + ++template_iter) + { + resultant_llsd.append(*template_iter); + } + } + } + else if (llsd_to_test.isMap()) + { + resultant_llsd = LLSD::emptyMap(); + + //now we loop over the keys of the two maps + //any excess is taken from the template + //excess is ignored in the test + + // Special tag for wildcarded LLSD map key templates + const LLSD::String wildcard_tag("*"); + + const bool template_has_wildcard = template_llsd.has(wildcard_tag); + LLSD wildcard_value; + LLSD value; + + const LLSD::map_const_iterator template_iter_end(template_llsd.endMap()); + for (LLSD::map_const_iterator template_iter(template_llsd.beginMap()); + template_iter_end != template_iter; + ++template_iter) + { + if (wildcard_tag == template_iter->first) + { + wildcard_value = template_iter->second; + } + else if (llsd_to_test.has(template_iter->first)) + { + //the test LLSD has the same key + if (! filter_llsd_with_template(llsd_to_test[template_iter->first], + template_iter->second, + value)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd[template_iter->first] = value; + } + } + else if (! template_has_wildcard) + { + // test llsd doesn't have it...take the + // template as default value + resultant_llsd[template_iter->first] = template_iter->second; + } + } + if (template_has_wildcard) + { + LLSD sub_value; + LLSD::map_const_iterator test_iter; + + for (test_iter = llsd_to_test.beginMap(); + test_iter != llsd_to_test.endMap(); + ++test_iter) + { + if (resultant_llsd.has(test_iter->first)) + { + // Final value has test key, assume more specific + // template matched and we shouldn't modify it again. + continue; + } + else if (! filter_llsd_with_template(test_iter->second, + wildcard_value, + sub_value)) + { + // Test value doesn't match wildcarded template + resultant_llsd = LLSD(); + return false; + } + else + { + // Test value matches template, add the actuals. + resultant_llsd[test_iter->first] = sub_value; + } + } + } + } + else + { + //of same type...take the test llsd's value + resultant_llsd = llsd_to_test; + } + + return true; } /***************************************************************************** @@ -944,9 +944,9 @@ LLSD drill(const LLSD& blob, const LLSD& path) } // namespace llsd -// Construct a deep partial clone of of an LLSD object. primitive types share +// Construct a deep partial clone of of an LLSD object. primitive types share // references, however maps, arrays and binary objects are duplicated. An optional -// filter may be include to exclude/include keys in a map. +// filter may be include to exclude/include keys in a map. LLSD llsd_clone(LLSD value, LLSD filter) { LL_PROFILE_ZONE_SCOPED diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index fdcc052bd0..aa497c53c7 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -1,4 +1,4 @@ -/** +/** * @file llsdutil.h * @author Phoenix * @date 2006-05-24 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -73,11 +73,11 @@ LL_COMMON_API std::string ll_stream_notation_sd(const LLSD& sd); //Otherwise, returns true LL_COMMON_API BOOL compare_llsd_with_template( - const LLSD& llsd_to_test, - const LLSD& template_llsd, - LLSD& resultant_llsd); + const LLSD& llsd_to_test, + const LLSD& template_llsd, + LLSD& resultant_llsd); -// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// filter_llsd_with_template() is a direct clone (copy-n-paste) of // compare_llsd_with_template with the following differences: // (1) bool vs BOOL return types // (2) A map with the key value "*" is a special value and maps any key in the @@ -86,9 +86,9 @@ LL_COMMON_API BOOL compare_llsd_with_template( // for *all* the elements of the test array. If the template array is of // different size, compare_llsd_with_template() semantics apply. bool filter_llsd_with_template( - const LLSD & llsd_to_test, - const LLSD & template_llsd, - LLSD & resultant_llsd); + const LLSD & llsd_to_test, + const LLSD & template_llsd, + LLSD & resultant_llsd); /** * Recursively determine whether a given LLSD data block "matches" another @@ -164,12 +164,12 @@ inline bool operator!=(const LLSD& lhs, const LLSD& rhs) // there is no need for casting. template<typename Input> LLSD llsd_copy_array(Input iter, Input end) { - LLSD dest; - for (; iter != end; ++iter) - { - dest.append(*iter); - } - return dest; + LLSD dest; + for (; iter != end; ++iter) + { + dest.append(*iter); + } + return dest; } namespace llsd @@ -526,19 +526,19 @@ private: } // namespace llsd -// Creates a deep clone of an LLSD object. Maps, Arrays and binary objects +// Creates a deep clone of an LLSD object. Maps, Arrays and binary objects // are duplicated, atomic primitives (Boolean, Integer, Real, etc) simply -// use a shared reference. -// Optionally a filter may be specified to control what is duplicated. The +// use a shared reference. +// Optionally a filter may be specified to control what is duplicated. The // map takes the form "keyname/boolean". -// If the value is true the value will be duplicated otherwise it will be skipped +// If the value is true the value will be duplicated otherwise it will be skipped // when encountered in a map. A key name of "*" can be specified as a wild card // and will specify the default behavior. If no wild card is given and the clone // encounters a name not in the filter, that value will be skipped. LLSD llsd_clone(LLSD value, LLSD filter = LLSD()); -// Creates a shallow copy of a map or array. If passed any other type of LLSD -// object it simply returns that value. See llsd_clone for a description of +// Creates a shallow copy of a map or array. If passed any other type of LLSD +// object it simply returns that value. See llsd_clone for a description of // the filter parameter. LLSD llsd_shallow(LLSD value, LLSD filter = LLSD()); @@ -561,7 +561,7 @@ struct hash<LLSD> { typedef LLSD argument_type; typedef std::size_t result_type; - result_type operator()(argument_type const& s) const + result_type operator()(argument_type const& s) const { result_type seed(0); diff --git a/indra/llcommon/llsimplehash.h b/indra/llcommon/llsimplehash.h index 727b4568d8..530d566466 100644 --- a/indra/llcommon/llsimplehash.h +++ b/indra/llcommon/llsimplehash.h @@ -1,24 +1,24 @@ -/** +/** * @file llsimplehash.h * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,124 +32,124 @@ template <typename HASH_KEY_TYPE> class LLSimpleHashEntry { protected: - HASH_KEY_TYPE mHashKey; - LLSimpleHashEntry<HASH_KEY_TYPE>* mNextEntry; + HASH_KEY_TYPE mHashKey; + LLSimpleHashEntry<HASH_KEY_TYPE>* mNextEntry; public: - LLSimpleHashEntry(HASH_KEY_TYPE key) : - mHashKey(key), - mNextEntry(0) - { - } - virtual ~LLSimpleHashEntry() - { - } - HASH_KEY_TYPE getHashKey() const - { - return mHashKey; - } - LLSimpleHashEntry<HASH_KEY_TYPE>* getNextEntry() const - { - return mNextEntry; - } - void setNextEntry(LLSimpleHashEntry<HASH_KEY_TYPE>* next) - { - mNextEntry = next; - } + LLSimpleHashEntry(HASH_KEY_TYPE key) : + mHashKey(key), + mNextEntry(0) + { + } + virtual ~LLSimpleHashEntry() + { + } + HASH_KEY_TYPE getHashKey() const + { + return mHashKey; + } + LLSimpleHashEntry<HASH_KEY_TYPE>* getNextEntry() const + { + return mNextEntry; + } + void setNextEntry(LLSimpleHashEntry<HASH_KEY_TYPE>* next) + { + mNextEntry = next; + } }; template <typename HASH_KEY_TYPE, int TABLE_SIZE> class LL_COMMON_API LLSimpleHash { public: - LLSimpleHash() - { - llassert(TABLE_SIZE); - llassert((TABLE_SIZE ^ (TABLE_SIZE-1)) == (TABLE_SIZE | (TABLE_SIZE-1))); // power of 2 - memset(mEntryTable, 0, sizeof(mEntryTable)); - } - virtual ~LLSimpleHash() - { - } + LLSimpleHash() + { + llassert(TABLE_SIZE); + llassert((TABLE_SIZE ^ (TABLE_SIZE-1)) == (TABLE_SIZE | (TABLE_SIZE-1))); // power of 2 + memset(mEntryTable, 0, sizeof(mEntryTable)); + } + virtual ~LLSimpleHash() + { + } + + virtual int getIndex(HASH_KEY_TYPE key) + { + return key & (TABLE_SIZE-1); + } + + bool insert(LLSimpleHashEntry<HASH_KEY_TYPE>* entry) + { + llassert(entry->getNextEntry() == 0); + int index = getIndex(entry->getHashKey()); + entry->setNextEntry(mEntryTable[index]); + mEntryTable[index] = entry; + return true; + } + LLSimpleHashEntry<HASH_KEY_TYPE>* find(HASH_KEY_TYPE key) + { + int index = getIndex(key); + LLSimpleHashEntry<HASH_KEY_TYPE>* res = mEntryTable[index]; + while(res && (res->getHashKey() != key)) + { + res = res->getNextEntry(); + } + return res; + } + bool erase(LLSimpleHashEntry<HASH_KEY_TYPE>* entry) + { + return erase(entry->getHashKey()); + } + bool erase(HASH_KEY_TYPE key) + { + int index = getIndex(key); + LLSimpleHashEntry<HASH_KEY_TYPE>* prev = 0; + LLSimpleHashEntry<HASH_KEY_TYPE>* res = mEntryTable[index]; + while(res && (res->getHashKey() != key)) + { + prev = res; + res = res->getNextEntry(); + } + if (res) + { + LLSimpleHashEntry<HASH_KEY_TYPE>* next = res->getNextEntry(); + if (prev) + { + prev->setNextEntry(next); + } + else + { + mEntryTable[index] = next; + } + return true; + } + else + { + return false; + } + } + // Removes and returns an arbitrary ("first") element from the table + // Used for deleting the entire table. + LLSimpleHashEntry<HASH_KEY_TYPE>* pop_element() + { + for (int i=0; i<TABLE_SIZE; i++) + { + LLSimpleHashEntry<HASH_KEY_TYPE>* entry = mEntryTable[i]; + if (entry) + { + mEntryTable[i] = entry->getNextEntry(); + return entry; + } + } + return 0; + } + // debugging + LLSimpleHashEntry<HASH_KEY_TYPE>* get_element_at_index(S32 index) const + { + return mEntryTable[index]; + } + - virtual int getIndex(HASH_KEY_TYPE key) - { - return key & (TABLE_SIZE-1); - } - - bool insert(LLSimpleHashEntry<HASH_KEY_TYPE>* entry) - { - llassert(entry->getNextEntry() == 0); - int index = getIndex(entry->getHashKey()); - entry->setNextEntry(mEntryTable[index]); - mEntryTable[index] = entry; - return true; - } - LLSimpleHashEntry<HASH_KEY_TYPE>* find(HASH_KEY_TYPE key) - { - int index = getIndex(key); - LLSimpleHashEntry<HASH_KEY_TYPE>* res = mEntryTable[index]; - while(res && (res->getHashKey() != key)) - { - res = res->getNextEntry(); - } - return res; - } - bool erase(LLSimpleHashEntry<HASH_KEY_TYPE>* entry) - { - return erase(entry->getHashKey()); - } - bool erase(HASH_KEY_TYPE key) - { - int index = getIndex(key); - LLSimpleHashEntry<HASH_KEY_TYPE>* prev = 0; - LLSimpleHashEntry<HASH_KEY_TYPE>* res = mEntryTable[index]; - while(res && (res->getHashKey() != key)) - { - prev = res; - res = res->getNextEntry(); - } - if (res) - { - LLSimpleHashEntry<HASH_KEY_TYPE>* next = res->getNextEntry(); - if (prev) - { - prev->setNextEntry(next); - } - else - { - mEntryTable[index] = next; - } - return true; - } - else - { - return false; - } - } - // Removes and returns an arbitrary ("first") element from the table - // Used for deleting the entire table. - LLSimpleHashEntry<HASH_KEY_TYPE>* pop_element() - { - for (int i=0; i<TABLE_SIZE; i++) - { - LLSimpleHashEntry<HASH_KEY_TYPE>* entry = mEntryTable[i]; - if (entry) - { - mEntryTable[i] = entry->getNextEntry(); - return entry; - } - } - return 0; - } - // debugging - LLSimpleHashEntry<HASH_KEY_TYPE>* get_element_at_index(S32 index) const - { - return mEntryTable[index]; - } - - private: - LLSimpleHashEntry<HASH_KEY_TYPE>* mEntryTable[TABLE_SIZE]; + LLSimpleHashEntry<HASH_KEY_TYPE>* mEntryTable[TABLE_SIZE]; }; #endif // LL_LLSIMPLEHASH_H diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 5f1a89670e..d00e703a10 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsingleton.cpp * @author Brad Kittenbrink * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -363,7 +363,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort() // should happen basically once: for deleteAll(). typedef LLDependencies<LLSingletonBase*> SingletonDeps; SingletonDeps sdeps; - // Lock while traversing the master list + // Lock while traversing the master list MasterList::LockedMaster master; for (LLSingletonBase* sp : master.get()) { @@ -455,7 +455,7 @@ std::ostream& operator<<(std::ostream& out, const LLSingletonBase::string_params return out; } -} // anonymous namespace +} // anonymous namespace //static void LLSingletonBase::logwarns(const string_params& args) diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 64027c16c7..91c05bd5ed 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -1,24 +1,24 @@ -/** +/** * @file llsingleton.h * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -841,7 +841,7 @@ private: \ // Relatively unsafe singleton implementation that is much faster // and simpler than LLSingleton, but has no dependency tracking -// or inherent thread safety and requires manual invocation of +// or inherent thread safety and requires manual invocation of // createInstance before first use. template<class T> class LLSimpleton diff --git a/indra/llcommon/llsmoothstep.h b/indra/llcommon/llsmoothstep.h index 1f97a3ec89..70686c60e2 100644 --- a/indra/llcommon/llsmoothstep.h +++ b/indra/llcommon/llsmoothstep.h @@ -1,25 +1,25 @@ -/** +/** * @file llsmoothstep.h * @brief Smoothstep - transition from 0 to 1 - function, first and second derivatives all continuous (smooth) * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,15 +31,15 @@ template <class LLDATATYPE> inline LLDATATYPE llsmoothstep(const LLDATATYPE& edge0, const LLDATATYPE& edge1, const LLDATATYPE& value) { if (value < edge0) - return (LLDATATYPE)0; + return (LLDATATYPE)0; - if (value >= edge1) - return (LLDATATYPE)1; + if (value >= edge1) + return (LLDATATYPE)1; - // Scale/bias into [0..1] range - LLDATATYPE scaled_value = (value - edge0) / (edge1 - edge0); + // Scale/bias into [0..1] range + LLDATATYPE scaled_value = (value - edge0) / (edge1 - edge0); - return scaled_value * scaled_value * (3 - 2 * scaled_value); + return scaled_value * scaled_value * (3 - 2 * scaled_value); } #endif // LL_LLSMOOTHSTEP_H diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index 80057bf0f2..1fe7f0f25f 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstacktrace.cpp * @brief stack tracing functionality * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,113 +50,113 @@ static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = bool ll_get_stack_trace(std::vector<std::string>& lines) { - const S32 MAX_STACK_DEPTH = 32; - const S32 STRING_NAME_LENGTH = 200; - const S32 FRAME_SKIP = 2; - static BOOL symbolsLoaded = false; - static BOOL firstCall = true; - - HANDLE hProc = GetCurrentProcess(); - - // load the symbols if they're not loaded - if(!symbolsLoaded && firstCall) - { - symbolsLoaded = SymInitialize(hProc, NULL, true); - firstCall = false; - } - - // if loaded, get the call stack - if(symbolsLoaded) - { - // create the frames to hold the addresses - void* frames[MAX_STACK_DEPTH]; - memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); - S32 depth = 0; - - // get the addresses - depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); - - IMAGEHLP_LINE64 line; - memset(&line, 0, sizeof(IMAGEHLP_LINE64)); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - // create something to hold address info - PIMAGEHLP_SYMBOL64 pSym; - pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - pSym->MaxNameLength = STRING_NAME_LENGTH; - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - - // get address info for each address frame - // and store - for(S32 i=0; i < depth; i++) - { - std::stringstream stack_line; - BOOL ret; - - DWORD64 addr = (DWORD64)frames[i]; - ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); - if(ret) - { - stack_line << pSym->Name << " "; - } - - DWORD dummy; - ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); - if(ret) - { - std::string file_name = line.FileName; - std::string::size_type index = file_name.rfind("\\"); - stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; - } - - lines.push_back(stack_line.str()); - } - - free(pSym); - - // TODO: figure out a way to cleanup symbol loading - // Not hugely necessary, however. - //SymCleanup(hProc); - return true; - } - else - { - lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); - } - - return false; + const S32 MAX_STACK_DEPTH = 32; + const S32 STRING_NAME_LENGTH = 200; + const S32 FRAME_SKIP = 2; + static BOOL symbolsLoaded = false; + static BOOL firstCall = true; + + HANDLE hProc = GetCurrentProcess(); + + // load the symbols if they're not loaded + if(!symbolsLoaded && firstCall) + { + symbolsLoaded = SymInitialize(hProc, NULL, true); + firstCall = false; + } + + // if loaded, get the call stack + if(symbolsLoaded) + { + // create the frames to hold the addresses + void* frames[MAX_STACK_DEPTH]; + memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); + S32 depth = 0; + + // get the addresses + depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); + + IMAGEHLP_LINE64 line; + memset(&line, 0, sizeof(IMAGEHLP_LINE64)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + // create something to hold address info + PIMAGEHLP_SYMBOL64 pSym; + pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + pSym->MaxNameLength = STRING_NAME_LENGTH; + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + + // get address info for each address frame + // and store + for(S32 i=0; i < depth; i++) + { + std::stringstream stack_line; + BOOL ret; + + DWORD64 addr = (DWORD64)frames[i]; + ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); + if(ret) + { + stack_line << pSym->Name << " "; + } + + DWORD dummy; + ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); + if(ret) + { + std::string file_name = line.FileName; + std::string::size_type index = file_name.rfind("\\"); + stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; + } + + lines.push_back(stack_line.str()); + } + + free(pSym); + + // TODO: figure out a way to cleanup symbol loading + // Not hugely necessary, however. + //SymCleanup(hProc); + return true; + } + else + { + lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); + } + + return false; } void ll_get_stack_trace_internal(std::vector<std::string>& lines) { - const S32 MAX_STACK_DEPTH = 100; - const S32 STRING_NAME_LENGTH = 256; + const S32 MAX_STACK_DEPTH = 100; + const S32 STRING_NAME_LENGTH = 256; - HANDLE process = GetCurrentProcess(); - SymInitialize( process, NULL, TRUE ); + HANDLE process = GetCurrentProcess(); + SymInitialize( process, NULL, TRUE ); - void *stack[MAX_STACK_DEPTH]; + void *stack[MAX_STACK_DEPTH]; - unsigned short frames = RtlCaptureStackBackTrace_fn( 0, MAX_STACK_DEPTH, stack, NULL ); - SYMBOL_INFO *symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + STRING_NAME_LENGTH * sizeof(char), 1); - symbol->MaxNameLen = STRING_NAME_LENGTH-1; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + unsigned short frames = RtlCaptureStackBackTrace_fn( 0, MAX_STACK_DEPTH, stack, NULL ); + SYMBOL_INFO *symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + STRING_NAME_LENGTH * sizeof(char), 1); + symbol->MaxNameLen = STRING_NAME_LENGTH-1; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - for(unsigned int i = 0; i < frames; i++) - { - SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); - lines.push_back(symbol->Name); - } + for(unsigned int i = 0; i < frames; i++) + { + SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); + lines.push_back(symbol->Name); + } - free( symbol ); + free( symbol ); } #else bool ll_get_stack_trace(std::vector<std::string>& lines) { - return false; + return false; } void ll_get_stack_trace_internal(std::vector<std::string>& lines) diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h index 335765386a..693eeced63 100644 --- a/indra/llcommon/llstacktrace.h +++ b/indra/llcommon/llstacktrace.h @@ -1,25 +1,25 @@ -/** +/** * @file llstacktrace.h * @brief stack trace functions * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index 6515a3e3cb..99f3d3c870 100644 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -1,24 +1,24 @@ -/** +/** * @file llstatenums.h * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h index d7e0e8a08d..66ba3487c4 100644 --- a/indra/llcommon/llstaticstringtable.h +++ b/indra/llcommon/llstaticstringtable.h @@ -1,4 +1,4 @@ -/** +/** * @file llstringtable.h * @brief The LLStringTable class provides a _fast_ method for finding * unique copies of strings. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,45 +36,45 @@ class LLStaticHashedString { public: - LLStaticHashedString(const std::string& s) - { - string_hash = makehash(s); - string = s; - } + LLStaticHashedString(const std::string& s) + { + string_hash = makehash(s); + string = s; + } - const std::string& String() const { return string; } - size_t Hash() const { return string_hash; } + const std::string& String() const { return string; } + size_t Hash() const { return string_hash; } - bool operator==(const LLStaticHashedString& b) const { return Hash() == b.Hash(); } + bool operator==(const LLStaticHashedString& b) const { return Hash() == b.Hash(); } protected: - size_t makehash(const std::string& s) - { - size_t len = s.size(); - const char* c = s.c_str(); - size_t hashval = 0; - for (size_t i=0; i<len; i++) - { - hashval = ((hashval<<5) + hashval) + *c++; - } - return hashval; - } + size_t makehash(const std::string& s) + { + size_t len = s.size(); + const char* c = s.c_str(); + size_t hashval = 0; + for (size_t i=0; i<len; i++) + { + hashval = ((hashval<<5) + hashval) + *c++; + } + return hashval; + } - std::string string; - size_t string_hash; + std::string string; + size_t string_hash; }; struct LLStaticStringHasher { - enum { bucket_size = 8 }; - size_t operator()(const LLStaticHashedString& key_value) const { return key_value.Hash(); } - bool operator()(const LLStaticHashedString& left, const LLStaticHashedString& right) const { return left.Hash() < right.Hash(); } + enum { bucket_size = 8 }; + size_t operator()(const LLStaticHashedString& key_value) const { return key_value.Hash(); } + bool operator()(const LLStaticHashedString& left, const LLStaticHashedString& right) const { return left.Hash() < right.Hash(); } }; template< typename MappedObject > class LL_COMMON_API LLStaticStringTable - : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > + : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > { }; diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 25131291f9..3a6efd7d34 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -1,25 +1,25 @@ -/** +/** * @file llstl.h * @brief helper object & functions for use with the stl. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,39 +41,39 @@ #include <string.h> #endif // Use to compare the first element only of a pair -// e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t; +// e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t; template <typename T1, typename T2> struct compare_pair_first { - bool operator()(const std::pair<T1, T2>& a, const std::pair<T1, T2>& b) const - { - return a.first < b.first; - } + bool operator()(const std::pair<T1, T2>& a, const std::pair<T1, T2>& b) const + { + return a.first < b.first; + } }; template <typename T1, typename T2> struct compare_pair_greater { - bool operator()(const std::pair<T1, T2>& a, const std::pair<T1, T2>& b) const - { - if (!(a.first < b.first)) - return true; - else if (!(b.first < a.first)) - return false; - else - return !(a.second < b.second); - } + bool operator()(const std::pair<T1, T2>& a, const std::pair<T1, T2>& b) const + { + if (!(a.first < b.first)) + return true; + else if (!(b.first < a.first)) + return false; + else + return !(a.second < b.second); + } }; // Use to compare the contents of two pointers (e.g. std::string*) template <typename T> struct compare_pointer_contents { - typedef const T* Tptr; - bool operator()(const Tptr& a, const Tptr& b) const - { - return *a < *b; - } + typedef const T* Tptr; + bool operator()(const Tptr& a, const Tptr& b) const + { + return *a < *b; + } }; // DeletePointer is a simple helper for deleting all pointers in a container. @@ -86,40 +86,40 @@ struct compare_pointer_contents struct DeletePointer { - template<typename T> void operator()(T* ptr) const - { - delete ptr; - } + template<typename T> void operator()(T* ptr) const + { + delete ptr; + } }; struct DeletePointerArray { - template<typename T> void operator()(T* ptr) const - { - delete[] ptr; - } + template<typename T> void operator()(T* ptr) const + { + delete[] ptr; + } }; // DeletePairedPointer is a simple helper for deleting all pointers in a map. // The general form is: // // std::for_each(somemap.begin(), somemap.end(), DeletePairedPointer()); -// somemap.clear(); // Don't leave dangling pointers around +// somemap.clear(); // Don't leave dangling pointers around struct DeletePairedPointer { - template<typename T> void operator()(T &ptr) const - { - delete ptr.second; - ptr.second = NULL; - } + template<typename T> void operator()(T &ptr) const + { + delete ptr.second; + ptr.second = NULL; + } }; struct DeletePairedPointerArray { - template<typename T> void operator()(T &ptr) const - { - delete[] ptr.second; - ptr.second = NULL; - } + template<typename T> void operator()(T &ptr) const + { + delete[] ptr.second; + ptr.second = NULL; + } }; @@ -144,22 +144,22 @@ struct DeletePairedPointerArray template<typename T> struct DeletePointerFunctor { - bool operator()(T* ptr) const - { - delete ptr; - return true; - } + bool operator()(T* ptr) const + { + delete ptr; + return true; + } }; // See notes about DeleteArray for why you should consider avoiding this. template<typename T> struct DeleteArrayFunctor { - bool operator()(T* ptr) const - { - delete[] ptr; - return true; - } + bool operator()(T* ptr) const + { + delete[] ptr; + return true; + } }; // CopyNewPointer is a simple helper which accepts a pointer, and @@ -169,91 +169,91 @@ struct DeleteArrayFunctor struct CopyNewPointer { - template<typename T> T* operator()(const T* ptr) const - { - return new T(*ptr); - } + template<typename T> T* operator()(const T* ptr) const + { + return new T(*ptr); + } }; template<typename T, typename ALLOC> void delete_and_clear(std::list<T*, ALLOC>& list) { - std::for_each(list.begin(), list.end(), DeletePointer()); - list.clear(); + std::for_each(list.begin(), list.end(), DeletePointer()); + list.clear(); } template<typename T, typename ALLOC> void delete_and_clear(std::vector<T*, ALLOC>& vector) { - std::for_each(vector.begin(), vector.end(), DeletePointer()); - vector.clear(); + std::for_each(vector.begin(), vector.end(), DeletePointer()); + vector.clear(); } template<typename T, typename COMPARE, typename ALLOC> void delete_and_clear(std::set<T*, COMPARE, ALLOC>& set) { - std::for_each(set.begin(), set.end(), DeletePointer()); - set.clear(); + std::for_each(set.begin(), set.end(), DeletePointer()); + set.clear(); } template<typename K, typename V, typename COMPARE, typename ALLOC> void delete_and_clear(std::map<K, V*, COMPARE, ALLOC>& map) { - std::for_each(map.begin(), map.end(), DeletePairedPointer()); - map.clear(); + std::for_each(map.begin(), map.end(), DeletePairedPointer()); + map.clear(); } template<typename T> void delete_and_clear(T*& ptr) { - delete ptr; - ptr = NULL; + delete ptr; + ptr = NULL; } template<typename T> void delete_and_clear_array(T*& ptr) { - delete[] ptr; - ptr = NULL; + delete[] ptr; + ptr = NULL; } // Simple function to help with finding pointers in maps. // For example: -// typedef map_t; +// typedef map_t; // std::map<int, const char*> foo; -// foo[18] = "there"; -// foo[2] = "hello"; -// const char* bar = get_ptr_in_map(foo, 2); // bar -> "hello" +// foo[18] = "there"; +// foo[2] = "hello"; +// const char* bar = get_ptr_in_map(foo, 2); // bar -> "hello" // const char* baz = get_ptr_in_map(foo, 3); // baz == NULL template <typename K, typename T> inline T* get_ptr_in_map(const std::map<K,T*>& inmap, const K& key) { - // Typedef here avoids warnings because of new c++ naming rules. - typedef typename std::map<K,T*>::const_iterator map_iter; - map_iter iter = inmap.find(key); - if(iter == inmap.end()) - { - return NULL; - } - else - { - return iter->second; - } + // Typedef here avoids warnings because of new c++ naming rules. + typedef typename std::map<K,T*>::const_iterator map_iter; + map_iter iter = inmap.find(key); + if(iter == inmap.end()) + { + return NULL; + } + else + { + return iter->second; + } }; // helper function which returns true if key is in inmap. template <typename K, typename T> inline bool is_in_map(const std::map<K,T>& inmap, const K& key) { - if(inmap.find(key) == inmap.end()) - { - return false; - } - else - { - return true; - } + if(inmap.find(key) == inmap.end()) + { + return false; + } + else + { + return true; + } } // Similar to get_ptr_in_map, but for any type with a valid T(0) constructor. @@ -263,17 +263,17 @@ inline bool is_in_map(const std::map<K,T>& inmap, const K& key) template <typename K, typename T> inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value) { - // Typedef here avoids warnings because of new c++ naming rules. - typedef typename std::map<K,T>::const_iterator map_iter; - map_iter iter = inmap.find(key); - if(iter == inmap.end()) - { - return default_value; - } - else - { - return iter->second; - } + // Typedef here avoids warnings because of new c++ naming rules. + typedef typename std::map<K,T>::const_iterator map_iter; + map_iter iter = inmap.find(key); + if(iter == inmap.end()) + { + return default_value; + } + else + { + return iter->second; + } }; // Useful for replacing the removeObj() functionality of LLDynamicArray @@ -288,22 +288,22 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value) template <typename T> inline typename std::vector<T>::iterator vector_replace_with_last(std::vector<T>& invec, typename std::vector<T>::iterator iter) { - typename std::vector<T>::iterator last = invec.end(); --last; - if (iter == invec.end()) - { - return iter; - } - else if (iter == last) - { - invec.pop_back(); - return invec.end(); - } - else - { - *iter = *last; - invec.pop_back(); - return iter; - } + typename std::vector<T>::iterator last = invec.end(); --last; + if (iter == invec.end()) + { + return iter; + } + else if (iter == last) + { + invec.pop_back(); + return invec.end(); + } + else + { + *iter = *last; + invec.pop_back(); + return iter; + } }; // Example: @@ -311,55 +311,55 @@ inline typename std::vector<T>::iterator vector_replace_with_last(std::vector<T> template <typename T> inline bool vector_replace_with_last(std::vector<T>& invec, const T& val) { - typename std::vector<T>::iterator iter = std::find(invec.begin(), invec.end(), val); - if (iter != invec.end()) - { - typename std::vector<T>::iterator last = invec.end(); --last; - *iter = *last; - invec.pop_back(); - return true; - } - return false; + typename std::vector<T>::iterator iter = std::find(invec.begin(), invec.end(), val); + if (iter != invec.end()) + { + typename std::vector<T>::iterator last = invec.end(); --last; + *iter = *last; + invec.pop_back(); + return true; + } + return false; } // Append N elements to the vector and return a pointer to the first new element. template <typename T> inline T* vector_append(std::vector<T>& invec, S32 N) { - U32 sz = invec.size(); - invec.resize(sz+N); - return &(invec[sz]); + U32 sz = invec.size(); + invec.resize(sz+N); + return &(invec[sz]); } // call function f to n members starting at first. similar to std::for_each template <class InputIter, class Size, class Function> Function ll_for_n(InputIter first, Size n, Function f) { - for ( ; n > 0; --n, ++first) - f(*first); - return f; + for ( ; n > 0; --n, ++first) + f(*first); + return f; } // copy first to result n times, incrementing each as we go template <class InputIter, class Size, class OutputIter> OutputIter ll_copy_n(InputIter first, Size n, OutputIter result) { - for ( ; n > 0; --n, ++result, ++first) - *result = *first; - return result; + for ( ; n > 0; --n, ++result, ++first) + *result = *first; + return result; } // set *result = op(*f) for n elements of f template <class InputIter, class OutputIter, class Size, class UnaryOp> OutputIter ll_transform_n( - InputIter first, - Size n, - OutputIter result, - UnaryOp op) -{ - for ( ; n > 0; --n, ++result, ++first) - *result = op(*first); - return result; + InputIter first, + Size n, + OutputIter result, + UnaryOp op) +{ + for ( ; n > 0; --n, ++result, ++first) + *result = op(*first); + return result; } @@ -448,7 +448,7 @@ protected: _Operation3 _M_op3; public: ll_binary_compose(const _Operation1& __x, const _Operation2& __y, - const _Operation3& __z) + const _Operation3& __z) : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } template<typename OP2ARG> auto @@ -495,17 +495,17 @@ template <class _Operation, typename _Arg2> class llbinder2nd { protected: - _Operation op; - _Arg2 value; + _Operation op; + _Arg2 value; public: - llbinder2nd(const _Operation& __x, - const _Arg2& __y) - : op(__x), value(__y) {} - template <typename _Arg1> - auto - operator()(const _Arg1& __x) const { - return op(__x, value); - } + llbinder2nd(const _Operation& __x, + const _Arg2& __y) + : op(__x), value(__y) {} + template <typename _Arg1> + auto + operator()(const _Arg1& __x) const { + return op(__x, value); + } }; template <class _Operation, class _Tp> @@ -544,23 +544,23 @@ bool before(const std::type_info* lhs, const std::type_info* rhs) */ namespace std { - template <> - struct less<const std::type_info*> - { - bool operator()(const std::type_info* lhs, const std::type_info* rhs) const - { - return before(lhs, rhs); - } - }; - - template <> - struct less<std::type_info*> - { - bool operator()(std::type_info* lhs, std::type_info* rhs) const - { - return before(lhs, rhs); - } - }; + template <> + struct less<const std::type_info*> + { + bool operator()(const std::type_info* lhs, const std::type_info* rhs) const + { + return before(lhs, rhs); + } + }; + + template <> + struct less<std::type_info*> + { + bool operator()(std::type_info* lhs, std::type_info* rhs) const + { + return before(lhs, rhs); + } + }; } // std diff --git a/indra/llcommon/llstreamqueue.cpp b/indra/llcommon/llstreamqueue.cpp index 1116a2b6a2..981d913749 100644 --- a/indra/llcommon/llstreamqueue.cpp +++ b/indra/llcommon/llstreamqueue.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-01-05 * @brief Implementation for llstreamqueue. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llstreamqueue.h b/indra/llcommon/llstreamqueue.h index 0726bad175..a09bf4cb4b 100644 --- a/indra/llcommon/llstreamqueue.h +++ b/indra/llcommon/llstreamqueue.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-01-04 * @brief Definition of LLStreamQueue - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llstreamtools.cpp b/indra/llcommon/llstreamtools.cpp index bc32b6fd9e..1021b08ad1 100644 --- a/indra/llcommon/llstreamtools.cpp +++ b/indra/llcommon/llstreamtools.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstreamtools.cpp * @brief some helper functions for parsing legacy simstate and asset files. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,275 +39,275 @@ // skips spaces and tabs bool skip_whitespace(std::istream& input_stream) { - int c = input_stream.peek(); - while (('\t' == c || ' ' == c) && input_stream.good()) - { - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + int c = input_stream.peek(); + while (('\t' == c || ' ' == c) && input_stream.good()) + { + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } // skips whitespace, newlines, and carriage returns bool skip_emptyspace(std::istream& input_stream) { - int c = input_stream.peek(); - while ( input_stream.good() - && ('\t' == c || ' ' == c || '\n' == c || '\r' == c) ) - { - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + int c = input_stream.peek(); + while ( input_stream.good() + && ('\t' == c || ' ' == c || '\n' == c || '\r' == c) ) + { + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } // skips emptyspace and lines that start with a # bool skip_comments_and_emptyspace(std::istream& input_stream) { - while (skip_emptyspace(input_stream)) - { - int c = input_stream.peek(); - if ('#' == c ) - { - while ('\n' != c && input_stream.good()) - { - c = input_stream.get(); - } - } - else - { - break; - } - } - return input_stream.good(); + while (skip_emptyspace(input_stream)) + { + int c = input_stream.peek(); + if ('#' == c ) + { + while ('\n' != c && input_stream.good()) + { + c = input_stream.get(); + } + } + else + { + break; + } + } + return input_stream.good(); } bool skip_line(std::istream& input_stream) { - int c; - do - { - c = input_stream.get(); - } while ('\n' != c && input_stream.good()); - return input_stream.good(); + int c; + do + { + c = input_stream.get(); + } while ('\n' != c && input_stream.good()); + return input_stream.good(); } bool skip_to_next_word(std::istream& input_stream) { - int c = input_stream.peek(); - while ( input_stream.good() - && ( (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || '_' == c ) ) - { - input_stream.get(); - c = input_stream.peek(); - } - while ( input_stream.good() - && !( (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || '_' == c ) ) - { - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + int c = input_stream.peek(); + while ( input_stream.good() + && ( (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || '_' == c ) ) + { + input_stream.get(); + c = input_stream.peek(); + } + while ( input_stream.good() + && !( (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || '_' == c ) ) + { + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream) { - auto key_length = strlen(keyword); /*Flawfinder: ignore*/ - if (0 == key_length) - { - return false; - } - while (input_stream.good()) - { - skip_emptyspace(input_stream); - int c = input_stream.get(); - if (keyword[0] != c) - { - skip_line(input_stream); - } - else - { - int key_index = 1; - while ( key_index < key_length - && keyword[key_index - 1] == c - && input_stream.good()) - { - key_index++; - c = input_stream.get(); - } - - if (key_index == key_length - && keyword[key_index-1] == c) - { - c = input_stream.peek(); - if (' ' == c || '\t' == c || '\r' == c || '\n' == c) - { - return true; - } - else - { - skip_line(input_stream); - } - } - else - { - skip_line(input_stream); - } - } - } - return false; + auto key_length = strlen(keyword); /*Flawfinder: ignore*/ + if (0 == key_length) + { + return false; + } + while (input_stream.good()) + { + skip_emptyspace(input_stream); + int c = input_stream.get(); + if (keyword[0] != c) + { + skip_line(input_stream); + } + else + { + int key_index = 1; + while ( key_index < key_length + && keyword[key_index - 1] == c + && input_stream.good()) + { + key_index++; + c = input_stream.get(); + } + + if (key_index == key_length + && keyword[key_index-1] == c) + { + c = input_stream.peek(); + if (' ' == c || '\t' == c || '\r' == c || '\n' == c) + { + return true; + } + else + { + skip_line(input_stream); + } + } + else + { + skip_line(input_stream); + } + } + } + return false; } /* skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug in windows iostream bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stream) { - int key_length = strlen(keyword); - if (0 == key_length) - { - return false; - } - while (input_stream.good()) - { - skip_emptyspace(input_stream); - int c = input_stream.get(); - if (keyword[0] != c) - { - skip_line(input_stream); - } - else - { - int key_index = 1; - while ( key_index < key_length - && keyword[key_index - 1] == c - && input_stream.good()) - { - key_index++; - c = input_stream.get(); - } - - if (key_index == key_length - && keyword[key_index-1] == c) - { - c = input_stream.peek(); - if (' ' == c || '\t' == c || '\r' == c || '\n' == c) - { - // put the keyword back onto the stream - for (int index = key_length - 1; index >= 0; index--) - { - input_stream.putback(keyword[index]); - } - return true; - } - else - { - skip_line(input_stream); - break; - } - } - else - { - skip_line(input_stream); - } - } - } - return false; + int key_length = strlen(keyword); + if (0 == key_length) + { + return false; + } + while (input_stream.good()) + { + skip_emptyspace(input_stream); + int c = input_stream.get(); + if (keyword[0] != c) + { + skip_line(input_stream); + } + else + { + int key_index = 1; + while ( key_index < key_length + && keyword[key_index - 1] == c + && input_stream.good()) + { + key_index++; + c = input_stream.get(); + } + + if (key_index == key_length + && keyword[key_index-1] == c) + { + c = input_stream.peek(); + if (' ' == c || '\t' == c || '\r' == c || '\n' == c) + { + // put the keyword back onto the stream + for (int index = key_length - 1; index >= 0; index--) + { + input_stream.putback(keyword[index]); + } + return true; + } + else + { + skip_line(input_stream); + break; + } + } + else + { + skip_line(input_stream); + } + } + } + return false; } */ bool get_word(std::string& output_string, std::istream& input_stream) { - skip_emptyspace(input_stream); - int c = input_stream.peek(); - while ( !isspace(c) - && '\n' != c - && '\r' != c - && input_stream.good() ) - { - output_string += c; - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + skip_emptyspace(input_stream); + int c = input_stream.peek(); + while ( !isspace(c) + && '\n' != c + && '\r' != c + && input_stream.good() ) + { + output_string += c; + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } bool get_word(std::string& output_string, std::istream& input_stream, int n) { - skip_emptyspace(input_stream); - int char_count = 0; - int c = input_stream.peek(); - while (!isspace(c) - && '\n' != c - && '\r' != c - && input_stream.good() - && char_count < n) - { - char_count++; - output_string += c; - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + skip_emptyspace(input_stream); + int char_count = 0; + int c = input_stream.peek(); + while (!isspace(c) + && '\n' != c + && '\r' != c + && input_stream.good() + && char_count < n) + { + char_count++; + output_string += c; + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } // get everything up to and including the next newline bool get_line(std::string& output_string, std::istream& input_stream) { - output_string.clear(); - int c = input_stream.get(); - while (input_stream.good()) - { - output_string += c; - if ('\n' == c) - { - break; - } - c = input_stream.get(); - } - return input_stream.good(); + output_string.clear(); + int c = input_stream.get(); + while (input_stream.good()) + { + output_string += c; + if ('\n' == c) + { + break; + } + c = input_stream.get(); + } + return input_stream.good(); } // get everything up to and including the next newline -// up to the next n characters. +// up to the next n characters. // add a newline on the end if bail before actual line ending bool get_line(std::string& output_string, std::istream& input_stream, int n) { - output_string.clear(); - int char_count = 0; - int c = input_stream.get(); - while (input_stream.good() && char_count < n) - { - char_count++; - output_string += c; - if ('\n' == c) - { - break; - } - if (char_count >= n) - { - output_string.append("\n"); - break; - } - c = input_stream.get(); - } - return input_stream.good(); + output_string.clear(); + int char_count = 0; + int c = input_stream.get(); + while (input_stream.good() && char_count < n) + { + char_count++; + output_string += c; + if ('\n' == c) + { + break; + } + if (char_count >= n) + { + output_string.append("\n"); + break; + } + c = input_stream.get(); + } + return input_stream.good(); } /* disabled -- might tickle bug in windows iostream // backs up the input_stream by line_size + 1 characters bool unget_line(const std::string& line, std::istream& input_stream) { - input_stream.putback('\n'); // unget the newline - for (int line_index = line.size()-1; line_index >= 0; line_index--) - { - input_stream.putback(line[line_index]); - } - return input_stream.good(); + input_stream.putback('\n'); // unget the newline + for (int line_index = line.size()-1; line_index >= 0; line_index--) + { + input_stream.putback(line[line_index]); + } + return input_stream.good(); } */ @@ -315,14 +315,14 @@ bool unget_line(const std::string& line, std::istream& input_stream) // returns true if removed last char bool remove_last_char(char c, std::string& line) { - auto line_size = line.size(); - if (line_size > 1 - && c == line[line_size - 1]) - { - line.replace(line_size - 1, 1, ""); - return true; - } - return false; + auto line_size = line.size(); + if (line_size > 1 + && c == line[line_size - 1]) + { + line.replace(line_size - 1, 1, ""); + return true; + } + return false; } // replaces escaped characters with the correct characters from left to right @@ -330,23 +330,23 @@ bool remove_last_char(char c, std::string& line) // "\\n" ---> '\n' (backslash n becomes carriage return) void unescape_string(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; line_size >= 1 && index < line_size - 1; ++index) - { - if ('\\' == line[index]) - { - if ('\\' == line[index + 1]) - { - line.replace(index, 2, "\\"); - line_size--; - } - else if ('n' == line[index + 1]) - { - line.replace(index, 2, "\n"); - line_size--; - } - } - } + auto line_size = line.size(); + for (size_t index = 0; line_size >= 1 && index < line_size - 1; ++index) + { + if ('\\' == line[index]) + { + if ('\\' == line[index + 1]) + { + line.replace(index, 2, "\\"); + line_size--; + } + else if ('n' == line[index + 1]) + { + line.replace(index, 2, "\n"); + line_size--; + } + } + } } // replaces unescaped characters with expanded equivalents from left to right @@ -354,164 +354,164 @@ void unescape_string(std::string& line) // '\n' ---> "\\n" (carriage return becomes backslash n) void escape_string(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; index < line_size; ++index) - { - if ('\\' == line[index]) - { - line.replace(index, 1, "\\\\"); - line_size++; - index++; - } - else if ('\n' == line[index]) - { - line.replace(index, 1, "\\n"); - line_size++; - index++; - } - } + auto line_size = line.size(); + for (size_t index = 0; index < line_size; ++index) + { + if ('\\' == line[index]) + { + line.replace(index, 1, "\\\\"); + line_size++; + index++; + } + else if ('\n' == line[index]) + { + line.replace(index, 1, "\\n"); + line_size++; + index++; + } + } } // removes '\n' characters void replace_newlines_with_whitespace(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; index < line_size; ++index) - { - if ('\n' == line[index]) - { - line.replace(index, 1, " "); - } - } + auto line_size = line.size(); + for (size_t index = 0; index < line_size; ++index) + { + if ('\n' == line[index]) + { + line.replace(index, 1, " "); + } + } } // erases any double-quote characters in 'line' void remove_double_quotes(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; index < line_size; ) - { - if ('"' == line[index]) - { - int count = 1; - while (index + count < line_size - && '"' == line[index + count]) - { - count++; - } - line.replace(index, count, ""); - line_size -= count; - } - else - { - index++; - } - } + auto line_size = line.size(); + for (size_t index = 0; index < line_size; ) + { + if ('"' == line[index]) + { + int count = 1; + while (index + count < line_size + && '"' == line[index + count]) + { + count++; + } + line.replace(index, count, ""); + line_size -= count; + } + else + { + index++; + } + } } // the 'keyword' is defined as the first word on a line // the 'value' is everything after the keyword on the same line // starting at the first non-whitespace and ending right before the newline -void get_keyword_and_value(std::string& keyword, - std::string& value, - const std::string& line) +void get_keyword_and_value(std::string& keyword, + std::string& value, + const std::string& line) { - // skip initial whitespace - auto line_size = line.size(); - size_t line_index = 0; - char c; - for ( ; line_index < line_size; ++line_index) - { - c = line[line_index]; - if (!LLStringOps::isSpace(c)) - { - break; - } - } - - // get the keyword - keyword.clear(); - for ( ; line_index < line_size; ++line_index) - { - c = line[line_index]; - if (LLStringOps::isSpace(c) || '\r' == c || '\n' == c) - { - break; - } - keyword += c; - } - - // get the value - value.clear(); - if (keyword.size() > 0 - && '\r' != line[line_index] - && '\n' != line[line_index]) - - { - // discard initial white spaces - while (line_index < line_size - && (' ' == line[line_index] - || '\t' == line[line_index]) ) - { - line_index++; - } - - for ( ; line_index < line_size; ++line_index) - { - c = line[line_index]; - if ('\r' == c || '\n' == c) - { - break; - } - value += c; - } - } + // skip initial whitespace + auto line_size = line.size(); + size_t line_index = 0; + char c; + for ( ; line_index < line_size; ++line_index) + { + c = line[line_index]; + if (!LLStringOps::isSpace(c)) + { + break; + } + } + + // get the keyword + keyword.clear(); + for ( ; line_index < line_size; ++line_index) + { + c = line[line_index]; + if (LLStringOps::isSpace(c) || '\r' == c || '\n' == c) + { + break; + } + keyword += c; + } + + // get the value + value.clear(); + if (keyword.size() > 0 + && '\r' != line[line_index] + && '\n' != line[line_index]) + + { + // discard initial white spaces + while (line_index < line_size + && (' ' == line[line_index] + || '\t' == line[line_index]) ) + { + line_index++; + } + + for ( ; line_index < line_size; ++line_index) + { + c = line[line_index]; + if ('\r' == c || '\n' == c) + { + break; + } + value += c; + } + } } std::streamsize fullread( - std::istream& istr, - char* buf, - std::streamsize requested) + std::istream& istr, + char* buf, + std::streamsize requested) { - std::streamsize got; - std::streamsize total = 0; - - istr.read(buf, requested); /*Flawfinder: ignore*/ - got = istr.gcount(); - total += got; - while(got && total < requested) - { - if(istr.fail()) - { - // If bad is true, not much we can doo -- it implies loss - // of stream integrity. Bail in that case, and otherwise - // clear and attempt to continue. - if(istr.bad()) return total; - istr.clear(); - } - istr.read(buf + total, requested - total); /*Flawfinder: ignore*/ - got = istr.gcount(); - total += got; - } - return total; + std::streamsize got; + std::streamsize total = 0; + + istr.read(buf, requested); /*Flawfinder: ignore*/ + got = istr.gcount(); + total += got; + while(got && total < requested) + { + if(istr.fail()) + { + // If bad is true, not much we can doo -- it implies loss + // of stream integrity. Bail in that case, and otherwise + // clear and attempt to continue. + if(istr.bad()) return total; + istr.clear(); + } + istr.read(buf + total, requested - total); /*Flawfinder: ignore*/ + got = istr.gcount(); + total += got; + } + return total; } std::istream& operator>>(std::istream& str, const char *tocheck) { - char c = '\0'; - const char *p; - p = tocheck; - while (*p && !str.bad()) - { - str.get(c); - if (c != *p) - { - str.setstate(std::ios::failbit); /*Flawfinder: ignore*/ - break; - } - p++; - } - return str; + char c = '\0'; + const char *p; + p = tocheck; + while (*p && !str.bad()) + { + str.get(c); + if (c != *p) + { + str.setstate(std::ios::failbit); /*Flawfinder: ignore*/ + break; + } + p++; + } + return str; } int cat_streambuf::underflow() diff --git a/indra/llcommon/llstreamtools.h b/indra/llcommon/llstreamtools.h index bb7bc20327..599484361b 100644 --- a/indra/llcommon/llstreamtools.h +++ b/indra/llcommon/llstreamtools.h @@ -1,25 +1,25 @@ -/** +/** * @file llstreamtools.h * @brief some helper functions for parsing legacy simstate and asset files. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,11 +49,11 @@ LL_COMMON_API bool skip_line(std::istream& input_stream); // skips to beginning of next non-emptyspace LL_COMMON_API bool skip_to_next_word(std::istream& input_stream); -// skips to character after the end of next keyword +// skips to character after the end of next keyword // a 'keyword' is defined as the first word on a line LL_COMMON_API bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream); -// skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug +// skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug // in windows iostream // skips to beginning of next keyword // a 'keyword' is defined as the first word on a line @@ -65,7 +65,7 @@ LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stre LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream); // characters are pulled out of input_stream (up to a max of 'n') -// and appended to output_string +// and appended to output_string // returns result of input_stream.good() after characters are pulled LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream, int n); LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream, int n); @@ -81,13 +81,13 @@ LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stre LL_COMMON_API bool remove_last_char(char c, std::string& line); // replaces escaped characters with the correct characters from left to right -// "\\" ---> '\\' -// "\n" ---> '\n' +// "\\" ---> '\\' +// "\n" ---> '\n' LL_COMMON_API void unescape_string(std::string& line); // replaces unescaped characters with expanded equivalents from left to right -// '\\' ---> "\\" -// '\n' ---> "\n" +// '\\' ---> "\\" +// '\n' ---> "\n" LL_COMMON_API void escape_string(std::string& line); // replaces each '\n' character with ' ' @@ -99,18 +99,18 @@ LL_COMMON_API void remove_double_quotes(std::string& line); // the 'keyword' is defined as the first word on a line // the 'value' is everything after the keyword on the same line // starting at the first non-whitespace and ending right before the newline -LL_COMMON_API void get_keyword_and_value(std::string& keyword, - std::string& value, - const std::string& line); +LL_COMMON_API void get_keyword_and_value(std::string& keyword, + std::string& value, + const std::string& line); // continue to read from the stream until you really can't // read anymore or until we hit the count. Some istream // implimentations have a max that they will read. // Returns the number of bytes read. LL_COMMON_API std::streamsize fullread( - std::istream& istr, - char* buf, - std::streamsize requested); + std::istream& istr, + char* buf, + std::streamsize requested); LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck); diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index ed9284d2c5..6c76ab8104 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -1,24 +1,24 @@ -/** +/** * @file llstrider.h * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,38 +30,38 @@ template <class Object> class LLStrider { - union - { - Object* mObjectp; - U8* mBytep; - }; - U32 mSkip; + union + { + Object* mObjectp; + U8* mBytep; + }; + U32 mSkip; public: - LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); } - ~LLStrider() { } + LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); } + ~LLStrider() { } - const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;} - void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} + const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;} + void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} - LLStrider<Object> operator+(const S32& index) - { - LLStrider<Object> ret; - ret.mBytep = mBytep + mSkip*index; - ret.mSkip = mSkip; + LLStrider<Object> operator+(const S32& index) + { + LLStrider<Object> ret; + ret.mBytep = mBytep + mSkip*index; + ret.mSkip = mSkip; - return ret; - } + return ret; + } - void skip(const U32 index) { mBytep += mSkip*index;} - U32 getSkip() const { return mSkip; } - Object* get() { return mObjectp; } - Object* operator->() { return mObjectp; } - Object& operator *() { return *mObjectp; } - Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } - Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } + void skip(const U32 index) { mBytep += mSkip*index;} + U32 getSkip() const { return mSkip; } + Object* get() { return mObjectp; } + Object* operator->() { return mObjectp; } + Object& operator *() { return *mObjectp; } + Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } + Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } - Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } + Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } }; #endif // LL_LLSTRIDER_H diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index a746cc11ec..6512bbc392 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstring.cpp * @brief String utility functions and the std::string class. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,7 +30,6 @@ #include "llerror.h" #include "llfasttimer.h" #include "llsd.h" -#include <unicode/uchar.h> #include <vector> #if LL_WINDOWS @@ -40,85 +39,85 @@ std::string ll_safe_string(const char* in) { - if(in) return std::string(in); - return std::string(); + if(in) return std::string(in); + return std::string(); } std::string ll_safe_string(const char* in, S32 maxlen) { - if(in && maxlen > 0 ) return std::string(in, maxlen); + if(in && maxlen > 0 ) return std::string(in, maxlen); - return std::string(); + return std::string(); } bool is_char_hex(char hex) { - if((hex >= '0') && (hex <= '9')) - { - return true; - } - else if((hex >= 'a') && (hex <='f')) - { - return true; - } - else if((hex >= 'A') && (hex <='F')) - { - return true; - } - return false; // uh - oh, not hex any more... + if((hex >= '0') && (hex <= '9')) + { + return true; + } + else if((hex >= 'a') && (hex <='f')) + { + return true; + } + else if((hex >= 'A') && (hex <='F')) + { + return true; + } + return false; // uh - oh, not hex any more... } U8 hex_as_nybble(char hex) { - if((hex >= '0') && (hex <= '9')) - { - return (U8)(hex - '0'); - } - else if((hex >= 'a') && (hex <='f')) - { - return (U8)(10 + hex - 'a'); - } - else if((hex >= 'A') && (hex <='F')) - { - return (U8)(10 + hex - 'A'); - } - return 0; // uh - oh, not hex any more... + if((hex >= '0') && (hex <= '9')) + { + return (U8)(hex - '0'); + } + else if((hex >= 'a') && (hex <='f')) + { + return (U8)(10 + hex - 'a'); + } + else if((hex >= 'A') && (hex <='F')) + { + return (U8)(10 + hex - 'A'); + } + return 0; // uh - oh, not hex any more... } bool iswindividual(llwchar elem) -{ - U32 cur_char = (U32)elem; - bool result = false; - if (0x2E80<= cur_char && cur_char <= 0x9FFF) - { - result = true; - } - else if (0xAC00<= cur_char && cur_char <= 0xD7A0 ) - { - result = true; - } - else if (0xF900<= cur_char && cur_char <= 0xFA60 ) - { - result = true; - } - return result; +{ + U32 cur_char = (U32)elem; + bool result = false; + if (0x2E80<= cur_char && cur_char <= 0x9FFF) + { + result = true; + } + else if (0xAC00<= cur_char && cur_char <= 0xD7A0 ) + { + result = true; + } + else if (0xF900<= cur_char && cur_char <= 0xFA60 ) + { + result = true; + } + return result; } bool _read_file_into_string(std::string& str, const std::string& filename) { - llifstream ifs(filename.c_str(), llifstream::binary); - if (!ifs.is_open()) - { - LL_INFOS() << "Unable to open file " << filename << LL_ENDL; - return false; - } + llifstream ifs(filename.c_str(), llifstream::binary); + if (!ifs.is_open()) + { + LL_INFOS() << "Unable to open file " << filename << LL_ENDL; + return false; + } - std::ostringstream oss; + std::ostringstream oss; - oss << ifs.rdbuf(); - str = oss.str(); - ifs.close(); - return true; + oss << ifs.rdbuf(); + str = oss.str(); + ifs.close(); + return true; } @@ -131,179 +130,179 @@ bool _read_file_into_string(std::string& str, const std::string& filename) std::ostream& operator<<(std::ostream &s, const LLWString &wstr) { - std::string utf8_str = wstring_to_utf8str(wstr); - s << utf8_str; - return s; + std::string utf8_str = wstring_to_utf8str(wstr); + s << utf8_str; + return s; } std::string rawstr_to_utf8(const std::string& raw) { - LLWString wstr(utf8str_to_wstring(raw)); - return wstring_to_utf8str(wstr); + LLWString wstr(utf8str_to_wstring(raw)); + return wstring_to_utf8str(wstr); } std::ptrdiff_t wchar_to_utf8chars(llwchar in_char, char* outchars) { - U32 cur_char = (U32)in_char; - char* base = outchars; - if (cur_char < 0x80) - { - *outchars++ = (U8)cur_char; - } - else if (cur_char < 0x800) - { - *outchars++ = 0xC0 | (cur_char >> 6); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x10000) - { - *outchars++ = 0xE0 | (cur_char >> 12); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x200000) - { - *outchars++ = 0xF0 | (cur_char >> 18); - *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x4000000) - { - *outchars++ = 0xF8 | (cur_char >> 24); - *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x80000000) - { - *outchars++ = 0xFC | (cur_char >> 30); - *outchars++ = 0x80 | ((cur_char >> 24) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else - { - LL_WARNS() << "Invalid Unicode character " << cur_char << "!" << LL_ENDL; - *outchars++ = LL_UNKNOWN_CHAR; - } - return outchars - base; -} + U32 cur_char = (U32)in_char; + char* base = outchars; + if (cur_char < 0x80) + { + *outchars++ = (U8)cur_char; + } + else if (cur_char < 0x800) + { + *outchars++ = 0xC0 | (cur_char >> 6); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x10000) + { + *outchars++ = 0xE0 | (cur_char >> 12); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x200000) + { + *outchars++ = 0xF0 | (cur_char >> 18); + *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x4000000) + { + *outchars++ = 0xF8 | (cur_char >> 24); + *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x80000000) + { + *outchars++ = 0xFC | (cur_char >> 30); + *outchars++ = 0x80 | ((cur_char >> 24) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else + { + LL_WARNS() << "Invalid Unicode character " << cur_char << "!" << LL_ENDL; + *outchars++ = LL_UNKNOWN_CHAR; + } + return outchars - base; +} auto utf16chars_to_wchar(const U16* inchars, llwchar* outchar) { - const U16* base = inchars; - U16 cur_char = *inchars++; - llwchar char32 = cur_char; - if ((cur_char >= 0xD800) && (cur_char <= 0xDFFF)) - { - // Surrogates - char32 = ((llwchar)(cur_char - 0xD800)) << 10; - cur_char = *inchars++; - char32 += (llwchar)(cur_char - 0xDC00) + 0x0010000UL; - } - else - { - char32 = (llwchar)cur_char; - } - *outchar = char32; - return inchars - base; + const U16* base = inchars; + U16 cur_char = *inchars++; + llwchar char32 = cur_char; + if ((cur_char >= 0xD800) && (cur_char <= 0xDFFF)) + { + // Surrogates + char32 = ((llwchar)(cur_char - 0xD800)) << 10; + cur_char = *inchars++; + char32 += (llwchar)(cur_char - 0xDC00) + 0x0010000UL; + } + else + { + char32 = (llwchar)cur_char; + } + *outchar = char32; + return inchars - base; } llutf16string wstring_to_utf16str(const llwchar* utf32str, size_t len) { - llutf16string out; - - S32 i = 0; - while (i < len) - { - U32 cur_char = utf32str[i]; - if (cur_char > 0xFFFF) - { - out += (0xD7C0 + (cur_char >> 10)); - out += (0xDC00 | (cur_char & 0x3FF)); - } - else - { - out += cur_char; - } - i++; - } - return out; + llutf16string out; + + S32 i = 0; + while (i < len) + { + U32 cur_char = utf32str[i]; + if (cur_char > 0xFFFF) + { + out += (0xD7C0 + (cur_char >> 10)); + out += (0xDC00 | (cur_char & 0x3FF)); + } + else + { + out += cur_char; + } + i++; + } + return out; } llutf16string utf8str_to_utf16str( const char* utf8str, size_t len ) { - LLWString wstr = utf8str_to_wstring ( utf8str, len ); - return wstring_to_utf16str ( wstr ); + LLWString wstr = utf8str_to_wstring ( utf8str, len ); + return wstring_to_utf16str ( wstr ); } LLWString utf16str_to_wstring(const U16* utf16str, size_t len) { - LLWString wout; - if (len == 0) return wout; + LLWString wout; + if (len == 0) return wout; - S32 i = 0; - const U16* chars16 = utf16str; - while (i < len) - { - llwchar cur_char; - i += utf16chars_to_wchar(chars16+i, &cur_char); - wout += cur_char; - } - return wout; + S32 i = 0; + const U16* chars16 = utf16str; + while (i < len) + { + llwchar cur_char; + i += utf16chars_to_wchar(chars16+i, &cur_char); + wout += cur_char; + } + return wout; } // Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len) { - S32 surrogate_pairs = 0; - // ... craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): - const U16 *const utf16_chars = &(*(utf16str.begin())); - S32 i = 0; - while (i < utf16_len) - { - const U16 c = utf16_chars[i++]; - if (c >= 0xD800 && c <= 0xDBFF) // See http://en.wikipedia.org/wiki/UTF-16 - { // Have first byte of a surrogate pair - if (i >= utf16_len) - { - break; - } - const U16 d = utf16_chars[i]; - if (d >= 0xDC00 && d <= 0xDFFF) - { // Have valid second byte of a surrogate pair - surrogate_pairs++; - i++; - } - } - } - return utf16_len - surrogate_pairs; + S32 surrogate_pairs = 0; + // ... craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): + const U16 *const utf16_chars = &(*(utf16str.begin())); + S32 i = 0; + while (i < utf16_len) + { + const U16 c = utf16_chars[i++]; + if (c >= 0xD800 && c <= 0xDBFF) // See http://en.wikipedia.org/wiki/UTF-16 + { // Have first byte of a surrogate pair + if (i >= utf16_len) + { + break; + } + const U16 d = utf16_chars[i]; + if (d >= 0xDC00 && d <= 0xDFFF) + { // Have valid second byte of a surrogate pair + surrogate_pairs++; + i++; + } + } + } + return utf16_len - surrogate_pairs; } // Length in utf16string (UTF-16) of wlen wchars beginning at woffset. S32 wstring_utf16_length(const LLWString &wstr, const S32 woffset, const S32 wlen) { - const S32 end = llmin((S32)wstr.length(), woffset + wlen); - if (end < woffset) - { - return 0; - } - else - { - S32 length = end - woffset; - for (S32 i = woffset; i < end; i++) - { - if (wstr[i] >= 0x10000) - { - length++; - } - } - return length; - } + const S32 end = llmin((S32)wstr.length(), woffset + wlen); + if (end < woffset) + { + return 0; + } + else + { + S32 length = end - woffset; + for (S32 i = woffset; i < end; i++) + { + if (wstr[i] >= 0x10000) + { + length++; + } + } + return length; + } } // Given a wstring and an offset in it, returns the length as wstring (i.e., @@ -311,56 +310,56 @@ S32 wstring_utf16_length(const LLWString &wstr, const S32 woffset, const S32 wle // and whose equivalent utf-16 string does not exceeds the given utf16_length. S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, const S32 woffset, const S32 utf16_length, BOOL *unaligned) { - const auto end = wstr.length(); - BOOL u = FALSE; - S32 n = woffset + utf16_length; - S32 i = woffset; - while (i < end) - { - if (wstr[i] >= 0x10000) - { - --n; - } - if (i >= n) - { - u = (i > n); - break; - } - i++; - } - if (unaligned) - { - *unaligned = u; - } - return i - woffset; + const auto end = wstr.length(); + BOOL u = FALSE; + S32 n = woffset + utf16_length; + S32 i = woffset; + while (i < end) + { + if (wstr[i] >= 0x10000) + { + --n; + } + if (i >= n) + { + u = (i > n); + break; + } + i++; + } + if (unaligned) + { + *unaligned = u; + } + return i - woffset; } S32 wchar_utf8_length(const llwchar wc) { - if (wc < 0x80) - { - return 1; - } - else if (wc < 0x800) - { - return 2; - } - else if (wc < 0x10000) - { - return 3; - } - else if (wc < 0x200000) - { - return 4; - } - else if (wc < 0x4000000) - { - return 5; - } - else - { - return 6; - } + if (wc < 0x80) + { + return 1; + } + else if (wc < 0x800) + { + return 2; + } + else if (wc < 0x10000) + { + return 3; + } + else if (wc < 0x200000) + { + return 4; + } + else if (wc < 0x4000000) + { + return 5; + } + else + { + return 6; + } } std::string wchar_utf8_preview(const llwchar wc) @@ -390,179 +389,179 @@ std::string wchar_utf8_preview(const llwchar wc) S32 wstring_utf8_length(const LLWString& wstr) { - S32 len = 0; - for (S32 i = 0; i < (S32)wstr.length(); i++) - { - len += wchar_utf8_length(wstr[i]); - } - return len; + S32 len = 0; + for (S32 i = 0; i < (S32)wstr.length(); i++) + { + len += wchar_utf8_length(wstr[i]); + } + return len; } LLWString utf8str_to_wstring(const char* utf8str, size_t len) { - LLWString wout; - - S32 i = 0; - while (i < len) - { - llwchar unichar; - U8 cur_char = utf8str[i]; - - if (cur_char < 0x80) - { - // Ascii character, just add it - unichar = cur_char; - } - else - { - S32 cont_bytes = 0; - if ((cur_char >> 5) == 0x6) // Two byte UTF8 -> 1 UTF32 - { - unichar = (0x1F&cur_char); - cont_bytes = 1; - } - else if ((cur_char >> 4) == 0xe) // Three byte UTF8 -> 1 UTF32 - { - unichar = (0x0F&cur_char); - cont_bytes = 2; - } - else if ((cur_char >> 3) == 0x1e) // Four byte UTF8 -> 1 UTF32 - { - unichar = (0x07&cur_char); - cont_bytes = 3; - } - else if ((cur_char >> 2) == 0x3e) // Five byte UTF8 -> 1 UTF32 - { - unichar = (0x03&cur_char); - cont_bytes = 4; - } - else if ((cur_char >> 1) == 0x7e) // Six byte UTF8 -> 1 UTF32 - { - unichar = (0x01&cur_char); - cont_bytes = 5; - } - else - { - wout += LL_UNKNOWN_CHAR; - ++i; - continue; - } - - // Check that this character doesn't go past the end of the string - auto end = (len < (i + cont_bytes)) ? len : (i + cont_bytes); - do - { - ++i; - - cur_char = utf8str[i]; - if ( (cur_char >> 6) == 0x2 ) - { - unichar <<= 6; - unichar += (0x3F&cur_char); - } - else - { - // Malformed sequence - roll back to look at this as a new char - unichar = LL_UNKNOWN_CHAR; - --i; - break; - } - } while(i < end); - - // Handle overlong characters and NULL characters - if ( ((cont_bytes == 1) && (unichar < 0x80)) - || ((cont_bytes == 2) && (unichar < 0x800)) - || ((cont_bytes == 3) && (unichar < 0x10000)) - || ((cont_bytes == 4) && (unichar < 0x200000)) - || ((cont_bytes == 5) && (unichar < 0x4000000)) ) - { - unichar = LL_UNKNOWN_CHAR; - } - } - - wout += unichar; - ++i; - } - return wout; + LLWString wout; + + S32 i = 0; + while (i < len) + { + llwchar unichar; + U8 cur_char = utf8str[i]; + + if (cur_char < 0x80) + { + // Ascii character, just add it + unichar = cur_char; + } + else + { + S32 cont_bytes = 0; + if ((cur_char >> 5) == 0x6) // Two byte UTF8 -> 1 UTF32 + { + unichar = (0x1F&cur_char); + cont_bytes = 1; + } + else if ((cur_char >> 4) == 0xe) // Three byte UTF8 -> 1 UTF32 + { + unichar = (0x0F&cur_char); + cont_bytes = 2; + } + else if ((cur_char >> 3) == 0x1e) // Four byte UTF8 -> 1 UTF32 + { + unichar = (0x07&cur_char); + cont_bytes = 3; + } + else if ((cur_char >> 2) == 0x3e) // Five byte UTF8 -> 1 UTF32 + { + unichar = (0x03&cur_char); + cont_bytes = 4; + } + else if ((cur_char >> 1) == 0x7e) // Six byte UTF8 -> 1 UTF32 + { + unichar = (0x01&cur_char); + cont_bytes = 5; + } + else + { + wout += LL_UNKNOWN_CHAR; + ++i; + continue; + } + + // Check that this character doesn't go past the end of the string + auto end = (len < (i + cont_bytes)) ? len : (i + cont_bytes); + do + { + ++i; + + cur_char = utf8str[i]; + if ( (cur_char >> 6) == 0x2 ) + { + unichar <<= 6; + unichar += (0x3F&cur_char); + } + else + { + // Malformed sequence - roll back to look at this as a new char + unichar = LL_UNKNOWN_CHAR; + --i; + break; + } + } while(i < end); + + // Handle overlong characters and NULL characters + if ( ((cont_bytes == 1) && (unichar < 0x80)) + || ((cont_bytes == 2) && (unichar < 0x800)) + || ((cont_bytes == 3) && (unichar < 0x10000)) + || ((cont_bytes == 4) && (unichar < 0x200000)) + || ((cont_bytes == 5) && (unichar < 0x4000000)) ) + { + unichar = LL_UNKNOWN_CHAR; + } + } + + wout += unichar; + ++i; + } + return wout; } std::string wstring_to_utf8str(const llwchar* utf32str, size_t len) { - std::string out; + std::string out; - S32 i = 0; - while (i < len) - { - char tchars[8]; /* Flawfinder: ignore */ - auto n = wchar_to_utf8chars(utf32str[i], tchars); - tchars[n] = 0; - out += tchars; - i++; - } - return out; + S32 i = 0; + while (i < len) + { + char tchars[8]; /* Flawfinder: ignore */ + auto n = wchar_to_utf8chars(utf32str[i], tchars); + tchars[n] = 0; + out += tchars; + i++; + } + return out; } std::string utf16str_to_utf8str(const U16* utf16str, size_t len) { - return wstring_to_utf8str(utf16str_to_wstring(utf16str, len)); + return wstring_to_utf8str(utf16str_to_wstring(utf16str, len)); } std::string utf8str_trim(const std::string& utf8str) { - LLWString wstr = utf8str_to_wstring(utf8str); - LLWStringUtil::trim(wstr); - return wstring_to_utf8str(wstr); + LLWString wstr = utf8str_to_wstring(utf8str); + LLWStringUtil::trim(wstr); + return wstring_to_utf8str(wstr); } std::string utf8str_tolower(const std::string& utf8str) { - LLWString out_str = utf8str_to_wstring(utf8str); - LLWStringUtil::toLower(out_str); - return wstring_to_utf8str(out_str); + LLWString out_str = utf8str_to_wstring(utf8str); + LLWStringUtil::toLower(out_str); + return wstring_to_utf8str(out_str); } S32 utf8str_compare_insensitive(const std::string& lhs, const std::string& rhs) { - LLWString wlhs = utf8str_to_wstring(lhs); - LLWString wrhs = utf8str_to_wstring(rhs); - return LLWStringUtil::compareInsensitive(wlhs, wrhs); + LLWString wlhs = utf8str_to_wstring(lhs); + LLWString wrhs = utf8str_to_wstring(rhs); + return LLWStringUtil::compareInsensitive(wlhs, wrhs); } std::string utf8str_truncate(const std::string& utf8str, const S32 max_len) { - if (0 == max_len) - { - return std::string(); - } - if ((S32)utf8str.length() <= max_len) - { - return utf8str; - } - else - { - S32 cur_char = max_len; - - // If we're ASCII, we don't need to do anything - if ((U8)utf8str[cur_char] > 0x7f) - { - // If first two bits are (10), it's the tail end of a multibyte char. We need to shift back - // to the first character - while (0x80 == (0xc0 & utf8str[cur_char])) - { - cur_char--; - // Keep moving forward until we hit the first char; - if (cur_char == 0) - { - // Make sure we don't trash memory if we've got a bogus string. - break; - } - } - } - // The byte index we're on is one we want to get rid of, so we only want to copy up to (cur_char-1) chars - return utf8str.substr(0, cur_char); - } + if (0 == max_len) + { + return std::string(); + } + if ((S32)utf8str.length() <= max_len) + { + return utf8str; + } + else + { + S32 cur_char = max_len; + + // If we're ASCII, we don't need to do anything + if ((U8)utf8str[cur_char] > 0x7f) + { + // If first two bits are (10), it's the tail end of a multibyte char. We need to shift back + // to the first character + while (0x80 == (0xc0 & utf8str[cur_char])) + { + cur_char--; + // Keep moving forward until we hit the first char; + if (cur_char == 0) + { + // Make sure we don't trash memory if we've got a bogus string. + break; + } + } + } + // The byte index we're on is one we want to get rid of, so we only want to copy up to (cur_char-1) chars + return utf8str.substr(0, cur_char); + } } std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len) @@ -593,56 +592,56 @@ std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol } std::string utf8str_substChar( - const std::string& utf8str, - const llwchar target_char, - const llwchar replace_char) -{ - LLWString wstr = utf8str_to_wstring(utf8str); - LLWStringUtil::replaceChar(wstr, target_char, replace_char); - //wstr = wstring_substChar(wstr, target_char, replace_char); - return wstring_to_utf8str(wstr); + const std::string& utf8str, + const llwchar target_char, + const llwchar replace_char) +{ + LLWString wstr = utf8str_to_wstring(utf8str); + LLWStringUtil::replaceChar(wstr, target_char, replace_char); + //wstr = wstring_substChar(wstr, target_char, replace_char); + return wstring_to_utf8str(wstr); } std::string utf8str_makeASCII(const std::string& utf8str) { - LLWString wstr = utf8str_to_wstring(utf8str); - LLWStringUtil::_makeASCII(wstr); - return wstring_to_utf8str(wstr); + LLWString wstr = utf8str_to_wstring(utf8str); + LLWStringUtil::_makeASCII(wstr); + return wstring_to_utf8str(wstr); } std::string mbcsstring_makeASCII(const std::string& wstr) { - // Replace non-ASCII chars with replace_char - std::string out_str = wstr; - for (S32 i = 0; i < (S32)out_str.length(); i++) - { - if ((U8)out_str[i] > 0x7f) - { - out_str[i] = LL_UNKNOWN_CHAR; - } - } - return out_str; + // Replace non-ASCII chars with replace_char + std::string out_str = wstr; + for (S32 i = 0; i < (S32)out_str.length(); i++) + { + if ((U8)out_str[i] > 0x7f) + { + out_str[i] = LL_UNKNOWN_CHAR; + } + } + return out_str; } std::string utf8str_removeCRLF(const std::string& utf8str) { - if (0 == utf8str.length()) - { - return std::string(); - } - const char CR = 13; - - std::string out; - out.reserve(utf8str.length()); - const S32 len = (S32)utf8str.length(); - for( S32 i = 0; i < len; i++ ) - { - if( utf8str[i] != CR ) - { - out.push_back(utf8str[i]); - } - } - return out; + if (0 == utf8str.length()) + { + return std::string(); + } + const char CR = 13; + + std::string out; + out.reserve(utf8str.length()); + const S32 len = (S32)utf8str.length(); + for( S32 i = 0; i < len; i++ ) + { + if( utf8str[i] != CR ) + { + out.push_back(utf8str[i]); + } + } + return out; } llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset, size_t length) @@ -758,6 +757,43 @@ std::string utf8str_showBytesUTF8(const std::string& utf8str) return result; } +// Search for any emoji symbol, return true if found +bool wstring_has_emoji(const LLWString& wstr) +{ + for (const llwchar& wch : wstr) + { + if (LLStringOps::isEmoji(wch)) + return true; + } + + return false; +} + +// Cut emoji symbols if exist +bool wstring_remove_emojis(LLWString& wstr) +{ + bool found = false; + for (size_t i = 0; i < wstr.size(); ++i) + { + if (LLStringOps::isEmoji(wstr[i])) + { + wstr.erase(i--, 1); + found = true; + } + } + return found; +} + +// Cut emoji symbols if exist +bool utf8str_remove_emojis(std::string& utf8str) +{ + LLWString wstr = utf8str_to_wstring(utf8str); + if (!wstring_remove_emojis(wstr)) + return false; + utf8str = wstring_to_utf8str(wstr); + return true; +} + #if LL_WINDOWS unsigned int ll_wstring_default_code_page() { @@ -766,63 +802,63 @@ unsigned int ll_wstring_default_code_page() std::string ll_convert_wide_to_string(const wchar_t* in, size_t len_in, unsigned int code_page) { - std::string out; - if(in) - { - int len_out = WideCharToMultiByte( - code_page, - 0, - in, - len_in, - NULL, - 0, - 0, - 0); - // We will need two more bytes for the double NULL ending - // created in WideCharToMultiByte(). - char* pout = new char [len_out + 2]; - memset(pout, 0, len_out + 2); - if(pout) - { - WideCharToMultiByte( - code_page, - 0, - in, - len_in, - pout, - len_out, - 0, - 0); - out.assign(pout); - delete[] pout; - } - } - return out; + std::string out; + if(in) + { + int len_out = WideCharToMultiByte( + code_page, + 0, + in, + len_in, + NULL, + 0, + 0, + 0); + // We will need two more bytes for the double NULL ending + // created in WideCharToMultiByte(). + char* pout = new char [len_out + 2]; + memset(pout, 0, len_out + 2); + if(pout) + { + WideCharToMultiByte( + code_page, + 0, + in, + len_in, + pout, + len_out, + 0, + 0); + out.assign(pout); + delete[] pout; + } + } + return out; } std::wstring ll_convert_string_to_wide(const char* in, size_t len, unsigned int code_page) { - // From review: - // We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input, - // plus one for a null terminator, and be guaranteed to not overflow. + // From review: + // We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input, + // plus one for a null terminator, and be guaranteed to not overflow. - // Normally, I'd call that sort of thing premature optimization, - // but we *are* seeing string operations taking a bunch of time, especially when constructing widgets. -// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0); + // Normally, I'd call that sort of thing premature optimization, + // but we *are* seeing string operations taking a bunch of time, especially when constructing widgets. +// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0); - // reserve an output buffer that will be destroyed on exit, with a place - // to put NULL terminator - std::vector<wchar_t> w_out(len + 1); + // reserve an output buffer that will be destroyed on exit, with a place + // to put NULL terminator + std::vector<wchar_t> w_out(len + 1); - memset(&w_out[0], 0, w_out.size()); - int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len, - &w_out[0], w_out.size() - 1); + memset(&w_out[0], 0, w_out.size()); + int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len, + &w_out[0], w_out.size() - 1); - //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858. - w_out[real_output_str_len] = 0; + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858. + w_out[real_output_str_len] = 0; - // construct string<wchar_t> from our temporary output buffer - return {&w_out[0]}; + // construct string<wchar_t> from our temporary output buffer + return {&w_out[0]}; } LLWString ll_convert_wide_to_wstring(const wchar_t* in, size_t len) @@ -846,11 +882,11 @@ std::wstring ll_convert_wstring_to_wide(const llwchar* in, size_t len) std::string ll_convert_string_to_utf8_string(const std::string& in) { - // If you pass code_page, you must also pass length, otherwise the code - // page parameter will be mistaken for length. - auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP); - // CP_UTF8 is default -- see ll_wstring_default_code_page() above. - return ll_convert_wide_to_string(w_mesg); + // If you pass code_page, you must also pass length, otherwise the code + // page parameter will be mistaken for length. + auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP); + // CP_UTF8 is default -- see ll_wstring_default_code_page() above. + return ll_convert_wide_to_string(w_mesg); } namespace @@ -971,246 +1007,224 @@ std::string LLStringOps::sAM; std::string LLStringOps::sPM; // static -bool LLStringOps::isEmoji(llwchar wch) -{ - int ublock = ublock_getCode(wch); - switch (ublock) - { - case UBLOCK_GENERAL_PUNCTUATION: - case UBLOCK_LETTERLIKE_SYMBOLS: - case UBLOCK_ARROWS: - case UBLOCK_MISCELLANEOUS_TECHNICAL: - case UBLOCK_ENCLOSED_ALPHANUMERICS: - case UBLOCK_GEOMETRIC_SHAPES: - case UBLOCK_MISCELLANEOUS_SYMBOLS: - case UBLOCK_DINGBATS: - case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: - case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: - case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS: - case UBLOCK_EMOTICONS: - case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS: -#if U_ICU_VERSION_MAJOR_NUM > 56 - // Boost uses ICU so we can't update it independently - case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS: -#endif // U_ICU_VERSION_MAJOR_NUM > 56 - return true; - default: -#if U_ICU_VERSION_MAJOR_NUM > 56 - return false; +bool LLStringOps::isEmoji(llwchar a) +{ +#if 0 // Do not consider special characters that might have a corresponding + // glyph in the monochorme fallback fonts as a "genuine" emoji. HB + return a == 0xa9 || a == 0xae || (a >= 0x2000 && a < 0x3300) || + (a >= 0x1f000 && a < 0x20000); #else - // See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs - return wch >= 0x1F900 && wch <= 0x1F9FF; -#endif // U_ICU_VERSION_MAJOR_NUM > 56 - } + // These are indeed "genuine" emojis, we *do want* rendered as such. HB + return a >= 0x1f000 && a < 0x20000; +#endif } - -S32 LLStringOps::collate(const llwchar* a, const llwchar* b) -{ - #if LL_WINDOWS - // in Windows, wide string functions operator on 16-bit strings, - // not the proper 32 bit wide string - return strcmp(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str()); - #else - return wcscoll(a, b); - #endif +S32 LLStringOps::collate(const llwchar* a, const llwchar* b) +{ + #if LL_WINDOWS + // in Windows, wide string functions operator on 16-bit strings, + // not the proper 32 bit wide string + return strcmp(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str()); + #else + return wcscoll(a, b); + #endif } void LLStringOps::setupDatetimeInfo (bool daylight) { - time_t nowT, localT, gmtT; - struct tm * tmpT; - - nowT = time (NULL); - - tmpT = gmtime (&nowT); - gmtT = mktime (tmpT); - - tmpT = localtime (&nowT); - localT = mktime (tmpT); - - sLocalTimeOffset = (long) (gmtT - localT); - if (tmpT->tm_isdst) - { - sLocalTimeOffset -= 60 * 60; // 1 hour - } - - sPacificDaylightTime = daylight; - sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60; - - datetimeToCodes["wkday"] = "%a"; // Thu - datetimeToCodes["weekday"] = "%A"; // Thursday - datetimeToCodes["year4"] = "%Y"; // 2009 - datetimeToCodes["year"] = "%Y"; // 2009 - datetimeToCodes["year2"] = "%y"; // 09 - datetimeToCodes["mth"] = "%b"; // Aug - datetimeToCodes["month"] = "%B"; // August - datetimeToCodes["mthnum"] = "%m"; // 08 - datetimeToCodes["day"] = "%d"; // 31 - datetimeToCodes["sday"] = "%-d"; // 9 - datetimeToCodes["hour24"] = "%H"; // 14 - datetimeToCodes["hour"] = "%H"; // 14 - datetimeToCodes["hour12"] = "%I"; // 02 - datetimeToCodes["min"] = "%M"; // 59 - datetimeToCodes["ampm"] = "%p"; // AM - datetimeToCodes["second"] = "%S"; // 59 - datetimeToCodes["timezone"] = "%Z"; // PST + time_t nowT, localT, gmtT; + struct tm * tmpT; + + nowT = time (NULL); + + tmpT = gmtime (&nowT); + gmtT = mktime (tmpT); + + tmpT = localtime (&nowT); + localT = mktime (tmpT); + + sLocalTimeOffset = (long) (gmtT - localT); + if (tmpT->tm_isdst) + { + sLocalTimeOffset -= 60 * 60; // 1 hour + } + + sPacificDaylightTime = daylight; + sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60; + + datetimeToCodes["wkday"] = "%a"; // Thu + datetimeToCodes["weekday"] = "%A"; // Thursday + datetimeToCodes["year4"] = "%Y"; // 2009 + datetimeToCodes["year"] = "%Y"; // 2009 + datetimeToCodes["year2"] = "%y"; // 09 + datetimeToCodes["mth"] = "%b"; // Aug + datetimeToCodes["month"] = "%B"; // August + datetimeToCodes["mthnum"] = "%m"; // 08 + datetimeToCodes["day"] = "%d"; // 31 + datetimeToCodes["sday"] = "%-d"; // 9 + datetimeToCodes["hour24"] = "%H"; // 14 + datetimeToCodes["hour"] = "%H"; // 14 + datetimeToCodes["hour12"] = "%I"; // 02 + datetimeToCodes["min"] = "%M"; // 59 + datetimeToCodes["ampm"] = "%p"; // AM + datetimeToCodes["second"] = "%S"; // 59 + datetimeToCodes["timezone"] = "%Z"; // PST } void tokenizeStringToArray(const std::string& data, std::vector<std::string>& output) { - output.clear(); - size_t length = data.size(); - - // tokenize it and put it in the array - std::string cur_word; - for(size_t i = 0; i < length; ++i) - { - if(data[i] == ':') - { - output.push_back(cur_word); - cur_word.clear(); - } - else - { - cur_word.append(1, data[i]); - } - } - output.push_back(cur_word); + output.clear(); + size_t length = data.size(); + + // tokenize it and put it in the array + std::string cur_word; + for(size_t i = 0; i < length; ++i) + { + if(data[i] == ':') + { + output.push_back(cur_word); + cur_word.clear(); + } + else + { + cur_word.append(1, data[i]); + } + } + output.push_back(cur_word); } void LLStringOps::setupWeekDaysNames(const std::string& data) { - tokenizeStringToArray(data,sWeekDayList); + tokenizeStringToArray(data,sWeekDayList); } void LLStringOps::setupWeekDaysShortNames(const std::string& data) { - tokenizeStringToArray(data,sWeekDayShortList); + tokenizeStringToArray(data,sWeekDayShortList); } void LLStringOps::setupMonthNames(const std::string& data) { - tokenizeStringToArray(data,sMonthList); + tokenizeStringToArray(data,sMonthList); } void LLStringOps::setupMonthShortNames(const std::string& data) { - tokenizeStringToArray(data,sMonthShortList); + tokenizeStringToArray(data,sMonthShortList); } void LLStringOps::setupDayFormat(const std::string& data) { - sDayFormat = data; + sDayFormat = data; } std::string LLStringOps::getDatetimeCode (std::string key) { - std::map<std::string, std::string>::iterator iter; + std::map<std::string, std::string>::iterator iter; - iter = datetimeToCodes.find (key); - if (iter != datetimeToCodes.end()) - { - return iter->second; - } - else - { - return std::string(""); - } + iter = datetimeToCodes.find (key); + if (iter != datetimeToCodes.end()) + { + return iter->second; + } + else + { + return std::string(""); + } } std::string LLStringOps::getReadableNumber(F64 num) { if (fabs(num)>=1e9) { - return llformat("%.2lfB", num / 1e9); + return llformat("%.2lfB", num / 1e9); } else if (fabs(num)>=1e6) { - return llformat("%.2lfM", num / 1e6); + return llformat("%.2lfM", num / 1e6); } else if (fabs(num)>=1e3) { - return llformat("%.2lfK", num / 1e3); + return llformat("%.2lfK", num / 1e3); } else { - return llformat("%.2lf", num); + return llformat("%.2lf", num); } } namespace LLStringFn { - // NOTE - this restricts output to ascii - void replace_nonprintable_in_ascii(std::basic_string<char>& string, char replacement) - { - const char MIN = 0x20; - std::basic_string<char>::size_type len = string.size(); - for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii) - { - if(string[ii] < MIN) - { - string[ii] = replacement; - } - } - } - - - // NOTE - this restricts output to ascii - void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, - char replacement) - { - const char MIN = 0x20; - const char PIPE = 0x7c; - std::basic_string<char>::size_type len = str.size(); - for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii) - { - if( (str[ii] < MIN) || (str[ii] == PIPE) ) - { - str[ii] = replacement; - } - } - } - - // https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on - // allowable code points for XML. Specifically, they are: - // 0x09, 0x0a, 0x0d, and 0x20 on up. JC - std::string strip_invalid_xml(const std::string& instr) - { - std::string output; - output.reserve( instr.size() ); - std::string::const_iterator it = instr.begin(); - while (it != instr.end()) - { - // Must compare as unsigned for >= - // Test most likely match first - const unsigned char c = (unsigned char)*it; - if ( c >= (unsigned char)0x20 // SPACE - || c == (unsigned char)0x09 // TAB - || c == (unsigned char)0x0a // LINE_FEED - || c == (unsigned char)0x0d ) // CARRIAGE_RETURN - { - output.push_back(c); - } - ++it; - } - return output; - } - - /** - * @brief Replace all control characters (c < 0x20) with replacement in - * string. - */ - void replace_ascii_controlchars(std::basic_string<char>& string, char replacement) - { - const unsigned char MIN = 0x20; - std::basic_string<char>::size_type len = string.size(); - for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii) - { - const unsigned char c = (unsigned char) string[ii]; - if(c < MIN) - { - string[ii] = replacement; - } - } - } + // NOTE - this restricts output to ascii + void replace_nonprintable_in_ascii(std::basic_string<char>& string, char replacement) + { + const char MIN = 0x20; + std::basic_string<char>::size_type len = string.size(); + for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii) + { + if(string[ii] < MIN) + { + string[ii] = replacement; + } + } + } + + + // NOTE - this restricts output to ascii + void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, + char replacement) + { + const char MIN = 0x20; + const char PIPE = 0x7c; + std::basic_string<char>::size_type len = str.size(); + for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii) + { + if( (str[ii] < MIN) || (str[ii] == PIPE) ) + { + str[ii] = replacement; + } + } + } + + // https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on + // allowable code points for XML. Specifically, they are: + // 0x09, 0x0a, 0x0d, and 0x20 on up. JC + std::string strip_invalid_xml(const std::string& instr) + { + std::string output; + output.reserve( instr.size() ); + std::string::const_iterator it = instr.begin(); + while (it != instr.end()) + { + // Must compare as unsigned for >= + // Test most likely match first + const unsigned char c = (unsigned char)*it; + if ( c >= (unsigned char)0x20 // SPACE + || c == (unsigned char)0x09 // TAB + || c == (unsigned char)0x0a // LINE_FEED + || c == (unsigned char)0x0d ) // CARRIAGE_RETURN + { + output.push_back(c); + } + ++it; + } + return output; + } + + /** + * @brief Replace all control characters (c < 0x20) with replacement in + * string. + */ + void replace_ascii_controlchars(std::basic_string<char>& string, char replacement) + { + const unsigned char MIN = 0x20; + std::basic_string<char>::size_type len = string.size(); + for(std::basic_string<char>::size_type ii = 0; ii < len; ++ii) + { + const unsigned char c = (unsigned char) string[ii]; + if(c < MIN) + { + string[ii] = replacement; + } + } + } } //////////////////////////////////////////////////////////// @@ -1220,268 +1234,268 @@ template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions); //static -template<> +template<> void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims) { - // Starting at offset 0, scan forward for the next non-delimiter. We're - // done when the only characters left in 'instr' are delimiters. - for (std::string::size_type begIdx, endIdx = 0; - (begIdx = instr.find_first_not_of (delims, endIdx)) != std::string::npos; ) - { - // Found a non-delimiter. After that, find the next delimiter. - endIdx = instr.find_first_of (delims, begIdx); - if (endIdx == std::string::npos) - { - // No more delimiters: this token extends to the end of the string. - endIdx = instr.length(); - } - - // extract the token between begIdx and endIdx; substr() needs length - std::string currToken(instr.substr(begIdx, endIdx - begIdx)); - LLStringUtil::trim (currToken); - tokens.push_back(currToken); - // next scan past delimiters starts at endIdx - } -} - -template<> + // Starting at offset 0, scan forward for the next non-delimiter. We're + // done when the only characters left in 'instr' are delimiters. + for (std::string::size_type begIdx, endIdx = 0; + (begIdx = instr.find_first_not_of (delims, endIdx)) != std::string::npos; ) + { + // Found a non-delimiter. After that, find the next delimiter. + endIdx = instr.find_first_of (delims, begIdx); + if (endIdx == std::string::npos) + { + // No more delimiters: this token extends to the end of the string. + endIdx = instr.length(); + } + + // extract the token between begIdx and endIdx; substr() needs length + std::string currToken(instr.substr(begIdx, endIdx - begIdx)); + LLStringUtil::trim (currToken); + tokens.push_back(currToken); + // next scan past delimiters starts at endIdx + } +} + +template<> LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector<std::string>& tokens) { - const std::string delims (","); - - // Find the first [ - size_type pos1 = instr.find('[', start); - if (pos1 == std::string::npos) - return std::string::npos; - - //Find the first ] after the initial [ - size_type pos2 = instr.find(']', pos1); - if (pos2 == std::string::npos) - return std::string::npos; - - // Find the last [ before ] in case of nested [[]] - pos1 = instr.find_last_of('[', pos2-1); - if (pos1 == std::string::npos || pos1 < start) - return std::string::npos; - - getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims); - start = pos2+1; - - return pos1; + const std::string delims (","); + + // Find the first [ + size_type pos1 = instr.find('[', start); + if (pos1 == std::string::npos) + return std::string::npos; + + //Find the first ] after the initial [ + size_type pos2 = instr.find(']', pos1); + if (pos2 == std::string::npos) + return std::string::npos; + + // Find the last [ before ] in case of nested [[]] + pos1 = instr.find_last_of('[', pos2-1); + if (pos1 == std::string::npos || pos1 < start) + return std::string::npos; + + getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims); + start = pos2+1; + + return pos1; } // static -template<> +template<> bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const format_map_t& substitutions) { - // see if we have a replacement for the bracketed string (without the brackets) - // test first using has() because if we just look up with operator[] we get back an - // empty string even if the value is missing. We want to distinguish between - // missing replacements and deliberately empty replacement strings. - format_map_t::const_iterator iter = substitutions.find(token); - if (iter != substitutions.end()) - { - replacement = iter->second; - return true; - } - // if not, see if there's one WITH brackets - iter = substitutions.find(std::string("[" + token + "]")); - if (iter != substitutions.end()) - { - replacement = iter->second; - return true; - } - - return false; + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + format_map_t::const_iterator iter = substitutions.find(token); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + // if not, see if there's one WITH brackets + iter = substitutions.find(std::string("[" + token + "]")); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + + return false; } // static -template<> +template<> bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const LLSD& substitutions) { - // see if we have a replacement for the bracketed string (without the brackets) - // test first using has() because if we just look up with operator[] we get back an - // empty string even if the value is missing. We want to distinguish between - // missing replacements and deliberately empty replacement strings. - if (substitutions.has(token)) - { - replacement = substitutions[token].asString(); - return true; - } - // if not, see if there's one WITH brackets - else if (substitutions.has(std::string("[" + token + "]"))) - { - replacement = substitutions[std::string("[" + token + "]")].asString(); - return true; - } - - return false; + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + if (substitutions.has(token)) + { + replacement = substitutions[token].asString(); + return true; + } + // if not, see if there's one WITH brackets + else if (substitutions.has(std::string("[" + token + "]"))) + { + replacement = substitutions[std::string("[" + token + "]")].asString(); + return true; + } + + return false; } //static template<> void LLStringUtil::setLocale(std::string inLocale) { - sLocale = inLocale; + sLocale = inLocale; }; //static template<> std::string LLStringUtil::getLocale(void) { - return sLocale; + return sLocale; }; // static -template<> +template<> void LLStringUtil::formatNumber(std::string& numStr, std::string decimals) { - std::stringstream strStream; - S32 intDecimals = 0; - - convertToS32 (decimals, intDecimals); - if (!sLocale.empty()) - { - // std::locale() throws if the locale is unknown! (EXT-7926) - try - { - strStream.imbue(std::locale(sLocale.c_str())); - } catch (const std::exception &) - { - LL_WARNS_ONCE("Locale") << "Cannot set locale to " << sLocale << LL_ENDL; - } - } - - if (!intDecimals) - { - S32 intStr; - - if (convertToS32(numStr, intStr)) - { - strStream << intStr; - numStr = strStream.str(); - } - } - else - { - F32 floatStr; - - if (convertToF32(numStr, floatStr)) - { - strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr; - numStr = strStream.str(); - } - } + std::stringstream strStream; + S32 intDecimals = 0; + + convertToS32 (decimals, intDecimals); + if (!sLocale.empty()) + { + // std::locale() throws if the locale is unknown! (EXT-7926) + try + { + strStream.imbue(std::locale(sLocale.c_str())); + } catch (const std::exception &) + { + LL_WARNS_ONCE("Locale") << "Cannot set locale to " << sLocale << LL_ENDL; + } + } + + if (!intDecimals) + { + S32 intStr; + + if (convertToS32(numStr, intStr)) + { + strStream << intStr; + numStr = strStream.str(); + } + } + else + { + F32 floatStr; + + if (convertToF32(numStr, floatStr)) + { + strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr; + numStr = strStream.str(); + } + } } // static -template<> +template<> bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, - std::string param, S32 secFromEpoch) -{ - if (param == "local") // local - { - secFromEpoch -= LLStringOps::getLocalTimeOffset(); - } - else if (param != "utc") // slt - { - secFromEpoch -= LLStringOps::getPacificTimeOffset(); - } - - // if never fell into those two ifs above, param must be utc - if (secFromEpoch < 0) secFromEpoch = 0; - - LLDate datetime((F64)secFromEpoch); - std::string code = LLStringOps::getDatetimeCode (token); - - // special case to handle timezone - if (code == "%Z") { - if (param == "utc") - { - replacement = "GMT"; - } - else if (param == "local") - { - replacement = ""; // user knows their own timezone - } - else - { + std::string param, S32 secFromEpoch) +{ + if (param == "local") // local + { + secFromEpoch -= LLStringOps::getLocalTimeOffset(); + } + else if (param != "utc") // slt + { + secFromEpoch -= LLStringOps::getPacificTimeOffset(); + } + + // if never fell into those two ifs above, param must be utc + if (secFromEpoch < 0) secFromEpoch = 0; + + LLDate datetime((F64)secFromEpoch); + std::string code = LLStringOps::getDatetimeCode (token); + + // special case to handle timezone + if (code == "%Z") { + if (param == "utc") + { + replacement = "GMT"; + } + else if (param == "local") + { + replacement = ""; // user knows their own timezone + } + else + { #if 0 - // EXT-1565 : Zai Lynch, James Linden : 15/Oct/09 - // [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT - // "slt" = Second Life Time, which is deprecated. - // If not utc or user local time, fallback to Pacific time - replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST"; + // EXT-1565 : Zai Lynch, James Linden : 15/Oct/09 + // [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT + // "slt" = Second Life Time, which is deprecated. + // If not utc or user local time, fallback to Pacific time + replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST"; #else - // SL-20370 : Steeltoe Linden : 29/Sep/23 - // Change "PDT" to "SLT" on menu bar - replacement = "SLT"; + // SL-20370 : Steeltoe Linden : 29/Sep/23 + // Change "PDT" to "SLT" on menu bar + replacement = "SLT"; #endif - } - return true; - } - - //EXT-7013 - //few codes are not suppotred by strtime function (example - weekdays for Japanise) - //so use predefined ones - - //if sWeekDayList is not empty than current locale doesn't support + } + return true; + } + + //EXT-7013 + //few codes are not suppotred by strtime function (example - weekdays for Japanise) + //so use predefined ones + + //if sWeekDayList is not empty than current locale doesn't support //weekday name. - time_t loc_seconds = (time_t) secFromEpoch; - if(LLStringOps::sWeekDayList.size() == 7 && code == "%A") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = LLStringOps::sWeekDayList[gmt->tm_wday]; - } - else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday]; - } - else if(LLStringOps::sMonthList.size() == 12 && code == "%B") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = LLStringOps::sMonthList[gmt->tm_mon]; - } - else if( !LLStringOps::sDayFormat.empty() && code == "%d" ) - { - struct tm * gmt = gmtime (&loc_seconds); - LLStringUtil::format_map_t args; - args["[MDAY]"] = llformat ("%d", gmt->tm_mday); - replacement = LLStringOps::sDayFormat; - LLStringUtil::format(replacement, args); - } - else if (code == "%-d") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = llformat ("%d", gmt->tm_mday); // day of the month without leading zero - } - else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" ) - { - struct tm * gmt = gmtime (&loc_seconds); - if(gmt->tm_hour<12) - { - replacement = LLStringOps::sAM; - } - else - { - replacement = LLStringOps::sPM; - } - } - else - { - replacement = datetime.toHTTPDateString(code); - } - - // *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format - // to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738). - // We could have used '%l' format instead, but it's not supported by Windows. - if(code == "%I" && token == "hour12" && replacement.at(0) == '0') - { - replacement = replacement.at(1); - } - - return !code.empty(); + time_t loc_seconds = (time_t) secFromEpoch; + if(LLStringOps::sWeekDayList.size() == 7 && code == "%A") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = LLStringOps::sWeekDayList[gmt->tm_wday]; + } + else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday]; + } + else if(LLStringOps::sMonthList.size() == 12 && code == "%B") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = LLStringOps::sMonthList[gmt->tm_mon]; + } + else if( !LLStringOps::sDayFormat.empty() && code == "%d" ) + { + struct tm * gmt = gmtime (&loc_seconds); + LLStringUtil::format_map_t args; + args["[MDAY]"] = llformat ("%d", gmt->tm_mday); + replacement = LLStringOps::sDayFormat; + LLStringUtil::format(replacement, args); + } + else if (code == "%-d") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = llformat ("%d", gmt->tm_mday); // day of the month without leading zero + } + else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" ) + { + struct tm * gmt = gmtime (&loc_seconds); + if(gmt->tm_hour<12) + { + replacement = LLStringOps::sAM; + } + else + { + replacement = LLStringOps::sPM; + } + } + else + { + replacement = datetime.toHTTPDateString(code); + } + + // *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format + // to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738). + // We could have used '%l' format instead, but it's not supported by Windows. + if(code == "%I" && token == "hour12" && replacement.at(0) == '0') + { + replacement = replacement.at(1); + } + + return !code.empty(); } // LLStringUtil::format recogizes the following patterns. @@ -1493,146 +1507,146 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, // static -template<> +template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING; - S32 res = 0; - - std::string output; - std::vector<std::string> tokens; - - std::string::size_type start = 0; - std::string::size_type prev_start = 0; - std::string::size_type key_start = 0; - while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) - { - output += std::string(s, prev_start, key_start-prev_start); - prev_start = start; - - bool found_replacement = false; - std::string replacement; - - if (tokens.size() == 0) - { - found_replacement = false; - } - else if (tokens.size() == 1) - { - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - } - else if (tokens[1] == "number") - { - std::string param = "0"; - - if (tokens.size() > 2) param = tokens[2]; - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - if (found_replacement) formatNumber (replacement, param); - } - else if (tokens[1] == "datetime") - { - std::string param; - if (tokens.size() > 2) param = tokens[2]; - - format_map_t::const_iterator iter = substitutions.find("datetime"); - if (iter != substitutions.end()) - { - S32 secFromEpoch = 0; - BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch); - if (r) - { - found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch); - } - } - } - - if (found_replacement) - { - output += replacement; - res++; - } - else - { - // we had no replacement, use the string as is - // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" - output += std::string(s, key_start, start-key_start); - } - tokens.clear(); - } - // send the remainder of the string (with no further matches for bracketed names) - output += std::string(s, start); - s = output; - return res; + S32 res = 0; + + std::string output; + std::vector<std::string> tokens; + + std::string::size_type start = 0; + std::string::size_type prev_start = 0; + std::string::size_type key_start = 0; + while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) + { + output += std::string(s, prev_start, key_start-prev_start); + prev_start = start; + + bool found_replacement = false; + std::string replacement; + + if (tokens.size() == 0) + { + found_replacement = false; + } + else if (tokens.size() == 1) + { + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::string param; + if (tokens.size() > 2) param = tokens[2]; + + format_map_t::const_iterator iter = substitutions.find("datetime"); + if (iter != substitutions.end()) + { + S32 secFromEpoch = 0; + BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch); + if (r) + { + found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch); + } + } + } + + if (found_replacement) + { + output += replacement; + res++; + } + else + { + // we had no replacement, use the string as is + // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" + output += std::string(s, key_start, start-key_start); + } + tokens.clear(); + } + // send the remainder of the string (with no further matches for bracketed names) + output += std::string(s, start); + s = output; + return res; } //static -template<> +template<> S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING; - S32 res = 0; - - if (!substitutions.isMap()) - { - return res; - } - - std::string output; - std::vector<std::string> tokens; - - std::string::size_type start = 0; - std::string::size_type prev_start = 0; - std::string::size_type key_start = 0; - while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) - { - output += std::string(s, prev_start, key_start-prev_start); - prev_start = start; - - bool found_replacement = false; - std::string replacement; - - if (tokens.size() == 0) - { - found_replacement = false; - } - else if (tokens.size() == 1) - { - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - } - else if (tokens[1] == "number") - { - std::string param = "0"; - - if (tokens.size() > 2) param = tokens[2]; - found_replacement = simpleReplacement (replacement, tokens[0], substitutions); - if (found_replacement) formatNumber (replacement, param); - } - else if (tokens[1] == "datetime") - { - std::string param; - if (tokens.size() > 2) param = tokens[2]; - - S32 secFromEpoch = (S32) substitutions["datetime"].asInteger(); - found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch); - } - - if (found_replacement) - { - output += replacement; - res++; - } - else - { - // we had no replacement, use the string as is - // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" - output += std::string(s, key_start, start-key_start); - } - tokens.clear(); - } - // send the remainder of the string (with no further matches for bracketed names) - output += std::string(s, start); - s = output; - return res; + S32 res = 0; + + if (!substitutions.isMap()) + { + return res; + } + + std::string output; + std::vector<std::string> tokens; + + std::string::size_type start = 0; + std::string::size_type prev_start = 0; + std::string::size_type key_start = 0; + while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) + { + output += std::string(s, prev_start, key_start-prev_start); + prev_start = start; + + bool found_replacement = false; + std::string replacement; + + if (tokens.size() == 0) + { + found_replacement = false; + } + else if (tokens.size() == 1) + { + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::string param; + if (tokens.size() > 2) param = tokens[2]; + + S32 secFromEpoch = (S32) substitutions["datetime"].asInteger(); + found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch); + } + + if (found_replacement) + { + output += replacement; + res++; + } + else + { + // we had no replacement, use the string as is + // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" + output += std::string(s, key_start, start-key_start); + } + tokens.clear(); + } + // send the remainder of the string (with no further matches for bracketed names) + output += std::string(s, start); + s = output; + return res; } //////////////////////////////////////////////////////////// @@ -1640,102 +1654,102 @@ S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) #ifdef _DEBUG -template<class T> +template<class T> void LLStringUtilBase<T>::testHarness() { - std::string s1; - - llassert( s1.c_str() == NULL ); - llassert( s1.size() == 0 ); - llassert( s1.empty() ); - - std::string s2( "hello"); - llassert( !strcmp( s2.c_str(), "hello" ) ); - llassert( s2.size() == 5 ); - llassert( !s2.empty() ); - std::string s3( s2 ); - - llassert( "hello" == s2 ); - llassert( s2 == "hello" ); - llassert( s2 > "gello" ); - llassert( "gello" < s2 ); - llassert( "gello" != s2 ); - llassert( s2 != "gello" ); - - std::string s4 = s2; - llassert( !s4.empty() ); - s4.empty(); - llassert( s4.empty() ); - - std::string s5(""); - llassert( s5.empty() ); - - llassert( isValidIndex(s5, 0) ); - llassert( !isValidIndex(s5, 1) ); - - s3 = s2; - s4 = "hello again"; - - s4 += "!"; - s4 += s4; - llassert( s4 == "hello again!hello again!" ); - - - std::string s6 = s2 + " " + s2; - std::string s7 = s6; - llassert( s6 == s7 ); - llassert( !( s6 != s7) ); - llassert( !(s6 < s7) ); - llassert( !(s6 > s7) ); - - llassert( !(s6 == "hi")); - llassert( s6 == "hello hello"); - llassert( s6 < "hi"); - - llassert( s6[1] == 'e' ); - s6[1] = 'f'; - llassert( s6[1] == 'f' ); - - s2.erase( 4, 1 ); - llassert( s2 == "hell"); - s2.insert( 0, "y" ); - llassert( s2 == "yhell"); - s2.erase( 1, 3 ); - llassert( s2 == "yl"); - s2.insert( 1, "awn, don't yel"); - llassert( s2 == "yawn, don't yell"); - - std::string s8 = s2.substr( 6, 5 ); - llassert( s8 == "don't" ); - - std::string s9 = " \t\ntest \t\t\n "; - trim(s9); - llassert( s9 == "test" ); - - s8 = "abc123&*(ABC"; - - s9 = s8; - toUpper(s9); - llassert( s9 == "ABC123&*(ABC" ); - - s9 = s8; - toLower(s9); - llassert( s9 == "abc123&*(abc" ); - - - std::string s10( 10, 'x' ); - llassert( s10 == "xxxxxxxxxx" ); - - std::string s11( "monkey in the middle", 7, 2 ); - llassert( s11 == "in" ); - - std::string s12; //empty - s12 += "foo"; - llassert( s12 == "foo" ); - - std::string s13; //empty - s13 += 'f'; - llassert( s13 == "f" ); + std::string s1; + + llassert( s1.c_str() == NULL ); + llassert( s1.size() == 0 ); + llassert( s1.empty() ); + + std::string s2( "hello"); + llassert( !strcmp( s2.c_str(), "hello" ) ); + llassert( s2.size() == 5 ); + llassert( !s2.empty() ); + std::string s3( s2 ); + + llassert( "hello" == s2 ); + llassert( s2 == "hello" ); + llassert( s2 > "gello" ); + llassert( "gello" < s2 ); + llassert( "gello" != s2 ); + llassert( s2 != "gello" ); + + std::string s4 = s2; + llassert( !s4.empty() ); + s4.empty(); + llassert( s4.empty() ); + + std::string s5(""); + llassert( s5.empty() ); + + llassert( isValidIndex(s5, 0) ); + llassert( !isValidIndex(s5, 1) ); + + s3 = s2; + s4 = "hello again"; + + s4 += "!"; + s4 += s4; + llassert( s4 == "hello again!hello again!" ); + + + std::string s6 = s2 + " " + s2; + std::string s7 = s6; + llassert( s6 == s7 ); + llassert( !( s6 != s7) ); + llassert( !(s6 < s7) ); + llassert( !(s6 > s7) ); + + llassert( !(s6 == "hi")); + llassert( s6 == "hello hello"); + llassert( s6 < "hi"); + + llassert( s6[1] == 'e' ); + s6[1] = 'f'; + llassert( s6[1] == 'f' ); + + s2.erase( 4, 1 ); + llassert( s2 == "hell"); + s2.insert( 0, "y" ); + llassert( s2 == "yhell"); + s2.erase( 1, 3 ); + llassert( s2 == "yl"); + s2.insert( 1, "awn, don't yel"); + llassert( s2 == "yawn, don't yell"); + + std::string s8 = s2.substr( 6, 5 ); + llassert( s8 == "don't" ); + + std::string s9 = " \t\ntest \t\t\n "; + trim(s9); + llassert( s9 == "test" ); + + s8 = "abc123&*(ABC"; + + s9 = s8; + toUpper(s9); + llassert( s9 == "ABC123&*(ABC" ); + + s9 = s8; + toLower(s9); + llassert( s9 == "abc123&*(abc" ); + + + std::string s10( 10, 'x' ); + llassert( s10 == "xxxxxxxxxx" ); + + std::string s11( "monkey in the middle", 7, 2 ); + llassert( s11 == "in" ); + + std::string s12; //empty + s12 += "foo"; + llassert( s12 == "foo" ); + + std::string s13; //empty + s13 += 'f'; + llassert( s13 == "f" ); } diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index be00aa277b..6503da2e77 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,25 +1,25 @@ -/** +/** * @file llstring.h * @brief String utility functions and std::string class. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,85 +59,85 @@ namespace std template<> struct char_traits<U16> { - typedef U16 char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - typedef mbstate_t state_type; - - static void - assign(char_type& __c1, const char_type& __c2) - { __c1 = __c2; } - - static bool - eq(const char_type& __c1, const char_type& __c2) - { return __c1 == __c2; } - - static bool - lt(const char_type& __c1, const char_type& __c2) - { return __c1 < __c2; } - - static int - compare(const char_type* __s1, const char_type* __s2, size_t __n) - { return memcmp(__s1, __s2, __n * sizeof(char_type)); } - - static size_t - length(const char_type* __s) - { - const char_type *cur_char = __s; - while (*cur_char != 0) - { - ++cur_char; - } - return cur_char - __s; - } - - static const char_type* - find(const char_type* __s, size_t __n, const char_type& __a) - { return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } - - static char_type* - move(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } - - static char_type* - copy(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ - - static char_type* - assign(char_type* __s, size_t __n, char_type __a) - { - // This isn't right. - //return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); - - // I don't think there's a standard 'memset' for 16-bit values. - // Do this the old-fashioned way. - - size_t __i; - for(__i = 0; __i < __n; __i++) - { - __s[__i] = __a; - } - return __s; - } - - static char_type - to_char_type(const int_type& __c) - { return static_cast<char_type>(__c); } - - static int_type - to_int_type(const char_type& __c) - { return static_cast<int_type>(__c); } - - static bool - eq_int_type(const int_type& __c1, const int_type& __c2) - { return __c1 == __c2; } - - static int_type - eof() { return static_cast<int_type>(EOF); } - - static int_type - not_eof(const int_type& __c) + typedef U16 char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + typedef mbstate_t state_type; + + static void + assign(char_type& __c1, const char_type& __c2) + { __c1 = __c2; } + + static bool + eq(const char_type& __c1, const char_type& __c2) + { return __c1 == __c2; } + + static bool + lt(const char_type& __c1, const char_type& __c2) + { return __c1 < __c2; } + + static int + compare(const char_type* __s1, const char_type* __s2, size_t __n) + { return memcmp(__s1, __s2, __n * sizeof(char_type)); } + + static size_t + length(const char_type* __s) + { + const char_type *cur_char = __s; + while (*cur_char != 0) + { + ++cur_char; + } + return cur_char - __s; + } + + static const char_type* + find(const char_type* __s, size_t __n, const char_type& __a) + { return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } + + static char_type* + move(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } + + static char_type* + copy(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ + + static char_type* + assign(char_type* __s, size_t __n, char_type __a) + { + // This isn't right. + //return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); + + // I don't think there's a standard 'memset' for 16-bit values. + // Do this the old-fashioned way. + + size_t __i; + for(__i = 0; __i < __n; __i++) + { + __s[__i] = __a; + } + return __s; + } + + static char_type + to_char_type(const int_type& __c) + { return static_cast<char_type>(__c); } + + static int_type + to_int_type(const char_type& __c) + { return static_cast<int_type>(__c); } + + static bool + eq_int_type(const int_type& __c1, const int_type& __c2) + { return __c1 == __c2; } + + static int_type + eof() { return static_cast<int_type>(EOF); } + + static int_type + not_eof(const int_type& __c) { return (__c == eof()) ? 0 : __c; } }; }; @@ -146,72 +146,73 @@ struct char_traits<U16> class LL_COMMON_API LLStringOps { private: - static long sPacificTimeOffset; - static long sLocalTimeOffset; - static bool sPacificDaylightTime; + static long sPacificTimeOffset; + static long sLocalTimeOffset; + static bool sPacificDaylightTime; - static std::map<std::string, std::string> datetimeToCodes; + static std::map<std::string, std::string> datetimeToCodes; public: - static std::vector<std::string> sWeekDayList; - static std::vector<std::string> sWeekDayShortList; - static std::vector<std::string> sMonthList; - static std::vector<std::string> sMonthShortList; - static std::string sDayFormat; + static std::vector<std::string> sWeekDayList; + static std::vector<std::string> sWeekDayShortList; + static std::vector<std::string> sMonthList; + static std::vector<std::string> sMonthShortList; + static std::string sDayFormat; - static std::string sAM; - static std::string sPM; + static std::string sAM; + static std::string sPM; - static char toUpper(char elem) { return toupper((unsigned char)elem); } - static llwchar toUpper(llwchar elem) { return towupper(elem); } - - static char toLower(char elem) { return tolower((unsigned char)elem); } - static llwchar toLower(llwchar elem) { return towlower(elem); } + static char toUpper(char elem) { return toupper((unsigned char)elem); } + static llwchar toUpper(llwchar elem) { return towupper(elem); } - static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } - static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + static char toLower(char elem) { return tolower((unsigned char)elem); } + static llwchar toLower(llwchar elem) { return towlower(elem); } - static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } - static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } + static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } - static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } - static bool isLower(llwchar elem) { return iswlower(elem) != 0; } + static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } + static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } - static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } - static bool isDigit(llwchar a) { return iswdigit(a) != 0; } + static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } + static bool isLower(llwchar elem) { return iswlower(elem) != 0; } - static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } - static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } + static bool isDigit(llwchar a) { return iswdigit(a) != 0; } - static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } - static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } + static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } + static bool isPunct(llwchar a) { return iswpunct(a) != 0; } - static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } - static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } + static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } - static bool isEmoji(llwchar wch); + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } + static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } - static S32 collate(const char* a, const char* b) { return strcoll(a, b); } - static S32 collate(const llwchar* a, const llwchar* b); + // Returns true when 'a' corresponds to a "genuine" emoji. HB + static bool isEmoji(llwchar a); - static void setupDatetimeInfo(bool pacific_daylight_time); + static S32 collate(const char* a, const char* b) { return strcoll(a, b); } + static S32 collate(const llwchar* a, const llwchar* b); - static void setupWeekDaysNames(const std::string& data); - static void setupWeekDaysShortNames(const std::string& data); - static void setupMonthNames(const std::string& data); - static void setupMonthShortNames(const std::string& data); - static void setupDayFormat(const std::string& data); + static void setupDatetimeInfo(bool pacific_daylight_time); + static void setupWeekDaysNames(const std::string& data); + static void setupWeekDaysShortNames(const std::string& data); + static void setupMonthNames(const std::string& data); + static void setupMonthShortNames(const std::string& data); + static void setupDayFormat(const std::string& data); - static long getPacificTimeOffset(void) { return sPacificTimeOffset;} - static long getLocalTimeOffset(void) { return sLocalTimeOffset;} - // Is the Pacific time zone (aka server time zone) - // currently in daylight savings time? - static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - static std::string getDatetimeCode (std::string key); + static long getPacificTimeOffset(void) { return sPacificTimeOffset;} + static long getLocalTimeOffset(void) { return sLocalTimeOffset;} + // Is the Pacific time zone (aka server time zone) + // currently in daylight savings time? + static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - // Express a value like 1234567 as "1.23M" + static std::string getDatetimeCode (std::string key); + + // Express a value like 1234567 as "1.23M" static std::string getReadableNumber(F64 num); }; @@ -228,216 +229,216 @@ LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); class LLFormatMapString { public: - LLFormatMapString() {}; - LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; - LLFormatMapString(const std::string& s) : mString(s) {}; - operator std::string() const { return mString; } - bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } - std::size_t length() const { return mString.length(); } - + LLFormatMapString() {}; + LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; + LLFormatMapString(const std::string& s) : mString(s) {}; + operator std::string() const { return mString; } + bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } + std::size_t length() const { return mString.length(); } + private: - std::string mString; + std::string mString; }; template <class T> class LLStringUtilBase { private: - static std::string sLocale; + static std::string sLocale; public: - typedef std::basic_string<T> string_type; - typedef typename string_type::size_type size_type; - + typedef std::basic_string<T> string_type; + typedef typename string_type::size_type size_type; + public: - ///////////////////////////////////////////////////////////////////////////////////////// - // Static Utility functions that operate on std::strings - - static const string_type null; - - typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; - /// considers any sequence of delims as a single field separator - LL_COMMON_API static void getTokens(const string_type& instr, - std::vector<string_type >& tokens, - const string_type& delims); - /// like simple scan overload, but returns scanned vector - static std::vector<string_type> getTokens(const string_type& instr, - const string_type& delims); - /// add support for keep_delims and quotes (either could be empty string) - static void getTokens(const string_type& instr, - std::vector<string_type>& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// like keep_delims-and-quotes overload, but returns scanned vector - static std::vector<string_type> getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// add support for escapes (could be empty string) - static void getTokens(const string_type& instr, - std::vector<string_type>& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - /// like escapes overload, but returns scanned vector - static std::vector<string_type> getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - - LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); - LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); - LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); - LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); - LL_COMMON_API static void setLocale (std::string inLocale); - LL_COMMON_API static std::string getLocale (void); - - static bool isValidIndex(const string_type& string, size_type i) - { - return !string.empty() && (0 <= i) && (i <= string.size()); - } - - static bool contains(const string_type& string, T c, size_type i=0) - { - return string.find(c, i) != string_type::npos; - } - - static void trimHead(string_type& string); - static void trimTail(string_type& string); - static void trim(string_type& string) { trimHead(string); trimTail(string); } - static void truncate(string_type& string, size_type count); - - static void toUpper(string_type& string); - static void toLower(string_type& string); - - // True if this is the head of s. - static BOOL isHead( const string_type& string, const T* s ); - - /** - * @brief Returns true if string starts with substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool startsWith( - const string_type& string, - const string_type& substr); - - /** - * @brief Returns true if string ends in substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool endsWith( - const string_type& string, - const string_type& substr); - - /** - * get environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by return value == dflt - */ - static string_type getenv(const std::string& key, const string_type& dflt=""); - /** - * get optional environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by (! return value) - */ - static boost::optional<string_type> getoptenv(const std::string& key); - - static void addCRLF(string_type& string); - static void removeCRLF(string_type& string); - static void removeWindowsCR(string_type& string); - - static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); - static void replaceNonstandardASCII( string_type& string, T replacement ); - static void replaceChar( string_type& string, T target, T replacement ); - static void replaceString( string_type& string, string_type target, string_type replacement ); - static string_type capitalize(const string_type& str); - static void capitalize(string_type& str); - - static BOOL containsNonprintable(const string_type& string); - static void stripNonprintable(string_type& string); - - /** - * Double-quote an argument string if needed, unless it's already - * double-quoted. Decide whether it's needed based on the presence of any - * character in @a triggers (default space or double-quote). If we quote - * it, escape any embedded double-quote with the @a escape string (default - * backslash). - * - * Passing triggers="" means always quote, unless it's already double-quoted. - */ - static string_type quote(const string_type& str, - const string_type& triggers=" \"", - const string_type& escape="\\"); - - /** - * @brief Unsafe way to make ascii characters. You should probably - * only call this when interacting with the host operating system. - * The 1 byte std::string does not work correctly. - * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII - * should work. - */ - static void _makeASCII(string_type& string); - - // Conversion to other data types - static BOOL convertToBOOL(const string_type& string, BOOL& value); - static BOOL convertToU8(const string_type& string, U8& value); - static BOOL convertToS8(const string_type& string, S8& value); - static BOOL convertToS16(const string_type& string, S16& value); - static BOOL convertToU16(const string_type& string, U16& value); - static BOOL convertToU32(const string_type& string, U32& value); - static BOOL convertToS32(const string_type& string, S32& value); - static BOOL convertToF32(const string_type& string, F32& value); - static BOOL convertToF64(const string_type& string, F64& value); - - ///////////////////////////////////////////////////////////////////////////////////////// - // Utility functions for working with char*'s and strings - - // Like strcmp but also handles empty strings. Uses - // current locale. - static S32 compareStrings(const T* lhs, const T* rhs); - static S32 compareStrings(const string_type& lhs, const string_type& rhs); - - // case insensitive version of above. Uses current locale on - // Win32, and falls back to a non-locale aware comparison on - // Linux. - static S32 compareInsensitive(const T* lhs, const T* rhs); - static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); - - // Case sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDict(const string_type& a, const string_type& b); - - // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDictInsensitive(const string_type& a, const string_type& b); - - // Puts compareDict() in a form appropriate for LL container classes to use for sorting. - static BOOL precedesDict( const string_type& a, const string_type& b ); - - // A replacement for strncpy. - // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds - // up to dst_size-1 characters of src. - static void copy(T* dst, const T* src, size_type dst_size); - - // Copies src into dst at a given offset. - static void copyInto(string_type& dst, const string_type& src, size_type offset); - - static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } - - -#ifdef _DEBUG - LL_COMMON_API static void testHarness(); + ///////////////////////////////////////////////////////////////////////////////////////// + // Static Utility functions that operate on std::strings + + static const string_type null; + + typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; + /// considers any sequence of delims as a single field separator + LL_COMMON_API static void getTokens(const string_type& instr, + std::vector<string_type >& tokens, + const string_type& delims); + /// like simple scan overload, but returns scanned vector + static std::vector<string_type> getTokens(const string_type& instr, + const string_type& delims); + /// add support for keep_delims and quotes (either could be empty string) + static void getTokens(const string_type& instr, + std::vector<string_type>& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// like keep_delims-and-quotes overload, but returns scanned vector + static std::vector<string_type> getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// add support for escapes (could be empty string) + static void getTokens(const string_type& instr, + std::vector<string_type>& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + /// like escapes overload, but returns scanned vector + static std::vector<string_type> getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + + LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); + LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); + LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); + LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); + LL_COMMON_API static void setLocale (std::string inLocale); + LL_COMMON_API static std::string getLocale (void); + + static bool isValidIndex(const string_type& string, size_type i) + { + return !string.empty() && (0 <= i) && (i <= string.size()); + } + + static bool contains(const string_type& string, T c, size_type i=0) + { + return string.find(c, i) != string_type::npos; + } + + static void trimHead(string_type& string); + static void trimTail(string_type& string); + static void trim(string_type& string) { trimHead(string); trimTail(string); } + static void truncate(string_type& string, size_type count); + + static void toUpper(string_type& string); + static void toLower(string_type& string); + + // True if this is the head of s. + static BOOL isHead( const string_type& string, const T* s ); + + /** + * @brief Returns true if string starts with substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool startsWith( + const string_type& string, + const string_type& substr); + + /** + * @brief Returns true if string ends in substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool endsWith( + const string_type& string, + const string_type& substr); + + /** + * get environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by return value == dflt + */ + static string_type getenv(const std::string& key, const string_type& dflt=""); + /** + * get optional environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by (! return value) + */ + static boost::optional<string_type> getoptenv(const std::string& key); + + static void addCRLF(string_type& string); + static void removeCRLF(string_type& string); + static void removeWindowsCR(string_type& string); + + static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); + static void replaceNonstandardASCII( string_type& string, T replacement ); + static void replaceChar( string_type& string, T target, T replacement ); + static void replaceString( string_type& string, string_type target, string_type replacement ); + static string_type capitalize(const string_type& str); + static void capitalize(string_type& str); + + static BOOL containsNonprintable(const string_type& string); + static void stripNonprintable(string_type& string); + + /** + * Double-quote an argument string if needed, unless it's already + * double-quoted. Decide whether it's needed based on the presence of any + * character in @a triggers (default space or double-quote). If we quote + * it, escape any embedded double-quote with the @a escape string (default + * backslash). + * + * Passing triggers="" means always quote, unless it's already double-quoted. + */ + static string_type quote(const string_type& str, + const string_type& triggers=" \"", + const string_type& escape="\\"); + + /** + * @brief Unsafe way to make ascii characters. You should probably + * only call this when interacting with the host operating system. + * The 1 byte std::string does not work correctly. + * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII + * should work. + */ + static void _makeASCII(string_type& string); + + // Conversion to other data types + static BOOL convertToBOOL(const string_type& string, BOOL& value); + static BOOL convertToU8(const string_type& string, U8& value); + static BOOL convertToS8(const string_type& string, S8& value); + static BOOL convertToS16(const string_type& string, S16& value); + static BOOL convertToU16(const string_type& string, U16& value); + static BOOL convertToU32(const string_type& string, U32& value); + static BOOL convertToS32(const string_type& string, S32& value); + static BOOL convertToF32(const string_type& string, F32& value); + static BOOL convertToF64(const string_type& string, F64& value); + + ///////////////////////////////////////////////////////////////////////////////////////// + // Utility functions for working with char*'s and strings + + // Like strcmp but also handles empty strings. Uses + // current locale. + static S32 compareStrings(const T* lhs, const T* rhs); + static S32 compareStrings(const string_type& lhs, const string_type& rhs); + + // case insensitive version of above. Uses current locale on + // Win32, and falls back to a non-locale aware comparison on + // Linux. + static S32 compareInsensitive(const T* lhs, const T* rhs); + static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); + + // Case sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDict(const string_type& a, const string_type& b); + + // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDictInsensitive(const string_type& a, const string_type& b); + + // Puts compareDict() in a form appropriate for LL container classes to use for sorting. + static BOOL precedesDict( const string_type& a, const string_type& b ); + + // A replacement for strncpy. + // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds + // up to dst_size-1 characters of src. + static void copy(T* dst, const T* src, size_type dst_size); + + // Copies src into dst at a given offset. + static void copyInto(string_type& dst, const string_type& src, size_type offset); + + static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + +#ifdef _DEBUG + LL_COMMON_API static void testHarness(); #endif private: - LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector<string_type >& tokens); + LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector<string_type >& tokens); }; template<class T> const std::basic_string<T> LLStringUtilBase<T>::null; @@ -453,18 +454,18 @@ typedef std::basic_string<llwchar> LLWString; class LLStringExplicit : public std::string { public: - explicit LLStringExplicit(const char* s) : std::string(s) {} - LLStringExplicit(const std::string& s) : std::string(s) {} - LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} + explicit LLStringExplicit(const char* s) : std::string(s) {} + LLStringExplicit(const std::string& s) : std::string(s) {} + LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} }; struct LLDictionaryLess { public: - bool operator()(const std::string& a, const std::string& b) const - { - return (LLStringUtil::precedesDict(a, b) ? true : false); - } + bool operator()(const std::string& a, const std::string& b) const + { + return (LLStringUtil::precedesDict(a, b) ? true : false); + } }; @@ -481,10 +482,10 @@ public: * @return a copy of in string minus the trailing count bytes. */ inline std::string chop_tail_copy( - const std::string& in, - std::string::size_type count) + const std::string& in, + std::string::size_type count) { - return std::string(in, 0, in.length() - count); + return std::string(in, 0, in.length() - count); } /** @@ -677,10 +678,10 @@ ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_u inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} // Length of this UTF32 string in bytes when transformed to UTF8 -LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); // Length in bytes of this wide char in a UTF8 string -LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); LL_COMMON_API std::string wchar_utf8_preview(const llwchar wc); @@ -697,7 +698,7 @@ LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wst /** * @brief Properly truncate a utf8 string to a maximum byte count. - * + * * The returned string may be less than max_len if the truncation * happens in the middle of a glyph. If max_len is longer than the * string passed in, the return value == utf8str. @@ -710,8 +711,8 @@ LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); LL_COMMON_API S32 utf8str_compare_insensitive( - const std::string& lhs, - const std::string& rhs); + const std::string& lhs, + const std::string& rhs); /** * @brief Properly truncate a utf8 string to a maximum character count. @@ -732,14 +733,14 @@ LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, co * @param replace_char The wchar which is written on replace */ LL_COMMON_API std::string utf8str_substChar( - const std::string& utf8str, - const llwchar target_char, - const llwchar replace_char); + const std::string& utf8str, + const llwchar target_char, + const llwchar replace_char); LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); // Hack - used for evil notecards. -LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); @@ -747,6 +748,12 @@ LL_COMMON_API llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset LL_COMMON_API std::string utf8str_showBytesUTF8(const std::string& utf8str); +LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr); + +LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr); + +LL_COMMON_API bool utf8str_remove_emojis(std::string& utf8str); + #if LL_WINDOWS /* @name Windows string helpers */ @@ -845,52 +852,52 @@ LL_COMMON_API boost::optional<std::string> llstring_getoptenv(const std::string */ namespace LLStringFn { - /** - * @brief Replace all non-printable characters with replacement in - * string. - * NOTE - this will zap non-ascii - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_in_ascii( - std::basic_string<char>& string, - char replacement); - - - /** - * @brief Replace all non-printable characters and pipe characters - * with replacement in a string. - * NOTE - this will zap non-ascii - * - * @param [in,out] the string to modify. out value is the string - * with zero non-printable characters and zero pipe characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, - char replacement); - - - /** - * @brief Remove all characters that are not allowed in XML 1.0. - * Returns a copy of the string with those characters removed. - * Works with US ASCII and UTF-8 encoded strings. JC - */ - LL_COMMON_API std::string strip_invalid_xml(const std::string& input); - - - /** - * @brief Replace all control characters (0 <= c < 0x20) with replacement in - * string. This is safe for utf-8 - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_ascii_controlchars( - std::basic_string<char>& string, - char replacement); + /** + * @brief Replace all non-printable characters with replacement in + * string. + * NOTE - this will zap non-ascii + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_in_ascii( + std::basic_string<char>& string, + char replacement); + + + /** + * @brief Replace all non-printable characters and pipe characters + * with replacement in a string. + * NOTE - this will zap non-ascii + * + * @param [in,out] the string to modify. out value is the string + * with zero non-printable characters and zero pipe characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, + char replacement); + + + /** + * @brief Remove all characters that are not allowed in XML 1.0. + * Returns a copy of the string with those characters removed. + * Works with US ASCII and UTF-8 encoded strings. JC + */ + LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + + + /** + * @brief Replace all control characters (0 <= c < 0x20) with replacement in + * string. This is safe for utf-8 + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_ascii_controlchars( + std::basic_string<char>& string, + char replacement); } //////////////////////////////////////////////////////////// @@ -905,36 +912,36 @@ template <class T> std::vector<typename LLStringUtilBase<T>::string_type> LLStringUtilBase<T>::getTokens(const string_type& instr, const string_type& delims) { - std::vector<string_type> tokens; - getTokens(instr, tokens, delims); - return tokens; + std::vector<string_type> tokens; + getTokens(instr, tokens, delims); + return tokens; } // static template <class T> std::vector<typename LLStringUtilBase<T>::string_type> LLStringUtilBase<T>::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes) { - std::vector<string_type> tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes); - return tokens; + std::vector<string_type> tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes); + return tokens; } // static template <class T> std::vector<typename LLStringUtilBase<T>::string_type> LLStringUtilBase<T>::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes) -{ - std::vector<string_type> tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); - return tokens; + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes) +{ + std::vector<string_type> tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); + return tokens; } namespace LLStringUtilBaseImpl @@ -950,62 +957,62 @@ namespace LLStringUtilBaseImpl template <class T> struct InString { - typedef std::basic_string<T> string_type; - typedef typename string_type::const_iterator const_iterator; - - InString(const_iterator b, const_iterator e): - mIter(b), - mEnd(e) - {} - virtual ~InString() {} - - bool done() const { return mIter == mEnd; } - /// Is the current character (*mIter) escaped? This implementation can - /// answer trivially because it doesn't support escapes. - virtual bool escaped() const { return false; } - /// Obtain the current character and advance @c mIter. - virtual T next() { return *mIter++; } - /// Does the current character match specified character? - virtual bool is(T ch) const { return (! done()) && *mIter == ch; } - /// Is the current character any one of the specified characters? - virtual bool oneof(const string_type& delims) const - { - return (! done()) && LLStringUtilBase<T>::contains(delims, *mIter); - } - - /** - * Scan forward from @from until either @a delim or end. This is primarily - * useful for processing quoted substrings. - * - * If we do see @a delim, append everything from @from until (excluding) - * @a delim to @a into, advance @c mIter to skip @a delim, and return @c - * true. - * - * If we do not see @a delim, do not alter @a into or @c mIter and return - * @c false. Do not pass GO, do not collect $200. - * - * @note The @c false case described above implements normal getTokens() - * treatment of an unmatched open quote: treat the quote character as if - * escaped, that is, simply collect it as part of the current token. Other - * plausible behaviors directly affect the way getTokens() deals with an - * unmatched quote: e.g. throwing an exception to treat it as an error, or - * assuming a close quote beyond end of string (in which case return @c - * true). - */ - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - const_iterator found = std::find(from, mEnd, delim); - // If we didn't find delim, change nothing, just tell caller. - if (found == mEnd) - return false; - // Found delim! Append everything between from and found. - into.append(from, found); - // advance past delim in input - mIter = found + 1; - return true; - } - - const_iterator mIter, mEnd; + typedef std::basic_string<T> string_type; + typedef typename string_type::const_iterator const_iterator; + + InString(const_iterator b, const_iterator e): + mIter(b), + mEnd(e) + {} + virtual ~InString() {} + + bool done() const { return mIter == mEnd; } + /// Is the current character (*mIter) escaped? This implementation can + /// answer trivially because it doesn't support escapes. + virtual bool escaped() const { return false; } + /// Obtain the current character and advance @c mIter. + virtual T next() { return *mIter++; } + /// Does the current character match specified character? + virtual bool is(T ch) const { return (! done()) && *mIter == ch; } + /// Is the current character any one of the specified characters? + virtual bool oneof(const string_type& delims) const + { + return (! done()) && LLStringUtilBase<T>::contains(delims, *mIter); + } + + /** + * Scan forward from @from until either @a delim or end. This is primarily + * useful for processing quoted substrings. + * + * If we do see @a delim, append everything from @from until (excluding) + * @a delim to @a into, advance @c mIter to skip @a delim, and return @c + * true. + * + * If we do not see @a delim, do not alter @a into or @c mIter and return + * @c false. Do not pass GO, do not collect $200. + * + * @note The @c false case described above implements normal getTokens() + * treatment of an unmatched open quote: treat the quote character as if + * escaped, that is, simply collect it as part of the current token. Other + * plausible behaviors directly affect the way getTokens() deals with an + * unmatched quote: e.g. throwing an exception to treat it as an error, or + * assuming a close quote beyond end of string (in which case return @c + * true). + */ + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + const_iterator found = std::find(from, mEnd, delim); + // If we didn't find delim, change nothing, just tell caller. + if (found == mEnd) + return false; + // Found delim! Append everything between from and found. + into.append(from, found); + // advance past delim in input + mIter = found + 1; + return true; + } + + const_iterator mIter, mEnd; }; /// InString subclass that handles escape characters @@ -1013,177 +1020,177 @@ template <class T> class InEscString: public InString<T> { public: - typedef InString<T> super; - typedef typename super::string_type string_type; - typedef typename super::const_iterator const_iterator; - using super::done; - using super::mIter; - using super::mEnd; - - InEscString(const_iterator b, const_iterator e, const string_type& escapes): - super(b, e), - mEscapes(escapes) - { - // Even though we've already initialized 'mIter' via our base-class - // constructor, set it again to check for initial escape char. - setiter(b); - } - - /// This implementation uses the answer cached by setiter(). - virtual bool escaped() const { return mIsEsc; } - virtual T next() - { - // If we're looking at the escape character of an escape sequence, - // skip that character. This is the one time we can modify 'mIter' - // without using setiter: for this one case we DO NOT CARE if the - // escaped character is itself an escape. - if (mIsEsc) - ++mIter; - // If we were looking at an escape character, this is the escaped - // character; otherwise it's just the next character. - T result(*mIter); - // Advance mIter, checking for escape sequence. - setiter(mIter + 1); - return result; - } - - virtual bool is(T ch) const - { - // Like base-class is(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && *mIter == ch; - } - - virtual bool oneof(const string_type& delims) const - { - // Like base-class oneof(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && LLStringUtilBase<T>::contains(delims, *mIter); - } - - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - // Deal with escapes in the characters we collect; that is, an escaped - // character must become just that character without the preceding - // escape. Collect characters in a separate string rather than - // directly appending to 'into' in case we do not find delim, in which - // case we're supposed to leave 'into' unmodified. - string_type collected; - // For scanning purposes, we're going to work directly with 'mIter'. - // Save its current value in case we fail to see delim. - const_iterator save_iter(mIter); - // Okay, set 'mIter', checking for escape. - setiter(from); - while (! done()) - { - // If we see an unescaped delim, stop and report success. - if ((! mIsEsc) && *mIter == delim) - { - // Append collected chars to 'into'. - into.append(collected); - // Don't forget to advance 'mIter' past delim. - setiter(mIter + 1); - return true; - } - // We're not at end, and either we're not looking at delim or it's - // escaped. Collect this character and keep going. - collected.push_back(next()); - } - // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell - // caller. - setiter(save_iter); - return false; - } + typedef InString<T> super; + typedef typename super::string_type string_type; + typedef typename super::const_iterator const_iterator; + using super::done; + using super::mIter; + using super::mEnd; + + InEscString(const_iterator b, const_iterator e, const string_type& escapes): + super(b, e), + mEscapes(escapes) + { + // Even though we've already initialized 'mIter' via our base-class + // constructor, set it again to check for initial escape char. + setiter(b); + } + + /// This implementation uses the answer cached by setiter(). + virtual bool escaped() const { return mIsEsc; } + virtual T next() + { + // If we're looking at the escape character of an escape sequence, + // skip that character. This is the one time we can modify 'mIter' + // without using setiter: for this one case we DO NOT CARE if the + // escaped character is itself an escape. + if (mIsEsc) + ++mIter; + // If we were looking at an escape character, this is the escaped + // character; otherwise it's just the next character. + T result(*mIter); + // Advance mIter, checking for escape sequence. + setiter(mIter + 1); + return result; + } + + virtual bool is(T ch) const + { + // Like base-class is(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && *mIter == ch; + } + + virtual bool oneof(const string_type& delims) const + { + // Like base-class oneof(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && LLStringUtilBase<T>::contains(delims, *mIter); + } + + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + // Deal with escapes in the characters we collect; that is, an escaped + // character must become just that character without the preceding + // escape. Collect characters in a separate string rather than + // directly appending to 'into' in case we do not find delim, in which + // case we're supposed to leave 'into' unmodified. + string_type collected; + // For scanning purposes, we're going to work directly with 'mIter'. + // Save its current value in case we fail to see delim. + const_iterator save_iter(mIter); + // Okay, set 'mIter', checking for escape. + setiter(from); + while (! done()) + { + // If we see an unescaped delim, stop and report success. + if ((! mIsEsc) && *mIter == delim) + { + // Append collected chars to 'into'. + into.append(collected); + // Don't forget to advance 'mIter' past delim. + setiter(mIter + 1); + return true; + } + // We're not at end, and either we're not looking at delim or it's + // escaped. Collect this character and keep going. + collected.push_back(next()); + } + // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell + // caller. + setiter(save_iter); + return false; + } private: - void setiter(const_iterator i) - { - mIter = i; - - // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively - // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches - // contains(mEscapes, *mIter). - - // We're looking at an escaped char if we're not already at end (that - // is, *mIter is even meaningful); if *mIter is in fact one of the - // specified escape characters; and if there's one more character - // following it. That is, if an escape character is the very last - // character of the input string, it loses its special meaning. - mIsEsc = (! done()) && - LLStringUtilBase<T>::contains(mEscapes, *mIter) && - (mIter+1) != mEnd; - } - - const string_type mEscapes; - bool mIsEsc; + void setiter(const_iterator i) + { + mIter = i; + + // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively + // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches + // contains(mEscapes, *mIter). + + // We're looking at an escaped char if we're not already at end (that + // is, *mIter is even meaningful); if *mIter is in fact one of the + // specified escape characters; and if there's one more character + // following it. That is, if an escape character is the very last + // character of the input string, it loses its special meaning. + mIsEsc = (! done()) && + LLStringUtilBase<T>::contains(mEscapes, *mIter) && + (mIter+1) != mEnd; + } + + const string_type mEscapes; + bool mIsEsc; }; /// getTokens() implementation based on InString concept template <typename INSTRING, typename string_type> void getTokens(INSTRING& instr, std::vector<string_type>& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) -{ - // There are times when we want to match either drop_delims or - // keep_delims. Concatenate them up front to speed things up. - string_type all_delims(drop_delims + keep_delims); - // no tokens yet - tokens.clear(); - - // try for another token - while (! instr.done()) - { - // scan past any drop_delims - while (instr.oneof(drop_delims)) - { - // skip this drop_delim - instr.next(); - // but if that was the end of the string, done - if (instr.done()) - return; - } - // found the start of another token: make a slot for it - tokens.push_back(string_type()); - if (instr.oneof(keep_delims)) - { - // *iter is a keep_delim, a token of exactly 1 character. Append - // that character to the new token and proceed. - tokens.back().push_back(instr.next()); - continue; - } - // Here we have a non-delimiter token, which might consist of a mix of - // quoted and unquoted parts. Use bash rules for quoting: you can - // embed a quoted substring in the midst of an unquoted token (e.g. - // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together - // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge - // from bash in that bash considers an unmatched quote an error. Our - // param signature doesn't allow for errors, so just pretend it's not - // a quote and embed it. - // At this level, keep scanning until we hit the next delimiter of - // either type (drop_delims or keep_delims). - while (! instr.oneof(all_delims)) - { - // If we're looking at an open quote, search forward for - // a close quote, collecting characters along the way. - if (instr.oneof(quotes) && - instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) - { - // collect_until is cleverly designed to do exactly what we - // need here. No further action needed if it returns true. - } - else - { - // Either *iter isn't a quote, or there's no matching close - // quote: in other words, just an ordinary char. Append it to - // current token. - tokens.back().push_back(instr.next()); - } - // having scanned that segment of this token, if we've reached the - // end of the string, we're done - if (instr.done()) - return; - } - } + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) +{ + // There are times when we want to match either drop_delims or + // keep_delims. Concatenate them up front to speed things up. + string_type all_delims(drop_delims + keep_delims); + // no tokens yet + tokens.clear(); + + // try for another token + while (! instr.done()) + { + // scan past any drop_delims + while (instr.oneof(drop_delims)) + { + // skip this drop_delim + instr.next(); + // but if that was the end of the string, done + if (instr.done()) + return; + } + // found the start of another token: make a slot for it + tokens.push_back(string_type()); + if (instr.oneof(keep_delims)) + { + // *iter is a keep_delim, a token of exactly 1 character. Append + // that character to the new token and proceed. + tokens.back().push_back(instr.next()); + continue; + } + // Here we have a non-delimiter token, which might consist of a mix of + // quoted and unquoted parts. Use bash rules for quoting: you can + // embed a quoted substring in the midst of an unquoted token (e.g. + // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together + // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge + // from bash in that bash considers an unmatched quote an error. Our + // param signature doesn't allow for errors, so just pretend it's not + // a quote and embed it. + // At this level, keep scanning until we hit the next delimiter of + // either type (drop_delims or keep_delims). + while (! instr.oneof(all_delims)) + { + // If we're looking at an open quote, search forward for + // a close quote, collecting characters along the way. + if (instr.oneof(quotes) && + instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) + { + // collect_until is cleverly designed to do exactly what we + // need here. No further action needed if it returns true. + } + else + { + // Either *iter isn't a quote, or there's no matching close + // quote: in other words, just an ordinary char. Append it to + // current token. + tokens.back().push_back(instr.next()); + } + // having scanned that segment of this token, if we've reached the + // end of the string, we're done + if (instr.done()) + return; + } + } } } // namespace LLStringUtilBaseImpl @@ -1191,256 +1198,256 @@ void getTokens(INSTRING& instr, std::vector<string_type>& tokens, // static template <class T> void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) { - // Because this overload doesn't support escapes, use simple InString to - // manage input range. - LLStringUtilBaseImpl::InString<T> instring(string.begin(), string.end()); - LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); + // Because this overload doesn't support escapes, use simple InString to + // manage input range. + LLStringUtilBaseImpl::InString<T> instring(string.begin(), string.end()); + LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); } // static template <class T> void LLStringUtilBase<T>::getTokens(const string_type& string, std::vector<string_type>& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes, const string_type& escapes) -{ - // This overload must deal with escapes. Delegate that to InEscString - // (unless there ARE no escapes). - std::unique_ptr< LLStringUtilBaseImpl::InString<T> > instrp; - if (escapes.empty()) - instrp.reset(new LLStringUtilBaseImpl::InString<T>(string.begin(), string.end())); - else - instrp.reset(new LLStringUtilBaseImpl::InEscString<T>(string.begin(), string.end(), escapes)); - LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes, const string_type& escapes) +{ + // This overload must deal with escapes. Delegate that to InEscString + // (unless there ARE no escapes). + std::unique_ptr< LLStringUtilBaseImpl::InString<T> > instrp; + if (escapes.empty()) + instrp.reset(new LLStringUtilBaseImpl::InString<T>(string.begin(), string.end())); + else + instrp.reset(new LLStringUtilBaseImpl::InEscString<T>(string.begin(), string.end(), escapes)); + LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); } // static -template<class T> +template<class T> S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs) -{ - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0]) - { - result = -1; - } - else - { - result = LLStringOps::collate(lhs, rhs); - } - return result; +{ + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0]) + { + result = -1; + } + else + { + result = LLStringOps::collate(lhs, rhs); + } + return result; } -//static -template<class T> +//static +template<class T> S32 LLStringUtilBase<T>::compareStrings(const string_type& lhs, const string_type& rhs) { - return LLStringOps::collate(lhs.c_str(), rhs.c_str()); + return LLStringOps::collate(lhs.c_str(), rhs.c_str()); } // static -template<class T> +template<class T> S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs ) { - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0] ) - { - result = -1; - } - else - { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase<T>::toUpper(lhs_string); - LLStringUtilBase<T>::toUpper(rhs_string); - result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); - } - return result; + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0] ) + { + result = -1; + } + else + { + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::toUpper(rhs_string); + result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + } + return result; } -//static -template<class T> +//static +template<class T> S32 LLStringUtilBase<T>::compareInsensitive(const string_type& lhs, const string_type& rhs) { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase<T>::toUpper(lhs_string); - LLStringUtilBase<T>::toUpper(rhs_string); - return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase<T>::toUpper(lhs_string); + LLStringUtilBase<T>::toUpper(rhs_string); + return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); } // Case sensitive comparison with good handling of numbers. Does not use current locale. // a.k.a. strdictcmp() -//static +//static template<class T> S32 LLStringUtilBase<T>::compareDict(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - S32 bias = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( bias==0 ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } - }else{ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai<bi ){ ca=0; break; } - if( bi<ai ){ cb=0; break; } - if( ca!=cb ) break; - cnt = ai; - } - }else if( ca!=cb ){ break; - } - ca = *(a++); - cb = *(b++); - } - if( ca==cb ) ca += bias; - return ca-cb; + const T* a = astr.c_str(); + const T* b = bstr.c_str(); + T ca, cb; + S32 ai, bi, cnt = 0; + S32 bias = 0; + + ca = *(a++); + cb = *(b++); + while( ca && cb ){ + if( bias==0 ){ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } + }else{ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } + } + if( LLStringOps::isDigit(ca) ){ + if( cnt-->0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai<bi ){ ca=0; break; } + if( bi<ai ){ cb=0; break; } + if( ca!=cb ) break; + cnt = ai; + } + }else if( ca!=cb ){ break; + } + ca = *(a++); + cb = *(b++); + } + if( ca==cb ) ca += bias; + return ca-cb; } // static template<class T> S32 LLStringUtilBase<T>::compareDictInsensitive(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai<bi ){ ca=0; break; } - if( bi<ai ){ cb=0; break; } - if( ca!=cb ) break; - cnt = ai; - } - }else if( ca!=cb ){ break; - } - ca = *(a++); - cb = *(b++); - } - return ca-cb; + const T* a = astr.c_str(); + const T* b = bstr.c_str(); + T ca, cb; + S32 ai, bi, cnt = 0; + + ca = *(a++); + cb = *(b++); + while( ca && cb ){ + if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } + if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } + if( LLStringOps::isDigit(ca) ){ + if( cnt-->0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai<bi ){ ca=0; break; } + if( bi<ai ){ cb=0; break; } + if( ca!=cb ) break; + cnt = ai; + } + }else if( ca!=cb ){ break; + } + ca = *(a++); + cb = *(b++); + } + return ca-cb; } // Puts compareDict() in a form appropriate for LL container classes to use for sorting. -// static -template<class T> +// static +template<class T> BOOL LLStringUtilBase<T>::precedesDict( const string_type& a, const string_type& b ) { - if( a.size() && b.size() ) - { - return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); - } - else - { - return (!b.empty()); - } + if( a.size() && b.size() ) + { + return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); + } + else + { + return (!b.empty()); + } } //static -template<class T> -void LLStringUtilBase<T>::toUpper(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toUpper); - } +template<class T> +void LLStringUtilBase<T>::toUpper(string_type& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toUpper); + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::toLower(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toLower); - } +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toLower); + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::trimHead(string_type& string) -{ - if( !string.empty() ) - { - size_type i = 0; - while( i < string.length() && LLStringOps::isSpace( string[i] ) ) - { - i++; - } - string.erase(0, i); - } +{ + if( !string.empty() ) + { + size_type i = 0; + while( i < string.length() && LLStringOps::isSpace( string[i] ) ) + { + i++; + } + string.erase(0, i); + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::trimTail(string_type& string) -{ - if( string.size() ) - { - size_type len = string.length(); - size_type i = len; - while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) - { - i--; - } - - string.erase( i, len - i ); - } +{ + if( string.size() ) + { + size_type len = string.length(); + size_type i = len; + while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) + { + i--; + } + + string.erase( i, len - i ); + } } @@ -1449,67 +1456,67 @@ void LLStringUtilBase<T>::trimTail(string_type& string) template<class T> void LLStringUtilBase<T>::addCRLF(string_type& string) { - const T LF = 10; - const T CR = 13; - - // Count the number of line feeds - size_type count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len; i++ ) - { - if( string[i] == LF ) - { - count++; - } - } - - // Insert a carriage return before each line feed - if( count ) - { - size_type size = len + count; - T *t = new T[size]; - size_type j = 0; - for( i = 0; i < len; ++i ) - { - if( string[i] == LF ) - { - t[j] = CR; - ++j; - } - t[j] = string[i]; - ++j; - } - - string.assign(t, size); - delete[] t; - } + const T LF = 10; + const T CR = 13; + + // Count the number of line feeds + size_type count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len; i++ ) + { + if( string[i] == LF ) + { + count++; + } + } + + // Insert a carriage return before each line feed + if( count ) + { + size_type size = len + count; + T *t = new T[size]; + size_type j = 0; + for( i = 0; i < len; ++i ) + { + if( string[i] == LF ) + { + t[j] = CR; + ++j; + } + t[j] = string[i]; + ++j; + } + + string.assign(t, size); + delete[] t; + } } // Remove all carriage returns //static -template<class T> +template<class T> void LLStringUtilBase<T>::removeCRLF(string_type& string) { - const T CR = 13; - - size_type cr_count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len - cr_count; i++ ) - { - if( string[i+cr_count] == CR ) - { - cr_count++; - } - - string[i] = string[i+cr_count]; - } - string.erase(i, cr_count); + const T CR = 13; + + size_type cr_count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len - cr_count; i++ ) + { + if( string[i+cr_count] == CR ) + { + cr_count++; + } + + string[i] = string[i+cr_count]; + } + string.erase(i, cr_count); } //static -template<class T> +template<class T> void LLStringUtilBase<T>::removeWindowsCR(string_type& string) { if (string.empty()) @@ -1538,269 +1545,269 @@ void LLStringUtilBase<T>::removeWindowsCR(string_type& string) template<class T> void LLStringUtilBase<T>::replaceChar( string_type& string, T target, T replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string[found_pos] = replacement; - found_pos++; // avoid infinite defeat if target == replacement - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::replaceString( string_type& string, string_type target, string_type replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string.replace( found_pos, target.length(), replacement ); - found_pos += replacement.length(); // avoid infinite defeat if replacement contains target - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::replaceNonstandardASCII( string_type& string, T replacement ) { - const char LF = 10; - const S8 MIN = 32; -// const S8 MAX = 127; - - size_type len = string.size(); - for( size_type i = 0; i < len; i++ ) - { - // No need to test MAX < mText[i] because we treat mText[i] as a signed char, - // which has a max value of 127. - if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) - { - string[i] = replacement; - } - } + const char LF = 10; + const S8 MIN = 32; +// const S8 MAX = 127; + + size_type len = string.size(); + for( size_type i = 0; i < len; i++ ) + { + // No need to test MAX < mText[i] because we treat mText[i] as a signed char, + // which has a max value of 127. + if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) + { + string[i] = replacement; + } + } } //static -template<class T> +template<class T> void LLStringUtilBase<T>::replaceTabsWithSpaces( string_type& str, size_type spaces_per_tab ) { - const T TAB = '\t'; - const T SPACE = ' '; - - string_type out_str; - // Replace tabs with spaces - for (size_type i = 0; i < str.length(); i++) - { - if (str[i] == TAB) - { - for (size_type j = 0; j < spaces_per_tab; j++) - out_str += SPACE; - } - else - { - out_str += str[i]; - } - } - str = out_str; + const T TAB = '\t'; + const T SPACE = ' '; + + string_type out_str; + // Replace tabs with spaces + for (size_type i = 0; i < str.length(); i++) + { + if (str[i] == TAB) + { + for (size_type j = 0; j < spaces_per_tab; j++) + out_str += SPACE; + } + else + { + out_str += str[i]; + } + } + str = out_str; } //static template<class T> std::basic_string<T> LLStringUtilBase<T>::capitalize(const string_type& str) { - string_type result(str); - capitalize(result); - return result; + string_type result(str); + capitalize(result); + return result; } //static template<class T> void LLStringUtilBase<T>::capitalize(string_type& str) { - if (str.size()) - { - auto last = str[0] = toupper(str[0]); - for (U32 i = 1; i < str.size(); ++i) - { - last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; - } - } + if (str.size()) + { + auto last = str[0] = toupper(str[0]); + for (U32 i = 1; i < str.size(); ++i) + { + last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; + } + } } //static -template<class T> +template<class T> BOOL LLStringUtilBase<T>::containsNonprintable(const string_type& string) { - const char MIN = 32; - BOOL rv = FALSE; - for (size_type i = 0; i < string.size(); i++) - { - if(string[i] < MIN) - { - rv = TRUE; - break; - } - } - return rv; + const char MIN = 32; + BOOL rv = FALSE; + for (size_type i = 0; i < string.size(); i++) + { + if(string[i] < MIN) + { + rv = TRUE; + break; + } + } + return rv; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm //static -template<class T> +template<class T> void LLStringUtilBase<T>::stripNonprintable(string_type& string) { - const char MIN = 32; - size_type j = 0; - if (string.empty()) - { - return; - } - size_t src_size = string.size(); - char* c_string = new char[src_size + 1]; - if(c_string == NULL) - { - return; - } - copy(c_string, string.c_str(), src_size+1); - char* write_head = &c_string[0]; - for (size_type i = 0; i < src_size; i++) - { - char* read_head = &string[i]; - write_head = &c_string[j]; - if(!(*read_head < MIN)) - { - *write_head = *read_head; - ++j; - } - } - c_string[j]= '\0'; - string = c_string; - delete []c_string; + const char MIN = 32; + size_type j = 0; + if (string.empty()) + { + return; + } + size_t src_size = string.size(); + char* c_string = new char[src_size + 1]; + if(c_string == NULL) + { + return; + } + copy(c_string, string.c_str(), src_size+1); + char* write_head = &c_string[0]; + for (size_type i = 0; i < src_size; i++) + { + char* read_head = &string[i]; + write_head = &c_string[j]; + if(!(*read_head < MIN)) + { + *write_head = *read_head; + ++j; + } + } + c_string[j]= '\0'; + string = c_string; + delete []c_string; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm template<class T> std::basic_string<T> LLStringUtilBase<T>::quote(const string_type& str, - const string_type& triggers, - const string_type& escape) -{ - size_type len(str.length()); - // If the string is already quoted, assume user knows what s/he's doing. - if (len >= 2 && str[0] == '"' && str[len-1] == '"') - { - return str; - } - - // Not already quoted: do we need to? triggers.empty() is a special case - // meaning "always quote." - if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) - { - // no trigger characters, don't bother quoting - return str; - } - - // For whatever reason, we must quote this string. - string_type result; - result.push_back('"'); - for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) - { - if (*ci == '"') - { - result.append(escape); - } - result.push_back(*ci); - } - result.push_back('"'); - return result; + const string_type& triggers, + const string_type& escape) +{ + size_type len(str.length()); + // If the string is already quoted, assume user knows what s/he's doing. + if (len >= 2 && str[0] == '"' && str[len-1] == '"') + { + return str; + } + + // Not already quoted: do we need to? triggers.empty() is a special case + // meaning "always quote." + if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) + { + // no trigger characters, don't bother quoting + return str; + } + + // For whatever reason, we must quote this string. + string_type result; + result.push_back('"'); + for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) + { + if (*ci == '"') + { + result.append(escape); + } + result.push_back(*ci); + } + result.push_back('"'); + return result; } -template<class T> +template<class T> void LLStringUtilBase<T>::_makeASCII(string_type& string) { - // Replace non-ASCII chars with LL_UNKNOWN_CHAR - for (size_type i = 0; i < string.length(); i++) - { - if (string[i] > 0x7f) - { - string[i] = LL_UNKNOWN_CHAR; - } - } + // Replace non-ASCII chars with LL_UNKNOWN_CHAR + for (size_type i = 0; i < string.length(); i++) + { + if (string[i] > 0x7f) + { + string[i] = LL_UNKNOWN_CHAR; + } + } } // static -template<class T> +template<class T> void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size ) { - if( dst_size > 0 ) - { - size_type min_len = 0; - if( src ) - { - min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ - memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ - } - dst[min_len] = '\0'; - } + if( dst_size > 0 ) + { + size_type min_len = 0; + if( src ) + { + min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ + memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ + } + dst[min_len] = '\0'; + } } // static -template<class T> +template<class T> void LLStringUtilBase<T>::copyInto(string_type& dst, const string_type& src, size_type offset) { - if ( offset == dst.length() ) - { - // special case - append to end of string and avoid expensive - // (when strings are large) string manipulations - dst += src; - } - else - { - string_type tail = dst.substr(offset); - - dst = dst.substr(0, offset); - dst += src; - dst += tail; - }; + if ( offset == dst.length() ) + { + // special case - append to end of string and avoid expensive + // (when strings are large) string manipulations + dst += src; + } + else + { + string_type tail = dst.substr(offset); + + dst = dst.substr(0, offset); + dst += src; + dst += tail; + }; } // True if this is the head of s. //static -template<class T> -BOOL LLStringUtilBase<T>::isHead( const string_type& string, const T* s ) -{ - if( string.empty() ) - { - // Early exit - return FALSE; - } - else - { - return (strncmp( s, string.c_str(), string.size() ) == 0); - } +template<class T> +BOOL LLStringUtilBase<T>::isHead( const string_type& string, const T* s ) +{ + if( string.empty() ) + { + // Early exit + return FALSE; + } + else + { + return (strncmp( s, string.c_str(), string.size() ) == 0); + } } // static -template<class T> +template<class T> bool LLStringUtilBase<T>::startsWith( - const string_type& string, - const string_type& substr) + const string_type& string, + const string_type& substr) { - if(string.empty() || (substr.empty())) return false; - if (substr.length() > string.length()) return false; - if (0 == string.compare(0, substr.length(), substr)) return true; - return false; + if(string.empty() || (substr.empty())) return false; + if (substr.length() > string.length()) return false; + if (0 == string.compare(0, substr.length(), substr)) return true; + return false; } // static -template<class T> +template<class T> bool LLStringUtilBase<T>::endsWith( - const string_type& string, - const string_type& substr) -{ - if(string.empty() || (substr.empty())) return false; - size_t sub_len = substr.length(); - size_t str_len = string.length(); - if (sub_len > str_len) return false; - if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; - return false; + const string_type& string, + const string_type& substr) +{ + if(string.empty() || (substr.empty())) return false; + size_t sub_len = substr.length(); + size_t str_len = string.length(); + if (sub_len > str_len) return false; + if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; + return false; } // static @@ -1835,187 +1842,187 @@ auto LLStringUtilBase<T>::getenv(const std::string& key, const string_type& dflt } } -template<class T> +template<class T> BOOL LLStringUtilBase<T>::convertToBOOL(const string_type& string, BOOL& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - if( - (temp == "1") || - (temp == "T") || - (temp == "t") || - (temp == "TRUE") || - (temp == "true") || - (temp == "True") ) - { - value = TRUE; - return TRUE; - } - else - if( - (temp == "0") || - (temp == "F") || - (temp == "f") || - (temp == "FALSE") || - (temp == "false") || - (temp == "False") ) - { - value = FALSE; - return TRUE; - } - - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + if( + (temp == "1") || + (temp == "T") || + (temp == "t") || + (temp == "TRUE") || + (temp == "true") || + (temp == "True") ) + { + value = TRUE; + return TRUE; + } + else + if( + (temp == "0") || + (temp == "F") || + (temp == "f") || + (temp == "FALSE") || + (temp == "false") || + (temp == "False") ) + { + value = FALSE; + return TRUE; + } + + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToU8(const string_type& string, U8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) - { - value = (U8) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToU8(const string_type& string, U8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) + { + value = (U8) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToS8(const string_type& string, S8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) - { - value = (S8) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToS8(const string_type& string, S8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) + { + value = (S8) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToS16(const string_type& string, S16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) - { - value = (S16) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToS16(const string_type& string, S16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) + { + value = (S16) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToU16(const string_type& string, U16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) - { - value = (U16) value32; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToU16(const string_type& string, U16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) + { + value = (U16) value32; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToU32(const string_type& string, U32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - U32 v; - std::basic_istringstream<T> i_stream((string_type)temp); - if(i_stream >> v) - { - value = v; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToU32(const string_type& string, U32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + U32 v; + std::basic_istringstream<T> i_stream((string_type)temp); + if(i_stream >> v) + { + value = v; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToS32(const string_type& string, S32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - S32 v; - std::basic_istringstream<T> i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if((LONG_MAX == v) || (LONG_MIN == v)) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToS32(const string_type& string, S32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + S32 v; + std::basic_istringstream<T> i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if((LONG_MAX == v) || (LONG_MIN == v)) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template<class T> -BOOL LLStringUtilBase<T>::convertToF32(const string_type& string, F32& value) -{ - F64 value64 = 0.0; - BOOL success = convertToF64(string, value64); - if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) - { - value = (F32) value64; - return TRUE; - } - return FALSE; +template<class T> +BOOL LLStringUtilBase<T>::convertToF32(const string_type& string, F32& value) +{ + F64 value64 = 0.0; + BOOL success = convertToF64(string, value64); + if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) + { + value = (F32) value64; + return TRUE; + } + return FALSE; } -template<class T> +template<class T> BOOL LLStringUtilBase<T>::convertToF64(const string_type& string, F64& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - F64 v; - std::basic_istringstream<T> i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + F64 v; + std::basic_istringstream<T> i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template<class T> +template<class T> void LLStringUtilBase<T>::truncate(string_type& string, size_type count) { - size_type cur_size = string.size(); - string.resize(count < cur_size ? count : cur_size); + size_type cur_size = string.size(); + string.resize(count < cur_size ? count : cur_size); } // The good thing about *declaration* macros, vs. usage macros, is that now diff --git a/indra/llcommon/llstringtable.cpp b/indra/llcommon/llstringtable.cpp index 92a5e777a6..d28e1e2219 100644 --- a/indra/llcommon/llstringtable.cpp +++ b/indra/llcommon/llstringtable.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llstringtable.cpp * @brief The LLStringTable class provides a _fast_ method for finding * unique copies of strings. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,101 +35,101 @@ LLStringTable gStringTable(32768); LLStringTableEntry::LLStringTableEntry(const char *str) : mString(NULL), mCount(1) { - // Copy string - U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/ - length = llmin(length, MAX_STRINGS_LENGTH); - mString = new char[length]; - strncpy(mString, str, length); /*Flawfinder: ignore*/ - mString[length - 1] = 0; + // Copy string + U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/ + length = llmin(length, MAX_STRINGS_LENGTH); + mString = new char[length]; + strncpy(mString, str, length); /*Flawfinder: ignore*/ + mString[length - 1] = 0; } LLStringTableEntry::~LLStringTableEntry() { - delete [] mString; - mCount = 0; + delete [] mString; + mCount = 0; } LLStringTable::LLStringTable(int tablesize) : mUniqueEntries(0) { - S32 i; - if (!tablesize) - tablesize = 4096; // some arbitrary default - // Make sure tablesize is power of 2 - for (i = 31; i>0; i--) - { - if (tablesize & (1<<i)) - { - if (tablesize >= (3<<(i-1))) - tablesize = (1<<(i+1)); - else - tablesize = (1<<i); - break; - } - } - mMaxEntries = tablesize; + S32 i; + if (!tablesize) + tablesize = 4096; // some arbitrary default + // Make sure tablesize is power of 2 + for (i = 31; i>0; i--) + { + if (tablesize & (1<<i)) + { + if (tablesize >= (3<<(i-1))) + tablesize = (1<<(i+1)); + else + tablesize = (1<<i); + break; + } + } + mMaxEntries = tablesize; #if !STRING_TABLE_HASH_MAP - // ALlocate strings - mStringList = new string_list_ptr_t[mMaxEntries]; - // Clear strings - for (i = 0; i < mMaxEntries; i++) - { - mStringList[i] = NULL; - } + // ALlocate strings + mStringList = new string_list_ptr_t[mMaxEntries]; + // Clear strings + for (i = 0; i < mMaxEntries; i++) + { + mStringList[i] = NULL; + } #endif } LLStringTable::~LLStringTable() { #if !STRING_TABLE_HASH_MAP - if (mStringList) - { - for (S32 i = 0; i < mMaxEntries; i++) - { - if (mStringList[i]) - { - for (LLStringTableEntry* entry : *mStringList[i]) - delete entry; - } - delete mStringList[i]; - } - delete [] mStringList; - mStringList = NULL; - } + if (mStringList) + { + for (S32 i = 0; i < mMaxEntries; i++) + { + if (mStringList[i]) + { + for (LLStringTableEntry* entry : *mStringList[i]) + delete entry; + } + delete mStringList[i]; + } + delete [] mStringList; + mStringList = NULL; + } #else - // Need to clean up the string hash - for_each(mStringHash.begin(), mStringHash.end(), DeletePairedPointer()); - mStringHash.clear(); + // Need to clean up the string hash + for_each(mStringHash.begin(), mStringHash.end(), DeletePairedPointer()); + mStringHash.clear(); #endif } static U32 hash_my_string(const char *str, int max_entries) { - U32 retval = 0; + U32 retval = 0; #if 0 - while (*str) - { - retval <<= 1; - retval += *str++; - } + while (*str) + { + retval <<= 1; + retval += *str++; + } #else - while (*str) - { - retval = (retval<<4) + *str; - U32 x = (retval & 0xf0000000); - if (x) retval = retval ^ (x>>24); - retval = retval & (~x); - str++; - } + while (*str) + { + retval = (retval<<4) + *str; + U32 x = (retval & 0xf0000000); + if (x) retval = retval ^ (x>>24); + retval = retval & (~x); + str++; + } #endif - return (retval & (max_entries-1)); // max_entries is gauranteed to be power of 2 + return (retval & (max_entries-1)); // max_entries is gauranteed to be power of 2 } char* LLStringTable::checkString(const std::string& str) { - return checkString(str.c_str()); + return checkString(str.c_str()); } char* LLStringTable::checkString(const char *str) @@ -137,11 +137,11 @@ char* LLStringTable::checkString(const char *str) LLStringTableEntry* entry = checkStringEntry(str); if (entry) { - return entry->mString; + return entry->mString; } else { - return NULL; + return NULL; } } @@ -152,51 +152,51 @@ LLStringTableEntry* LLStringTable::checkStringEntry(const std::string& str) LLStringTableEntry* LLStringTable::checkStringEntry(const char *str) { - if (str) - { - char *ret_val; - U32 hash_value = hash_my_string(str, mMaxEntries); + if (str) + { + char *ret_val; + U32 hash_value = hash_my_string(str, mMaxEntries); #if STRING_TABLE_HASH_MAP - LLStringTableEntry *entry; + LLStringTableEntry *entry; #if 1 // Microsoft - string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); - string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); + string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); + string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); #else // stlport - std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); - string_hash_t::iterator lower = P.first; - string_hash_t::iterator upper = P.second; + std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); + string_hash_t::iterator lower = P.first; + string_hash_t::iterator upper = P.second; #endif - for (string_hash_t::iterator iter = lower; iter != upper; iter++) - { - entry = iter->second; - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - return entry; - } - } + for (string_hash_t::iterator iter = lower; iter != upper; iter++) + { + entry = iter->second; + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + return entry; + } + } #else - string_list_t *strlist = mStringList[hash_value]; - if (strlist) - { - for (LLStringTableEntry* entry : *strlist) - { - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - return entry; - } - } - } + string_list_t *strlist = mStringList[hash_value]; + if (strlist) + { + for (LLStringTableEntry* entry : *strlist) + { + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + return entry; + } + } + } #endif - } - return NULL; + } + return NULL; } char* LLStringTable::addString(const std::string& str) { - //RN: safe to use temporary c_str since string is copied - return addString(str.c_str()); + //RN: safe to use temporary c_str since string is copied + return addString(str.c_str()); } char* LLStringTable::addString(const char *str) @@ -205,11 +205,11 @@ char* LLStringTable::addString(const char *str) LLStringTableEntry* entry = addStringEntry(str); if (entry) { - return entry->mString; + return entry->mString; } else { - return NULL; + return NULL; } } @@ -220,132 +220,132 @@ LLStringTableEntry* LLStringTable::addStringEntry(const std::string& str) LLStringTableEntry* LLStringTable::addStringEntry(const char *str) { - if (str) - { - char *ret_val = NULL; - U32 hash_value = hash_my_string(str, mMaxEntries); + if (str) + { + char *ret_val = NULL; + U32 hash_value = hash_my_string(str, mMaxEntries); #if STRING_TABLE_HASH_MAP - LLStringTableEntry *entry; + LLStringTableEntry *entry; #if 1 // Microsoft - string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); - string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); + string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); + string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); #else // stlport - std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); - string_hash_t::iterator lower = P.first; - string_hash_t::iterator upper = P.second; + std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); + string_hash_t::iterator lower = P.first; + string_hash_t::iterator upper = P.second; #endif - for (string_hash_t::iterator iter = lower; iter != upper; iter++) - { - entry = iter->second; - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - entry->incCount(); - return entry; - } - } + for (string_hash_t::iterator iter = lower; iter != upper; iter++) + { + entry = iter->second; + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + entry->incCount(); + return entry; + } + } - // not found, so add! - LLStringTableEntry* newentry = new LLStringTableEntry(str); - ret_val = newentry->mString; - mStringHash.insert(string_hash_t::value_type(hash_value, newentry)); + // not found, so add! + LLStringTableEntry* newentry = new LLStringTableEntry(str); + ret_val = newentry->mString; + mStringHash.insert(string_hash_t::value_type(hash_value, newentry)); #else - string_list_t *strlist = mStringList[hash_value]; + string_list_t *strlist = mStringList[hash_value]; - if (strlist) - { - for (LLStringTableEntry* entry : *strlist) - { - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - entry->incCount(); - return entry; - } - } - } - else - { - mStringList[hash_value] = new string_list_t; - strlist = mStringList[hash_value]; - } + if (strlist) + { + for (LLStringTableEntry* entry : *strlist) + { + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + entry->incCount(); + return entry; + } + } + } + else + { + mStringList[hash_value] = new string_list_t; + strlist = mStringList[hash_value]; + } - // not found, so add! - LLStringTableEntry *newentry = new LLStringTableEntry(str); - //ret_val = newentry->mString; - strlist->push_front(newentry); + // not found, so add! + LLStringTableEntry *newentry = new LLStringTableEntry(str); + //ret_val = newentry->mString; + strlist->push_front(newentry); #endif - mUniqueEntries++; - return newentry; - } - else - { - return NULL; - } + mUniqueEntries++; + return newentry; + } + else + { + return NULL; + } } void LLStringTable::removeString(const char *str) { - if (str) - { - char *ret_val; - U32 hash_value = hash_my_string(str, mMaxEntries); + if (str) + { + char *ret_val; + U32 hash_value = hash_my_string(str, mMaxEntries); #if STRING_TABLE_HASH_MAP - { - LLStringTableEntry *entry; + { + LLStringTableEntry *entry; #if 1 // Microsoft - string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); - string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); + string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); + string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); #else // stlport - std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); - string_hash_t::iterator lower = P.first; - string_hash_t::iterator upper = P.second; + std::pair<string_hash_t::iterator, string_hash_t::iterator> P = mStringHash.equal_range(hash_value); + string_hash_t::iterator lower = P.first; + string_hash_t::iterator upper = P.second; #endif - for (string_hash_t::iterator iter = lower; iter != upper; iter++) - { - entry = iter->second; - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - if (!entry->decCount()) - { - mUniqueEntries--; - if (mUniqueEntries < 0) - { - LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; - } - delete iter->second; - mStringHash.erase(iter); - } - return; - } - } - } + for (string_hash_t::iterator iter = lower; iter != upper; iter++) + { + entry = iter->second; + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + if (!entry->decCount()) + { + mUniqueEntries--; + if (mUniqueEntries < 0) + { + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; + } + delete iter->second; + mStringHash.erase(iter); + } + return; + } + } + } #else - string_list_t *strlist = mStringList[hash_value]; + string_list_t *strlist = mStringList[hash_value]; - if (strlist) - { - for (LLStringTableEntry* entry : *strlist) - { - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - if (!entry->decCount()) - { - mUniqueEntries--; - if (mUniqueEntries < 0) - { - LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; - } - strlist->remove(entry); - delete entry; - } - return; - } - } - } + if (strlist) + { + for (LLStringTableEntry* entry : *strlist) + { + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + if (!entry->decCount()) + { + mUniqueEntries--; + if (mUniqueEntries < 0) + { + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; + } + strlist->remove(entry); + delete entry; + } + return; + } + } + } #endif - } + } } diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h index 0a292c8bac..e41701ce9c 100644 --- a/indra/llcommon/llstringtable.h +++ b/indra/llcommon/llstringtable.h @@ -1,4 +1,4 @@ -/** +/** * @file llstringtable.h * @brief The LLStringTable class provides a _fast_ method for finding * unique copies of strings. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,48 +47,48 @@ const U32 MAX_STRINGS_LENGTH = 256; class LL_COMMON_API LLStringTableEntry { public: - LLStringTableEntry(const char *str); - ~LLStringTableEntry(); + LLStringTableEntry(const char *str); + ~LLStringTableEntry(); - void incCount() { mCount++; } - BOOL decCount() { return --mCount; } + void incCount() { mCount++; } + BOOL decCount() { return --mCount; } - char *mString; - S32 mCount; + char *mString; + S32 mCount; }; class LL_COMMON_API LLStringTable { public: - LLStringTable(int tablesize); - ~LLStringTable(); - - char *checkString(const char *str); - char *checkString(const std::string& str); - LLStringTableEntry *checkStringEntry(const char *str); - LLStringTableEntry *checkStringEntry(const std::string& str); - - char *addString(const char *str); - char *addString(const std::string& str); - LLStringTableEntry *addStringEntry(const char *str); - LLStringTableEntry *addStringEntry(const std::string& str); - void removeString(const char *str); - - S32 mMaxEntries; - S32 mUniqueEntries; - + LLStringTable(int tablesize); + ~LLStringTable(); + + char *checkString(const char *str); + char *checkString(const std::string& str); + LLStringTableEntry *checkStringEntry(const char *str); + LLStringTableEntry *checkStringEntry(const std::string& str); + + char *addString(const char *str); + char *addString(const std::string& str); + LLStringTableEntry *addStringEntry(const char *str); + LLStringTableEntry *addStringEntry(const std::string& str); + void removeString(const char *str); + + S32 mMaxEntries; + S32 mUniqueEntries; + #if STRING_TABLE_HASH_MAP #if LL_WINDOWS - typedef std::hash_multimap<U32, LLStringTableEntry *> string_hash_t; + typedef std::hash_multimap<U32, LLStringTableEntry *> string_hash_t; #else - typedef __gnu_cxx::hash_multimap<U32, LLStringTableEntry *> string_hash_t; + typedef __gnu_cxx::hash_multimap<U32, LLStringTableEntry *> string_hash_t; #endif - string_hash_t mStringHash; + string_hash_t mStringHash; #else - typedef std::list<LLStringTableEntry *> string_list_t; - typedef string_list_t * string_list_ptr_t; - string_list_ptr_t *mStringList; -#endif + typedef std::list<LLStringTableEntry *> string_list_t; + typedef string_list_t * string_list_ptr_t; + string_list_ptr_t *mStringList; +#endif }; extern LL_COMMON_API LLStringTable gStringTable; @@ -104,105 +104,105 @@ typedef const std::string* LLStdStringHandle; class LL_COMMON_API LLStdStringTable { public: - LLStdStringTable(S32 tablesize = 0) - { - if (tablesize == 0) - { - tablesize = 256; // default - } - // Make sure tablesize is power of 2 - for (S32 i = 31; i>0; i--) - { - if (tablesize & (1<<i)) - { - if (tablesize >= (3<<(i-1))) - tablesize = (1<<(i+1)); - else - tablesize = (1<<i); - break; - } - } - mTableSize = tablesize; - mStringList = new string_set_t[tablesize]; - } - ~LLStdStringTable() - { - cleanup(); - delete[] mStringList; - } - void cleanup() - { - // remove strings - for (S32 i = 0; i<mTableSize; i++) - { - string_set_t& stringset = mStringList[i]; - for (LLStdStringHandle str : stringset) - { - delete str; - } - stringset.clear(); - } - } - - LLStdStringHandle lookup(const std::string& s) - { - U32 hashval = makehash(s); - return lookup(hashval, s); - } - - LLStdStringHandle checkString(const std::string& s) - { - U32 hashval = makehash(s); - return lookup(hashval, s); - } - - LLStdStringHandle insert(const std::string& s) - { - U32 hashval = makehash(s); - LLStdStringHandle result = lookup(hashval, s); - if (result == NULL) - { - result = new std::string(s); - mStringList[hashval].insert(result); - } - return result; - } - LLStdStringHandle addString(const std::string& s) - { - return insert(s); - } - + LLStdStringTable(S32 tablesize = 0) + { + if (tablesize == 0) + { + tablesize = 256; // default + } + // Make sure tablesize is power of 2 + for (S32 i = 31; i>0; i--) + { + if (tablesize & (1<<i)) + { + if (tablesize >= (3<<(i-1))) + tablesize = (1<<(i+1)); + else + tablesize = (1<<i); + break; + } + } + mTableSize = tablesize; + mStringList = new string_set_t[tablesize]; + } + ~LLStdStringTable() + { + cleanup(); + delete[] mStringList; + } + void cleanup() + { + // remove strings + for (S32 i = 0; i<mTableSize; i++) + { + string_set_t& stringset = mStringList[i]; + for (LLStdStringHandle str : stringset) + { + delete str; + } + stringset.clear(); + } + } + + LLStdStringHandle lookup(const std::string& s) + { + U32 hashval = makehash(s); + return lookup(hashval, s); + } + + LLStdStringHandle checkString(const std::string& s) + { + U32 hashval = makehash(s); + return lookup(hashval, s); + } + + LLStdStringHandle insert(const std::string& s) + { + U32 hashval = makehash(s); + LLStdStringHandle result = lookup(hashval, s); + if (result == NULL) + { + result = new std::string(s); + mStringList[hashval].insert(result); + } + return result; + } + LLStdStringHandle addString(const std::string& s) + { + return insert(s); + } + private: - U32 makehash(const std::string& s) - { - S32 len = (S32)s.size(); - const char* c = s.c_str(); - U32 hashval = 0; - for (S32 i=0; i<len; i++) - { - hashval = ((hashval<<5) + hashval) + *c++; - } - return hashval & (mTableSize-1); - } - LLStdStringHandle lookup(U32 hashval, const std::string& s) - { - string_set_t& stringset = mStringList[hashval]; - LLStdStringHandle handle = &s; - string_set_t::iterator iter = stringset.find(handle); // compares actual strings - if (iter != stringset.end()) - { - return *iter; - } - else - { - return NULL; - } - } - + U32 makehash(const std::string& s) + { + S32 len = (S32)s.size(); + const char* c = s.c_str(); + U32 hashval = 0; + for (S32 i=0; i<len; i++) + { + hashval = ((hashval<<5) + hashval) + *c++; + } + return hashval & (mTableSize-1); + } + LLStdStringHandle lookup(U32 hashval, const std::string& s) + { + string_set_t& stringset = mStringList[hashval]; + LLStdStringHandle handle = &s; + string_set_t::iterator iter = stringset.find(handle); // compares actual strings + if (iter != stringset.end()) + { + return *iter; + } + else + { + return NULL; + } + } + private: - S32 mTableSize; - typedef std::set<LLStdStringHandle, compare_pointer_contents<std::string> > string_set_t; - string_set_t* mStringList; // [mTableSize] + S32 mTableSize; + typedef std::set<LLStdStringHandle, compare_pointer_contents<std::string> > string_set_t; + string_set_t* mStringList; // [mTableSize] }; diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 42400e90af..b7ffddc023 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsys.cpp * @brief Implementation of the basic system query functions. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,26 +59,26 @@ using namespace llsd; #if LL_WINDOWS -# include "llwin32headerslean.h" +# include "llwin32headerslean.h" # include <psapi.h> // GetPerformanceInfo() et al. -# include <VersionHelpers.h> +# include <VersionHelpers.h> #elif LL_DARWIN # include "llsys_objc.h" -# include <errno.h> -# include <sys/sysctl.h> -# include <sys/utsname.h> -# include <stdint.h> -# include <CoreServices/CoreServices.h> +# include <errno.h> +# include <sys/sysctl.h> +# include <sys/utsname.h> +# include <stdint.h> +# include <CoreServices/CoreServices.h> # include <stdexcept> -# include <mach/host_info.h> -# include <mach/mach_host.h> -# include <mach/task.h> -# include <mach/task_info.h> +# include <mach/host_info.h> +# include <mach/mach_host.h> +# include <mach/task.h> +# include <mach/task_info.h> #elif LL_LINUX -# include <errno.h> -# include <sys/utsname.h> -# include <unistd.h> -# include <sys/sysinfo.h> +# include <errno.h> +# include <sys/utsname.h> +# include <unistd.h> +# include <sys/sysinfo.h> # include <stdexcept> const char MEMINFO_FILE[] = "/proc/meminfo"; # include <gnu/libc-version.h> @@ -96,132 +96,132 @@ static const F32 MEM_INFO_THROTTLE = 20; static const F32 MEM_INFO_WINDOW = 10*60; LLOSInfo::LLOSInfo() : - mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") + mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") { #if LL_WINDOWS if (IsWindows10OrGreater()) - { - mMajorVer = 10; - mMinorVer = 0; - mOSStringSimple = "Microsoft Windows 10 "; - } - else if (IsWindows8Point1OrGreater()) - { - mMajorVer = 6; - mMinorVer = 3; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2012 R2 "; - } - else - { - mOSStringSimple = "Microsoft Windows 8.1 "; - } - } - else if (IsWindows8OrGreater()) - { - mMajorVer = 6; - mMinorVer = 2; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2012 "; - } - else - { - mOSStringSimple = "Microsoft Windows 8 "; - } - } - else if (IsWindows7SP1OrGreater()) - { - mMajorVer = 6; - mMinorVer = 1; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2008 R2 SP1 "; - } - else - { - mOSStringSimple = "Microsoft Windows 7 SP1 "; - } - } - else if (IsWindows7OrGreater()) - { - mMajorVer = 6; - mMinorVer = 1; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2008 R2 "; - } - else - { - mOSStringSimple = "Microsoft Windows 7 "; - } - } - else if (IsWindowsVistaSP2OrGreater()) - { - mMajorVer = 6; - mMinorVer = 0; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2008 SP2 "; - } - else - { - mOSStringSimple = "Microsoft Windows Vista SP2 "; - } - } - else - { - mOSStringSimple = "Unsupported Windows version "; - } - - ///get native system info if available.. - typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo - SYSTEM_INFO si; //System Info object file contains architecture info - PGNSI pGNSI; //pointer object - ZeroMemory(&si, sizeof(SYSTEM_INFO)); //zero out the memory in information - pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); //load kernel32 get function - if (NULL != pGNSI) //check if it has failed - pGNSI(&si); //success - else - GetSystemInfo(&si); //if it fails get regular system info - //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load) - - // Try calling GetVersionEx using the OSVERSIONINFOEX structure. - OSVERSIONINFOEX osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if (GetVersionEx((OSVERSIONINFO *)&osvi)) - { - mBuild = osvi.dwBuildNumber & 0xffff; - } - else - { - // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx((OSVERSIONINFO *)&osvi)) - { - mBuild = osvi.dwBuildNumber & 0xffff; - } - } - - S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry - if (mMajorVer == 10) - { - DWORD cbData(sizeof(DWORD)); - DWORD data(0); - HKEY key; - BOOL ret_code = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &key); - if (ERROR_SUCCESS == ret_code) - { - ret_code = RegQueryValueExW(key, L"UBR", 0, NULL, reinterpret_cast<LPBYTE>(&data), &cbData); - if (ERROR_SUCCESS == ret_code) - { - ubr = data; - } - } + { + mMajorVer = 10; + mMinorVer = 0; + mOSStringSimple = "Microsoft Windows 10 "; + } + else if (IsWindows8Point1OrGreater()) + { + mMajorVer = 6; + mMinorVer = 3; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2012 R2 "; + } + else + { + mOSStringSimple = "Microsoft Windows 8.1 "; + } + } + else if (IsWindows8OrGreater()) + { + mMajorVer = 6; + mMinorVer = 2; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2012 "; + } + else + { + mOSStringSimple = "Microsoft Windows 8 "; + } + } + else if (IsWindows7SP1OrGreater()) + { + mMajorVer = 6; + mMinorVer = 1; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2008 R2 SP1 "; + } + else + { + mOSStringSimple = "Microsoft Windows 7 SP1 "; + } + } + else if (IsWindows7OrGreater()) + { + mMajorVer = 6; + mMinorVer = 1; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2008 R2 "; + } + else + { + mOSStringSimple = "Microsoft Windows 7 "; + } + } + else if (IsWindowsVistaSP2OrGreater()) + { + mMajorVer = 6; + mMinorVer = 0; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2008 SP2 "; + } + else + { + mOSStringSimple = "Microsoft Windows Vista SP2 "; + } + } + else + { + mOSStringSimple = "Unsupported Windows version "; + } + + ///get native system info if available.. + typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo + SYSTEM_INFO si; //System Info object file contains architecture info + PGNSI pGNSI; //pointer object + ZeroMemory(&si, sizeof(SYSTEM_INFO)); //zero out the memory in information + pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); //load kernel32 get function + if (NULL != pGNSI) //check if it has failed + pGNSI(&si); //success + else + GetSystemInfo(&si); //if it fails get regular system info + //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load) + + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (GetVersionEx((OSVERSIONINFO *)&osvi)) + { + mBuild = osvi.dwBuildNumber & 0xffff; + } + else + { + // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx((OSVERSIONINFO *)&osvi)) + { + mBuild = osvi.dwBuildNumber & 0xffff; + } + } + + S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry + if (mMajorVer == 10) + { + DWORD cbData(sizeof(DWORD)); + DWORD data(0); + HKEY key; + BOOL ret_code = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &key); + if (ERROR_SUCCESS == ret_code) + { + ret_code = RegQueryValueExW(key, L"UBR", 0, NULL, reinterpret_cast<LPBYTE>(&data), &cbData); + if (ERROR_SUCCESS == ret_code) + { + ubr = data; + } + } if (mBuild >= 22000) { @@ -251,315 +251,315 @@ LLOSInfo::LLOSInfo() : mOSStringSimple += "32-bit "; } - mOSString = mOSStringSimple; - if (mBuild > 0) - { - mOSString += llformat("(Build %d", mBuild); - if (ubr > 0) - { - mOSString += llformat(".%d", ubr); - } - mOSString += ")"; - } + mOSString = mOSStringSimple; + if (mBuild > 0) + { + mOSString += llformat("(Build %d", mBuild); + if (ubr > 0) + { + mOSString += llformat(".%d", ubr); + } + mOSString += ")"; + } - LLStringUtil::trim(mOSStringSimple); - LLStringUtil::trim(mOSString); + LLStringUtil::trim(mOSStringSimple); + LLStringUtil::trim(mOSString); #elif LL_DARWIN - - // Initialize mOSStringSimple to something like: - // "Mac OS X 10.6.7" - { - const char * DARWIN_PRODUCT_NAME = "Mac OS X"; - - int64_t major_version, minor_version, bugfix_version = 0; - - if (LLGetDarwinOSInfo(major_version, minor_version, bugfix_version)) - { - mMajorVer = major_version; - mMinorVer = minor_version; - mBuild = bugfix_version; - - std::stringstream os_version_string; - os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild; - - // Put it in the OS string we are compiling - mOSStringSimple.append(os_version_string.str()); - } - else - { - mOSStringSimple.append("Unable to collect OS info"); - } - } - - // Initialize mOSString to something like: - // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" - struct utsname un; - if(uname(&un) != -1) - { - mOSString = mOSStringSimple; - mOSString.append(" "); - mOSString.append(un.sysname); - mOSString.append(" "); - mOSString.append(un.release); - mOSString.append(" "); - mOSString.append(un.version); - mOSString.append(" "); - mOSString.append(un.machine); - } - else - { - mOSString = mOSStringSimple; - } - + + // Initialize mOSStringSimple to something like: + // "Mac OS X 10.6.7" + { + const char * DARWIN_PRODUCT_NAME = "Mac OS X"; + + int64_t major_version, minor_version, bugfix_version = 0; + + if (LLGetDarwinOSInfo(major_version, minor_version, bugfix_version)) + { + mMajorVer = major_version; + mMinorVer = minor_version; + mBuild = bugfix_version; + + std::stringstream os_version_string; + os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild; + + // Put it in the OS string we are compiling + mOSStringSimple.append(os_version_string.str()); + } + else + { + mOSStringSimple.append("Unable to collect OS info"); + } + } + + // Initialize mOSString to something like: + // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" + struct utsname un; + if(uname(&un) != -1) + { + mOSString = mOSStringSimple; + mOSString.append(" "); + mOSString.append(un.sysname); + mOSString.append(" "); + mOSString.append(un.release); + mOSString.append(" "); + mOSString.append(un.version); + mOSString.append(" "); + mOSString.append(un.machine); + } + else + { + mOSString = mOSStringSimple; + } + #elif LL_LINUX - - struct utsname un; - if(uname(&un) != -1) - { - mOSStringSimple.append(un.sysname); - mOSStringSimple.append(" "); - mOSStringSimple.append(un.release); - - mOSString = mOSStringSimple; - mOSString.append(" "); - mOSString.append(un.version); - mOSString.append(" "); - mOSString.append(un.machine); - - // Simplify 'Simple' - std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); - if (ostype == "Linux") - { - // Only care about major and minor Linux versions, truncate at second '.' - std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); - std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; - std::string simple = mOSStringSimple.substr(0, idx2); - if (simple.length() > 0) - mOSStringSimple = simple; - } - } - else - { - mOSStringSimple.append("Unable to collect OS info"); - mOSString = mOSStringSimple; - } - - const char OS_VERSION_MATCH_EXPRESSION[] = "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?"; - boost::regex os_version_parse(OS_VERSION_MATCH_EXPRESSION); - boost::smatch matched; - - std::string glibc_version(gnu_get_libc_version()); - if ( ll_regex_match(glibc_version, matched, os_version_parse) ) - { - LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; - - std::string version_value; - - if ( matched[1].matched ) // Major version - { - version_value.assign(matched[1].first, matched[1].second); - if (sscanf(version_value.c_str(), "%d", &mMajorVer) != 1) - { - LL_WARNS("AppInit") << "failed to parse major version '" << version_value << "' as a number" << LL_ENDL; - } - } - else - { - LL_ERRS("AppInit") - << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION - << "' returned true, but major version [1] did not match" - << LL_ENDL; - } - - if ( matched[2].matched ) // Minor version - { - version_value.assign(matched[2].first, matched[2].second); - if (sscanf(version_value.c_str(), "%d", &mMinorVer) != 1) - { - LL_ERRS("AppInit") << "failed to parse minor version '" << version_value << "' as a number" << LL_ENDL; - } - } - else - { - LL_ERRS("AppInit") - << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION - << "' returned true, but minor version [1] did not match" - << LL_ENDL; - } - - if ( matched[4].matched ) // Build version (optional) - note that [3] includes the '.' - { - version_value.assign(matched[4].first, matched[4].second); - if (sscanf(version_value.c_str(), "%d", &mBuild) != 1) - { - LL_ERRS("AppInit") << "failed to parse build version '" << version_value << "' as a number" << LL_ENDL; - } - } - else - { - LL_INFOS("AppInit") - << "OS build version not provided; using zero" - << LL_ENDL; - } - } - else - { - LL_WARNS("AppInit") << "glibc version '" << glibc_version << "' cannot be parsed to three numbers; using all zeros" << LL_ENDL; - } + + struct utsname un; + if(uname(&un) != -1) + { + mOSStringSimple.append(un.sysname); + mOSStringSimple.append(" "); + mOSStringSimple.append(un.release); + + mOSString = mOSStringSimple; + mOSString.append(" "); + mOSString.append(un.version); + mOSString.append(" "); + mOSString.append(un.machine); + + // Simplify 'Simple' + std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); + if (ostype == "Linux") + { + // Only care about major and minor Linux versions, truncate at second '.' + std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); + std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; + std::string simple = mOSStringSimple.substr(0, idx2); + if (simple.length() > 0) + mOSStringSimple = simple; + } + } + else + { + mOSStringSimple.append("Unable to collect OS info"); + mOSString = mOSStringSimple; + } + + const char OS_VERSION_MATCH_EXPRESSION[] = "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?"; + boost::regex os_version_parse(OS_VERSION_MATCH_EXPRESSION); + boost::smatch matched; + + std::string glibc_version(gnu_get_libc_version()); + if ( ll_regex_match(glibc_version, matched, os_version_parse) ) + { + LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; + + std::string version_value; + + if ( matched[1].matched ) // Major version + { + version_value.assign(matched[1].first, matched[1].second); + if (sscanf(version_value.c_str(), "%d", &mMajorVer) != 1) + { + LL_WARNS("AppInit") << "failed to parse major version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_ERRS("AppInit") + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "' returned true, but major version [1] did not match" + << LL_ENDL; + } + + if ( matched[2].matched ) // Minor version + { + version_value.assign(matched[2].first, matched[2].second); + if (sscanf(version_value.c_str(), "%d", &mMinorVer) != 1) + { + LL_ERRS("AppInit") << "failed to parse minor version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_ERRS("AppInit") + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "' returned true, but minor version [1] did not match" + << LL_ENDL; + } + + if ( matched[4].matched ) // Build version (optional) - note that [3] includes the '.' + { + version_value.assign(matched[4].first, matched[4].second); + if (sscanf(version_value.c_str(), "%d", &mBuild) != 1) + { + LL_ERRS("AppInit") << "failed to parse build version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_INFOS("AppInit") + << "OS build version not provided; using zero" + << LL_ENDL; + } + } + else + { + LL_WARNS("AppInit") << "glibc version '" << glibc_version << "' cannot be parsed to three numbers; using all zeros" << LL_ENDL; + } #else - - struct utsname un; - if(uname(&un) != -1) - { - mOSStringSimple.append(un.sysname); - mOSStringSimple.append(" "); - mOSStringSimple.append(un.release); - - mOSString = mOSStringSimple; - mOSString.append(" "); - mOSString.append(un.version); - mOSString.append(" "); - mOSString.append(un.machine); - - // Simplify 'Simple' - std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); - if (ostype == "Linux") - { - // Only care about major and minor Linux versions, truncate at second '.' - std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); - std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; - std::string simple = mOSStringSimple.substr(0, idx2); - if (simple.length() > 0) - mOSStringSimple = simple; - } - } - else - { - mOSStringSimple.append("Unable to collect OS info"); - mOSString = mOSStringSimple; - } + + struct utsname un; + if(uname(&un) != -1) + { + mOSStringSimple.append(un.sysname); + mOSStringSimple.append(" "); + mOSStringSimple.append(un.release); + + mOSString = mOSStringSimple; + mOSString.append(" "); + mOSString.append(un.version); + mOSString.append(" "); + mOSString.append(un.machine); + + // Simplify 'Simple' + std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); + if (ostype == "Linux") + { + // Only care about major and minor Linux versions, truncate at second '.' + std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); + std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; + std::string simple = mOSStringSimple.substr(0, idx2); + if (simple.length() > 0) + mOSStringSimple = simple; + } + } + else + { + mOSStringSimple.append("Unable to collect OS info"); + mOSString = mOSStringSimple; + } #endif - std::stringstream dotted_version_string; - dotted_version_string << mMajorVer << "." << mMinorVer << "." << mBuild; - mOSVersionString.append(dotted_version_string.str()); + std::stringstream dotted_version_string; + dotted_version_string << mMajorVer << "." << mMinorVer << "." << mBuild; + mOSVersionString.append(dotted_version_string.str()); - mOSBitness = is64Bit() ? 64 : 32; - LL_INFOS("LLOSInfo") << "OS bitness: " << mOSBitness << LL_ENDL; + mOSBitness = is64Bit() ? 64 : 32; + LL_INFOS("LLOSInfo") << "OS bitness: " << mOSBitness << LL_ENDL; } #ifndef LL_WINDOWS // static long LLOSInfo::getMaxOpenFiles() { - const long OPEN_MAX_GUESS = 256; + const long OPEN_MAX_GUESS = 256; -#ifdef OPEN_MAX - static long open_max = OPEN_MAX; +#ifdef OPEN_MAX + static long open_max = OPEN_MAX; #else - static long open_max = 0; + static long open_max = 0; #endif - if (0 == open_max) - { - // First time through. - errno = 0; - if ( (open_max = sysconf(_SC_OPEN_MAX)) < 0) - { - if (0 == errno) - { - // Indeterminate. - open_max = OPEN_MAX_GUESS; - } - else - { - LL_ERRS() << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << LL_ENDL; - } - } - } - return open_max; + if (0 == open_max) + { + // First time through. + errno = 0; + if ( (open_max = sysconf(_SC_OPEN_MAX)) < 0) + { + if (0 == errno) + { + // Indeterminate. + open_max = OPEN_MAX_GUESS; + } + else + { + LL_ERRS() << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << LL_ENDL; + } + } + } + return open_max; } #endif void LLOSInfo::stream(std::ostream& s) const { - s << mOSString; + s << mOSString; } const std::string& LLOSInfo::getOSString() const { - return mOSString; + return mOSString; } const std::string& LLOSInfo::getOSStringSimple() const { - return mOSStringSimple; + return mOSStringSimple; } const std::string& LLOSInfo::getOSVersionString() const { - return mOSVersionString; + return mOSVersionString; } const S32 LLOSInfo::getOSBitness() const { - return mOSBitness; + return mOSBitness; } //static U32 LLOSInfo::getProcessVirtualSizeKB() { - U32 virtual_size = 0; + U32 virtual_size = 0; #if LL_LINUX -# define STATUS_SIZE 2048 - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ - - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; - - // All these guys return numbers in KB - char *memp = strstr(buff, "VmSize:"); - if (memp) - { - numRead += sscanf(memp, "%*s %u", &virtual_size); - } - fclose(status_filep); - } +# define STATUS_SIZE 2048 + LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); + if (status_filep) + { + S32 numRead = 0; + char buff[STATUS_SIZE]; /* Flawfinder: ignore */ + + size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); + buff[nbytes] = '\0'; + + // All these guys return numbers in KB + char *memp = strstr(buff, "VmSize:"); + if (memp) + { + numRead += sscanf(memp, "%*s %u", &virtual_size); + } + fclose(status_filep); + } #endif - return virtual_size; + return virtual_size; } //static U32 LLOSInfo::getProcessResidentSizeKB() { - U32 resident_size = 0; + U32 resident_size = 0; #if LL_LINUX - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep != NULL) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ - - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; - - // All these guys return numbers in KB - char *memp = strstr(buff, "VmRSS:"); - if (memp) - { - numRead += sscanf(memp, "%*s %u", &resident_size); - } - fclose(status_filep); - } + LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); + if (status_filep != NULL) + { + S32 numRead = 0; + char buff[STATUS_SIZE]; /* Flawfinder: ignore */ + + size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); + buff[nbytes] = '\0'; + + // All these guys return numbers in KB + char *memp = strstr(buff, "VmRSS:"); + if (memp) + { + numRead += sscanf(memp, "%*s %u", &resident_size); + } + fclose(status_filep); + } #endif - return resident_size; + return resident_size; } //static @@ -577,34 +577,34 @@ bool LLOSInfo::is64Bit() #endif #else // ! LL_WINDOWS // we only build a 64-bit mac viewer and currently we don't build for linux at all - return true; + return true; #endif } LLCPUInfo::LLCPUInfo() { - std::ostringstream out; - LLProcessorInfo proc; - // proc.WriteInfoTextFile("procInfo.txt"); - mHasSSE = proc.hasSSE(); - mHasSSE2 = proc.hasSSE2(); + std::ostringstream out; + LLProcessorInfo proc; + // proc.WriteInfoTextFile("procInfo.txt"); + mHasSSE = proc.hasSSE(); + mHasSSE2 = proc.hasSSE2(); mHasSSE3 = proc.hasSSE3(); mHasSSE3S = proc.hasSSE3S(); mHasSSE41 = proc.hasSSE41(); mHasSSE42 = proc.hasSSE42(); mHasSSE4a = proc.hasSSE4a(); - mHasAltivec = proc.hasAltivec(); - mCPUMHz = (F64)proc.getCPUFrequency(); - mFamily = proc.getCPUFamilyName(); - mCPUString = "Unknown"; - - out << proc.getCPUBrandName(); - if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check - { - out << " (" << mCPUMHz << " MHz)"; - } - mCPUString = out.str(); - LLStringUtil::trim(mCPUString); + mHasAltivec = proc.hasAltivec(); + mCPUMHz = (F64)proc.getCPUFrequency(); + mFamily = proc.getCPUFamilyName(); + mCPUString = "Unknown"; + + out << proc.getCPUBrandName(); + if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check + { + out << " (" << mCPUMHz << " MHz)"; + } + mCPUString = out.str(); + LLStringUtil::trim(mCPUString); if (mHasSSE) { @@ -638,17 +638,17 @@ LLCPUInfo::LLCPUInfo() bool LLCPUInfo::hasAltivec() const { - return mHasAltivec; + return mHasAltivec; } bool LLCPUInfo::hasSSE() const { - return mHasSSE; + return mHasSSE; } bool LLCPUInfo::hasSSE2() const { - return mHasSSE2; + return mHasSSE2; } bool LLCPUInfo::hasSSE3() const @@ -678,12 +678,12 @@ bool LLCPUInfo::hasSSE4a() const F64 LLCPUInfo::getMHz() const { - return mCPUMHz; + return mCPUMHz; } std::string LLCPUInfo::getCPUString() const { - return mCPUString; + return mCPUString; } const LLSD& LLCPUInfo::getSSEVersions() const @@ -693,21 +693,21 @@ const LLSD& LLCPUInfo::getSSEVersions() const void LLCPUInfo::stream(std::ostream& s) const { - // gather machine information. - s << LLProcessorInfo().getCPUFeatureDescription(); + // gather machine information. + s << LLProcessorInfo().getCPUFeatureDescription(); - // These are interesting as they reflect our internal view of the - // CPU's attributes regardless of platform - s << "->mHasSSE: " << (U32)mHasSSE << std::endl; - s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl; + // These are interesting as they reflect our internal view of the + // CPU's attributes regardless of platform + s << "->mHasSSE: " << (U32)mHasSSE << std::endl; + s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl; s << "->mHasSSE3: " << (U32)mHasSSE3 << std::endl; s << "->mHasSSE3S: " << (U32)mHasSSE3S << std::endl; s << "->mHasSSE41: " << (U32)mHasSSE41 << std::endl; s << "->mHasSSE42: " << (U32)mHasSSE42 << std::endl; s << "->mHasSSE4a: " << (U32)mHasSSE4a << std::endl; - s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl; - s << "->mCPUMHz: " << mCPUMHz << std::endl; - s << "->mCPUString: " << mCPUString << std::endl; + s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl; + s << "->mCPUMHz: " << mCPUMHz << std::endl; + s << "->mCPUString: " << mCPUString << std::endl; } // Helper class for LLMemoryInfo: accumulate stats in the form we store for @@ -715,58 +715,58 @@ void LLCPUInfo::stream(std::ostream& s) const class Stats { public: - Stats(): - mStats(LLSD::emptyMap()) - {} - - // Store every integer type as LLSD::Integer. - template <class T> - void add(const LLSD::String& name, const T& value, - typename boost::enable_if<boost::is_integral<T> >::type* = 0) - { - mStats[name] = LLSD::Integer(value); - } - - // Store every floating-point type as LLSD::Real. - template <class T> - void add(const LLSD::String& name, const T& value, - typename boost::enable_if<boost::is_float<T> >::type* = 0) - { - mStats[name] = LLSD::Real(value); - } - - // Hope that LLSD::Date values are sufficiently unambiguous. - void add(const LLSD::String& name, const LLSD::Date& value) - { - mStats[name] = value; - } - - LLSD get() const { return mStats; } + Stats(): + mStats(LLSD::emptyMap()) + {} + + // Store every integer type as LLSD::Integer. + template <class T> + void add(const LLSD::String& name, const T& value, + typename boost::enable_if<boost::is_integral<T> >::type* = 0) + { + mStats[name] = LLSD::Integer(value); + } + + // Store every floating-point type as LLSD::Real. + template <class T> + void add(const LLSD::String& name, const T& value, + typename boost::enable_if<boost::is_float<T> >::type* = 0) + { + mStats[name] = LLSD::Real(value); + } + + // Hope that LLSD::Date values are sufficiently unambiguous. + void add(const LLSD::String& name, const LLSD::Date& value) + { + mStats[name] = value; + } + + LLSD get() const { return mStats; } private: - LLSD mStats; + LLSD mStats; }; LLMemoryInfo::LLMemoryInfo() { - refresh(); + refresh(); } #if LL_WINDOWS static U32Kilobytes LLMemoryAdjustKBResult(U32Kilobytes inKB) { - // Moved this here from llfloaterabout.cpp - - //! \bug - // For some reason, the reported amount of memory is always wrong. - // The original adjustment assumes it's always off by one meg, however - // errors of as much as 2520 KB have been observed in the value - // returned from the GetMemoryStatusEx function. Here we keep the - // original adjustment from llfoaterabout.cpp until this can be - // fixed somehow. - inKB += U32Megabytes(1); - - return inKB; + // Moved this here from llfloaterabout.cpp + + //! \bug + // For some reason, the reported amount of memory is always wrong. + // The original adjustment assumes it's always off by one meg, however + // errors of as much as 2520 KB have been observed in the value + // returned from the GetMemoryStatusEx function. Here we keep the + // original adjustment from llfoaterabout.cpp until this can be + // fixed somehow. + inKB += U32Megabytes(1); + + return inKB; } #endif @@ -788,18 +788,18 @@ U32Kilobytes LLMemoryInfo::getHardwareMemSize() U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const { #if LL_WINDOWS - return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger())); + return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger())); #elif LL_DARWIN return getHardwareMemSize(); #elif LL_LINUX - U64 phys = 0; - phys = (U64)(getpagesize()) * (U64)(get_phys_pages()); - return U64Bytes(phys); + U64 phys = 0; + phys = (U64)(getpagesize()) * (U64)(get_phys_pages()); + return U64Bytes(phys); #else - return 0; + return 0; #endif } @@ -808,373 +808,373 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb) { #if LL_WINDOWS - // Sigh, this shouldn't be a static method, then we wouldn't have to - // reload this data separately from refresh() - LLSD statsMap(loadStatsMap()); + // Sigh, this shouldn't be a static method, then we wouldn't have to + // reload this data separately from refresh() + LLSD statsMap(loadStatsMap()); - avail_physical_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger(); - avail_virtual_mem_kb = (U32Kilobytes)statsMap["Avail Virtual KB"].asInteger(); + avail_physical_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger(); + avail_virtual_mem_kb = (U32Kilobytes)statsMap["Avail Virtual KB"].asInteger(); #elif LL_DARWIN - // mStatsMap is derived from vm_stat, look for (e.g.) "kb free": - // $ vm_stat - // Mach Virtual Memory Statistics: (page size of 4096 bytes) - // Pages free: 462078. - // Pages active: 142010. - // Pages inactive: 220007. - // Pages wired down: 159552. - // "Translation faults": 220825184. - // Pages copy-on-write: 2104153. - // Pages zero filled: 167034876. - // Pages reactivated: 65153. - // Pageins: 2097212. - // Pageouts: 41759. - // Object cache: 841598 hits of 7629869 lookups (11% hit rate) - avail_physical_mem_kb = (U32Kilobytes)-1 ; - avail_virtual_mem_kb = (U32Kilobytes)-1 ; + // mStatsMap is derived from vm_stat, look for (e.g.) "kb free": + // $ vm_stat + // Mach Virtual Memory Statistics: (page size of 4096 bytes) + // Pages free: 462078. + // Pages active: 142010. + // Pages inactive: 220007. + // Pages wired down: 159552. + // "Translation faults": 220825184. + // Pages copy-on-write: 2104153. + // Pages zero filled: 167034876. + // Pages reactivated: 65153. + // Pageins: 2097212. + // Pageouts: 41759. + // Object cache: 841598 hits of 7629869 lookups (11% hit rate) + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #elif LL_LINUX - // mStatsMap is derived from MEMINFO_FILE: - // $ cat /proc/meminfo - // MemTotal: 4108424 kB - // MemFree: 1244064 kB - // Buffers: 85164 kB - // Cached: 1990264 kB - // SwapCached: 0 kB - // Active: 1176648 kB - // Inactive: 1427532 kB - // Active(anon): 529152 kB - // Inactive(anon): 15924 kB - // Active(file): 647496 kB - // Inactive(file): 1411608 kB - // Unevictable: 16 kB - // Mlocked: 16 kB - // HighTotal: 3266316 kB - // HighFree: 721308 kB - // LowTotal: 842108 kB - // LowFree: 522756 kB - // SwapTotal: 6384632 kB - // SwapFree: 6384632 kB - // Dirty: 28 kB - // Writeback: 0 kB - // AnonPages: 528820 kB - // Mapped: 89472 kB - // Shmem: 16324 kB - // Slab: 159624 kB - // SReclaimable: 145168 kB - // SUnreclaim: 14456 kB - // KernelStack: 2560 kB - // PageTables: 5560 kB - // NFS_Unstable: 0 kB - // Bounce: 0 kB - // WritebackTmp: 0 kB - // CommitLimit: 8438844 kB - // Committed_AS: 1271596 kB - // VmallocTotal: 122880 kB - // VmallocUsed: 65252 kB - // VmallocChunk: 52356 kB - // HardwareCorrupted: 0 kB - // HugePages_Total: 0 - // HugePages_Free: 0 - // HugePages_Rsvd: 0 - // HugePages_Surp: 0 - // Hugepagesize: 2048 kB - // DirectMap4k: 434168 kB - // DirectMap2M: 477184 kB - // (could also run 'free', but easier to read a file than run a program) - avail_physical_mem_kb = (U32Kilobytes)-1 ; - avail_virtual_mem_kb = (U32Kilobytes)-1 ; + // mStatsMap is derived from MEMINFO_FILE: + // $ cat /proc/meminfo + // MemTotal: 4108424 kB + // MemFree: 1244064 kB + // Buffers: 85164 kB + // Cached: 1990264 kB + // SwapCached: 0 kB + // Active: 1176648 kB + // Inactive: 1427532 kB + // Active(anon): 529152 kB + // Inactive(anon): 15924 kB + // Active(file): 647496 kB + // Inactive(file): 1411608 kB + // Unevictable: 16 kB + // Mlocked: 16 kB + // HighTotal: 3266316 kB + // HighFree: 721308 kB + // LowTotal: 842108 kB + // LowFree: 522756 kB + // SwapTotal: 6384632 kB + // SwapFree: 6384632 kB + // Dirty: 28 kB + // Writeback: 0 kB + // AnonPages: 528820 kB + // Mapped: 89472 kB + // Shmem: 16324 kB + // Slab: 159624 kB + // SReclaimable: 145168 kB + // SUnreclaim: 14456 kB + // KernelStack: 2560 kB + // PageTables: 5560 kB + // NFS_Unstable: 0 kB + // Bounce: 0 kB + // WritebackTmp: 0 kB + // CommitLimit: 8438844 kB + // Committed_AS: 1271596 kB + // VmallocTotal: 122880 kB + // VmallocUsed: 65252 kB + // VmallocChunk: 52356 kB + // HardwareCorrupted: 0 kB + // HugePages_Total: 0 + // HugePages_Free: 0 + // HugePages_Rsvd: 0 + // HugePages_Surp: 0 + // Hugepagesize: 2048 kB + // DirectMap4k: 434168 kB + // DirectMap2M: 477184 kB + // (could also run 'free', but easier to read a file than run a program) + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #else - //do not know how to collect available memory info for other systems. - //leave it blank here for now. + //do not know how to collect available memory info for other systems. + //leave it blank here for now. - avail_physical_mem_kb = (U32Kilobytes)-1 ; - avail_virtual_mem_kb = (U32Kilobytes)-1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #endif } void LLMemoryInfo::stream(std::ostream& s) const { - // We want these memory stats to be easy to grep from the log, along with - // the timestamp. So preface each line with the timestamp and a - // distinctive marker. Without that, we'd have to search the log for the - // introducer line, then read subsequent lines, etc... - std::string pfx(LLError::utcTime() + " <mem> "); - - // Max key length - size_t key_width(0); - for (const auto& [key, value] : inMap(mStatsMap)) - { - size_t len(key.length()); - if (len > key_width) - { - key_width = len; - } - } - - // Now stream stats - for (const auto& [key, value] : inMap(mStatsMap)) - { - s << pfx << std::setw(narrow<size_t>(key_width+1)) << (key + ':') << ' '; - if (value.isInteger()) - s << std::setw(12) << value.asInteger(); - else if (value.isReal()) - s << std::fixed << std::setprecision(1) << value.asReal(); - else if (value.isDate()) - value.asDate().toStream(s); - else - s << value; // just use default LLSD formatting - s << std::endl; - } + // We want these memory stats to be easy to grep from the log, along with + // the timestamp. So preface each line with the timestamp and a + // distinctive marker. Without that, we'd have to search the log for the + // introducer line, then read subsequent lines, etc... + std::string pfx(LLError::utcTime() + " <mem> "); + + // Max key length + size_t key_width(0); + for (const auto& [key, value] : inMap(mStatsMap)) + { + size_t len(key.length()); + if (len > key_width) + { + key_width = len; + } + } + + // Now stream stats + for (const auto& [key, value] : inMap(mStatsMap)) + { + s << pfx << std::setw(narrow<size_t>(key_width+1)) << (key + ':') << ' '; + if (value.isInteger()) + s << std::setw(12) << value.asInteger(); + else if (value.isReal()) + s << std::fixed << std::setprecision(1) << value.asReal(); + else if (value.isDate()) + value.asDate().toStream(s); + else + s << value; // just use default LLSD formatting + s << std::endl; + } } LLSD LLMemoryInfo::getStatsMap() const { - return mStatsMap; + return mStatsMap; } LLMemoryInfo& LLMemoryInfo::refresh() { - LL_PROFILE_ZONE_SCOPED - mStatsMap = loadStatsMap(); + LL_PROFILE_ZONE_SCOPED + mStatsMap = loadStatsMap(); - LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; - LLSDSerialize::toPrettyXML(mStatsMap, LL_CONT); - LL_ENDL; + LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; + LLSDSerialize::toPrettyXML(mStatsMap, LL_CONT); + LL_ENDL; - return *this; + return *this; } LLSD LLMemoryInfo::loadStatsMap() { LL_PROFILE_ZONE_SCOPED; - // This implementation is derived from stream() code (as of 2011-06-29). - Stats stats; + // This implementation is derived from stream() code (as of 2011-06-29). + Stats stats; - // associate timestamp for analysis over time - stats.add("timestamp", LLDate::now()); + // associate timestamp for analysis over time + stats.add("timestamp", LLDate::now()); #if LL_WINDOWS - MEMORYSTATUSEX state; - state.dwLength = sizeof(state); - GlobalMemoryStatusEx(&state); - - DWORDLONG div = 1024; - - stats.add("Percent Memory use", state.dwMemoryLoad/div); - stats.add("Total Physical KB", state.ullTotalPhys/div); - stats.add("Avail Physical KB", state.ullAvailPhys/div); - stats.add("Total page KB", state.ullTotalPageFile/div); - stats.add("Avail page KB", state.ullAvailPageFile/div); - stats.add("Total Virtual KB", state.ullTotalVirtual/div); - stats.add("Avail Virtual KB", state.ullAvailVirtual/div); - - // SL-12122 - Call to GetPerformanceInfo() was removed here. Took - // on order of 10 ms, causing unacceptable frame time spike every - // second, and results were never used. If this is needed in the - // future, must find a way to avoid frame time impact (e.g. move - // to another thread, call much less often). - - PROCESS_MEMORY_COUNTERS_EX pmem; - pmem.cb = sizeof(pmem); - // GetProcessMemoryInfo() is documented to accept either - // PROCESS_MEMORY_COUNTERS* or PROCESS_MEMORY_COUNTERS_EX*, presumably - // using the redundant size info to distinguish. But its prototype - // specifically accepts PROCESS_MEMORY_COUNTERS*, and since this is a - // classic-C API, PROCESS_MEMORY_COUNTERS_EX isn't a subclass. Cast the - // pointer. - GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem)); - - stats.add("Page Fault Count", pmem.PageFaultCount); - stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); - stats.add("WorkingSetSize KB", pmem.WorkingSetSize/div); - stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/div); - stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/div); - stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); - stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/div); - stats.add("PagefileUsage KB", pmem.PagefileUsage/div); - stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/div); - stats.add("PrivateUsage KB", pmem.PrivateUsage/div); + MEMORYSTATUSEX state; + state.dwLength = sizeof(state); + GlobalMemoryStatusEx(&state); + + DWORDLONG div = 1024; + + stats.add("Percent Memory use", state.dwMemoryLoad/div); + stats.add("Total Physical KB", state.ullTotalPhys/div); + stats.add("Avail Physical KB", state.ullAvailPhys/div); + stats.add("Total page KB", state.ullTotalPageFile/div); + stats.add("Avail page KB", state.ullAvailPageFile/div); + stats.add("Total Virtual KB", state.ullTotalVirtual/div); + stats.add("Avail Virtual KB", state.ullAvailVirtual/div); + + // SL-12122 - Call to GetPerformanceInfo() was removed here. Took + // on order of 10 ms, causing unacceptable frame time spike every + // second, and results were never used. If this is needed in the + // future, must find a way to avoid frame time impact (e.g. move + // to another thread, call much less often). + + PROCESS_MEMORY_COUNTERS_EX pmem; + pmem.cb = sizeof(pmem); + // GetProcessMemoryInfo() is documented to accept either + // PROCESS_MEMORY_COUNTERS* or PROCESS_MEMORY_COUNTERS_EX*, presumably + // using the redundant size info to distinguish. But its prototype + // specifically accepts PROCESS_MEMORY_COUNTERS*, and since this is a + // classic-C API, PROCESS_MEMORY_COUNTERS_EX isn't a subclass. Cast the + // pointer. + GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem)); + + stats.add("Page Fault Count", pmem.PageFaultCount); + stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); + stats.add("WorkingSetSize KB", pmem.WorkingSetSize/div); + stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/div); + stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/div); + stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); + stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/div); + stats.add("PagefileUsage KB", pmem.PagefileUsage/div); + stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/div); + stats.add("PrivateUsage KB", pmem.PrivateUsage/div); #elif LL_DARWIN - const vm_size_t pagekb(vm_page_size / 1024); - - // - // Collect the vm_stat's - // - - { - vm_statistics64_data_t vmstat; - mach_msg_type_number_t vmstatCount = HOST_VM_INFO64_COUNT; - - if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) &vmstat, &vmstatCount) != KERN_SUCCESS) - { - LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; - } - else - { - stats.add("Pages free KB", pagekb * vmstat.free_count); - stats.add("Pages active KB", pagekb * vmstat.active_count); - stats.add("Pages inactive KB", pagekb * vmstat.inactive_count); - stats.add("Pages wired KB", pagekb * vmstat.wire_count); - - stats.add("Pages zero fill", vmstat.zero_fill_count); - stats.add("Page reactivations", vmstat.reactivations); - stats.add("Page-ins", vmstat.pageins); - stats.add("Page-outs", vmstat.pageouts); - - stats.add("Faults", vmstat.faults); - stats.add("Faults copy-on-write", vmstat.cow_faults); - - stats.add("Cache lookups", vmstat.lookups); - stats.add("Cache hits", vmstat.hits); - - stats.add("Page purgeable count", vmstat.purgeable_count); - stats.add("Page purges", vmstat.purges); - - stats.add("Page speculative reads", vmstat.speculative_count); - } - } - - // - // Collect the misc task info - // - - { - task_events_info_data_t taskinfo; - unsigned taskinfoSize = sizeof(taskinfo); - - if (task_info(mach_task_self(), TASK_EVENTS_INFO, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) - { - LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; - } - else - { - stats.add("Task page-ins", taskinfo.pageins); - stats.add("Task copy-on-write faults", taskinfo.cow_faults); - stats.add("Task messages sent", taskinfo.messages_sent); - stats.add("Task messages received", taskinfo.messages_received); - stats.add("Task mach system call count", taskinfo.syscalls_mach); - stats.add("Task unix system call count", taskinfo.syscalls_unix); - stats.add("Task context switch count", taskinfo.csw); - } - } - - // - // Collect the basic task info - // - - { - mach_task_basic_info_data_t taskinfo; - mach_msg_type_number_t task_count = MACH_TASK_BASIC_INFO_COUNT; - if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t) &taskinfo, &task_count) != KERN_SUCCESS) - { - LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; - } - else - { - stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024); - stats.add("Basic resident memory KB", taskinfo.resident_size / 1024); - stats.add("Basic max resident memory KB", taskinfo.resident_size_max / 1024); - stats.add("Basic new thread policy", taskinfo.policy); - stats.add("Basic suspend count", taskinfo.suspend_count); - } - } + const vm_size_t pagekb(vm_page_size / 1024); + + // + // Collect the vm_stat's + // + + { + vm_statistics64_data_t vmstat; + mach_msg_type_number_t vmstatCount = HOST_VM_INFO64_COUNT; + + if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) &vmstat, &vmstatCount) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; + } + else + { + stats.add("Pages free KB", pagekb * vmstat.free_count); + stats.add("Pages active KB", pagekb * vmstat.active_count); + stats.add("Pages inactive KB", pagekb * vmstat.inactive_count); + stats.add("Pages wired KB", pagekb * vmstat.wire_count); + + stats.add("Pages zero fill", vmstat.zero_fill_count); + stats.add("Page reactivations", vmstat.reactivations); + stats.add("Page-ins", vmstat.pageins); + stats.add("Page-outs", vmstat.pageouts); + + stats.add("Faults", vmstat.faults); + stats.add("Faults copy-on-write", vmstat.cow_faults); + + stats.add("Cache lookups", vmstat.lookups); + stats.add("Cache hits", vmstat.hits); + + stats.add("Page purgeable count", vmstat.purgeable_count); + stats.add("Page purges", vmstat.purges); + + stats.add("Page speculative reads", vmstat.speculative_count); + } + } + + // + // Collect the misc task info + // + + { + task_events_info_data_t taskinfo; + unsigned taskinfoSize = sizeof(taskinfo); + + if (task_info(mach_task_self(), TASK_EVENTS_INFO, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; + } + else + { + stats.add("Task page-ins", taskinfo.pageins); + stats.add("Task copy-on-write faults", taskinfo.cow_faults); + stats.add("Task messages sent", taskinfo.messages_sent); + stats.add("Task messages received", taskinfo.messages_received); + stats.add("Task mach system call count", taskinfo.syscalls_mach); + stats.add("Task unix system call count", taskinfo.syscalls_unix); + stats.add("Task context switch count", taskinfo.csw); + } + } + + // + // Collect the basic task info + // + + { + mach_task_basic_info_data_t taskinfo; + mach_msg_type_number_t task_count = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t) &taskinfo, &task_count) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; + } + else + { + stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024); + stats.add("Basic resident memory KB", taskinfo.resident_size / 1024); + stats.add("Basic max resident memory KB", taskinfo.resident_size_max / 1024); + stats.add("Basic new thread policy", taskinfo.policy); + stats.add("Basic suspend count", taskinfo.suspend_count); + } + } #elif LL_LINUX - std::ifstream meminfo(MEMINFO_FILE); - if (meminfo.is_open()) - { - // MemTotal: 4108424 kB - // MemFree: 1244064 kB - // Buffers: 85164 kB - // Cached: 1990264 kB - // SwapCached: 0 kB - // Active: 1176648 kB - // Inactive: 1427532 kB - // ... - // VmallocTotal: 122880 kB - // VmallocUsed: 65252 kB - // VmallocChunk: 52356 kB - // HardwareCorrupted: 0 kB - // HugePages_Total: 0 - // HugePages_Free: 0 - // HugePages_Rsvd: 0 - // HugePages_Surp: 0 - // Hugepagesize: 2048 kB - // DirectMap4k: 434168 kB - // DirectMap2M: 477184 kB - - // Intentionally don't pass the boost::no_except flag. This - // boost::regex object is constructed with a string literal, so it - // should be valid every time. If it becomes invalid, we WANT an - // exception, hopefully even before the dev checks in. - boost::regex stat_rx("(.+): +([0-9]+)( kB)?"); - boost::smatch matched; - - std::string line; - while (std::getline(meminfo, line)) - { - LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL; - if (ll_regex_match(line, matched, stat_rx)) - { - // e.g. "MemTotal: 4108424 kB" - LLSD::String key(matched[1].first, matched[1].second); - LLSD::String value_str(matched[2].first, matched[2].second); - LLSD::Integer value(0); - try - { - value = boost::lexical_cast<LLSD::Integer>(value_str); - } - catch (const boost::bad_lexical_cast&) - { - LL_WARNS("LLMemoryInfo") << "couldn't parse '" << value_str - << "' in " << MEMINFO_FILE << " line: " - << line << LL_ENDL; - continue; - } - // Store this statistic. - stats.add(key, value); - } - else - { - LL_WARNS("LLMemoryInfo") << "unrecognized " << MEMINFO_FILE << " line: " - << line << LL_ENDL; - } - } - } - else - { - LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; - } + std::ifstream meminfo(MEMINFO_FILE); + if (meminfo.is_open()) + { + // MemTotal: 4108424 kB + // MemFree: 1244064 kB + // Buffers: 85164 kB + // Cached: 1990264 kB + // SwapCached: 0 kB + // Active: 1176648 kB + // Inactive: 1427532 kB + // ... + // VmallocTotal: 122880 kB + // VmallocUsed: 65252 kB + // VmallocChunk: 52356 kB + // HardwareCorrupted: 0 kB + // HugePages_Total: 0 + // HugePages_Free: 0 + // HugePages_Rsvd: 0 + // HugePages_Surp: 0 + // Hugepagesize: 2048 kB + // DirectMap4k: 434168 kB + // DirectMap2M: 477184 kB + + // Intentionally don't pass the boost::no_except flag. This + // boost::regex object is constructed with a string literal, so it + // should be valid every time. If it becomes invalid, we WANT an + // exception, hopefully even before the dev checks in. + boost::regex stat_rx("(.+): +([0-9]+)( kB)?"); + boost::smatch matched; + + std::string line; + while (std::getline(meminfo, line)) + { + LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL; + if (ll_regex_match(line, matched, stat_rx)) + { + // e.g. "MemTotal: 4108424 kB" + LLSD::String key(matched[1].first, matched[1].second); + LLSD::String value_str(matched[2].first, matched[2].second); + LLSD::Integer value(0); + try + { + value = boost::lexical_cast<LLSD::Integer>(value_str); + } + catch (const boost::bad_lexical_cast&) + { + LL_WARNS("LLMemoryInfo") << "couldn't parse '" << value_str + << "' in " << MEMINFO_FILE << " line: " + << line << LL_ENDL; + continue; + } + // Store this statistic. + stats.add(key, value); + } + else + { + LL_WARNS("LLMemoryInfo") << "unrecognized " << MEMINFO_FILE << " line: " + << line << LL_ENDL; + } + } + } + else + { + LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; + } #else - LL_WARNS("LLMemoryInfo") << "Unknown system; unable to collect memory information" << LL_ENDL; + LL_WARNS("LLMemoryInfo") << "Unknown system; unable to collect memory information" << LL_ENDL; #endif - return stats.get(); + return stats.get(); } std::ostream& operator<<(std::ostream& s, const LLOSInfo& info) { - info.stream(s); - return s; + info.stream(s); + return s; } std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info) { - info.stream(s); - return s; + info.stream(s); + return s; } std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info) { - info.stream(s); - return s; + info.stream(s); + return s; } class FrameWatcher @@ -1286,13 +1286,13 @@ public: << " seconds "; } - auto precision = LL_CONT.precision(); + auto precision = LL_CONT.precision(); LL_CONT << std::fixed << std::setprecision(1) << framerate << '\n' << LLMemoryInfo(); - LL_CONT.precision(precision); - LL_CONT << LL_ENDL; + LL_CONT.precision(precision); + LL_CONT << LL_ENDL; return false; } @@ -1321,53 +1321,57 @@ static FrameWatcher sFrameWatcher; BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) { - std::string tmpfile; - const S32 UNCOMPRESS_BUFFER_SIZE = 32768; - BOOL retval = FALSE; - gzFile src = NULL; - U8 buffer[UNCOMPRESS_BUFFER_SIZE]; - LLFILE *dst = NULL; - S32 bytes = 0; - tmpfile = dstfile + ".t"; + std::string tmpfile; + const S32 UNCOMPRESS_BUFFER_SIZE = 32768; + BOOL retval = FALSE; + gzFile src = NULL; + U8 buffer[UNCOMPRESS_BUFFER_SIZE]; + LLFILE *dst = NULL; + S32 bytes = 0; + tmpfile = dstfile + ".t"; #ifdef LL_WINDOWS llutf16string utf16filename = utf8str_to_utf16str(srcfile); src = gzopen_w(utf16filename.c_str(), "rb"); #else src = gzopen(srcfile.c_str(), "rb"); #endif - if (! src) goto err; - dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ - if (! dst) goto err; - do - { - bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE); - size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst); - if (nwrit < (size_t) bytes) - { - LL_WARNS() << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << LL_ENDL; - goto err; - } - } while(gzeof(src) == 0); - fclose(dst); - dst = NULL; - if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ - retval = TRUE; + if (! src) goto err; + dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ + if (! dst) goto err; + do + { + bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE); + size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst); + if (nwrit < (size_t) bytes) + { + LL_WARNS() << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << LL_ENDL; + goto err; + } + } while(gzeof(src) == 0); + fclose(dst); + dst = NULL; +#if LL_WINDOWS + // Rename in windows needs the dstfile to not exist. + LLFile::remove(dstfile, ENOENT); +#endif + if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ + retval = TRUE; err: - if (src != NULL) gzclose(src); - if (dst != NULL) fclose(dst); - return retval; + if (src != NULL) gzclose(src); + if (dst != NULL) fclose(dst); + return retval; } BOOL gzip_file(const std::string& srcfile, const std::string& dstfile) { - const S32 COMPRESS_BUFFER_SIZE = 32768; - std::string tmpfile; - BOOL retval = FALSE; - U8 buffer[COMPRESS_BUFFER_SIZE]; - gzFile dst = NULL; - LLFILE *src = NULL; - S32 bytes = 0; - tmpfile = dstfile + ".t"; + const S32 COMPRESS_BUFFER_SIZE = 32768; + std::string tmpfile; + BOOL retval = FALSE; + U8 buffer[COMPRESS_BUFFER_SIZE]; + gzFile dst = NULL; + LLFILE *src = NULL; + S32 bytes = 0; + tmpfile = dstfile + ".t"; #ifdef LL_WINDOWS llutf16string utf16filename = utf8str_to_utf16str(tmpfile); @@ -1376,35 +1380,35 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile) dst = gzopen(tmpfile.c_str(), "wb"); #endif - if (! dst) goto err; - src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ - if (! src) goto err; - - while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) - { - if (gzwrite(dst, buffer, bytes) <= 0) - { - LL_WARNS() << "gzwrite failed: " << gzerror(dst, NULL) << LL_ENDL; - goto err; - } - } - - if (ferror(src)) - { - LL_WARNS() << "Error reading " << srcfile << LL_ENDL; - goto err; - } - - gzclose(dst); - dst = NULL; + if (! dst) goto err; + src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ + if (! src) goto err; + + while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) + { + if (gzwrite(dst, buffer, bytes) <= 0) + { + LL_WARNS() << "gzwrite failed: " << gzerror(dst, NULL) << LL_ENDL; + goto err; + } + } + + if (ferror(src)) + { + LL_WARNS() << "Error reading " << srcfile << LL_ENDL; + goto err; + } + + gzclose(dst); + dst = NULL; #if LL_WINDOWS - // Rename in windows needs the dstfile to not exist. - LLFile::remove(dstfile); + // Rename in windows needs the dstfile to not exist. + LLFile::remove(dstfile); #endif - if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ - retval = TRUE; + if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ + retval = TRUE; err: - if (src != NULL) fclose(src); - if (dst != NULL) gzclose(dst); - return retval; + if (src != NULL) fclose(src); + if (dst != NULL) gzclose(dst); + return retval; } diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index 08d4abffa2..5c87ce6bf2 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -1,25 +1,25 @@ -/** +/** * @file llsys.h * @brief System information debugging classes. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,120 +43,120 @@ class LL_COMMON_API LLOSInfo : public LLSingleton<LLOSInfo> { - LLSINGLETON(LLOSInfo); + LLSINGLETON(LLOSInfo); public: - void stream(std::ostream& s) const; + void stream(std::ostream& s) const; + + const std::string& getOSString() const; + const std::string& getOSStringSimple() const; - const std::string& getOSString() const; - const std::string& getOSStringSimple() const; + const std::string& getOSVersionString() const; - const std::string& getOSVersionString() const; + const S32 getOSBitness() const; - const S32 getOSBitness() const; - - S32 mMajorVer; - S32 mMinorVer; - S32 mBuild; + S32 mMajorVer; + S32 mMinorVer; + S32 mBuild; #ifndef LL_WINDOWS - static long getMaxOpenFiles(); + static long getMaxOpenFiles(); #endif - static bool is64Bit(); + static bool is64Bit(); - static U32 getProcessVirtualSizeKB(); - static U32 getProcessResidentSizeKB(); + static U32 getProcessVirtualSizeKB(); + static U32 getProcessResidentSizeKB(); private: - std::string mOSString; - std::string mOSStringSimple; - std::string mOSVersionString; - S32 mOSBitness; + std::string mOSString; + std::string mOSStringSimple; + std::string mOSVersionString; + S32 mOSBitness; }; class LL_COMMON_API LLCPUInfo { public: - LLCPUInfo(); - void stream(std::ostream& s) const; + LLCPUInfo(); + void stream(std::ostream& s) const; - std::string getCPUString() const; - const LLSD& getSSEVersions() const; + std::string getCPUString() const; + const LLSD& getSSEVersions() const; - bool hasAltivec() const; - bool hasSSE() const; - bool hasSSE2() const; + bool hasAltivec() const; + bool hasSSE() const; + bool hasSSE2() const; bool hasSSE3() const; bool hasSSE3S() const; bool hasSSE41() const; bool hasSSE42() const; bool hasSSE4a() const; - F64 getMHz() const; + F64 getMHz() const; - // Family is "AMD Duron" or "Intel Pentium Pro" - const std::string& getFamily() const { return mFamily; } + // Family is "AMD Duron" or "Intel Pentium Pro" + const std::string& getFamily() const { return mFamily; } private: - bool mHasSSE; - bool mHasSSE2; + bool mHasSSE; + bool mHasSSE2; bool mHasSSE3; bool mHasSSE3S; bool mHasSSE41; bool mHasSSE42; bool mHasSSE4a; - bool mHasAltivec; - F64 mCPUMHz; - std::string mFamily; - std::string mCPUString; + bool mHasAltivec; + F64 mCPUMHz; + std::string mFamily; + std::string mCPUString; LLSD mSSEVersions; }; //============================================================================= // -// CLASS LLMemoryInfo +// CLASS LLMemoryInfo class LL_COMMON_API LLMemoryInfo -/*! @brief Class to query the memory subsystem +/*! @brief Class to query the memory subsystem + + @details + Here's how you use an LLMemoryInfo: - @details - Here's how you use an LLMemoryInfo: - - LLMemoryInfo info; -<br> LL_INFOS() << info << LL_ENDL; + LLMemoryInfo info; +<br> LL_INFOS() << info << LL_ENDL; */ { public: - LLMemoryInfo(); ///< Default constructor - void stream(std::ostream& s) const; ///< output text info to s + LLMemoryInfo(); ///< Default constructor + void stream(std::ostream& s) const; ///< output text info to s - U32Kilobytes getPhysicalMemoryKB() const; + U32Kilobytes getPhysicalMemoryKB() const; #if LL_DARWIN static U32Kilobytes getHardwareMemSize(); // Because some Mac linkers won't let us reference extern gSysMemory from a different lib. #endif - //get the available memory infomation in KiloBytes. - static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb); + //get the available memory infomation in KiloBytes. + static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb); - // Retrieve a map of memory statistics. The keys of the map are platform- - // dependent. The values are in kilobytes to try to avoid integer overflow. - LLSD getStatsMap() const; + // Retrieve a map of memory statistics. The keys of the map are platform- + // dependent. The values are in kilobytes to try to avoid integer overflow. + LLSD getStatsMap() const; - // Re-fetch memory data (as reported by stream() and getStatsMap()) from the - // system. Normally this is fetched at construction time. Return (*this) - // to permit usage of the form: - // @code - // LLMemoryInfo info; - // ... - // info.refresh().getStatsMap(); - // @endcode - LLMemoryInfo& refresh(); + // Re-fetch memory data (as reported by stream() and getStatsMap()) from the + // system. Normally this is fetched at construction time. Return (*this) + // to permit usage of the form: + // @code + // LLMemoryInfo info; + // ... + // info.refresh().getStatsMap(); + // @endcode + LLMemoryInfo& refresh(); private: - // set mStatsMap - static LLSD loadStatsMap(); + // set mStatsMap + static LLSD loadStatsMap(); - // Memory stats for getStatsMap(). - LLSD mStatsMap; + // Memory stats for getStatsMap(). + LLSD mStatsMap; }; diff --git a/indra/llcommon/lltempredirect.cpp b/indra/llcommon/lltempredirect.cpp index ec194c1d29..ee7923e8ca 100644 --- a/indra/llcommon/lltempredirect.cpp +++ b/indra/llcommon/lltempredirect.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-10-31 * @brief Implementation for lltempredirect. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/lltempredirect.h b/indra/llcommon/lltempredirect.h index 33e05dc06b..0ab3575d30 100644 --- a/indra/llcommon/lltempredirect.h +++ b/indra/llcommon/lltempredirect.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-10-31 * @brief RAII low-level file-descriptor redirection - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index cd4975d9d3..e6b0c03371 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010-2013, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -91,7 +91,7 @@ void set_thread_name( DWORD dwThreadID, const char* threadName) // break; // } // } -// +// //---------------------------------------------------------------------------- namespace { @@ -155,7 +155,7 @@ void LLThread::threadRun() mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder()); // Run the user supplied function - do + do { try { @@ -258,7 +258,7 @@ void LLThread::shutdown() // This thread just wouldn't stop, even though we gave it time //LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL; // Put a stake in its heart. (A very hostile method to force a thread to quit) -#if LL_WINDOWS +#if LL_WINDOWS TerminateThread(mNativeHandle, 0); #else pthread_cancel(mNativeHandle); @@ -291,7 +291,7 @@ void LLThread::shutdown() void LLThread::start() { llassert(isStopped()); - + // Set thread state to running mStatus = RUNNING; @@ -319,7 +319,7 @@ void LLThread::pause() { // this will cause the thread to stop execution as soon as checkPause() is called mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread - } + } } void LLThread::unpause() @@ -355,7 +355,7 @@ void LLThread::checkPause() mDataLock->lock(); // mRunCondition is locked when the thread wakes up } - + mDataLock->unlock(); } @@ -441,7 +441,7 @@ void LLThreadSafeRefCount::cleanupThreadSafeRefCount() delete sMutex; sMutex = NULL; } - + //---------------------------------------------------------------------------- @@ -456,10 +456,10 @@ LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src) } LLThreadSafeRefCount::~LLThreadSafeRefCount() -{ +{ if (mRef != 0) { - LL_ERRS() << "deleting referenced object mRef = " << mRef << LL_ENDL; + LL_ERRS() << "deleting referenced object mRef = " << mRef << LL_ENDL; } } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 9f1c589fcd..e21e6265ea 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -1,25 +1,25 @@ -/** +/** * @file llthread.h * @brief Base classes for thread, mutex and condition handling. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010-2013, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -55,21 +55,21 @@ public: LLThread(const std::string& name, apr_pool_t *poolp = NULL); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. virtual void shutdown(); // stops the thread - + bool isQuitting() const { return (QUITTING == mStatus); } bool isStopped() const { return (STOPPED == mStatus) || (CRASHED == mStatus); } - bool isCrashed() const { return (CRASHED == mStatus); } - + bool isCrashed() const { return (CRASHED == mStatus); } + static id_t currentID(); // Return ID of current thread static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. - + public: // PAUSE / RESUME functionality. See source code for important usage notes. // Called from MAIN THREAD. void pause(); void unpause(); bool isPaused() { return isStopped() || mPaused == TRUE; } - + // Cause the thread to wake up and check its condition void wake(); @@ -90,11 +90,11 @@ public: // internal state used by LLMutex. You must call this once early // in the running thread to prevent collisions with the main thread. static void registerThreadID(); - + private: bool mPaused; std::thread::native_handle_type mNativeHandle; // for termination in case of issues - + // static function passed to APR thread creation routine void threadRun(); @@ -111,21 +111,21 @@ protected: //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. // otherwise it will cause severe memory leaking!!! --bao - LLVolatileAPRPool *mLocalAPRFilePoolp ; + LLVolatileAPRPool *mLocalAPRFilePoolp ; void setQuitting(); - + // virtual function overridden by subclass -- this will be called when the thread runs - virtual void run(void) = 0; - + virtual void run(void) = 0; + // virtual predicate function -- returns true if the thread should wake up, false if it should sleep. virtual bool runCondition(void); // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition() void lockData(); void unlockData(); - - // This is the predicate that decides whether the thread should sleep. + + // This is the predicate that decides whether the thread should sleep. // It should only be called with mDataLock locked, since the virtual runCondition() function may need to access // data structures that are thread-unsafe. bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); } diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h index bdd28ec865..151d8a666b 100644 --- a/indra/llcommon/llthreadlocalstorage.h +++ b/indra/llcommon/llthreadlocalstorage.h @@ -1,4 +1,4 @@ -/** +/** * @file llthreadlocalstorage.h * @author Richard * @brief Class wrappers for thread local storage @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,18 +34,18 @@ template<typename DERIVED_TYPE> class LLThreadLocalSingletonPointer { public: - LL_FORCE_INLINE static DERIVED_TYPE* getInstance() - { - return sInstance; - } + LL_FORCE_INLINE static DERIVED_TYPE* getInstance() + { + return sInstance; + } - static void setInstance(DERIVED_TYPE* instance) - { - sInstance = instance; - } + static void setInstance(DERIVED_TYPE* instance) + { + sInstance = instance; + } private: - static thread_local DERIVED_TYPE* sInstance; + static thread_local DERIVED_TYPE* sInstance; }; template<typename DERIVED_TYPE> diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index bde36999ba..03baca2f0a 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index f396a71e6f..034e3f7897 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -1,25 +1,25 @@ -/** +/** * @file llthreadsafequeue.h * @brief Queue protected with mutexes for cross-thread use * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,14 +44,14 @@ // A general queue exception. // class LL_COMMON_API LLThreadSafeQueueError: - public LLException + public LLException { public: - LLThreadSafeQueueError(std::string const & message): - LLException(message) - { - ; // No op. - } + LLThreadSafeQueueError(std::string const & message): + LLException(message) + { + ; // No op. + } }; @@ -59,14 +59,14 @@ public: // An exception raised when blocking operations are interrupted. // class LL_COMMON_API LLThreadSafeQueueInterrupt: - public LLThreadSafeQueueError + public LLThreadSafeQueueError { public: - LLThreadSafeQueueInterrupt(void): - LLThreadSafeQueueError("queue operation interrupted") - { - ; // No op. - } + LLThreadSafeQueueInterrupt(void): + LLThreadSafeQueueError("queue operation interrupted") + { + ; // No op. + } }; /** @@ -78,138 +78,138 @@ template<typename ElementT, typename QueueT=std::queue<ElementT>> class LLThreadSafeQueue { public: - typedef ElementT value_type; - - // Limiting the number of pending items prevents unbounded growth of the - // underlying queue. - LLThreadSafeQueue(size_t capacity = 1024); - virtual ~LLThreadSafeQueue() {} - - // Add an element to the queue (will block if the queue has reached - // capacity). - // - // This call will raise an interrupt error if the queue is closed while - // the caller is blocked. - template <typename T> - void push(T&& element); - // legacy name - void pushFront(ElementT const & element) { return push(element); } - - // Add an element to the queue (will block if the queue has reached - // capacity). Return false if the queue is closed before push is possible. - template <typename T> - bool pushIfOpen(T&& element); - - // Try to add an element to the queue without blocking. Returns - // true only if the element was actually added. - template <typename T> - bool tryPush(T&& element); - // legacy name - bool tryPushFront(ElementT const & element) { return tryPush(element); } - - // Try to add an element to the queue, blocking if full but with timeout - // after specified duration. Returns true if the element was added. - // There are potentially two different timeouts involved: how long to try - // to lock the mutex, versus how long to wait for the queue to stop being - // full. Careful settings for each timeout might be orders of magnitude - // apart. However, this method conflates them. - template <typename Rep, typename Period, typename T> - bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout, - T&& element); - // legacy name - template <typename Rep, typename Period> - bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout, - ElementT const & element) { return tryPushFor(timeout, element); } - - // Try to add an element to the queue, blocking if full but with - // timeout at specified time_point. Returns true if the element was added. - template <typename Clock, typename Duration, typename T> - bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until, - T&& element); - // no legacy name because this is a newer method - - // Pop the element at the head of the queue (will block if the queue is - // empty). - // - // This call will raise an interrupt error if the queue is closed while - // the caller is blocked. - ElementT pop(void); - // legacy name - ElementT popBack(void) { return pop(); } - - // Pop an element from the head of the queue if there is one available. - // Returns true only if an element was popped. - bool tryPop(ElementT & element); - // legacy name - bool tryPopBack(ElementT & element) { return tryPop(element); } - - // Pop the element at the head of the queue, blocking if empty, with - // timeout after specified duration. Returns true if an element was popped. - template <typename Rep, typename Period> - bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, ElementT& element); - // no legacy name because this is a newer method - - // Pop the element at the head of the queue, blocking if empty, with - // timeout at specified time_point. Returns true if an element was popped. - template <typename Clock, typename Duration> - bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until, - ElementT& element); - // no legacy name because this is a newer method - - // Returns the size of the queue. - size_t size(); + typedef ElementT value_type; + + // Limiting the number of pending items prevents unbounded growth of the + // underlying queue. + LLThreadSafeQueue(size_t capacity = 1024); + virtual ~LLThreadSafeQueue() {} + + // Add an element to the queue (will block if the queue has reached + // capacity). + // + // This call will raise an interrupt error if the queue is closed while + // the caller is blocked. + template <typename T> + void push(T&& element); + // legacy name + void pushFront(ElementT const & element) { return push(element); } + + // Add an element to the queue (will block if the queue has reached + // capacity). Return false if the queue is closed before push is possible. + template <typename T> + bool pushIfOpen(T&& element); + + // Try to add an element to the queue without blocking. Returns + // true only if the element was actually added. + template <typename T> + bool tryPush(T&& element); + // legacy name + bool tryPushFront(ElementT const & element) { return tryPush(element); } + + // Try to add an element to the queue, blocking if full but with timeout + // after specified duration. Returns true if the element was added. + // There are potentially two different timeouts involved: how long to try + // to lock the mutex, versus how long to wait for the queue to stop being + // full. Careful settings for each timeout might be orders of magnitude + // apart. However, this method conflates them. + template <typename Rep, typename Period, typename T> + bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout, + T&& element); + // legacy name + template <typename Rep, typename Period> + bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout, + ElementT const & element) { return tryPushFor(timeout, element); } + + // Try to add an element to the queue, blocking if full but with + // timeout at specified time_point. Returns true if the element was added. + template <typename Clock, typename Duration, typename T> + bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until, + T&& element); + // no legacy name because this is a newer method + + // Pop the element at the head of the queue (will block if the queue is + // empty). + // + // This call will raise an interrupt error if the queue is closed while + // the caller is blocked. + ElementT pop(void); + // legacy name + ElementT popBack(void) { return pop(); } + + // Pop an element from the head of the queue if there is one available. + // Returns true only if an element was popped. + bool tryPop(ElementT & element); + // legacy name + bool tryPopBack(ElementT & element) { return tryPop(element); } + + // Pop the element at the head of the queue, blocking if empty, with + // timeout after specified duration. Returns true if an element was popped. + template <typename Rep, typename Period> + bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, ElementT& element); + // no legacy name because this is a newer method + + // Pop the element at the head of the queue, blocking if empty, with + // timeout at specified time_point. Returns true if an element was popped. + template <typename Clock, typename Duration> + bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until, + ElementT& element); + // no legacy name because this is a newer method + + // Returns the size of the queue. + size_t size(); //Returns the capacity of the queue. U32 capacity() { return mCapacity; } - // closes the queue: - // - every subsequent push() call will throw LLThreadSafeQueueInterrupt - // - every subsequent tryPush() call will return false - // - pop() calls will return normally until the queue is drained, then - // every subsequent pop() will throw LLThreadSafeQueueInterrupt - // - tryPop() calls will return normally until the queue is drained, - // then every subsequent tryPop() call will return false - void close(); + // closes the queue: + // - every subsequent push() call will throw LLThreadSafeQueueInterrupt + // - every subsequent tryPush() call will return false + // - pop() calls will return normally until the queue is drained, then + // every subsequent pop() will throw LLThreadSafeQueueInterrupt + // - tryPop() calls will return normally until the queue is drained, + // then every subsequent tryPop() call will return false + void close(); - // producer end: are we prevented from pushing any additional items? - bool isClosed(); - // consumer end: are we done, is the queue entirely drained? - bool done(); + // producer end: are we prevented from pushing any additional items? + bool isClosed(); + // consumer end: are we done, is the queue entirely drained? + bool done(); protected: - typedef QueueT queue_type; - QueueT mStorage; - size_t mCapacity; - bool mClosed; - - boost::fibers::timed_mutex mLock; - typedef std::unique_lock<decltype(mLock)> lock_t; - boost::fibers::condition_variable_any mCapacityCond; - boost::fibers::condition_variable_any mEmptyCond; - - enum pop_result { EMPTY, DONE, WAITING, POPPED }; - // implementation logic, suitable for passing to tryLockUntil() - template <typename Clock, typename Duration> - pop_result tryPopUntil_(lock_t& lock, - const std::chrono::time_point<Clock, Duration>& until, - ElementT& element); - // if we're able to lock immediately, do so and run the passed callable, - // which must accept lock_t& and return bool - template <typename CALLABLE> - bool tryLock(CALLABLE&& callable); - // if we're able to lock before the passed time_point, do so and run the - // passed callable, which must accept lock_t& and return bool - template <typename Clock, typename Duration, typename CALLABLE> - bool tryLockUntil(const std::chrono::time_point<Clock, Duration>& until, - CALLABLE&& callable); - // while lock is locked, really push the passed element, if we can - template <typename T> - bool push_(lock_t& lock, T&& element); - // while lock is locked, really pop the head element, if we can - pop_result pop_(lock_t& lock, ElementT& element); - // Is the current head element ready to pop? We say yes; subclass can - // override as needed. - virtual bool canPop(const ElementT& head) const { return true; } + typedef QueueT queue_type; + QueueT mStorage; + size_t mCapacity; + bool mClosed; + + boost::fibers::timed_mutex mLock; + typedef std::unique_lock<decltype(mLock)> lock_t; + boost::fibers::condition_variable_any mCapacityCond; + boost::fibers::condition_variable_any mEmptyCond; + + enum pop_result { EMPTY, DONE, WAITING, POPPED }; + // implementation logic, suitable for passing to tryLockUntil() + template <typename Clock, typename Duration> + pop_result tryPopUntil_(lock_t& lock, + const std::chrono::time_point<Clock, Duration>& until, + ElementT& element); + // if we're able to lock immediately, do so and run the passed callable, + // which must accept lock_t& and return bool + template <typename CALLABLE> + bool tryLock(CALLABLE&& callable); + // if we're able to lock before the passed time_point, do so and run the + // passed callable, which must accept lock_t& and return bool + template <typename Clock, typename Duration, typename CALLABLE> + bool tryLockUntil(const std::chrono::time_point<Clock, Duration>& until, + CALLABLE&& callable); + // while lock is locked, really push the passed element, if we can + template <typename T> + bool push_(lock_t& lock, T&& element); + // while lock is locked, really pop the head element, if we can + pop_result pop_(lock_t& lock, ElementT& element); + // Is the current head element ready to pop? We say yes; subclass can + // override as needed. + virtual bool canPop(const ElementT& head) const { return true; } }; /***************************************************************************** @@ -426,7 +426,7 @@ LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element) if (mStorage.empty()) return mClosed? DONE : EMPTY; - // If there's a head element, pass it to canPop() to see if it's ready to pop. + // If there's a head element, pass it to canPop() to see if it's ready to pop. if (! canPop(mStorage.front())) return WAITING; diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 1a99ac2886..6f74bf3fc8 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltimer.cpp - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,12 +34,12 @@ #include <thread> #if LL_WINDOWS -# include "llwin32headerslean.h" +# include "llwin32headerslean.h" #elif LL_LINUX || LL_DARWIN # include <errno.h> -# include <sys/time.h> -#else -# error "architecture not supported" +# include <sys/time.h> +#else +# error "architecture not supported" #endif // @@ -83,7 +83,7 @@ U32 micro_sleep(U64 us, U32 max_yields) { // max_yields is unused; just fiddle with it to avoid warnings. max_yields = 0; - ms_sleep((U32)(us / 1000)); + ms_sleep((U32)(us / 1000)); return 0; } @@ -118,43 +118,43 @@ void ms_sleep(U32 ms) #elif LL_LINUX || LL_DARWIN static void _sleep_loop(struct timespec& thiswait) { - struct timespec nextwait; - bool sleep_more = false; - - do { - int result = nanosleep(&thiswait, &nextwait); - - // check if sleep was interrupted by a signal; unslept - // remainder was written back into 't' and we just nanosleep - // again. - sleep_more = (result == -1 && EINTR == errno); - - if (sleep_more) - { - if ( nextwait.tv_sec > thiswait.tv_sec || - (nextwait.tv_sec == thiswait.tv_sec && - nextwait.tv_nsec >= thiswait.tv_nsec) ) - { - // if the remaining time isn't actually going - // down then we're being shafted by low clock - // resolution - manually massage the sleep time - // downward. - if (nextwait.tv_nsec > 1000000) { - // lose 1ms - nextwait.tv_nsec -= 1000000; - } else { - if (nextwait.tv_sec == 0) { - // already so close to finished - sleep_more = false; - } else { - // lose up to 1ms - nextwait.tv_nsec = 0; - } - } - } - thiswait = nextwait; - } - } while (sleep_more); + struct timespec nextwait; + bool sleep_more = false; + + do { + int result = nanosleep(&thiswait, &nextwait); + + // check if sleep was interrupted by a signal; unslept + // remainder was written back into 't' and we just nanosleep + // again. + sleep_more = (result == -1 && EINTR == errno); + + if (sleep_more) + { + if ( nextwait.tv_sec > thiswait.tv_sec || + (nextwait.tv_sec == thiswait.tv_sec && + nextwait.tv_nsec >= thiswait.tv_nsec) ) + { + // if the remaining time isn't actually going + // down then we're being shafted by low clock + // resolution - manually massage the sleep time + // downward. + if (nextwait.tv_nsec > 1000000) { + // lose 1ms + nextwait.tv_nsec -= 1000000; + } else { + if (nextwait.tv_sec == 0) { + // already so close to finished + sleep_more = false; + } else { + // lose up to 1ms + nextwait.tv_nsec = 0; + } + } + } + thiswait = nextwait; + } + } while (sleep_more); } U32 micro_sleep(U64 us, U32 max_yields) @@ -193,10 +193,10 @@ U32 micro_sleep(U64 us, U32 max_yields) void ms_sleep(U32 ms) { - long mslong = ms; // tv_nsec is a long - struct timespec thiswait; - thiswait.tv_sec = ms / 1000; - thiswait.tv_nsec = (mslong % 1000) * 1000000l; + long mslong = ms; // tv_nsec is a long + struct timespec thiswait; + thiswait.tv_sec = ms / 1000; + thiswait.tv_nsec = (mslong % 1000) * 1000000l; _sleep_loop(thiswait); } #else @@ -210,25 +210,25 @@ void ms_sleep(U32 ms) #if LL_WINDOWS U64 get_clock_count() { - static bool firstTime = true; - static U64 offset; - // ensures that callers to this function never have to deal with wrap + static bool firstTime = true; + static U64 offset; + // ensures that callers to this function never have to deal with wrap - // QueryPerformanceCounter implementation - LARGE_INTEGER clock_count; - QueryPerformanceCounter(&clock_count); - if (firstTime) { - offset = clock_count.QuadPart; - firstTime = false; - } - return clock_count.QuadPart - offset; + // QueryPerformanceCounter implementation + LARGE_INTEGER clock_count; + QueryPerformanceCounter(&clock_count); + if (firstTime) { + offset = clock_count.QuadPart; + firstTime = false; + } + return clock_count.QuadPart - offset; } F64 calc_clock_frequency() { - __int64 freq; - QueryPerformanceFrequency((LARGE_INTEGER *) &freq); - return (F64)freq; + __int64 freq; + QueryPerformanceFrequency((LARGE_INTEGER *) &freq); + return (F64)freq; } #endif // LL_WINDOWS @@ -237,81 +237,81 @@ F64 calc_clock_frequency() // Both Linux and Mac use gettimeofday for accurate time F64 calc_clock_frequency() { - return 1000000.0; // microseconds, so 1 MHz. + return 1000000.0; // microseconds, so 1 MHz. } U64 get_clock_count() { - // Linux clocks are in microseconds - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec*SEC_TO_MICROSEC_U64 + tv.tv_usec; + // Linux clocks are in microseconds + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*SEC_TO_MICROSEC_U64 + tv.tv_usec; } #endif TimerInfo::TimerInfo() -: mClockFrequency(0.0), - mTotalTimeClockCount(0), - mLastTotalTimeClockCount(0) +: mClockFrequency(0.0), + mTotalTimeClockCount(0), + mLastTotalTimeClockCount(0) {} void TimerInfo::update() { - mClockFrequency = calc_clock_frequency(); - mClockFrequencyInv = 1.0/mClockFrequency; - mClocksToMicroseconds = mClockFrequencyInv; + mClockFrequency = calc_clock_frequency(); + mClockFrequencyInv = 1.0/mClockFrequency; + mClocksToMicroseconds = mClockFrequencyInv; } TimerInfo& get_timer_info() { - static TimerInfo sTimerInfo; - return sTimerInfo; + static TimerInfo sTimerInfo; + return sTimerInfo; } /////////////////////////////////////////////////////////////////////////////// -// returns a U64 number that represents the number of +// returns a U64 number that represents the number of // microseconds since the Unix epoch - Jan 1, 1970 U64MicrosecondsImplicit totalTime() { - U64 current_clock_count = get_clock_count(); - if (!get_timer_info().mTotalTimeClockCount || get_timer_info().mClocksToMicroseconds.value() == 0) - { - get_timer_info().update(); - get_timer_info().mTotalTimeClockCount = current_clock_count; + U64 current_clock_count = get_clock_count(); + if (!get_timer_info().mTotalTimeClockCount || get_timer_info().mClocksToMicroseconds.value() == 0) + { + get_timer_info().update(); + get_timer_info().mTotalTimeClockCount = current_clock_count; #if LL_WINDOWS - // Sync us up with local time (even though we PROBABLY don't need to, this is how it was implemented) - // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to - // make in the future. + // Sync us up with local time (even though we PROBABLY don't need to, this is how it was implemented) + // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to + // make in the future. - get_timer_info().mTotalTimeClockCount = (U64)(time(NULL) * get_timer_info().mClockFrequency); + get_timer_info().mTotalTimeClockCount = (U64)(time(NULL) * get_timer_info().mClockFrequency); #endif - // Update the last clock count - get_timer_info().mLastTotalTimeClockCount = current_clock_count; - } - else - { - if (current_clock_count >= get_timer_info().mLastTotalTimeClockCount) - { - // No wrapping, we're all okay. - get_timer_info().mTotalTimeClockCount += current_clock_count - get_timer_info().mLastTotalTimeClockCount; - } - else - { - // We've wrapped. Compensate correctly - get_timer_info().mTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - get_timer_info().mLastTotalTimeClockCount) + current_clock_count; - } - - // Update the last clock count - get_timer_info().mLastTotalTimeClockCount = current_clock_count; - } + // Update the last clock count + get_timer_info().mLastTotalTimeClockCount = current_clock_count; + } + else + { + if (current_clock_count >= get_timer_info().mLastTotalTimeClockCount) + { + // No wrapping, we're all okay. + get_timer_info().mTotalTimeClockCount += current_clock_count - get_timer_info().mLastTotalTimeClockCount; + } + else + { + // We've wrapped. Compensate correctly + get_timer_info().mTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - get_timer_info().mLastTotalTimeClockCount) + current_clock_count; + } + + // Update the last clock count + get_timer_info().mLastTotalTimeClockCount = current_clock_count; + } - // Return the total clock tick count in microseconds. - U64Microseconds time(get_timer_info().mTotalTimeClockCount*get_timer_info().mClocksToMicroseconds); - return time; + // Return the total clock tick count in microseconds. + U64Microseconds time(get_timer_info().mTotalTimeClockCount*get_timer_info().mClocksToMicroseconds); + return time; } @@ -319,13 +319,13 @@ U64MicrosecondsImplicit totalTime() LLTimer::LLTimer() { - if (!get_timer_info().mClockFrequency) - { - get_timer_info().update(); - } + if (!get_timer_info().mClockFrequency) + { + get_timer_info().update(); + } - mStarted = TRUE; - reset(); + mStarted = TRUE; + reset(); } LLTimer::~LLTimer() @@ -334,47 +334,47 @@ LLTimer::~LLTimer() // static void LLTimer::initClass() { - if (!sTimer) sTimer = new LLTimer; + if (!sTimer) sTimer = new LLTimer; } // static void LLTimer::cleanupClass() { - delete sTimer; sTimer = NULL; + delete sTimer; sTimer = NULL; } // static U64MicrosecondsImplicit LLTimer::getTotalTime() { - // simply call into the implementation function. - U64MicrosecondsImplicit total_time = totalTime(); - return total_time; -} + // simply call into the implementation function. + U64MicrosecondsImplicit total_time = totalTime(); + return total_time; +} // static F64SecondsImplicit LLTimer::getTotalSeconds() { - return F64Microseconds(U64_to_F64(getTotalTime())); + return F64Microseconds(U64_to_F64(getTotalTime())); } void LLTimer::reset() { - mLastClockCount = get_clock_count(); - mExpirationTicks = 0; + mLastClockCount = get_clock_count(); + mExpirationTicks = 0; } /////////////////////////////////////////////////////////////////////////////// U64 LLTimer::getCurrentClockCount() { - return get_clock_count(); + return get_clock_count(); } /////////////////////////////////////////////////////////////////////////////// void LLTimer::setLastClockCount(U64 current_count) { - mLastClockCount = current_count; + mLastClockCount = current_count; } /////////////////////////////////////////////////////////////////////////////// @@ -382,152 +382,152 @@ void LLTimer::setLastClockCount(U64 current_count) static U64 getElapsedTimeAndUpdate(U64& lastClockCount) { - U64 current_clock_count = get_clock_count(); - U64 result; + U64 current_clock_count = get_clock_count(); + U64 result; - if (current_clock_count >= lastClockCount) - { - result = current_clock_count - lastClockCount; - } - else - { - // time has gone backward - result = 0; - } + if (current_clock_count >= lastClockCount) + { + result = current_clock_count - lastClockCount; + } + else + { + // time has gone backward + result = 0; + } - lastClockCount = current_clock_count; + lastClockCount = current_clock_count; - return result; + return result; } F64SecondsImplicit LLTimer::getElapsedTimeF64() const { - U64 last = mLastClockCount; - return (F64)getElapsedTimeAndUpdate(last) * get_timer_info().mClockFrequencyInv; + U64 last = mLastClockCount; + return (F64)getElapsedTimeAndUpdate(last) * get_timer_info().mClockFrequencyInv; } F32SecondsImplicit LLTimer::getElapsedTimeF32() const { - return (F32)getElapsedTimeF64(); + return (F32)getElapsedTimeF64(); } F64SecondsImplicit LLTimer::getElapsedTimeAndResetF64() { - return (F64)getElapsedTimeAndUpdate(mLastClockCount) * get_timer_info().mClockFrequencyInv; + return (F64)getElapsedTimeAndUpdate(mLastClockCount) * get_timer_info().mClockFrequencyInv; } F32SecondsImplicit LLTimer::getElapsedTimeAndResetF32() { - return (F32)getElapsedTimeAndResetF64(); + return (F32)getElapsedTimeAndResetF64(); } /////////////////////////////////////////////////////////////////////////////// void LLTimer::setTimerExpirySec(F32SecondsImplicit expiration) { - mExpirationTicks = get_clock_count() - + (U64)((F32)(expiration * get_timer_info().mClockFrequency.value())); + mExpirationTicks = get_clock_count() + + (U64)((F32)(expiration * get_timer_info().mClockFrequency.value())); } F32SecondsImplicit LLTimer::getRemainingTimeF32() const { - U64 cur_ticks = get_clock_count(); - if (cur_ticks > mExpirationTicks) - { - return 0.0f; - } - return F32((mExpirationTicks - cur_ticks) * get_timer_info().mClockFrequencyInv); + U64 cur_ticks = get_clock_count(); + if (cur_ticks > mExpirationTicks) + { + return 0.0f; + } + return F32((mExpirationTicks - cur_ticks) * get_timer_info().mClockFrequencyInv); } BOOL LLTimer::checkExpirationAndReset(F32 expiration) { - U64 cur_ticks = get_clock_count(); - if (cur_ticks < mExpirationTicks) - { - return FALSE; - } + U64 cur_ticks = get_clock_count(); + if (cur_ticks < mExpirationTicks) + { + return FALSE; + } - mExpirationTicks = cur_ticks - + (U64)((F32)(expiration * get_timer_info().mClockFrequency)); - return TRUE; + mExpirationTicks = cur_ticks + + (U64)((F32)(expiration * get_timer_info().mClockFrequency)); + return TRUE; } BOOL LLTimer::hasExpired() const { - return (get_clock_count() >= mExpirationTicks) - ? TRUE : FALSE; + return (get_clock_count() >= mExpirationTicks) + ? TRUE : FALSE; } /////////////////////////////////////////////////////////////////////////////// BOOL LLTimer::knownBadTimer() { - BOOL failed = FALSE; + BOOL failed = FALSE; #if LL_WINDOWS - WCHAR bad_pci_list[][10] = {L"1039:0530", - L"1039:0620", - L"10B9:0533", - L"10B9:1533", - L"1106:0596", - L"1106:0686", - L"1166:004F", - L"1166:0050", - L"8086:7110", - L"\0" - }; - - HKEY hKey = NULL; - LONG nResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Enum\\PCI", 0, - KEY_EXECUTE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey); - - WCHAR name[1024]; - DWORD name_len = 1024; - FILETIME scrap; - - S32 key_num = 0; - WCHAR pci_id[10]; - - wcscpy(pci_id, L"0000:0000"); /*Flawfinder: ignore*/ - - while (nResult == ERROR_SUCCESS) - { - nResult = ::RegEnumKeyEx(hKey, key_num++, name, &name_len, NULL, NULL, NULL, &scrap); - - if (nResult == ERROR_SUCCESS) - { - memcpy(&pci_id[0],&name[4],4); /* Flawfinder: ignore */ - memcpy(&pci_id[5],&name[13],4); /* Flawfinder: ignore */ - - for (S32 check = 0; bad_pci_list[check][0]; check++) - { - if (!wcscmp(pci_id, bad_pci_list[check])) - { -// LL_WARNS() << "unreliable PCI chipset found!! " << pci_id << endl; - failed = TRUE; - break; - } - } -// llinfo << "PCI chipset found: " << pci_id << endl; - name_len = 1024; - } - } + WCHAR bad_pci_list[][10] = {L"1039:0530", + L"1039:0620", + L"10B9:0533", + L"10B9:1533", + L"1106:0596", + L"1106:0686", + L"1166:004F", + L"1166:0050", + L"8086:7110", + L"\0" + }; + + HKEY hKey = NULL; + LONG nResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Enum\\PCI", 0, + KEY_EXECUTE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey); + + WCHAR name[1024]; + DWORD name_len = 1024; + FILETIME scrap; + + S32 key_num = 0; + WCHAR pci_id[10]; + + wcscpy(pci_id, L"0000:0000"); /*Flawfinder: ignore*/ + + while (nResult == ERROR_SUCCESS) + { + nResult = ::RegEnumKeyEx(hKey, key_num++, name, &name_len, NULL, NULL, NULL, &scrap); + + if (nResult == ERROR_SUCCESS) + { + memcpy(&pci_id[0],&name[4],4); /* Flawfinder: ignore */ + memcpy(&pci_id[5],&name[13],4); /* Flawfinder: ignore */ + + for (S32 check = 0; bad_pci_list[check][0]; check++) + { + if (!wcscmp(pci_id, bad_pci_list[check])) + { +// LL_WARNS() << "unreliable PCI chipset found!! " << pci_id << endl; + failed = TRUE; + break; + } + } +// llinfo << "PCI chipset found: " << pci_id << endl; + name_len = 1024; + } + } #endif - return(failed); + return(failed); } /////////////////////////////////////////////////////////////////////////////// -// +// // NON-MEMBER FUNCTIONS // /////////////////////////////////////////////////////////////////////////////// time_t time_corrected() { - return time(NULL) + gUTCOffset; + return time(NULL) + gUTCOffset; } @@ -535,75 +535,75 @@ time_t time_corrected() // observing daylight savings time? BOOL is_daylight_savings() { - time_t now = time(NULL); + time_t now = time(NULL); - // Internal buffer to local server time - struct tm* internal_time = localtime(&now); + // Internal buffer to local server time + struct tm* internal_time = localtime(&now); - // tm_isdst > 0 => daylight savings - // tm_isdst = 0 => not daylight savings - // tm_isdst < 0 => can't tell - return (internal_time->tm_isdst > 0); + // tm_isdst > 0 => daylight savings + // tm_isdst = 0 => not daylight savings + // tm_isdst < 0 => can't tell + return (internal_time->tm_isdst > 0); } struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) { - S32Hours pacific_offset_hours; - if (pacific_daylight_time) - { - pacific_offset_hours = S32Hours(7); - } - else - { - pacific_offset_hours = S32Hours(8); - } + S32Hours pacific_offset_hours; + if (pacific_daylight_time) + { + pacific_offset_hours = S32Hours(7); + } + else + { + pacific_offset_hours = S32Hours(8); + } + + // We subtract off the PST/PDT offset _before_ getting + // "UTC" time, because this will handle wrapping around + // for 5 AM UTC -> 10 PM PDT of the previous day. + utc_time -= S32SecondsImplicit(pacific_offset_hours); - // We subtract off the PST/PDT offset _before_ getting - // "UTC" time, because this will handle wrapping around - // for 5 AM UTC -> 10 PM PDT of the previous day. - utc_time -= S32SecondsImplicit(pacific_offset_hours); - - // Internal buffer to PST/PDT (see above) - struct tm* internal_time = gmtime(&utc_time); + // Internal buffer to PST/PDT (see above) + struct tm* internal_time = gmtime(&utc_time); - /* - // Don't do this, this won't correctly tell you if daylight savings is active in CA or not. - if (pacific_daylight_time) - { - internal_time->tm_isdst = 1; - } - */ + /* + // Don't do this, this won't correctly tell you if daylight savings is active in CA or not. + if (pacific_daylight_time) + { + internal_time->tm_isdst = 1; + } + */ - return internal_time; + return internal_time; } void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring) { - U64 hours; - U64 minutes; - U64 seconds; - U64 frames; - U64 subframes; + U64 hours; + U64 minutes; + U64 seconds; + U64 frames; + U64 subframes; - hours = current_time / (U64)3600000000ul; - minutes = current_time / (U64)60000000; - minutes %= 60; - seconds = current_time / (U64)1000000; - seconds %= 60; - frames = current_time / (U64)41667; - frames %= 24; - subframes = current_time / (U64)42; - subframes %= 100; + hours = current_time / (U64)3600000000ul; + minutes = current_time / (U64)60000000; + minutes %= 60; + seconds = current_time / (U64)1000000; + seconds %= 60; + frames = current_time / (U64)41667; + frames %= 24; + subframes = current_time / (U64)42; + subframes %= 100; - tcstring = llformat("%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); + tcstring = llformat("%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); } void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring) { - microsecondsToTimecodeString(current_time, tcstring); + microsecondsToTimecodeString(current_time, tcstring); } diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 010f290b24..fe4a3afc7a 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -1,30 +1,30 @@ -/** +/** * @file lltimer.h - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_TIMER_H +#ifndef LL_TIMER_H #define LL_TIMER_H #if LL_LINUX || LL_DARWIN @@ -39,76 +39,76 @@ // units conversions #include "llunits.h" #ifndef USEC_PER_SEC - const U32 USEC_PER_SEC = 1000000; + const U32 USEC_PER_SEC = 1000000; #endif -const U32 SEC_PER_MIN = 60; -const U32 MIN_PER_HOUR = 60; -const U32 USEC_PER_MIN = USEC_PER_SEC * SEC_PER_MIN; -const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR; -const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR; -const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC; - -class LL_COMMON_API LLTimer +const U32 SEC_PER_MIN = 60; +const U32 MIN_PER_HOUR = 60; +const U32 USEC_PER_MIN = USEC_PER_SEC * SEC_PER_MIN; +const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR; +const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR; +const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC; + +class LL_COMMON_API LLTimer { public: - static LLTimer *sTimer; // global timer - -protected: - U64 mLastClockCount; - U64 mExpirationTicks; - bool mStarted; + static LLTimer *sTimer; // global timer + +protected: + U64 mLastClockCount; + U64 mExpirationTicks; + bool mStarted; public: - LLTimer(); - ~LLTimer(); + LLTimer(); + ~LLTimer(); - static void initClass(); - static void cleanupClass(); + static void initClass(); + static void cleanupClass(); - // Return a high precision number of seconds since the start of - // this application instance. - static F64SecondsImplicit getElapsedSeconds() - { - if (sTimer) - { - return sTimer->getElapsedTimeF64(); - } - else - { - return 0; - } - } + // Return a high precision number of seconds since the start of + // this application instance. + static F64SecondsImplicit getElapsedSeconds() + { + if (sTimer) + { + return sTimer->getElapsedTimeF64(); + } + else + { + return 0; + } + } - // Return a high precision usec since epoch - static U64MicrosecondsImplicit getTotalTime(); + // Return a high precision usec since epoch + static U64MicrosecondsImplicit getTotalTime(); - // Return a high precision seconds since epoch - static F64SecondsImplicit getTotalSeconds(); + // Return a high precision seconds since epoch + static F64SecondsImplicit getTotalSeconds(); - // MANIPULATORS - void start() { reset(); mStarted = TRUE; } - void stop() { mStarted = FALSE; } - void reset(); // Resets the timer - void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time - void setTimerExpirySec(F32SecondsImplicit expiration); - BOOL checkExpirationAndReset(F32 expiration); - BOOL hasExpired() const; - F32SecondsImplicit getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset - F64SecondsImplicit getElapsedTimeAndResetF64(); + // MANIPULATORS + void start() { reset(); mStarted = TRUE; } + void stop() { mStarted = FALSE; } + void reset(); // Resets the timer + void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time + void setTimerExpirySec(F32SecondsImplicit expiration); + BOOL checkExpirationAndReset(F32 expiration); + BOOL hasExpired() const; + F32SecondsImplicit getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset + F64SecondsImplicit getElapsedTimeAndResetF64(); - F32SecondsImplicit getRemainingTimeF32() const; + F32SecondsImplicit getRemainingTimeF32() const; - static BOOL knownBadTimer(); + static BOOL knownBadTimer(); - // ACCESSORS - F32SecondsImplicit getElapsedTimeF32() const; // Returns elapsed time in seconds - F64SecondsImplicit getElapsedTimeF64() const; // Returns elapsed time in seconds + // ACCESSORS + F32SecondsImplicit getElapsedTimeF32() const; // Returns elapsed time in seconds + F64SecondsImplicit getElapsedTimeF64() const; // Returns elapsed time in seconds - bool getStarted() const { return mStarted; } + bool getStarted() const { return mStarted; } - static U64 getCurrentClockCount(); // Returns the raw clockticks + static U64 getCurrentClockCount(); // Returns the raw clockticks }; // @@ -116,14 +116,14 @@ public: // struct TimerInfo { - TimerInfo(); - void update(); - - F64HertzImplicit mClockFrequency; - F64SecondsImplicit mClockFrequencyInv; - F64MicrosecondsImplicit mClocksToMicroseconds; - U64 mTotalTimeClockCount; - U64 mLastTotalTimeClockCount; + TimerInfo(); + void update(); + + F64HertzImplicit mClockFrequency; + F64SecondsImplicit mClockFrequencyInv; + F64MicrosecondsImplicit mClocksToMicroseconds; + U64 mTotalTimeClockCount; + U64 mLastTotalTimeClockCount; }; TimerInfo& get_timer_info(); @@ -140,30 +140,30 @@ LL_COMMON_API time_t time_corrected(); static inline time_t time_min() { - if (sizeof(time_t) == 4) - { - return (time_t) INT_MIN; - } else { + if (sizeof(time_t) == 4) + { + return (time_t) INT_MIN; + } else { #ifdef LLONG_MIN - return (time_t) LLONG_MIN; + return (time_t) LLONG_MIN; #else - return (time_t) LONG_MIN; + return (time_t) LONG_MIN; #endif - } + } } static inline time_t time_max() { - if (sizeof(time_t) == 4) - { - return (time_t) INT_MAX; - } else { + if (sizeof(time_t) == 4) + { + return (time_t) INT_MAX; + } else { #ifdef LLONG_MAX - return (time_t) LLONG_MAX; + return (time_t) LLONG_MAX; #else - return (time_t) LONG_MAX; + return (time_t) LONG_MAX; #endif - } + } } // Correction factor used by time_corrected() above. @@ -183,6 +183,6 @@ LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_dayli LL_COMMON_API void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring); LL_COMMON_API void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring); -U64MicrosecondsImplicit LL_COMMON_API totalTime(); // Returns current system time in microseconds +U64MicrosecondsImplicit LL_COMMON_API totalTime(); // Returns current system time in microseconds #endif diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index 87457ad907..440529b8e8 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltrace.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,53 +33,53 @@ namespace LLTrace { -StatBase::StatBase( const char* name, const char* description ) -: mName(name), - mDescription(description ? description : "") +StatBase::StatBase( const char* name, const char* description ) +: mName(name), + mDescription(description ? description : "") { #ifndef LL_RELEASE_FOR_DOWNLOAD - if (LLTrace::get_thread_recorder() != NULL) - { - LL_ERRS() << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << LL_ENDL; - } + if (LLTrace::get_thread_recorder() != NULL) + { + LL_ERRS() << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << LL_ENDL; + } #endif } const char* StatBase::getUnitLabel() const { - return ""; + return ""; } -TimeBlockTreeNode::TimeBlockTreeNode() -: mBlock(NULL), - mParent(NULL), - mNeedsSorting(false), - mCollapsed(true) +TimeBlockTreeNode::TimeBlockTreeNode() +: mBlock(NULL), + mParent(NULL), + mNeedsSorting(false), + mCollapsed(true) {} void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent ) { LL_PROFILE_ZONE_SCOPED; - llassert_always(parent != mBlock); - llassert_always(parent != NULL); + llassert_always(parent != mBlock); + llassert_always(parent != NULL); - TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow<size_t>(parent->getIndex())); - if (!parent_tree_node) return; + TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow<size_t>(parent->getIndex())); + if (!parent_tree_node) return; - if (mParent) - { - std::vector<BlockTimerStatHandle*>& children = mParent->getChildren(); - std::vector<BlockTimerStatHandle*>::iterator found_it = std::find(children.begin(), children.end(), mBlock); - if (found_it != children.end()) - { - children.erase(found_it); - } - } + if (mParent) + { + std::vector<BlockTimerStatHandle*>& children = mParent->getChildren(); + std::vector<BlockTimerStatHandle*>::iterator found_it = std::find(children.begin(), children.end(), mBlock); + if (found_it != children.end()) + { + children.erase(found_it); + } + } - mParent = parent; - mBlock->getCurrentAccumulator().mParent = parent; - parent_tree_node->mChildren.push_back(mBlock); - parent_tree_node->mNeedsSorting = true; + mParent = parent; + mBlock->getCurrentAccumulator().mParent = parent; + parent_tree_node->mChildren.push_back(mBlock); + parent_tree_node->mNeedsSorting = true; } } diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 21a5803a76..edb010b0a4 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -1,25 +1,25 @@ -/** +/** * @file lltrace.h * @brief Runtime statistics accumulation. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,90 +47,90 @@ class Recording; template<typename T> T storage_value(T val) { return val; } -template<typename UNIT_TYPE, typename STORAGE_TYPE> +template<typename UNIT_TYPE, typename STORAGE_TYPE> STORAGE_TYPE storage_value(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } -template<typename UNIT_TYPE, typename STORAGE_TYPE> +template<typename UNIT_TYPE, typename STORAGE_TYPE> STORAGE_TYPE storage_value(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } class StatBase { public: - StatBase(const char* name, const char* description); - virtual ~StatBase() {} - virtual const char* getUnitLabel() const; + StatBase(const char* name, const char* description); + virtual ~StatBase() {} + virtual const char* getUnitLabel() const; - const std::string& getName() const { return mName; } - const std::string& getDescription() const { return mDescription; } + const std::string& getName() const { return mName; } + const std::string& getDescription() const { return mDescription; } protected: - std::string mName; - std::string mDescription; + std::string mName; + std::string mDescription; }; template<typename ACCUMULATOR> -class StatType -: public StatBase, - public LLInstanceTracker<StatType<ACCUMULATOR>, std::string> +class StatType +: public StatBase, + public LLInstanceTracker<StatType<ACCUMULATOR>, std::string> { public: - typedef LLInstanceTracker<StatType<ACCUMULATOR>, std::string> instance_tracker_t; - StatType(const char* name, const char* description) - : instance_tracker_t(name), - StatBase(name, description), - mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot()) - {} - - LL_FORCE_INLINE ACCUMULATOR& getCurrentAccumulator() const - { - ACCUMULATOR* accumulator_storage = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance(); - return accumulator_storage ? accumulator_storage[mAccumulatorIndex] : (*AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer())[mAccumulatorIndex]; - } - - size_t getIndex() const { return mAccumulatorIndex; } - static size_t getNumIndices() { return AccumulatorBuffer<ACCUMULATOR>::getNumIndices(); } + typedef LLInstanceTracker<StatType<ACCUMULATOR>, std::string> instance_tracker_t; + StatType(const char* name, const char* description) + : instance_tracker_t(name), + StatBase(name, description), + mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot()) + {} + + LL_FORCE_INLINE ACCUMULATOR& getCurrentAccumulator() const + { + ACCUMULATOR* accumulator_storage = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance(); + return accumulator_storage ? accumulator_storage[mAccumulatorIndex] : (*AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer())[mAccumulatorIndex]; + } + + size_t getIndex() const { return mAccumulatorIndex; } + static size_t getNumIndices() { return AccumulatorBuffer<ACCUMULATOR>::getNumIndices(); } protected: - const size_t mAccumulatorIndex; + const size_t mAccumulatorIndex; }; template<> class StatType<TimeBlockAccumulator::CallCountFacet> -: public StatType<TimeBlockAccumulator> +: public StatType<TimeBlockAccumulator> { public: - StatType(const char* name, const char* description = "") - : StatType<TimeBlockAccumulator>(name, description) - {} + StatType(const char* name, const char* description = "") + : StatType<TimeBlockAccumulator>(name, description) + {} }; template<> class StatType<TimeBlockAccumulator::SelfTimeFacet> - : public StatType<TimeBlockAccumulator> + : public StatType<TimeBlockAccumulator> { public: - StatType(const char* name, const char* description = "") - : StatType<TimeBlockAccumulator>(name, description) - {} + StatType(const char* name, const char* description = "") + : StatType<TimeBlockAccumulator>(name, description) + {} }; template <typename T = F64> class EventStatHandle -: public StatType<EventAccumulator> +: public StatType<EventAccumulator> { public: - typedef F64 storage_t; - typedef StatType<EventAccumulator> stat_t; - typedef EventStatHandle<T> self_t; + typedef F64 storage_t; + typedef StatType<EventAccumulator> stat_t; + typedef EventStatHandle<T> self_t; - EventStatHandle(const char* name, const char* description = NULL) - : stat_t(name, description) - {} + EventStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} - /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } }; @@ -138,58 +138,58 @@ template<typename T, typename VALUE_T> void record(EventStatHandle<T>& measurement, VALUE_T value) { #if LL_TRACE_ENABLED - T converted_value(value); - measurement.getCurrentAccumulator().record(storage_value(converted_value)); + T converted_value(value); + measurement.getCurrentAccumulator().record(storage_value(converted_value)); #endif } template <typename T = F64> class SampleStatHandle -: public StatType<SampleAccumulator> +: public StatType<SampleAccumulator> { public: - typedef F64 storage_t; - typedef StatType<SampleAccumulator> stat_t; - typedef SampleStatHandle<T> self_t; + typedef F64 storage_t; + typedef StatType<SampleAccumulator> stat_t; + typedef SampleStatHandle<T> self_t; - SampleStatHandle(const char* name, const char* description = NULL) - : stat_t(name, description) - {} + SampleStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} - /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } }; template<typename T, typename VALUE_T> void sample(SampleStatHandle<T>& measurement, VALUE_T value) { #if LL_TRACE_ENABLED - T converted_value(value); - measurement.getCurrentAccumulator().sample(storage_value(converted_value)); + T converted_value(value); + measurement.getCurrentAccumulator().sample(storage_value(converted_value)); #endif } template <typename T = F64> class CountStatHandle -: public StatType<CountAccumulator> +: public StatType<CountAccumulator> { public: - typedef F64 storage_t; - typedef StatType<CountAccumulator> stat_t; - typedef CountStatHandle<T> self_t; + typedef F64 storage_t; + typedef StatType<CountAccumulator> stat_t; + typedef CountStatHandle<T> self_t; - CountStatHandle(const char* name, const char* description = NULL) - : stat_t(name, description) - {} + CountStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} - /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } }; template<typename T, typename VALUE_T> void add(CountStatHandle<T>& count, VALUE_T value) { #if LL_TRACE_ENABLED - T converted_value(value); - count.getCurrentAccumulator().add(storage_value(converted_value)); + T converted_value(value); + count.getCurrentAccumulator().add(storage_value(converted_value)); #endif } @@ -198,85 +198,85 @@ void add(CountStatHandle<T>& count, VALUE_T value) template<typename T, typename IS_MEM_TRACKABLE = void, typename IS_UNITS = void> struct MeasureMem { - static size_t measureFootprint(const T& value) - { - return sizeof(T); - } + static size_t measureFootprint(const T& value) + { + return sizeof(T); + } }; template<typename T, typename IS_BYTES> struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES> { - static size_t measureFootprint(const T& value) - { + static size_t measureFootprint(const T& value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return sizeof(T) + value.getMemFootprint(); - } + return sizeof(T) + value.getMemFootprint(); + } }; template<typename T, typename IS_MEM_TRACKABLE> struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t> { - static size_t measureFootprint(const T& value) - { + static size_t measureFootprint(const T& value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return U32Bytes(value).value(); - } + return U32Bytes(value).value(); + } }; template<typename T, typename IS_MEM_TRACKABLE, typename IS_BYTES> struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES> { - static size_t measureFootprint(const T* value) - { + static size_t measureFootprint(const T* value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (!value) - { - return 0; - } - return MeasureMem<T>::measureFootprint(*value); - } + if (!value) + { + return 0; + } + return MeasureMem<T>::measureFootprint(*value); + } }; template<typename T, typename IS_MEM_TRACKABLE, typename IS_BYTES> struct MeasureMem<LLPointer<T>, IS_MEM_TRACKABLE, IS_BYTES> { - static size_t measureFootprint(const LLPointer<T> value) - { - if (value.isNull()) - { - return 0; - } - return MeasureMem<T>::measureFootprint(*value); - } + static size_t measureFootprint(const LLPointer<T> value) + { + if (value.isNull()) + { + return 0; + } + return MeasureMem<T>::measureFootprint(*value); + } }; template<typename IS_MEM_TRACKABLE, typename IS_BYTES> struct MeasureMem<S32, IS_MEM_TRACKABLE, IS_BYTES> { - static size_t measureFootprint(S32 value) - { - return value; - } + static size_t measureFootprint(S32 value) + { + return value; + } }; template<typename IS_MEM_TRACKABLE, typename IS_BYTES> struct MeasureMem<U32, IS_MEM_TRACKABLE, IS_BYTES> { - static size_t measureFootprint(U32 value) - { - return value; - } + static size_t measureFootprint(U32 value) + { + return value; + } }; template<typename T, typename IS_MEM_TRACKABLE, typename IS_BYTES> struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES> { - static size_t measureFootprint(const std::basic_string<T>& value) - { + static size_t measureFootprint(const std::basic_string<T>& value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return value.capacity() * sizeof(T); - } + return value.capacity() * sizeof(T); + } }; } diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index b5b32cba38..8741087f3a 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -38,246 +38,246 @@ namespace LLTrace AccumulatorBufferGroup::AccumulatorBufferGroup() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& other) -: mCounts(other.mCounts), - mSamples(other.mSamples), - mEvents(other.mEvents), - mStackTimers(other.mStackTimers) +: mCounts(other.mCounts), + mSamples(other.mSamples), + mEvents(other.mEvents), + mStackTimers(other.mStackTimers) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } AccumulatorBufferGroup::~AccumulatorBufferGroup() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - other.mCounts.reset(&mCounts); - other.mSamples.reset(&mSamples); - other.mEvents.reset(&mEvents); - other.mStackTimers.reset(&mStackTimers); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + other.mCounts.reset(&mCounts); + other.mSamples.reset(&mSamples); + other.mEvents.reset(&mEvents); + other.mStackTimers.reset(&mStackTimers); } void AccumulatorBufferGroup::makeCurrent() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.makeCurrent(); - mSamples.makeCurrent(); - mEvents.makeCurrent(); - mStackTimers.makeCurrent(); - - ThreadRecorder* thread_recorder = get_thread_recorder(); - AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers; - // update stacktimer parent pointers - for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++) - { - TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow<size_t>(i)); - if (tree_node) - { - timer_accumulator_buffer[i].mParent = tree_node->mParent; - } - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.makeCurrent(); + mSamples.makeCurrent(); + mEvents.makeCurrent(); + mStackTimers.makeCurrent(); + + ThreadRecorder* thread_recorder = get_thread_recorder(); + AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers; + // update stacktimer parent pointers + for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++) + { + TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow<size_t>(i)); + if (tree_node) + { + timer_accumulator_buffer[i].mParent = tree_node->mParent; + } + } } //static void AccumulatorBufferGroup::clearCurrent() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - AccumulatorBuffer<CountAccumulator>::clearCurrent(); - AccumulatorBuffer<SampleAccumulator>::clearCurrent(); - AccumulatorBuffer<EventAccumulator>::clearCurrent(); - AccumulatorBuffer<TimeBlockAccumulator>::clearCurrent(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + AccumulatorBuffer<CountAccumulator>::clearCurrent(); + AccumulatorBuffer<SampleAccumulator>::clearCurrent(); + AccumulatorBuffer<EventAccumulator>::clearCurrent(); + AccumulatorBuffer<TimeBlockAccumulator>::clearCurrent(); } bool AccumulatorBufferGroup::isCurrent() const { - return mCounts.isCurrent(); + return mCounts.isCurrent(); } void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.addSamples(other.mCounts, SEQUENTIAL); - mSamples.addSamples(other.mSamples, SEQUENTIAL); - mEvents.addSamples(other.mEvents, SEQUENTIAL); - mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.addSamples(other.mCounts, SEQUENTIAL); + mSamples.addSamples(other.mSamples, SEQUENTIAL); + mEvents.addSamples(other.mEvents, SEQUENTIAL); + mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL); } void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); - mSamples.addSamples(other.mSamples, NON_SEQUENTIAL); - mEvents.addSamples(other.mEvents, NON_SEQUENTIAL); - // for now, hold out timers from merge, need to be displayed per thread - //mStackTimers.addSamples(other.mStackTimers, NON_SEQUENTIAL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); + mSamples.addSamples(other.mSamples, NON_SEQUENTIAL); + mEvents.addSamples(other.mEvents, NON_SEQUENTIAL); + // for now, hold out timers from merge, need to be displayed per thread + //mStackTimers.addSamples(other.mStackTimers, NON_SEQUENTIAL); } void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.reset(other ? &other->mCounts : NULL); - mSamples.reset(other ? &other->mSamples : NULL); - mEvents.reset(other ? &other->mEvents : NULL); - mStackTimers.reset(other ? &other->mStackTimers : NULL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.reset(other ? &other->mCounts : NULL); + mSamples.reset(other ? &other->mSamples : NULL); + mEvents.reset(other ? &other->mEvents : NULL); + mStackTimers.reset(other ? &other->mStackTimers : NULL); } void AccumulatorBufferGroup::sync() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (isCurrent()) - { - F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); - mSamples.sync(time_stamp); - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (isCurrent()) + { + F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); + mSamples.sync(time_stamp); + } } F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b) { - const F64 epsilon = 0.0000001; - - if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon) - { - // combine variance (and hence standard deviation) of 2 different sized sample groups using - // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm - F64 n_1 = a.getSamplingTime(), - n_2 = b.getSamplingTime(); - F64 m_1 = a.getMean(), - m_2 = b.getMean(); - F64 v_1 = a.getSumOfSquares() / a.getSamplingTime(), - v_2 = b.getSumOfSquares() / b.getSamplingTime(); - if (n_1 < epsilon) - { - return b.getSumOfSquares(); - } - else - { - return a.getSamplingTime() - * ((((n_1 - epsilon) * v_1) - + ((n_2 - epsilon) * v_2) - + (((n_1 * n_2) / (n_1 + n_2)) - * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) - / (n_1 + n_2 - epsilon)); - } - } - - return a.getSumOfSquares(); + const F64 epsilon = 0.0000001; + + if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.getSamplingTime(), + n_2 = b.getSamplingTime(); + F64 m_1 = a.getMean(), + m_2 = b.getMean(); + F64 v_1 = a.getSumOfSquares() / a.getSamplingTime(), + v_2 = b.getSumOfSquares() / b.getSamplingTime(); + if (n_1 < epsilon) + { + return b.getSumOfSquares(); + } + else + { + return a.getSamplingTime() + * ((((n_1 - epsilon) * v_1) + + ((n_2 - epsilon) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - epsilon)); + } + } + + return a.getSumOfSquares(); } void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type ) { - if (append_type == NON_SEQUENTIAL) - { - return; - } - - if (!mHasValue) - { - *this = other; - - if (append_type == NON_SEQUENTIAL) - { - // restore own last value state - mLastValue = NaN; - mHasValue = false; - } - } - else if (other.mHasValue) - { - mSum += other.mSum; - - if (other.mMin < mMin) { mMin = other.mMin; } - if (other.mMax > mMax) { mMax = other.mMax; } - - mSumOfSquares = mergeSumsOfSquares(*this, other); - - if (append_type == SEQUENTIAL) - { - mLastValue = other.mLastValue; - mLastSampleTimeStamp = other.mLastSampleTimeStamp; - } - } + if (append_type == NON_SEQUENTIAL) + { + return; + } + + if (!mHasValue) + { + *this = other; + + if (append_type == NON_SEQUENTIAL) + { + // restore own last value state + mLastValue = NaN; + mHasValue = false; + } + } + else if (other.mHasValue) + { + mSum += other.mSum; + + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + mSumOfSquares = mergeSumsOfSquares(*this, other); + + if (append_type == SEQUENTIAL) + { + mLastValue = other.mLastValue; + mLastSampleTimeStamp = other.mLastSampleTimeStamp; + } + } } void SampleAccumulator::reset( const SampleAccumulator* other ) { - mLastValue = other ? other->mLastValue : NaN; - mHasValue = other ? other->mHasValue : false; - mNumSamples = 0; - mSum = 0; - mMin = mLastValue; - mMax = mLastValue; - mMean = mLastValue; - llassert(!mHasValue || mMean < 0 || mMean >= 0); - mSumOfSquares = 0; - mLastSampleTimeStamp = LLTimer::getTotalSeconds(); - mTotalSamplingTime = 0; + mLastValue = other ? other->mLastValue : NaN; + mHasValue = other ? other->mHasValue : false; + mNumSamples = 0; + mSum = 0; + mMin = mLastValue; + mMax = mLastValue; + mMean = mLastValue; + llassert(!mHasValue || mMean < 0 || mMean >= 0); + mSumOfSquares = 0; + mLastSampleTimeStamp = LLTimer::getTotalSeconds(); + mTotalSamplingTime = 0; } F64 EventAccumulator::mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b) { - if (a.mNumSamples && b.mNumSamples) - { - // combine variance (and hence standard deviation) of 2 different sized sample groups using - // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm - F64 n_1 = a.mNumSamples, - n_2 = b.mNumSamples; - F64 m_1 = a.mMean, - m_2 = b.mMean; - F64 v_1 = a.mSumOfSquares / a.mNumSamples, - v_2 = b.mSumOfSquares / b.mNumSamples; - return (F64)a.mNumSamples - * ((((n_1 - 1.f) * v_1) - + ((n_2 - 1.f) * v_2) - + (((n_1 * n_2) / (n_1 + n_2)) - * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) - / (n_1 + n_2 - 1.f)); - } - - return a.mSumOfSquares; + if (a.mNumSamples && b.mNumSamples) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.mNumSamples, + n_2 = b.mNumSamples; + F64 m_1 = a.mMean, + m_2 = b.mMean; + F64 v_1 = a.mSumOfSquares / a.mNumSamples, + v_2 = b.mSumOfSquares / b.mNumSamples; + return (F64)a.mNumSamples + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); + } + + return a.mSumOfSquares; } void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendType append_type ) { - if (other.mNumSamples) - { - if (!mNumSamples) - { - *this = other; - } - else - { - mSum += other.mSum; - - // NOTE: both conditions will hold first time through - if (other.mMin < mMin) { mMin = other.mMin; } - if (other.mMax > mMax) { mMax = other.mMax; } - - mSumOfSquares = mergeSumsOfSquares(*this, other); - - F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); - mNumSamples += other.mNumSamples; - mMean = mMean * weight + other.mMean * (1.f - weight); - if (append_type == SEQUENTIAL) mLastValue = other.mLastValue; - } - } + if (other.mNumSamples) + { + if (!mNumSamples) + { + *this = other; + } + else + { + mSum += other.mSum; + + // NOTE: both conditions will hold first time through + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + mSumOfSquares = mergeSumsOfSquares(*this, other); + + F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); + mNumSamples += other.mNumSamples; + mMean = mMean * weight + other.mMean * (1.f - weight); + if (append_type == SEQUENTIAL) mLastValue = other.mLastValue; + } + } } void EventAccumulator::reset( const EventAccumulator* other ) { - mNumSamples = 0; - mSum = 0; - mMin = F32(NaN); - mMax = F32(NaN); - mMean = NaN; - mSumOfSquares = 0; - mLastValue = other ? other->mLastValue : NaN; + mNumSamples = 0; + mSum = 0; + mMin = F32(NaN); + mMax = F32(NaN); + mMean = NaN; + mSumOfSquares = 0; + mLastValue = other ? other->mLastValue : NaN; } } diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index b9d577be9e..692bbe5acf 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -39,515 +39,515 @@ namespace LLTrace { - const F64 NaN = std::numeric_limits<double>::quiet_NaN(); - - enum EBufferAppendType - { - SEQUENTIAL, - NON_SEQUENTIAL - }; - - template<typename ACCUMULATOR> - class AccumulatorBuffer : public LLRefCount - { - typedef AccumulatorBuffer<ACCUMULATOR> self_t; - static const S32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 32; - private: - struct StaticAllocationMarker { }; - - AccumulatorBuffer(StaticAllocationMarker m) - : mStorageSize(0), - mStorage(NULL) - {} - - public: - AccumulatorBuffer() - : mStorageSize(0), - mStorage(NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - const AccumulatorBuffer& other = *getDefaultBuffer(); - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - ~AccumulatorBuffer() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (isCurrent()) - { - LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); - } - delete[] mStorage; - } - - LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) - { - return mStorage[index]; - } - - LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const - { - return mStorage[index]; - } - - - AccumulatorBuffer(const AccumulatorBuffer& other) - : mStorageSize(0), - mStorage(NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].addSamples(other.mStorage[i], append_type); - } - } - - void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].reset(other ? &other->mStorage[i] : NULL); - } - } - - void sync(F64SecondsImplicit time_stamp) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].sync(time_stamp); - } - } - - void makeCurrent() - { - LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); - } - - bool isCurrent() const - { - return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; - } - - static void clearCurrent() - { - LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); - } - - // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned - size_t reserveSlot() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - size_t next_slot = sNextStorageSlot++; - if (next_slot >= mStorageSize) - { - // don't perform doubling, as this should only happen during startup - // want to keep a tight bounds as we will have a lot of these buffers - resize(mStorageSize + mStorageSize / 2); - } - llassert(mStorage && next_slot < mStorageSize); - return next_slot; - } - - void resize(size_t new_size) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (new_size <= mStorageSize) return; - - ACCUMULATOR* old_storage = mStorage; - mStorage = new ACCUMULATOR[new_size]; - if (old_storage) - { - for (S32 i = 0; i < mStorageSize; i++) - { - mStorage[i] = old_storage[i]; - } - } - mStorageSize = new_size; - delete[] old_storage; - - self_t* default_buffer = getDefaultBuffer(); - if (this != default_buffer - && new_size > default_buffer->size()) - { - //NB: this is not thread safe, but we assume that all resizing occurs during static initialization - default_buffer->resize(new_size); - } - } - - size_t size() const - { - return getNumIndices(); - } - - size_t capacity() const - { - return mStorageSize; - } - - static size_t getNumIndices() - { - return sNextStorageSlot; - } - - static self_t* getDefaultBuffer() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - static bool sInitialized = false; - if (!sInitialized) - { - // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data - // so as not to trigger an access violation - sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); - sInitialized = true; - sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); - } - return sDefaultBuffer; - } - - private: - ACCUMULATOR* mStorage; - size_t mStorageSize; - static size_t sNextStorageSlot; - static self_t* sDefaultBuffer; - }; - - template<typename ACCUMULATOR> size_t AccumulatorBuffer<ACCUMULATOR>::sNextStorageSlot = 0; - template<typename ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>* AccumulatorBuffer<ACCUMULATOR>::sDefaultBuffer = NULL; - - class EventAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return NaN; } - - EventAccumulator() - : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), - mMean(NaN), - mSumOfSquares(0), - mNumSamples(0), - mLastValue(NaN) - {} - - void record(F64 value) - { - if (mNumSamples == 0) - { - mSum = value; - mMean = value; - mMin = value; - mMax = value; - } - else - { - mSum += value; - F64 old_mean = mMean; - mMean += (value - old_mean) / (F64)mNumSamples; - mSumOfSquares += (value - old_mean) * (value - mMean); - - if (value < mMin) { mMin = value; } - else if (value > mMax) { mMax = value; } - } - - mNumSamples++; - mLastValue = value; - } - - void addSamples(const EventAccumulator& other, EBufferAppendType append_type); - void reset(const EventAccumulator* other); - void sync(F64SecondsImplicit) {} - - F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } - F64 getLastValue() const { return mLastValue; } - F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } - F64 getSumOfSquares() const { return mSumOfSquares; } - S32 getSampleCount() const { return mNumSamples; } - bool hasValue() const { return mNumSamples > 0; } - - // helper utility to calculate combined sumofsquares total - static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); - - private: - F64 mSum, - mLastValue; - - F64 mMean, - mSumOfSquares; - - F32 mMin, - mMax; - - S32 mNumSamples; - }; - - - class SampleAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return NaN; } - - SampleAccumulator() - : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), - mMean(NaN), - mSumOfSquares(0), - mLastSampleTimeStamp(0), - mTotalSamplingTime(0), - mNumSamples(0), - mLastValue(NaN), - mHasValue(false) - {} - - void sample(F64 value) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); - - // store effect of last value - sync(time_stamp); - - if (!mHasValue) - { - mHasValue = true; - - mMin = value; - mMax = value; - mMean = value; - mLastSampleTimeStamp = time_stamp; - } - else - { - if (value < mMin) { mMin = value; } - else if (value > mMax) { mMax = value; } - } - - mLastValue = value; - mNumSamples++; - } - - void addSamples(const SampleAccumulator& other, EBufferAppendType append_type); - void reset(const SampleAccumulator* other); - - void sync(F64SecondsImplicit time_stamp) - { - if (mHasValue && time_stamp != mLastSampleTimeStamp) - { - F64SecondsImplicit delta_time = time_stamp - mLastSampleTimeStamp; - mSum += mLastValue * delta_time; - mTotalSamplingTime += delta_time; - F64 old_mean = mMean; - mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); - mSumOfSquares += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); - } - mLastSampleTimeStamp = time_stamp; - } - - F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } - F64 getLastValue() const { return mLastValue; } - F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } - F64 getSumOfSquares() const { return mSumOfSquares; } - F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } - S32 getSampleCount() const { return mNumSamples; } - bool hasValue() const { return mHasValue; } - - // helper utility to calculate combined sumofsquares total - static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); - - private: - F64 mSum, - mLastValue; - - F64 mMean, - mSumOfSquares; - - F64SecondsImplicit - mLastSampleTimeStamp, - mTotalSamplingTime; - - F32 mMin, - mMax; - - S32 mNumSamples; - // distinct from mNumSamples, since we might have inherited a last value from - // a previous sampling period - bool mHasValue; - }; - - class CountAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return 0; } - - CountAccumulator() - : mSum(0), - mNumSamples(0) - {} - - void add(F64 value) - { - mNumSamples++; - mSum += value; - } - - void addSamples(const CountAccumulator& other, EBufferAppendType /*type*/) - { - mSum += other.mSum; - mNumSamples += other.mNumSamples; - } - - void reset(const CountAccumulator* other) - { - mNumSamples = 0; - mSum = 0; - } - - void sync(F64SecondsImplicit) {} - - F64 getSum() const { return mSum; } - - S32 getSampleCount() const { return mNumSamples; } - - bool hasValue() const { return true; } - - private: - F64 mSum; - - S32 mNumSamples; - }; - - class alignas(32) TimeBlockAccumulator - { - public: - typedef F64Seconds value_t; - static F64Seconds getDefaultValue() { return F64Seconds(0); } - - typedef TimeBlockAccumulator self_t; - - // fake classes that allows us to view different facets of underlying statistic - struct CallCountFacet - { - typedef S32 value_t; - }; - - struct SelfTimeFacet - { - typedef F64Seconds value_t; - }; - - // arrays are allocated with 32 byte alignment - void *operator new [](size_t size) - { - return ll_aligned_malloc<32>(size); - } - - void operator delete[](void* ptr, size_t size) - { - ll_aligned_free<32>(ptr); - } - - TimeBlockAccumulator(); - void addSamples(const self_t& other, EBufferAppendType append_type); - void reset(const self_t* other); - void sync(F64SecondsImplicit) {} - bool hasValue() const { return true; } - - // - // members - // - U64 mTotalTimeCounter, - mSelfTimeCounter; - S32 mCalls; - class BlockTimerStatHandle* mParent; // last acknowledged parent of this time block - class BlockTimerStatHandle* mLastCaller; // used to bootstrap tree construction - U16 mActiveCount; // number of timers with this ID active on stack - bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame - - }; - - class BlockTimerStatHandle; - - class TimeBlockTreeNode - { - public: - TimeBlockTreeNode(); - - void setParent(BlockTimerStatHandle* parent); - BlockTimerStatHandle* getParent() { return mParent; } - - BlockTimerStatHandle* mBlock; - BlockTimerStatHandle* mParent; - std::vector<BlockTimerStatHandle*> mChildren; - bool mCollapsed; - bool mNeedsSorting; - }; - - struct BlockTimerStackRecord - { - class BlockTimer* mActiveTimer; - class BlockTimerStatHandle* mTimeBlock; - U64 mChildTime; - }; - - struct AccumulatorBufferGroup : public LLRefCount - { - AccumulatorBufferGroup(); - AccumulatorBufferGroup(const AccumulatorBufferGroup&); - ~AccumulatorBufferGroup(); - - void handOffTo(AccumulatorBufferGroup& other); - void makeCurrent(); - bool isCurrent() const; - static void clearCurrent(); - - void append(const AccumulatorBufferGroup& other); - void merge(const AccumulatorBufferGroup& other); - void reset(AccumulatorBufferGroup* other = NULL); - void sync(); - - AccumulatorBuffer<CountAccumulator> mCounts; - AccumulatorBuffer<SampleAccumulator> mSamples; - AccumulatorBuffer<EventAccumulator> mEvents; - AccumulatorBuffer<TimeBlockAccumulator> mStackTimers; - }; + const F64 NaN = std::numeric_limits<double>::quiet_NaN(); + + enum EBufferAppendType + { + SEQUENTIAL, + NON_SEQUENTIAL + }; + + template<typename ACCUMULATOR> + class AccumulatorBuffer : public LLRefCount + { + typedef AccumulatorBuffer<ACCUMULATOR> self_t; + static const S32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 32; + private: + struct StaticAllocationMarker { }; + + AccumulatorBuffer(StaticAllocationMarker m) + : mStorageSize(0), + mStorage(NULL) + {} + + public: + AccumulatorBuffer() + : mStorageSize(0), + mStorage(NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + const AccumulatorBuffer& other = *getDefaultBuffer(); + resize(sNextStorageSlot); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + ~AccumulatorBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (isCurrent()) + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); + } + delete[] mStorage; + } + + LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) + { + return mStorage[index]; + } + + LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const + { + return mStorage[index]; + } + + + AccumulatorBuffer(const AccumulatorBuffer& other) + : mStorageSize(0), + mStorage(NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + resize(sNextStorageSlot); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].addSamples(other.mStorage[i], append_type); + } + } + + void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].reset(other ? &other->mStorage[i] : NULL); + } + } + + void sync(F64SecondsImplicit time_stamp) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].sync(time_stamp); + } + } + + void makeCurrent() + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); + } + + bool isCurrent() const + { + return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; + } + + static void clearCurrent() + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); + } + + // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned + size_t reserveSlot() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + size_t next_slot = sNextStorageSlot++; + if (next_slot >= mStorageSize) + { + // don't perform doubling, as this should only happen during startup + // want to keep a tight bounds as we will have a lot of these buffers + resize(mStorageSize + mStorageSize / 2); + } + llassert(mStorage && next_slot < mStorageSize); + return next_slot; + } + + void resize(size_t new_size) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (new_size <= mStorageSize) return; + + ACCUMULATOR* old_storage = mStorage; + mStorage = new ACCUMULATOR[new_size]; + if (old_storage) + { + for (S32 i = 0; i < mStorageSize; i++) + { + mStorage[i] = old_storage[i]; + } + } + mStorageSize = new_size; + delete[] old_storage; + + self_t* default_buffer = getDefaultBuffer(); + if (this != default_buffer + && new_size > default_buffer->size()) + { + //NB: this is not thread safe, but we assume that all resizing occurs during static initialization + default_buffer->resize(new_size); + } + } + + size_t size() const + { + return getNumIndices(); + } + + size_t capacity() const + { + return mStorageSize; + } + + static size_t getNumIndices() + { + return sNextStorageSlot; + } + + static self_t* getDefaultBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + static bool sInitialized = false; + if (!sInitialized) + { + // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data + // so as not to trigger an access violation + sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); + sInitialized = true; + sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); + } + return sDefaultBuffer; + } + + private: + ACCUMULATOR* mStorage; + size_t mStorageSize; + static size_t sNextStorageSlot; + static self_t* sDefaultBuffer; + }; + + template<typename ACCUMULATOR> size_t AccumulatorBuffer<ACCUMULATOR>::sNextStorageSlot = 0; + template<typename ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>* AccumulatorBuffer<ACCUMULATOR>::sDefaultBuffer = NULL; + + class EventAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return NaN; } + + EventAccumulator() + : mSum(0), + mMin(F32(NaN)), + mMax(F32(NaN)), + mMean(NaN), + mSumOfSquares(0), + mNumSamples(0), + mLastValue(NaN) + {} + + void record(F64 value) + { + if (mNumSamples == 0) + { + mSum = value; + mMean = value; + mMin = value; + mMax = value; + } + else + { + mSum += value; + F64 old_mean = mMean; + mMean += (value - old_mean) / (F64)mNumSamples; + mSumOfSquares += (value - old_mean) * (value - mMean); + + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mNumSamples++; + mLastValue = value; + } + + void addSamples(const EventAccumulator& other, EBufferAppendType append_type); + void reset(const EventAccumulator* other); + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } + F64 getSumOfSquares() const { return mSumOfSquares; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mNumSamples > 0; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F32 mMin, + mMax; + + S32 mNumSamples; + }; + + + class SampleAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return NaN; } + + SampleAccumulator() + : mSum(0), + mMin(F32(NaN)), + mMax(F32(NaN)), + mMean(NaN), + mSumOfSquares(0), + mLastSampleTimeStamp(0), + mTotalSamplingTime(0), + mNumSamples(0), + mLastValue(NaN), + mHasValue(false) + {} + + void sample(F64 value) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); + + // store effect of last value + sync(time_stamp); + + if (!mHasValue) + { + mHasValue = true; + + mMin = value; + mMax = value; + mMean = value; + mLastSampleTimeStamp = time_stamp; + } + else + { + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mLastValue = value; + mNumSamples++; + } + + void addSamples(const SampleAccumulator& other, EBufferAppendType append_type); + void reset(const SampleAccumulator* other); + + void sync(F64SecondsImplicit time_stamp) + { + if (mHasValue && time_stamp != mLastSampleTimeStamp) + { + F64SecondsImplicit delta_time = time_stamp - mLastSampleTimeStamp; + mSum += mLastValue * delta_time; + mTotalSamplingTime += delta_time; + F64 old_mean = mMean; + mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); + mSumOfSquares += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); + } + mLastSampleTimeStamp = time_stamp; + } + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } + F64 getSumOfSquares() const { return mSumOfSquares; } + F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mHasValue; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F64SecondsImplicit + mLastSampleTimeStamp, + mTotalSamplingTime; + + F32 mMin, + mMax; + + S32 mNumSamples; + // distinct from mNumSamples, since we might have inherited a last value from + // a previous sampling period + bool mHasValue; + }; + + class CountAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return 0; } + + CountAccumulator() + : mSum(0), + mNumSamples(0) + {} + + void add(F64 value) + { + mNumSamples++; + mSum += value; + } + + void addSamples(const CountAccumulator& other, EBufferAppendType /*type*/) + { + mSum += other.mSum; + mNumSamples += other.mNumSamples; + } + + void reset(const CountAccumulator* other) + { + mNumSamples = 0; + mSum = 0; + } + + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + + S32 getSampleCount() const { return mNumSamples; } + + bool hasValue() const { return true; } + + private: + F64 mSum; + + S32 mNumSamples; + }; + + class alignas(32) TimeBlockAccumulator + { + public: + typedef F64Seconds value_t; + static F64Seconds getDefaultValue() { return F64Seconds(0); } + + typedef TimeBlockAccumulator self_t; + + // fake classes that allows us to view different facets of underlying statistic + struct CallCountFacet + { + typedef S32 value_t; + }; + + struct SelfTimeFacet + { + typedef F64Seconds value_t; + }; + + // arrays are allocated with 32 byte alignment + void *operator new [](size_t size) + { + return ll_aligned_malloc<32>(size); + } + + void operator delete[](void* ptr, size_t size) + { + ll_aligned_free<32>(ptr); + } + + TimeBlockAccumulator(); + void addSamples(const self_t& other, EBufferAppendType append_type); + void reset(const self_t* other); + void sync(F64SecondsImplicit) {} + bool hasValue() const { return true; } + + // + // members + // + U64 mTotalTimeCounter, + mSelfTimeCounter; + S32 mCalls; + class BlockTimerStatHandle* mParent; // last acknowledged parent of this time block + class BlockTimerStatHandle* mLastCaller; // used to bootstrap tree construction + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + + }; + + class BlockTimerStatHandle; + + class TimeBlockTreeNode + { + public: + TimeBlockTreeNode(); + + void setParent(BlockTimerStatHandle* parent); + BlockTimerStatHandle* getParent() { return mParent; } + + BlockTimerStatHandle* mBlock; + BlockTimerStatHandle* mParent; + std::vector<BlockTimerStatHandle*> mChildren; + bool mCollapsed; + bool mNeedsSorting; + }; + + struct BlockTimerStackRecord + { + class BlockTimer* mActiveTimer; + class BlockTimerStatHandle* mTimeBlock; + U64 mChildTime; + }; + + struct AccumulatorBufferGroup : public LLRefCount + { + AccumulatorBufferGroup(); + AccumulatorBufferGroup(const AccumulatorBufferGroup&); + ~AccumulatorBufferGroup(); + + void handOffTo(AccumulatorBufferGroup& other); + void makeCurrent(); + bool isCurrent() const; + static void clearCurrent(); + + void append(const AccumulatorBufferGroup& other); + void merge(const AccumulatorBufferGroup& other); + void reset(AccumulatorBufferGroup* other = NULL); + void sync(); + + AccumulatorBuffer<CountAccumulator> mCounts; + AccumulatorBuffer<SampleAccumulator> mSamples; + AccumulatorBuffer<EventAccumulator> mEvents; + AccumulatorBuffer<TimeBlockAccumulator> mStackTimers; + }; } #endif // LL_LLTRACEACCUMULATORS_H diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 075e7c1d28..1ec83be7cb 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -34,7 +34,7 @@ inline F64 lerp(F64 a, F64 b, F64 u) { - return a + ((b - a) * u); + return a + ((b - a) * u); } namespace LLTrace @@ -45,388 +45,388 @@ namespace LLTrace /////////////////////////////////////////////////////////////////////// Recording::Recording(EPlayState state) -: mElapsedSeconds(0), - mActiveBuffers(NULL) +: mElapsedSeconds(0), + mActiveBuffers(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mBuffers = new AccumulatorBufferGroup(); - setPlayState(state); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mBuffers = new AccumulatorBufferGroup(); + setPlayState(state); } Recording::Recording( const Recording& other ) -: mActiveBuffers(NULL) +: mActiveBuffers(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - *this = other; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + *this = other; } Recording& Recording::operator = (const Recording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // this will allow us to seamlessly start without affecting any data we've acquired from other - setPlayState(PAUSED); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + // this will allow us to seamlessly start without affecting any data we've acquired from other + setPlayState(PAUSED); - const_cast<Recording&>(other).update(); - EPlayState other_play_state = other.getPlayState(); + const_cast<Recording&>(other).update(); + EPlayState other_play_state = other.getPlayState(); - mBuffers = other.mBuffers; + mBuffers = other.mBuffers; - // above call will clear mElapsedSeconds as a side effect, so copy it here - mElapsedSeconds = other.mElapsedSeconds; - mSamplingTimer = other.mSamplingTimer; + // above call will clear mElapsedSeconds as a side effect, so copy it here + mElapsedSeconds = other.mElapsedSeconds; + mSamplingTimer = other.mSamplingTimer; - setPlayState(other_play_state); + setPlayState(other_play_state); - return *this; + return *this; } Recording::~Recording() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // allow recording destruction without thread recorder running, - // otherwise thread shutdown could crash if a recording outlives the thread recorder - // besides, recording construction and destruction is fine without a recorder...just don't attempt to start one - if (isStarted() && LLTrace::get_thread_recorder() != NULL) - { - LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); - } + // allow recording destruction without thread recorder running, + // otherwise thread shutdown could crash if a recording outlives the thread recorder + // besides, recording construction and destruction is fine without a recorder...just don't attempt to start one + if (isStarted() && LLTrace::get_thread_recorder() != NULL) + { + LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); + } } // brings recording to front of recorder stack, with up to date info void Recording::update() { #if LL_TRACE_ENABLED - if (isStarted()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); - - // must have - llassert(mActiveBuffers != NULL - && LLTrace::get_thread_recorder() != NULL); - - if (!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL) - { - AccumulatorBufferGroup* buffers = mBuffers.write(); - LLTrace::get_thread_recorder()->deactivate(buffers); - mActiveBuffers = LLTrace::get_thread_recorder()->activate(buffers); - } - - mSamplingTimer.reset(); - } + if (isStarted()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + + // must have + llassert(mActiveBuffers != NULL + && LLTrace::get_thread_recorder() != NULL); + + if (!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL) + { + AccumulatorBufferGroup* buffers = mBuffers.write(); + LLTrace::get_thread_recorder()->deactivate(buffers); + mActiveBuffers = LLTrace::get_thread_recorder()->activate(buffers); + } + + mSamplingTimer.reset(); + } #endif } void Recording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED - mBuffers.write()->reset(); + mBuffers.write()->reset(); - mElapsedSeconds = F64Seconds(0.0); - mSamplingTimer.reset(); + mElapsedSeconds = F64Seconds(0.0); + mSamplingTimer.reset(); #endif } void Recording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED - mSamplingTimer.reset(); - mBuffers.setStayUnique(true); - // must have thread recorder running on this thread - llassert(LLTrace::get_thread_recorder() != NULL); - mActiveBuffers = LLTrace::get_thread_recorder()->activate(mBuffers.write()); + mSamplingTimer.reset(); + mBuffers.setStayUnique(true); + // must have thread recorder running on this thread + llassert(LLTrace::get_thread_recorder() != NULL); + mActiveBuffers = LLTrace::get_thread_recorder()->activate(mBuffers.write()); #endif } void Recording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED - mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); - // must have thread recorder running on this thread - llassert(LLTrace::get_thread_recorder() != NULL); - LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); - mActiveBuffers = NULL; - mBuffers.setStayUnique(false); + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + // must have thread recorder running on this thread + llassert(LLTrace::get_thread_recorder() != NULL); + LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); + mActiveBuffers = NULL; + mBuffers.setStayUnique(false); #endif } void Recording::handleSplitTo(Recording& other) { #if LL_TRACE_ENABLED - mBuffers.write()->handOffTo(*other.mBuffers.write()); + mBuffers.write()->handOffTo(*other.mBuffers.write()); #endif } void Recording::appendRecording( Recording& other ) { #if LL_TRACE_ENABLED - update(); - other.update(); - mBuffers.write()->append(*other.mBuffers); - mElapsedSeconds += other.mElapsedSeconds; + update(); + other.update(); + mBuffers.write()->append(*other.mBuffers); + mElapsedSeconds += other.mElapsedSeconds; #endif } bool Recording::hasValue(const StatType<TimeBlockAccumulator>& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64Seconds Recording::getSum(const StatType<TimeBlockAccumulator>& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mTotalTimeCounter) + (F64)(active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) - / (F64)LLTrace::BlockTimer::countsPerSecond(); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds((F64)(accumulator.mTotalTimeCounter) + (F64)(active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + / (F64)LLTrace::BlockTimer::countsPerSecond(); } F64Seconds Recording::getSum(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds(((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / (F64)LLTrace::BlockTimer::countsPerSecond()); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds(((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / (F64)LLTrace::BlockTimer::countsPerSecond()); } S32 Recording::getSum(const StatType<TimeBlockAccumulator::CallCountFacet>& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0); } F64Seconds Recording::getPerSec(const StatType<TimeBlockAccumulator>& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) - / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); + return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); } F64Seconds Recording::getPerSec(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mSelfTimeCounter + (active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) - / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); + return F64Seconds((F64)(accumulator.mSelfTimeCounter + (active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) + / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); } F32 Recording::getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value(); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value(); } bool Recording::hasValue(const StatType<CountAccumulator>& stat) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); } F64 Recording::getSum(const StatType<CountAccumulator>& stat) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); } F64 Recording::getPerSec( const StatType<CountAccumulator>& stat ) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); - return sum / mElapsedSeconds.value(); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); + return sum / mElapsedSeconds.value(); } S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat ) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); } bool Recording::hasValue(const StatType<SampleAccumulator>& stat) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64 Recording::getMin( const StatType<SampleAccumulator>& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); } F64 Recording::getMax( const StatType<SampleAccumulator>& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); } F64 Recording::getMean( const StatType<SampleAccumulator>& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F32 t = 0.0f; - S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); - if (div > 0) - { - t = active_accumulator->getSampleCount() / div; - } - return lerp(accumulator.getMean(), active_accumulator->getMean(), t); - } - else - { - return accumulator.getMean(); - } + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + F32 t = 0.0f; + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } + return lerp(accumulator.getMean(), active_accumulator->getMean(), t); + } + else + { + return accumulator.getMean(); + } } F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); - return sqrtf(sum_of_squares / (accumulator.getSamplingTime() + active_accumulator->getSamplingTime())); - } - else - { - return accumulator.getStandardDeviation(); - } + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSamplingTime() + active_accumulator->getSamplingTime())); + } + else + { + return accumulator.getStandardDeviation(); + } } F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); } S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); } bool Recording::hasValue(const StatType<EventAccumulator>& stat) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64 Recording::getSum( const StatType<EventAccumulator>& stat) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); } F64 Recording::getMin( const StatType<EventAccumulator>& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); } F64 Recording::getMax( const StatType<EventAccumulator>& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); } F64 Recording::getMean( const StatType<EventAccumulator>& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F32 t = 0.0f; - S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); - if (div > 0) - { - t = active_accumulator->getSampleCount() / div; - } - return lerp(accumulator.getMean(), active_accumulator->getMean(), t); - } - else - { - return accumulator.getMean(); - } + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + F32 t = 0.0f; + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } + return lerp(accumulator.getMean(), active_accumulator->getMean(), t); + } + else + { + return accumulator.getMean(); + } } F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F64 sum_of_squares = EventAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); - return sqrtf(sum_of_squares / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); - } - else - { - return accumulator.getStandardDeviation(); - } + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = EventAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getStandardDeviation(); + } } F64 Recording::getLastValue( const StatType<EventAccumulator>& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); } S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); } /////////////////////////////////////////////////////////////////////// @@ -434,408 +434,408 @@ S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat ) /////////////////////////////////////////////////////////////////////// PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state) -: mAutoResize(num_periods == 0), - mCurPeriod(0), - mNumRecordedPeriods(0), - // This guarantee that mRecordingPeriods cannot be empty is essential for - // code in several methods. - mRecordingPeriods(num_periods ? num_periods : 1) +: mAutoResize(num_periods == 0), + mCurPeriod(0), + mNumRecordedPeriods(0), + // This guarantee that mRecordingPeriods cannot be empty is essential for + // code in several methods. + mRecordingPeriods(num_periods ? num_periods : 1) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - setPlayState(state); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + setPlayState(state); } PeriodicRecording::~PeriodicRecording() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } void PeriodicRecording::nextPeriod() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (mAutoResize) - { - mRecordingPeriods.push_back(Recording()); - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (mAutoResize) + { + mRecordingPeriods.push_back(Recording()); + } - Recording& old_recording = getCurRecording(); - inci(mCurPeriod); - old_recording.splitTo(getCurRecording()); + Recording& old_recording = getCurRecording(); + inci(mCurPeriod); + old_recording.splitTo(getCurRecording()); - // Since mRecordingPeriods always has at least one entry, we can always - // safely subtract 1 from its size(). - mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1); + // Since mRecordingPeriods always has at least one entry, we can always + // safely subtract 1 from its size(). + mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1); } void PeriodicRecording::appendRecording(Recording& recording) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().appendRecording(recording); - nextPeriod(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().appendRecording(recording); + nextPeriod(); } void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (other.mRecordingPeriods.empty()) return; - - getCurRecording().update(); - other.getCurRecording().update(); - - const auto other_num_recordings = other.getNumRecordedPeriods(); - const auto other_current_recording_index = other.mCurPeriod; - const auto other_oldest_recording_index = other.previ(other_current_recording_index, other_num_recordings); - - // append first recording into our current slot - getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); - - // from now on, add new recordings for everything after the first - auto other_index = other.nexti(other_oldest_recording_index); - - if (mAutoResize) - { - // push back recordings for everything in the middle - while (other_index != other_current_recording_index) - { - mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); - other.inci(other_index); - } - - // add final recording, if it wasn't already added as the first - if (other_num_recordings > 1) - { - mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]); - } - - // mRecordingPeriods is never empty() - mCurPeriod = mRecordingPeriods.size() - 1; - mNumRecordedPeriods = mCurPeriod; - } - else - { - auto num_to_copy = llmin(mRecordingPeriods.size(), other_num_recordings); - // already consumed the first recording from other, so start counting at 1 - for (size_t n = 1, srci = other_index, dsti = mCurPeriod; - n < num_to_copy; - ++n, other.inci(srci), inci(dsti)) - { - mRecordingPeriods[dsti] = other.mRecordingPeriods[srci]; - } - - // want argument to % to be positive, otherwise result could be negative and thus out of bounds - llassert(num_to_copy >= 1); - // advance to last recording period copied, and make that our current period - inci(mCurPeriod, num_to_copy - 1); - mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1); - } - - // end with fresh period, otherwise next appendPeriodicRecording() will merge the first - // recording period with the last one appended here - nextPeriod(); - getCurRecording().setPlayState(getPlayState()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (other.mRecordingPeriods.empty()) return; + + getCurRecording().update(); + other.getCurRecording().update(); + + const auto other_num_recordings = other.getNumRecordedPeriods(); + const auto other_current_recording_index = other.mCurPeriod; + const auto other_oldest_recording_index = other.previ(other_current_recording_index, other_num_recordings); + + // append first recording into our current slot + getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); + + // from now on, add new recordings for everything after the first + auto other_index = other.nexti(other_oldest_recording_index); + + if (mAutoResize) + { + // push back recordings for everything in the middle + while (other_index != other_current_recording_index) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); + other.inci(other_index); + } + + // add final recording, if it wasn't already added as the first + if (other_num_recordings > 1) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]); + } + + // mRecordingPeriods is never empty() + mCurPeriod = mRecordingPeriods.size() - 1; + mNumRecordedPeriods = mCurPeriod; + } + else + { + auto num_to_copy = llmin(mRecordingPeriods.size(), other_num_recordings); + // already consumed the first recording from other, so start counting at 1 + for (size_t n = 1, srci = other_index, dsti = mCurPeriod; + n < num_to_copy; + ++n, other.inci(srci), inci(dsti)) + { + mRecordingPeriods[dsti] = other.mRecordingPeriods[srci]; + } + + // want argument to % to be positive, otherwise result could be negative and thus out of bounds + llassert(num_to_copy >= 1); + // advance to last recording period copied, and make that our current period + inci(mCurPeriod, num_to_copy - 1); + mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1); + } + + // end with fresh period, otherwise next appendPeriodicRecording() will merge the first + // recording period with the last one appended here + nextPeriod(); + getCurRecording().setPlayState(getPlayState()); } F64Seconds PeriodicRecording::getDuration() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - F64Seconds duration; - for (size_t n = 0; n < mRecordingPeriods.size(); ++n) - { - duration += mRecordingPeriods[nexti(mCurPeriod, n)].getDuration(); - } - return duration; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + F64Seconds duration; + for (size_t n = 0; n < mRecordingPeriods.size(); ++n) + { + duration += mRecordingPeriods[nexti(mCurPeriod, n)].getDuration(); + } + return duration; } LLTrace::Recording PeriodicRecording::snapshotCurRecording() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - Recording recording_copy(getCurRecording()); - recording_copy.stop(); - return recording_copy; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + Recording recording_copy(getCurRecording()); + recording_copy.stop(); + return recording_copy; } Recording& PeriodicRecording::getLastRecording() { - return getPrevRecording(1); + return getPrevRecording(1); } const Recording& PeriodicRecording::getLastRecording() const { - return getPrevRecording(1); + return getPrevRecording(1); } Recording& PeriodicRecording::getCurRecording() { - return mRecordingPeriods[mCurPeriod]; + return mRecordingPeriods[mCurPeriod]; } const Recording& PeriodicRecording::getCurRecording() const { - return mRecordingPeriods[mCurPeriod]; + return mRecordingPeriods[mCurPeriod]; } Recording& PeriodicRecording::getPrevRecording( size_t offset ) { - // reuse const implementation, but return non-const reference - return const_cast<Recording&>( - const_cast<const PeriodicRecording*>(this)->getPrevRecording(offset)); + // reuse const implementation, but return non-const reference + return const_cast<Recording&>( + const_cast<const PeriodicRecording*>(this)->getPrevRecording(offset)); } const Recording& PeriodicRecording::getPrevRecording( size_t offset ) const { - return mRecordingPeriods[previ(mCurPeriod, offset)]; + return mRecordingPeriods[previ(mCurPeriod, offset)]; } void PeriodicRecording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().start(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().start(); } void PeriodicRecording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().pause(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().pause(); } void PeriodicRecording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().stop(); - - if (mAutoResize) - { - mRecordingPeriods.clear(); - mRecordingPeriods.push_back(Recording()); - } - else - { - for (Recording& rec : mRecordingPeriods) - { - rec.reset(); - } - } - mCurPeriod = 0; - mNumRecordedPeriods = 0; - getCurRecording().setPlayState(getPlayState()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().stop(); + + if (mAutoResize) + { + mRecordingPeriods.clear(); + mRecordingPeriods.push_back(Recording()); + } + else + { + for (Recording& rec : mRecordingPeriods) + { + rec.reset(); + } + } + mCurPeriod = 0; + mNumRecordedPeriods = 0; + getCurRecording().setPlayState(getPlayState()); } void PeriodicRecording::handleSplitTo(PeriodicRecording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().splitTo(other.getCurRecording()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().splitTo(other.getCurRecording()); } F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 min_val = std::numeric_limits<F64>::max(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - min_val = llmin(min_val, recording.getMin(stat)); - has_value = true; - } - } + bool has_value = false; + F64 min_val = std::numeric_limits<F64>::max(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getMin(stat)); + has_value = true; + } + } - return has_value - ? min_val - : NaN; + return has_value + ? min_val + : NaN; } F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 max_val = std::numeric_limits<F64>::min(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - max_val = llmax(max_val, recording.getMax(stat)); - has_value = true; - } - } + bool has_value = false; + F64 max_val = std::numeric_limits<F64>::min(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getMax(stat)); + has_value = true; + } + } - return has_value - ? max_val - : NaN; + return has_value + ? max_val + : NaN; } // calculates means using aggregates per period F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - F64 mean = 0; - S32 valid_period_count = 0; + F64 mean = 0; + S32 valid_period_count = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - mean += recording.getMean(stat); - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + mean += recording.getMean(stat); + valid_period_count++; + } + } - return valid_period_count - ? mean / (F64)valid_period_count - : NaN; + return valid_period_count + ? mean / (F64)valid_period_count + : NaN; } F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - F64 period_mean = getPeriodMean(stat, num_periods); - F64 sum_of_squares = 0; - S32 valid_period_count = 0; + F64 period_mean = getPeriodMean(stat, num_periods); + F64 sum_of_squares = 0; + S32 valid_period_count = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - F64 delta = recording.getMean(stat) - period_mean; - sum_of_squares += delta * delta; - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + F64 delta = recording.getMean(stat) - period_mean; + sum_of_squares += delta * delta; + valid_period_count++; + } + } - return valid_period_count - ? sqrt((F64)sum_of_squares / (F64)valid_period_count) - : NaN; + return valid_period_count + ? sqrt((F64)sum_of_squares / (F64)valid_period_count) + : NaN; } F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 min_val = std::numeric_limits<F64>::max(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - min_val = llmin(min_val, recording.getMin(stat)); - has_value = true; - } - } + bool has_value = false; + F64 min_val = std::numeric_limits<F64>::max(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getMin(stat)); + has_value = true; + } + } - return has_value - ? min_val - : NaN; + return has_value + ? min_val + : NaN; } F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 max_val = std::numeric_limits<F64>::min(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - max_val = llmax(max_val, recording.getMax(stat)); - has_value = true; - } - } + bool has_value = false; + F64 max_val = std::numeric_limits<F64>::min(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getMax(stat)); + has_value = true; + } + } - return has_value - ? max_val - : NaN; + return has_value + ? max_val + : NaN; } F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - S32 valid_period_count = 0; - F64 mean = 0; + S32 valid_period_count = 0; + F64 mean = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - mean += recording.getMean(stat); - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + mean += recording.getMean(stat); + valid_period_count++; + } + } - return valid_period_count - ? mean / F64(valid_period_count) - : NaN; + return valid_period_count + ? mean / F64(valid_period_count) + : NaN; } F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - std::vector<F64> buf; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - if (recording.hasValue(stat)) - { - buf.push_back(recording.getMean(stat)); - } - } - } - if (buf.size()==0) - { - return 0.0f; - } - std::sort(buf.begin(), buf.end()); - - return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector<F64> buf; + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + if (recording.hasValue(stat)) + { + buf.push_back(recording.getMean(stat)); + } + } + } + if (buf.size()==0) + { + return 0.0f; + } + std::sort(buf.begin(), buf.end()); + + return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); } F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - F64 period_mean = getPeriodMean(stat, num_periods); - S32 valid_period_count = 0; - F64 sum_of_squares = 0; + F64 period_mean = getPeriodMean(stat, num_periods); + S32 valid_period_count = 0; + F64 sum_of_squares = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - F64 delta = recording.getMean(stat) - period_mean; - sum_of_squares += delta * delta; - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + F64 delta = recording.getMean(stat) - period_mean; + sum_of_squares += delta * delta; + valid_period_count++; + } + } - return valid_period_count - ? sqrt(sum_of_squares / (F64)valid_period_count) - : NaN; + return valid_period_count + ? sqrt(sum_of_squares / (F64)valid_period_count) + : NaN; } /////////////////////////////////////////////////////////////////////// @@ -844,36 +844,36 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula void ExtendableRecording::extend() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // push the data back to accepted recording - mAcceptedRecording.appendRecording(mPotentialRecording); - // flush data, so we can start from scratch - mPotentialRecording.reset(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + // push the data back to accepted recording + mAcceptedRecording.appendRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); } void ExtendableRecording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mPotentialRecording.start(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mPotentialRecording.start(); } void ExtendableRecording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mPotentialRecording.pause(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mPotentialRecording.pause(); } void ExtendableRecording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mAcceptedRecording.reset(); - mPotentialRecording.reset(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mAcceptedRecording.reset(); + mPotentialRecording.reset(); } void ExtendableRecording::handleSplitTo(ExtendableRecording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mPotentialRecording.splitTo(other.mPotentialRecording); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mPotentialRecording.splitTo(other.mPotentialRecording); } /////////////////////////////////////////////////////////////////////// @@ -881,203 +881,203 @@ void ExtendableRecording::handleSplitTo(ExtendableRecording& other) /////////////////////////////////////////////////////////////////////// ExtendablePeriodicRecording::ExtendablePeriodicRecording() -: mAcceptedRecording(0), - mPotentialRecording(0) +: mAcceptedRecording(0), + mPotentialRecording(0) {} void ExtendablePeriodicRecording::extend() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // push the data back to accepted recording - mAcceptedRecording.appendPeriodicRecording(mPotentialRecording); - // flush data, so we can start from scratch - mPotentialRecording.reset(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + // push the data back to accepted recording + mAcceptedRecording.appendPeriodicRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); } void ExtendablePeriodicRecording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mPotentialRecording.start(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mPotentialRecording.start(); } void ExtendablePeriodicRecording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mPotentialRecording.pause(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mPotentialRecording.pause(); } void ExtendablePeriodicRecording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mAcceptedRecording.reset(); - mPotentialRecording.reset(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mAcceptedRecording.reset(); + mPotentialRecording.reset(); } void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mPotentialRecording.splitTo(other.mPotentialRecording); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mPotentialRecording.splitTo(other.mPotentialRecording); } PeriodicRecording& get_frame_recording() { - static thread_local PeriodicRecording sRecording(200, PeriodicRecording::STARTED); - return sRecording; + static thread_local PeriodicRecording sRecording(200, PeriodicRecording::STARTED); + return sRecording; } } void LLStopWatchControlsMixinCommon::start() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - switch (mPlayState) - { - case STOPPED: - handleReset(); - handleStart(); - mPlayState = STARTED; - break; - case PAUSED: - handleStart(); - mPlayState = STARTED; - break; - case STARTED: - break; - default: - llassert(false); - break; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + mPlayState = STARTED; + break; + case PAUSED: + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + break; + default: + llassert(false); + break; + } } void LLStopWatchControlsMixinCommon::stop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - switch (mPlayState) - { - case STOPPED: - break; - case PAUSED: - mPlayState = STOPPED; - break; - case STARTED: - handleStop(); - mPlayState = STOPPED; - break; - default: - llassert(false); - break; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + mPlayState = STOPPED; + break; + case STARTED: + handleStop(); + mPlayState = STOPPED; + break; + default: + llassert(false); + break; + } } void LLStopWatchControlsMixinCommon::pause() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - switch (mPlayState) - { - case STOPPED: - // stay stopped, don't go to pause - break; - case PAUSED: - break; - case STARTED: - handleStop(); - mPlayState = PAUSED; - break; - default: - llassert(false); - break; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + switch (mPlayState) + { + case STOPPED: + // stay stopped, don't go to pause + break; + case PAUSED: + break; + case STARTED: + handleStop(); + mPlayState = PAUSED; + break; + default: + llassert(false); + break; + } } void LLStopWatchControlsMixinCommon::unpause() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - switch (mPlayState) - { - case STOPPED: - // stay stopped, don't start - break; - case PAUSED: - handleStart(); - mPlayState = STARTED; - break; - case STARTED: - break; - default: - llassert(false); - break; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + switch (mPlayState) + { + case STOPPED: + // stay stopped, don't start + break; + case PAUSED: + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + break; + default: + llassert(false); + break; + } } void LLStopWatchControlsMixinCommon::resume() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - switch (mPlayState) - { - case STOPPED: - handleStart(); - mPlayState = STARTED; - break; - case PAUSED: - handleStart(); - mPlayState = STARTED; - break; - case STARTED: - break; - default: - llassert(false); - break; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + switch (mPlayState) + { + case STOPPED: + handleStart(); + mPlayState = STARTED; + break; + case PAUSED: + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + break; + default: + llassert(false); + break; + } } void LLStopWatchControlsMixinCommon::restart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - switch (mPlayState) - { - case STOPPED: - handleReset(); - handleStart(); - mPlayState = STARTED; - break; - case PAUSED: - handleReset(); - handleStart(); - mPlayState = STARTED; - break; - case STARTED: - handleReset(); - break; - default: - llassert(false); - break; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + mPlayState = STARTED; + break; + case PAUSED: + handleReset(); + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + handleReset(); + break; + default: + llassert(false); + break; + } } void LLStopWatchControlsMixinCommon::reset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - handleReset(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + handleReset(); } void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - switch(state) - { - case STOPPED: - stop(); - break; - case PAUSED: - pause(); - break; - case STARTED: - start(); - break; - default: - llassert(false); - break; - } - - mPlayState = state; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + switch(state) + { + case STOPPED: + stop(); + break; + case PAUSED: + pause(); + break; + case STARTED: + start(); + break; + default: + llassert(false); + break; + } + + mPlayState = state; } diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index 61b9096ae2..985f06cd59 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -38,680 +38,680 @@ class LLStopWatchControlsMixinCommon { public: - virtual ~LLStopWatchControlsMixinCommon() {} - - enum EPlayState - { - STOPPED, - PAUSED, - STARTED - }; - - void start(); // moves to started state, resetting if stopped - void stop(); // moves to stopped state - void pause(); // moves to paused state, unless stopped - void unpause(); // moves to started state if paused - void resume(); // moves to started state, without resetting - void restart(); // moves to started state, always resetting - void reset(); // resets - - bool isStarted() const { return mPlayState == STARTED; } - bool isPaused() const { return mPlayState == PAUSED; } - bool isStopped() const { return mPlayState == STOPPED; } - - EPlayState getPlayState() const { return mPlayState; } - // force play state to specific value by calling appropriate handle* methods - void setPlayState(EPlayState state); + virtual ~LLStopWatchControlsMixinCommon() {} + + enum EPlayState + { + STOPPED, + PAUSED, + STARTED + }; + + void start(); // moves to started state, resetting if stopped + void stop(); // moves to stopped state + void pause(); // moves to paused state, unless stopped + void unpause(); // moves to started state if paused + void resume(); // moves to started state, without resetting + void restart(); // moves to started state, always resetting + void reset(); // resets + + bool isStarted() const { return mPlayState == STARTED; } + bool isPaused() const { return mPlayState == PAUSED; } + bool isStopped() const { return mPlayState == STOPPED; } + + EPlayState getPlayState() const { return mPlayState; } + // force play state to specific value by calling appropriate handle* methods + void setPlayState(EPlayState state); protected: - LLStopWatchControlsMixinCommon() - : mPlayState(STOPPED) - {} + LLStopWatchControlsMixinCommon() + : mPlayState(STOPPED) + {} private: - // override these methods to provide started/stopped semantics + // override these methods to provide started/stopped semantics - // activate behavior (without reset) - virtual void handleStart() = 0; - // deactivate behavior - virtual void handleStop() = 0; - // clear accumulated state, may be called while started - virtual void handleReset() = 0; + // activate behavior (without reset) + virtual void handleStart() = 0; + // deactivate behavior + virtual void handleStop() = 0; + // clear accumulated state, may be called while started + virtual void handleReset() = 0; - EPlayState mPlayState; + EPlayState mPlayState; }; template<typename DERIVED> class LLStopWatchControlsMixin -: public LLStopWatchControlsMixinCommon +: public LLStopWatchControlsMixinCommon { public: - typedef LLStopWatchControlsMixin<DERIVED> self_t; - virtual void splitTo(DERIVED& other) - { - EPlayState play_state = getPlayState(); - stop(); - other.reset(); + typedef LLStopWatchControlsMixin<DERIVED> self_t; + virtual void splitTo(DERIVED& other) + { + EPlayState play_state = getPlayState(); + stop(); + other.reset(); - handleSplitTo(other); + handleSplitTo(other); - other.setPlayState(play_state); - } + other.setPlayState(play_state); + } - virtual void splitFrom(DERIVED& other) - { - static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this)); - } + virtual void splitFrom(DERIVED& other) + { + static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this)); + } private: - self_t& operator = (const self_t& other) - { - // don't do anything, derived class must implement logic - } - - // atomically stop this object while starting the other - // no data can be missed in between stop and start - virtual void handleSplitTo(DERIVED& other) {}; + self_t& operator = (const self_t& other) + { + // don't do anything, derived class must implement logic + } + + // atomically stop this object while starting the other + // no data can be missed in between stop and start + virtual void handleSplitTo(DERIVED& other) {}; }; namespace LLTrace { - template<typename T> - class StatType; - - template<typename T> - class CountStatHandle; - - template<typename T> - class SampleStatHandle; - - template<typename T> - class EventStatHandle; - - template<typename T> - struct RelatedTypes - { - typedef F64 fractional_t; - typedef T sum_t; - }; - - template<typename T, typename UNIT_T> - struct RelatedTypes<LLUnit<T, UNIT_T> > - { - typedef LLUnit<typename RelatedTypes<T>::fractional_t, UNIT_T> fractional_t; - typedef LLUnit<typename RelatedTypes<T>::sum_t, UNIT_T> sum_t; - }; - - template<> - struct RelatedTypes<bool> - { - typedef F64 fractional_t; - typedef S32 sum_t; - }; - - class Recording - : public LLStopWatchControlsMixin<Recording> - { - public: - Recording(EPlayState state = LLStopWatchControlsMixinCommon::STOPPED); - - Recording(const Recording& other); - ~Recording(); - - Recording& operator = (const Recording& other); - - // accumulate data from subsequent, non-overlapping recording - void appendRecording(Recording& other); - - // grab latest recorded data - void update(); - - // ensure that buffers are exclusively owned by this recording - void makeUnique() { mBuffers.makeUnique(); } - - // Timer accessors - bool hasValue(const StatType<TimeBlockAccumulator>& stat); - F64Seconds getSum(const StatType<TimeBlockAccumulator>& stat); - F64Seconds getSum(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat); - S32 getSum(const StatType<TimeBlockAccumulator::CallCountFacet>& stat); - - F64Seconds getPerSec(const StatType<TimeBlockAccumulator>& stat); - F64Seconds getPerSec(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat); - F32 getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& stat); - - // CountStatHandle accessors - bool hasValue(const StatType<CountAccumulator>& stat); - F64 getSum(const StatType<CountAccumulator>& stat); - template <typename T> - typename RelatedTypes<T>::sum_t getSum(const CountStatHandle<T>& stat) - { - return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const StatType<CountAccumulator>&> (stat)); - } - - F64 getPerSec(const StatType<CountAccumulator>& stat); - template <typename T> - typename RelatedTypes<T>::fractional_t getPerSec(const CountStatHandle<T>& stat) - { - return (typename RelatedTypes<T>::fractional_t)getPerSec(static_cast<const StatType<CountAccumulator>&> (stat)); - } - - S32 getSampleCount(const StatType<CountAccumulator>& stat); - - - // SampleStatHandle accessors - bool hasValue(const StatType<SampleAccumulator>& stat); - - F64 getMin(const StatType<SampleAccumulator>& stat); - template <typename T> - T getMin(const SampleStatHandle<T>& stat) - { - return (T)getMin(static_cast<const StatType<SampleAccumulator>&> (stat)); - } - - F64 getMax(const StatType<SampleAccumulator>& stat); - template <typename T> - T getMax(const SampleStatHandle<T>& stat) - { - return (T)getMax(static_cast<const StatType<SampleAccumulator>&> (stat)); - } - - F64 getMean(const StatType<SampleAccumulator>& stat); - template <typename T> - typename RelatedTypes<T>::fractional_t getMean(SampleStatHandle<T>& stat) - { - return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const StatType<SampleAccumulator>&> (stat)); - } - - F64 getStandardDeviation(const StatType<SampleAccumulator>& stat); - template <typename T> - typename RelatedTypes<T>::fractional_t getStandardDeviation(const SampleStatHandle<T>& stat) - { - return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const StatType<SampleAccumulator>&> (stat)); - } - - F64 getLastValue(const StatType<SampleAccumulator>& stat); - template <typename T> - T getLastValue(const SampleStatHandle<T>& stat) - { - return (T)getLastValue(static_cast<const StatType<SampleAccumulator>&> (stat)); - } - - S32 getSampleCount(const StatType<SampleAccumulator>& stat); - - // EventStatHandle accessors - bool hasValue(const StatType<EventAccumulator>& stat); - - F64 getSum(const StatType<EventAccumulator>& stat); - template <typename T> - typename RelatedTypes<T>::sum_t getSum(const EventStatHandle<T>& stat) - { - return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const StatType<EventAccumulator>&> (stat)); - } - - F64 getMin(const StatType<EventAccumulator>& stat); - template <typename T> - T getMin(const EventStatHandle<T>& stat) - { - return (T)getMin(static_cast<const StatType<EventAccumulator>&> (stat)); - } - - F64 getMax(const StatType<EventAccumulator>& stat); - template <typename T> - T getMax(const EventStatHandle<T>& stat) - { - return (T)getMax(static_cast<const StatType<EventAccumulator>&> (stat)); - } - - F64 getMean(const StatType<EventAccumulator>& stat); - template <typename T> - typename RelatedTypes<T>::fractional_t getMean(EventStatHandle<T>& stat) - { - return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const StatType<EventAccumulator>&> (stat)); - } - - F64 getStandardDeviation(const StatType<EventAccumulator>& stat); - template <typename T> - typename RelatedTypes<T>::fractional_t getStandardDeviation(const EventStatHandle<T>& stat) - { - return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const StatType<EventAccumulator>&> (stat)); - } - - F64 getLastValue(const StatType<EventAccumulator>& stat); - template <typename T> - T getLastValue(const EventStatHandle<T>& stat) - { - return (T)getLastValue(static_cast<const StatType<EventAccumulator>&> (stat)); - } - - S32 getSampleCount(const StatType<EventAccumulator>& stat); - - F64Seconds getDuration() const { return mElapsedSeconds; } - - protected: - friend class ThreadRecorder; - - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(Recording& other); - - // returns data for current thread - class ThreadRecorder* getThreadRecorder(); - - LLTimer mSamplingTimer; - F64Seconds mElapsedSeconds; - LLCopyOnWritePointer<AccumulatorBufferGroup> mBuffers; - AccumulatorBufferGroup* mActiveBuffers; - - }; - - class LL_COMMON_API PeriodicRecording - : public LLStopWatchControlsMixin<PeriodicRecording> - { - public: - PeriodicRecording(size_t num_periods, EPlayState state = STOPPED); - ~PeriodicRecording(); - - void nextPeriod(); - auto getNumRecordedPeriods() - { - // current period counts if not active - return mNumRecordedPeriods + (isStarted() ? 0 : 1); - } - - F64Seconds getDuration() const; - - void appendPeriodicRecording(PeriodicRecording& other); - void appendRecording(Recording& recording); - Recording& getLastRecording(); - const Recording& getLastRecording() const; - Recording& getCurRecording(); - const Recording& getCurRecording() const; - Recording& getPrevRecording(size_t offset); - const Recording& getPrevRecording(size_t offset) const; - Recording snapshotCurRecording() const; - - template <typename T> - auto getSampleCount(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - size_t num_samples = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - num_samples += recording.getSampleCount(stat); - } - return num_samples; - } - - // - // PERIODIC MIN - // - - // catch all for stats that have a defined sum - template <typename T> - typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - bool has_value = false; - typename T::value_t min_val(std::numeric_limits<typename T::value_t>::max()); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - min_val = llmin(min_val, recording.getSum(stat)); - has_value = true; - } - } - - return has_value - ? min_val - : T::getDefaultValue(); - } - - template<typename T> - T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); - } - - F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - template<typename T> - T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); - } - - F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - template<typename T> - T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); - } - - template <typename T> - typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max()); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - min_val = llmin(min_val, recording.getPerSec(stat)); - } - return (typename RelatedTypes<typename T::value_t>::fractional_t) min_val; - } - - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); - } - - // - // PERIODIC MAX - // - - // catch all for stats that have a defined sum - template <typename T> - typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - bool has_value = false; - typename T::value_t max_val(std::numeric_limits<typename T::value_t>::min()); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - max_val = llmax(max_val, recording.getSum(stat)); - has_value = true; - } - } - - return has_value - ? max_val - : T::getDefaultValue(); - } - - template<typename T> - T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); - } - - F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - template<typename T> - T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); - } - - F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - template<typename T> - T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); - } - - template <typename T> - typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - F64 max_val = std::numeric_limits<F64>::min(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - max_val = llmax(max_val, recording.getPerSec(stat)); - } - return (typename RelatedTypes<typename T::value_t>::fractional_t)max_val; - } - - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); - } - - // - // PERIODIC MEAN - // - - // catch all for stats that have a defined sum - template <typename T> - typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - typename RelatedTypes<typename T::value_t>::fractional_t mean(0); - - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - mean += recording.getSum(stat); - } - } - return (num_periods - ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) - : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); - } - - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); - } - F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); - } - - F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); - } - - template <typename T> - typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - typename RelatedTypes<typename T::value_t>::fractional_t mean = 0; - - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - mean += recording.getPerSec(stat); - } - } - - return (num_periods - ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) - : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); - } - - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); - } - - F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - - template <typename T> - typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - buf.push_back(recording.getPerSec(stat)); - } - } - std::sort(buf.begin(), buf.end()); - - return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); - } - - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); - } - - // - // PERIODIC STANDARD DEVIATION - // - - F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); - } - - F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); - template<typename T> - typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); - } - - private: - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(PeriodicRecording& other); - - // helper methods for wraparound ring-buffer arithmetic - inline - size_t wrapi(size_t i) const - { - return i % mRecordingPeriods.size(); - } - - inline - size_t nexti(size_t i, size_t offset=1) const - { - return wrapi(i + offset); - } - - inline - size_t previ(size_t i, size_t offset=1) const - { - auto num_periods = mRecordingPeriods.size(); - // constrain offset - offset = llclamp(offset, 0, num_periods - 1); - // add size() so expression can't go (unsigned) "negative" - return wrapi(i + num_periods - offset); - } - - inline - void inci(size_t& i, size_t offset=1) const - { - i = nexti(i, offset); - } - - private: - std::vector<Recording> mRecordingPeriods; - const bool mAutoResize; - size_t mCurPeriod; - size_t mNumRecordedPeriods; - }; - - PeriodicRecording& get_frame_recording(); - - class ExtendableRecording - : public LLStopWatchControlsMixin<ExtendableRecording> - { - public: - void extend(); - - Recording& getAcceptedRecording() { return mAcceptedRecording; } - const Recording& getAcceptedRecording() const {return mAcceptedRecording;} - - Recording& getPotentialRecording() { return mPotentialRecording; } - const Recording& getPotentialRecording() const { return mPotentialRecording;} - - private: - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(ExtendableRecording& other); - - private: - Recording mAcceptedRecording; - Recording mPotentialRecording; - }; - - class ExtendablePeriodicRecording - : public LLStopWatchControlsMixin<ExtendablePeriodicRecording> - { - public: - ExtendablePeriodicRecording(); - void extend(); - - PeriodicRecording& getResults() { return mAcceptedRecording; } - const PeriodicRecording& getResults() const {return mAcceptedRecording;} - - void nextPeriod() { mPotentialRecording.nextPeriod(); } - - private: - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other); - - private: - PeriodicRecording mAcceptedRecording; - PeriodicRecording mPotentialRecording; - }; + template<typename T> + class StatType; + + template<typename T> + class CountStatHandle; + + template<typename T> + class SampleStatHandle; + + template<typename T> + class EventStatHandle; + + template<typename T> + struct RelatedTypes + { + typedef F64 fractional_t; + typedef T sum_t; + }; + + template<typename T, typename UNIT_T> + struct RelatedTypes<LLUnit<T, UNIT_T> > + { + typedef LLUnit<typename RelatedTypes<T>::fractional_t, UNIT_T> fractional_t; + typedef LLUnit<typename RelatedTypes<T>::sum_t, UNIT_T> sum_t; + }; + + template<> + struct RelatedTypes<bool> + { + typedef F64 fractional_t; + typedef S32 sum_t; + }; + + class Recording + : public LLStopWatchControlsMixin<Recording> + { + public: + Recording(EPlayState state = LLStopWatchControlsMixinCommon::STOPPED); + + Recording(const Recording& other); + ~Recording(); + + Recording& operator = (const Recording& other); + + // accumulate data from subsequent, non-overlapping recording + void appendRecording(Recording& other); + + // grab latest recorded data + void update(); + + // ensure that buffers are exclusively owned by this recording + void makeUnique() { mBuffers.makeUnique(); } + + // Timer accessors + bool hasValue(const StatType<TimeBlockAccumulator>& stat); + F64Seconds getSum(const StatType<TimeBlockAccumulator>& stat); + F64Seconds getSum(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat); + S32 getSum(const StatType<TimeBlockAccumulator::CallCountFacet>& stat); + + F64Seconds getPerSec(const StatType<TimeBlockAccumulator>& stat); + F64Seconds getPerSec(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat); + F32 getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& stat); + + // CountStatHandle accessors + bool hasValue(const StatType<CountAccumulator>& stat); + F64 getSum(const StatType<CountAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::sum_t getSum(const CountStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const StatType<CountAccumulator>&> (stat)); + } + + F64 getPerSec(const StatType<CountAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getPerSec(const CountStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getPerSec(static_cast<const StatType<CountAccumulator>&> (stat)); + } + + S32 getSampleCount(const StatType<CountAccumulator>& stat); + + + // SampleStatHandle accessors + bool hasValue(const StatType<SampleAccumulator>& stat); + + F64 getMin(const StatType<SampleAccumulator>& stat); + template <typename T> + T getMin(const SampleStatHandle<T>& stat) + { + return (T)getMin(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getMax(const StatType<SampleAccumulator>& stat); + template <typename T> + T getMax(const SampleStatHandle<T>& stat) + { + return (T)getMax(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getMean(const StatType<SampleAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getMean(SampleStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const StatType<SampleAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getStandardDeviation(const SampleStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getLastValue(const StatType<SampleAccumulator>& stat); + template <typename T> + T getLastValue(const SampleStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + S32 getSampleCount(const StatType<SampleAccumulator>& stat); + + // EventStatHandle accessors + bool hasValue(const StatType<EventAccumulator>& stat); + + F64 getSum(const StatType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::sum_t getSum(const EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getMin(const StatType<EventAccumulator>& stat); + template <typename T> + T getMin(const EventStatHandle<T>& stat) + { + return (T)getMin(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getMax(const StatType<EventAccumulator>& stat); + template <typename T> + T getMax(const EventStatHandle<T>& stat) + { + return (T)getMax(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getMean(const StatType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getMean(EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const StatType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getStandardDeviation(const EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getLastValue(const StatType<EventAccumulator>& stat); + template <typename T> + T getLastValue(const EventStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + S32 getSampleCount(const StatType<EventAccumulator>& stat); + + F64Seconds getDuration() const { return mElapsedSeconds; } + + protected: + friend class ThreadRecorder; + + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(Recording& other); + + // returns data for current thread + class ThreadRecorder* getThreadRecorder(); + + LLTimer mSamplingTimer; + F64Seconds mElapsedSeconds; + LLCopyOnWritePointer<AccumulatorBufferGroup> mBuffers; + AccumulatorBufferGroup* mActiveBuffers; + + }; + + class LL_COMMON_API PeriodicRecording + : public LLStopWatchControlsMixin<PeriodicRecording> + { + public: + PeriodicRecording(size_t num_periods, EPlayState state = STOPPED); + ~PeriodicRecording(); + + void nextPeriod(); + auto getNumRecordedPeriods() + { + // current period counts if not active + return mNumRecordedPeriods + (isStarted() ? 0 : 1); + } + + F64Seconds getDuration() const; + + void appendPeriodicRecording(PeriodicRecording& other); + void appendRecording(Recording& recording); + Recording& getLastRecording(); + const Recording& getLastRecording() const; + Recording& getCurRecording(); + const Recording& getCurRecording() const; + Recording& getPrevRecording(size_t offset); + const Recording& getPrevRecording(size_t offset) const; + Recording snapshotCurRecording() const; + + template <typename T> + auto getSampleCount(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + size_t num_samples = 0; + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + num_samples += recording.getSampleCount(stat); + } + return num_samples; + } + + // + // PERIODIC MIN + // + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + typename T::value_t min_val(std::numeric_limits<typename T::value_t>::max()); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getSum(stat)); + has_value = true; + } + } + + return has_value + ? min_val + : T::getDefaultValue(); + } + + template<typename T> + T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMin(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + template<typename T> + T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMin(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + template<typename T> + T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max()); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + min_val = llmin(min_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes<typename T::value_t>::fractional_t) min_val; + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC MAX + // + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + typename T::value_t max_val(std::numeric_limits<typename T::value_t>::min()); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getSum(stat)); + has_value = true; + } + } + + return has_value + ? max_val + : T::getDefaultValue(); + } + + template<typename T> + T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + template<typename T> + T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMax(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + template<typename T> + T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64 max_val = std::numeric_limits<F64>::min(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + max_val = llmax(max_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes<typename T::value_t>::fractional_t)max_val; + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC MEAN + // + + // catch all for stats that have a defined sum + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes<typename T::value_t>::fractional_t mean(0); + + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getSum(stat); + } + } + return (num_periods + ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) + : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMean(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes<typename T::value_t>::fractional_t mean = 0; + + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getPerSec(stat); + } + } + + return (num_periods + ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) + : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf; + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + buf.push_back(recording.getPerSec(stat)); + } + } + std::sort(buf.begin(), buf.end()); + + return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC STANDARD DEVIATION + // + + F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max()); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(PeriodicRecording& other); + + // helper methods for wraparound ring-buffer arithmetic + inline + size_t wrapi(size_t i) const + { + return i % mRecordingPeriods.size(); + } + + inline + size_t nexti(size_t i, size_t offset=1) const + { + return wrapi(i + offset); + } + + inline + size_t previ(size_t i, size_t offset=1) const + { + auto num_periods = mRecordingPeriods.size(); + // constrain offset + offset = llclamp(offset, 0, num_periods - 1); + // add size() so expression can't go (unsigned) "negative" + return wrapi(i + num_periods - offset); + } + + inline + void inci(size_t& i, size_t offset=1) const + { + i = nexti(i, offset); + } + + private: + std::vector<Recording> mRecordingPeriods; + const bool mAutoResize; + size_t mCurPeriod; + size_t mNumRecordedPeriods; + }; + + PeriodicRecording& get_frame_recording(); + + class ExtendableRecording + : public LLStopWatchControlsMixin<ExtendableRecording> + { + public: + void extend(); + + Recording& getAcceptedRecording() { return mAcceptedRecording; } + const Recording& getAcceptedRecording() const {return mAcceptedRecording;} + + Recording& getPotentialRecording() { return mPotentialRecording; } + const Recording& getPotentialRecording() const { return mPotentialRecording;} + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendableRecording& other); + + private: + Recording mAcceptedRecording; + Recording mPotentialRecording; + }; + + class ExtendablePeriodicRecording + : public LLStopWatchControlsMixin<ExtendablePeriodicRecording> + { + public: + ExtendablePeriodicRecording(); + void extend(); + + PeriodicRecording& getResults() { return mAcceptedRecording; } + const PeriodicRecording& getResults() const {return mAcceptedRecording;} + + void nextPeriod() { mPotentialRecording.nextPeriod(); } + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other); + + private: + PeriodicRecording mAcceptedRecording; + PeriodicRecording mPotentialRecording; + }; } #endif // LL_LLTRACERECORDING_H diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 914bfb55dc..be3e585ef8 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltracethreadrecorder.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,203 +41,203 @@ static ThreadRecorder* sMasterThreadRecorder = NULL; /////////////////////////////////////////////////////////////////////// ThreadRecorder::ThreadRecorder() -: mParentRecorder(NULL) +: mParentRecorder(NULL) { - init(); + init(); } void ThreadRecorder::init() { #if LL_TRACE_ENABLED - LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(&mBlockTimerStackRecord); - //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies - set_thread_recorder(this); - BlockTimerStatHandle& root_time_block = BlockTimer::getRootTimeBlock(); + LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(&mBlockTimerStackRecord); + //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies + set_thread_recorder(this); + BlockTimerStatHandle& root_time_block = BlockTimer::getRootTimeBlock(); - BlockTimerStackRecord* timer_stack = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); - timer_stack->mTimeBlock = &root_time_block; - timer_stack->mActiveTimer = NULL; + BlockTimerStackRecord* timer_stack = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + timer_stack->mTimeBlock = &root_time_block; + timer_stack->mActiveTimer = NULL; - mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size(); + mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size(); - mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; + mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; - activate(&mThreadRecordingBuffers); + activate(&mThreadRecordingBuffers); - // initialize time block parent pointers - for (auto& base : BlockTimerStatHandle::instance_snapshot()) - { - // because of indirect derivation from LLInstanceTracker, have to downcast - BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(base); - TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[time_block.getIndex()]; - tree_node.mBlock = &time_block; - tree_node.mParent = &root_time_block; + // initialize time block parent pointers + for (auto& base : BlockTimerStatHandle::instance_snapshot()) + { + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(base); + TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[time_block.getIndex()]; + tree_node.mBlock = &time_block; + tree_node.mParent = &root_time_block; - time_block.getCurrentAccumulator().mParent = &root_time_block; - } + time_block.getCurrentAccumulator().mParent = &root_time_block; + } - mRootTimer = new BlockTimer(root_time_block); - timer_stack->mActiveTimer = mRootTimer; + mRootTimer = new BlockTimer(root_time_block); + timer_stack->mActiveTimer = mRootTimer; - BlockTimer::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1; + BlockTimer::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1; - //claim_alloc(gTraceMemStat, this); - //claim_alloc(gTraceMemStat, mRootTimer); - //claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); + //claim_alloc(gTraceMemStat, this); + //claim_alloc(gTraceMemStat, mRootTimer); + //claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); #endif } ThreadRecorder::ThreadRecorder( ThreadRecorder& parent ) -: mParentRecorder(&parent) +: mParentRecorder(&parent) { - init(); - mParentRecorder->addChildRecorder(this); + init(); + mParentRecorder->addChildRecorder(this); } ThreadRecorder::~ThreadRecorder() { #if LL_TRACE_ENABLED - LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(NULL); + LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(NULL); - //disclaim_alloc(gTraceMemStat, this); - //disclaim_alloc(gTraceMemStat, sizeof(BlockTimer)); - //disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); + //disclaim_alloc(gTraceMemStat, this); + //disclaim_alloc(gTraceMemStat, sizeof(BlockTimer)); + //disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); - deactivate(&mThreadRecordingBuffers); + deactivate(&mThreadRecordingBuffers); - delete mRootTimer; + delete mRootTimer; - if (!mActiveRecordings.empty()) - { - std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer()); - mActiveRecordings.clear(); - } + if (!mActiveRecordings.empty()) + { + std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer()); + mActiveRecordings.clear(); + } - set_thread_recorder(NULL); - delete[] mTimeBlockTreeNodes; + set_thread_recorder(NULL); + delete[] mTimeBlockTreeNodes; - if (mParentRecorder) - { - mParentRecorder->removeChildRecorder(this); - } + if (mParentRecorder) + { + mParentRecorder->removeChildRecorder(this); + } #endif } TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode( size_t index ) { #if LL_TRACE_ENABLED - if (0 <= index && index < mNumTimeBlockTreeNodes) - { - return &mTimeBlockTreeNodes[index]; - } + if (0 <= index && index < mNumTimeBlockTreeNodes) + { + return &mTimeBlockTreeNodes[index]; + } #endif - return NULL; + return NULL; } AccumulatorBufferGroup* ThreadRecorder::activate( AccumulatorBufferGroup* recording) { #if LL_TRACE_ENABLED - ActiveRecording* active_recording = new ActiveRecording(recording); - if (!mActiveRecordings.empty()) - { - AccumulatorBufferGroup& prev_active_recording = mActiveRecordings.back()->mPartialRecording; - prev_active_recording.sync(); - BlockTimer::updateTimes(); - prev_active_recording.handOffTo(active_recording->mPartialRecording); - } - mActiveRecordings.push_back(active_recording); - - mActiveRecordings.back()->mPartialRecording.makeCurrent(); - return &active_recording->mPartialRecording; + ActiveRecording* active_recording = new ActiveRecording(recording); + if (!mActiveRecordings.empty()) + { + AccumulatorBufferGroup& prev_active_recording = mActiveRecordings.back()->mPartialRecording; + prev_active_recording.sync(); + BlockTimer::updateTimes(); + prev_active_recording.handOffTo(active_recording->mPartialRecording); + } + mActiveRecordings.push_back(active_recording); + + mActiveRecordings.back()->mPartialRecording.makeCurrent(); + return &active_recording->mPartialRecording; #else - return NULL; + return NULL; #endif } ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::bringUpToDate( AccumulatorBufferGroup* recording ) { #if LL_TRACE_ENABLED - if (mActiveRecordings.empty()) return mActiveRecordings.end(); - - mActiveRecordings.back()->mPartialRecording.sync(); - BlockTimer::updateTimes(); - - active_recording_list_t::reverse_iterator it, end_it; - for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); - it != end_it; - ++it) - { - ActiveRecording* cur_recording = *it; - - active_recording_list_t::reverse_iterator next_it = it; - ++next_it; - - // if we have another recording further down in the stack... - if (next_it != mActiveRecordings.rend()) - { - // ...push our gathered data down to it - (*next_it)->mPartialRecording.append(cur_recording->mPartialRecording); - } - - // copy accumulated measurements into result buffer and clear accumulator (mPartialRecording) - cur_recording->movePartialToTarget(); - - if (cur_recording->mTargetRecording == recording) - { - // found the recording, so return it - break; - } - } - - if (it == end_it) - { - LL_WARNS() << "Recording not active on this thread" << LL_ENDL; - } - - return (++it).base(); + if (mActiveRecordings.empty()) return mActiveRecordings.end(); + + mActiveRecordings.back()->mPartialRecording.sync(); + BlockTimer::updateTimes(); + + active_recording_list_t::reverse_iterator it, end_it; + for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); + it != end_it; + ++it) + { + ActiveRecording* cur_recording = *it; + + active_recording_list_t::reverse_iterator next_it = it; + ++next_it; + + // if we have another recording further down in the stack... + if (next_it != mActiveRecordings.rend()) + { + // ...push our gathered data down to it + (*next_it)->mPartialRecording.append(cur_recording->mPartialRecording); + } + + // copy accumulated measurements into result buffer and clear accumulator (mPartialRecording) + cur_recording->movePartialToTarget(); + + if (cur_recording->mTargetRecording == recording) + { + // found the recording, so return it + break; + } + } + + if (it == end_it) + { + LL_WARNS() << "Recording not active on this thread" << LL_ENDL; + } + + return (++it).base(); #else - return ThreadRecorder::active_recording_list_t::iterator(); + return ThreadRecorder::active_recording_list_t::iterator(); #endif } void ThreadRecorder::deactivate( AccumulatorBufferGroup* recording ) { #if LL_TRACE_ENABLED - active_recording_list_t::iterator recording_it = bringUpToDate(recording); - // this method should only be called on a thread where the recorder is active - llassert_always(recording_it != mActiveRecordings.end()); - - ActiveRecording* recording_to_remove = *recording_it; - bool was_current = recording_to_remove->mPartialRecording.isCurrent(); - llassert(recording_to_remove->mTargetRecording == recording); - mActiveRecordings.erase(recording_it); - if (was_current) - { - if (mActiveRecordings.empty()) - { - AccumulatorBufferGroup::clearCurrent(); - } - else - { - mActiveRecordings.back()->mPartialRecording.makeCurrent(); - } - } - delete recording_to_remove; + active_recording_list_t::iterator recording_it = bringUpToDate(recording); + // this method should only be called on a thread where the recorder is active + llassert_always(recording_it != mActiveRecordings.end()); + + ActiveRecording* recording_to_remove = *recording_it; + bool was_current = recording_to_remove->mPartialRecording.isCurrent(); + llassert(recording_to_remove->mTargetRecording == recording); + mActiveRecordings.erase(recording_it); + if (was_current) + { + if (mActiveRecordings.empty()) + { + AccumulatorBufferGroup::clearCurrent(); + } + else + { + mActiveRecordings.back()->mPartialRecording.makeCurrent(); + } + } + delete recording_to_remove; #endif } -ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target ) -: mTargetRecording(target) +ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target ) +: mTargetRecording(target) {} void ThreadRecorder::ActiveRecording::movePartialToTarget() { #if LL_TRACE_ENABLED - mTargetRecording->append(mPartialRecording); - // reset based on self to keep history - mPartialRecording.reset(&mPartialRecording); + mTargetRecording->append(mPartialRecording); + // reset based on self to keep history + mPartialRecording.reset(&mPartialRecording); #endif } @@ -246,30 +246,30 @@ void ThreadRecorder::ActiveRecording::movePartialToTarget() void ThreadRecorder::addChildRecorder( class ThreadRecorder* child ) { #if LL_TRACE_ENABLED - { LLMutexLock lock(&mChildListMutex); - mChildThreadRecorders.push_back(child); - } + { LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.push_back(child); + } #endif } // called by child thread void ThreadRecorder::removeChildRecorder( class ThreadRecorder* child ) -{ +{ #if LL_TRACE_ENABLED - { LLMutexLock lock(&mChildListMutex); - mChildThreadRecorders.remove(child); - } + { LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.remove(child); + } #endif } void ThreadRecorder::pushToParent() { #if LL_TRACE_ENABLED - { LLMutexLock lock(&mSharedRecordingMutex); - LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers); - mSharedRecordingBuffers.append(mThreadRecordingBuffers); - mThreadRecordingBuffers.reset(); - } + { LLMutexLock lock(&mSharedRecordingMutex); + LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers); + mSharedRecordingBuffers.append(mThreadRecordingBuffers); + mThreadRecordingBuffers.reset(); + } #endif } @@ -278,48 +278,48 @@ void ThreadRecorder::pullFromChildren() { #if LL_TRACE_ENABLED LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (mActiveRecordings.empty()) return; + if (mActiveRecordings.empty()) return; - { LLMutexLock lock(&mChildListMutex); + { LLMutexLock lock(&mChildListMutex); - AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; - target_recording_buffers.sync(); - for (LLTrace::ThreadRecorder* rec : mChildThreadRecorders) - { LLMutexLock lock(&(rec->mSharedRecordingMutex)); + AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; + target_recording_buffers.sync(); + for (LLTrace::ThreadRecorder* rec : mChildThreadRecorders) + { LLMutexLock lock(&(rec->mSharedRecordingMutex)); - target_recording_buffers.merge(rec->mSharedRecordingBuffers); - rec->mSharedRecordingBuffers.reset(); - } - } + target_recording_buffers.merge(rec->mSharedRecordingBuffers); + rec->mSharedRecordingBuffers.reset(); + } + } #endif } void set_master_thread_recorder( ThreadRecorder* recorder ) { - sMasterThreadRecorder = recorder; + sMasterThreadRecorder = recorder; } ThreadRecorder* get_master_thread_recorder() { - return sMasterThreadRecorder; + return sMasterThreadRecorder; } ThreadRecorder*& get_thread_recorder_ptr() { - static thread_local ThreadRecorder* s_thread_recorder; - return s_thread_recorder; + static thread_local ThreadRecorder* s_thread_recorder; + return s_thread_recorder; } ThreadRecorder* get_thread_recorder() { - return get_thread_recorder_ptr(); + return get_thread_recorder_ptr(); } void set_thread_recorder( ThreadRecorder* recorder ) { - get_thread_recorder_ptr() = recorder; + get_thread_recorder_ptr() = recorder; } } diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h index 8ee6729ac6..e3eadfb0bd 100644 --- a/indra/llcommon/lltracethreadrecorder.h +++ b/indra/llcommon/lltracethreadrecorder.h @@ -1,25 +1,25 @@ -/** +/** * @file lltrace.h * @brief Runtime statistics accumulation. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,67 +35,67 @@ namespace LLTrace { - class LL_COMMON_API ThreadRecorder - { - protected: - struct ActiveRecording; - typedef std::vector<ActiveRecording*> active_recording_list_t; - public: - ThreadRecorder(); - explicit ThreadRecorder(ThreadRecorder& parent); + class LL_COMMON_API ThreadRecorder + { + protected: + struct ActiveRecording; + typedef std::vector<ActiveRecording*> active_recording_list_t; + public: + ThreadRecorder(); + explicit ThreadRecorder(ThreadRecorder& parent); - ~ThreadRecorder(); + ~ThreadRecorder(); - AccumulatorBufferGroup* activate(AccumulatorBufferGroup* recording); - void deactivate(AccumulatorBufferGroup* recording); - active_recording_list_t::iterator bringUpToDate(AccumulatorBufferGroup* recording); + AccumulatorBufferGroup* activate(AccumulatorBufferGroup* recording); + void deactivate(AccumulatorBufferGroup* recording); + active_recording_list_t::iterator bringUpToDate(AccumulatorBufferGroup* recording); - void addChildRecorder(class ThreadRecorder* child); - void removeChildRecorder(class ThreadRecorder* child); + void addChildRecorder(class ThreadRecorder* child); + void removeChildRecorder(class ThreadRecorder* child); - // call this periodically to gather stats data from child threads - void pullFromChildren(); - void pushToParent(); + // call this periodically to gather stats data from child threads + void pullFromChildren(); + void pushToParent(); - TimeBlockTreeNode* getTimeBlockTreeNode(size_t index); + TimeBlockTreeNode* getTimeBlockTreeNode(size_t index); - protected: - void init(); + protected: + void init(); - protected: - struct ActiveRecording - { - ActiveRecording(AccumulatorBufferGroup* target); + protected: + struct ActiveRecording + { + ActiveRecording(AccumulatorBufferGroup* target); - AccumulatorBufferGroup* mTargetRecording; - AccumulatorBufferGroup mPartialRecording; + AccumulatorBufferGroup* mTargetRecording; + AccumulatorBufferGroup mPartialRecording; - void movePartialToTarget(); - }; + void movePartialToTarget(); + }; - AccumulatorBufferGroup mThreadRecordingBuffers; + AccumulatorBufferGroup mThreadRecordingBuffers; - BlockTimerStackRecord mBlockTimerStackRecord; - active_recording_list_t mActiveRecordings; + BlockTimerStackRecord mBlockTimerStackRecord; + active_recording_list_t mActiveRecordings; - class BlockTimer* mRootTimer; - TimeBlockTreeNode* mTimeBlockTreeNodes; - size_t mNumTimeBlockTreeNodes; - typedef std::list<class ThreadRecorder*> child_thread_recorder_list_t; + class BlockTimer* mRootTimer; + TimeBlockTreeNode* mTimeBlockTreeNodes; + size_t mNumTimeBlockTreeNodes; + typedef std::list<class ThreadRecorder*> child_thread_recorder_list_t; - child_thread_recorder_list_t mChildThreadRecorders; // list of child thread recorders associated with this master - LLMutex mChildListMutex; // protects access to child list - LLMutex mSharedRecordingMutex; - AccumulatorBufferGroup mSharedRecordingBuffers; - ThreadRecorder* mParentRecorder; + child_thread_recorder_list_t mChildThreadRecorders; // list of child thread recorders associated with this master + LLMutex mChildListMutex; // protects access to child list + LLMutex mSharedRecordingMutex; + AccumulatorBufferGroup mSharedRecordingBuffers; + ThreadRecorder* mParentRecorder; - }; + }; - ThreadRecorder* get_thread_recorder(); - void set_thread_recorder(ThreadRecorder*); + ThreadRecorder* get_thread_recorder(); + void set_thread_recorder(ThreadRecorder*); - void set_master_thread_recorder(ThreadRecorder*); - ThreadRecorder* get_master_thread_recorder(); + void set_master_thread_recorder(ThreadRecorder*); + ThreadRecorder* get_master_thread_recorder(); } #endif // LL_LLTRACETHREADRECORDER_H diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h index ba861ae70b..cef501b987 100644 --- a/indra/llcommon/lltreeiterators.h +++ b/indra/llcommon/lltreeiterators.h @@ -33,25 +33,25 @@ * child of its own. Child nodes with multiple parents will be visited * once for each parent. Cycles in the graph will result in either an * infinite loop or an out-of-memory crash. You Have Been Warned. - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -338,9 +338,9 @@ public: /// functors to extract the 'child begin' and 'child end' iterators from /// each node. LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc) - : mBeginFunc(beginfunc), - mEndFunc(endfunc), - mSkipChildren(false) + : mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipChildren(false) { // Only push back this node if it's non-NULL! if (node) @@ -364,13 +364,13 @@ private: ptr_type current = mPending.back(); // Remove it from mPending so we don't process it again later mPending.pop_back(); - if (!mSkipChildren) - { - // Add all its children to mPending - addChildren(current); - } - // reset flag after each step - mSkipChildren = false; + if (!mSkipChildren) + { + // Add all its children to mPending + addChildren(current); + } + // reset flag after each step + mSkipChildren = false; } /// equality bool equal(const self_type& that) const { return this->mPending == that.mPending; } @@ -400,7 +400,7 @@ private: /// functor to extract end() child iterator func_type mEndFunc; /// flag which controls traversal of children (skip children of current node if true) - bool mSkipChildren; + bool mSkipChildren; }; /** @@ -446,10 +446,10 @@ public: /// functors to extract the 'child begin' and 'child end' iterators from /// each node. LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc) - : mBeginFunc(beginfunc), - mEndFunc(endfunc), - mSkipAncestors(false) - { + : mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipAncestors(false) + { if (! node) return; mPending.push_back(typename list_type::value_type(node, false)); @@ -478,24 +478,24 @@ private: /// implement dereference/indirection operators ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); } - struct isOpen - { - bool operator()(const typename list_type::value_type& item) - { - return item.second; - } - }; + struct isOpen + { + bool operator()(const typename list_type::value_type& item) + { + return item.second; + } + }; /// Call this each time we change mPending.back() -- that is, every time /// we're about to change the value returned by dereference(). If we /// haven't yet pushed the new node's children, do so now. void makeCurrent() { - if (mSkipAncestors) - { - mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end()); - mSkipAncestors = false; - } + if (mSkipAncestors) + { + mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end()); + mSkipAncestors = false; + } // Once we've popped the last node, this becomes a no-op. if (mPending.empty()) @@ -536,13 +536,13 @@ private: } /// list of the nodes yet to be processed - list_type mPending; + list_type mPending; /// functor to extract begin() child iterator - func_type mBeginFunc; + func_type mBeginFunc; /// functor to extract end() child iterator - func_type mEndFunc; - /// flags logic to skip traversal of ancestors of current node - bool mSkipAncestors; + func_type mEndFunc; + /// flags logic to skip traversal of ancestors of current node + bool mSkipAncestors; }; /** diff --git a/indra/llcommon/llunits.h b/indra/llcommon/llunits.h index 0fcb8281a0..122d4557bf 100644 --- a/indra/llcommon/llunits.h +++ b/indra/llcommon/llunits.h @@ -1,25 +1,25 @@ -/** +/** * @file llunits.h * @brief Unit definitions * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,10 +51,10 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabytes); namespace LLUnits { // technically, these are kibibits, mibibits, etc. but we should stick with commonly accepted terminology -LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, * 8 ); -LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bits, / 1024); -LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, / 1024); -LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, / 1024); +LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, * 8 ); +LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bits, / 1024); +LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, / 1024); +LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, / 1024); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bits); @@ -65,12 +65,12 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabits); namespace LLUnits { LL_DECLARE_BASE_UNIT(Seconds, "s"); -LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, / 60); -LL_DECLARE_DERIVED_UNIT(Hours, "h", Minutes, / 60); -LL_DECLARE_DERIVED_UNIT(Days, "d", Hours, / 24); -LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, * 1000); -LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, * 1000); -LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, / 60); +LL_DECLARE_DERIVED_UNIT(Hours, "h", Minutes, / 60); +LL_DECLARE_DERIVED_UNIT(Days, "d", Hours, / 24); +LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Seconds); @@ -84,9 +84,9 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Nanoseconds); namespace LLUnits { LL_DECLARE_BASE_UNIT(Meters, "m"); -LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, / 1000); -LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, * 100); -LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, * 1000); +LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, / 1000); +LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, * 100); +LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Meters); diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h index 81f244e422..83ce0d05a8 100644 --- a/indra/llcommon/llunittype.h +++ b/indra/llcommon/llunittype.h @@ -1,25 +1,25 @@ -/** +/** * @file llunit.h * @brief Unit conversion classes * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,122 +32,122 @@ #include "llerror.h" //lightweight replacement of type traits for simple type equality check -template<typename S, typename T> +template<typename S, typename T> struct LLIsSameType { - static const bool value = false; + static const bool value = false; }; template<typename T> struct LLIsSameType<T, T> { - static const bool value = true; + static const bool value = true; }; // workaround for decltype() not existing and typeof() not working inline in gcc 4.2 template<typename S, typename T> struct LLResultTypeAdd { - typedef LL_TYPEOF(S() + T()) type_t; + typedef LL_TYPEOF(S() + T()) type_t; }; template<typename S, typename T> struct LLResultTypeSubtract { - typedef LL_TYPEOF(S() - T()) type_t; + typedef LL_TYPEOF(S() - T()) type_t; }; template<typename S, typename T> struct LLResultTypeMultiply { - typedef LL_TYPEOF(S() * T()) type_t; + typedef LL_TYPEOF(S() * T()) type_t; }; template<typename S, typename T> struct LLResultTypeDivide { - typedef LL_TYPEOF(S() / T(1)) type_t; + typedef LL_TYPEOF(S() / T(1)) type_t; }; template<typename S, typename T> struct LLResultTypePromote { - typedef LL_TYPEOF((true) ? S() : T()) type_t; + typedef LL_TYPEOF((true) ? S() : T()) type_t; }; template<typename STORAGE_TYPE, typename UNITS> struct LLUnit { - typedef LLUnit<STORAGE_TYPE, UNITS> self_t; - typedef STORAGE_TYPE storage_t; - typedef void is_unit_t; - - // value initialization - LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) - : mValue(value) - {} - - - LL_FORCE_INLINE static self_t convert(self_t v) - { - return v; - } - - template<typename FROM_STORAGE_TYPE> - LL_FORCE_INLINE static self_t convert(LLUnit<FROM_STORAGE_TYPE, UNITS> v) - { - self_t result; - result.mValue = (STORAGE_TYPE)v.value(); - return result; - } - - template<typename FROM_UNITS> - LL_FORCE_INLINE static self_t convert(LLUnit<STORAGE_TYPE, FROM_UNITS> v) - { - self_t result; - STORAGE_TYPE divisor = ll_convert_units(v, result); - result.mValue /= divisor; - return result; - } - - template<typename FROM_STORAGE_TYPE, typename FROM_UNITS> - LL_FORCE_INLINE static self_t convert(LLUnit<FROM_STORAGE_TYPE, FROM_UNITS> v) - { - typedef typename LLResultTypePromote<FROM_STORAGE_TYPE, STORAGE_TYPE>::type_t result_storage_t; - LLUnit<result_storage_t, UNITS> result; - result_storage_t divisor = ll_convert_units(v, result); - result.value(result.value() / divisor); - return self_t(result.value()); - } - - - // unit initialization and conversion - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE LLUnit(LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) - : mValue(convert(other).mValue) - {} - - LL_FORCE_INLINE storage_t value() const - { - return mValue; - } - - LL_FORCE_INLINE void value(const storage_t& value) - { - mValue = value; - } - - template<typename NEW_UNITS> - storage_t valueInUnits() const - { - return LLUnit<storage_t, NEW_UNITS>(*this).value(); - } - - template<typename NEW_UNITS> - void valueInUnits(const storage_t& value) const - { - *this = LLUnit<storage_t, NEW_UNITS>(value); - } + typedef LLUnit<STORAGE_TYPE, UNITS> self_t; + typedef STORAGE_TYPE storage_t; + typedef void is_unit_t; + + // value initialization + LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + + LL_FORCE_INLINE static self_t convert(self_t v) + { + return v; + } + + template<typename FROM_STORAGE_TYPE> + LL_FORCE_INLINE static self_t convert(LLUnit<FROM_STORAGE_TYPE, UNITS> v) + { + self_t result; + result.mValue = (STORAGE_TYPE)v.value(); + return result; + } + + template<typename FROM_UNITS> + LL_FORCE_INLINE static self_t convert(LLUnit<STORAGE_TYPE, FROM_UNITS> v) + { + self_t result; + STORAGE_TYPE divisor = ll_convert_units(v, result); + result.mValue /= divisor; + return result; + } + + template<typename FROM_STORAGE_TYPE, typename FROM_UNITS> + LL_FORCE_INLINE static self_t convert(LLUnit<FROM_STORAGE_TYPE, FROM_UNITS> v) + { + typedef typename LLResultTypePromote<FROM_STORAGE_TYPE, STORAGE_TYPE>::type_t result_storage_t; + LLUnit<result_storage_t, UNITS> result; + result_storage_t divisor = ll_convert_units(v, result); + result.value(result.value() / divisor); + return self_t(result.value()); + } + + + // unit initialization and conversion + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE LLUnit(LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + : mValue(convert(other).mValue) + {} + + LL_FORCE_INLINE storage_t value() const + { + return mValue; + } + + LL_FORCE_INLINE void value(const storage_t& value) + { + mValue = value; + } + + template<typename NEW_UNITS> + storage_t valueInUnits() const + { + return LLUnit<storage_t, NEW_UNITS>(*this).value(); + } + + template<typename NEW_UNITS> + void valueInUnits(const storage_t& value) const + { + *this = LLUnit<storage_t, NEW_UNITS>(value); + } LL_FORCE_INLINE operator storage_t() const { @@ -155,81 +155,81 @@ struct LLUnit } /*LL_FORCE_INLINE self_t& operator= (storage_t v) - { - value(v); + { + value(v); return *this; - }*/ - - LL_FORCE_INLINE void operator += (self_t other) - { - mValue += convert(other).mValue; - } - - LL_FORCE_INLINE void operator -= (self_t other) - { - mValue -= convert(other).mValue; - } - - LL_FORCE_INLINE void operator *= (const storage_t& multiplicand) - { - mValue *= multiplicand; - } - - LL_FORCE_INLINE void operator *= (const self_t& multiplicand) - { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); - } - - LL_FORCE_INLINE void operator /= (const storage_t& divisor) - { - mValue /= divisor; - } - - void operator /= (const self_t& divisor) - { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator == (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const - { - return mValue == convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator != (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const - { - return mValue != convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator < (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const - { - return mValue < convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator <= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const - { - return mValue <= convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator > (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const - { - return mValue > convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator >= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const - { - return mValue >= convert(other).value(); - } + }*/ + + LL_FORCE_INLINE void operator += (self_t other) + { + mValue += convert(other).mValue; + } + + LL_FORCE_INLINE void operator -= (self_t other) + { + mValue -= convert(other).mValue; + } + + LL_FORCE_INLINE void operator *= (const storage_t& multiplicand) + { + mValue *= multiplicand; + } + + LL_FORCE_INLINE void operator *= (const self_t& multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); + } + + LL_FORCE_INLINE void operator /= (const storage_t& divisor) + { + mValue /= divisor; + } + + void operator /= (const self_t& divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator == (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const + { + return mValue == convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator != (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const + { + return mValue != convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator < (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const + { + return mValue < convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator <= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const + { + return mValue <= convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator > (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const + { + return mValue > convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator >= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const + { + return mValue >= convert(other).value(); + } protected: - storage_t mValue; + storage_t mValue; }; template<typename STORAGE_TYPE, typename UNITS> @@ -251,161 +251,161 @@ std::istream& operator >>(std::istream& s, LLUnit<STORAGE_TYPE, UNITS>& unit) template<typename STORAGE_TYPE, typename UNITS> struct LLUnitImplicit : public LLUnit<STORAGE_TYPE, UNITS> { - typedef LLUnitImplicit<STORAGE_TYPE, UNITS> self_t; - typedef typename LLUnit<STORAGE_TYPE, UNITS>::storage_t storage_t; - typedef LLUnit<STORAGE_TYPE, UNITS> base_t; - - LL_FORCE_INLINE LLUnitImplicit(storage_t value = storage_t()) - : base_t(value) - {} - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE LLUnitImplicit(LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) - : base_t(other) - {} - - // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) - // this allows for interoperability with legacy code - LL_FORCE_INLINE operator storage_t() const - { - return base_t::value(); - } - - using base_t::operator +=; - LL_FORCE_INLINE void operator += (storage_t value) - { + typedef LLUnitImplicit<STORAGE_TYPE, UNITS> self_t; + typedef typename LLUnit<STORAGE_TYPE, UNITS>::storage_t storage_t; + typedef LLUnit<STORAGE_TYPE, UNITS> base_t; + + LL_FORCE_INLINE LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE LLUnitImplicit(LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + : base_t(other) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) + // this allows for interoperability with legacy code + LL_FORCE_INLINE operator storage_t() const + { + return base_t::value(); + } + + using base_t::operator +=; + LL_FORCE_INLINE void operator += (storage_t value) + { base_t::mValue += value; - } + } - // this overload exists to explicitly catch use of another implicit unit - // without ambiguity between conversion to storage_t vs conversion to base_t - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE void operator += (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) - { + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE void operator += (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + { base_t::mValue += base_t::convert(other).value(); - } + } - using base_t::operator -=; - LL_FORCE_INLINE void operator -= (storage_t value) - { + using base_t::operator -=; + LL_FORCE_INLINE void operator -= (storage_t value) + { base_t::mValue -= value; - } + } - // this overload exists to explicitly catch use of another implicit unit - // without ambiguity between conversion to storage_t vs conversion to base_t - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE void operator -= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) - { + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE void operator -= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + { base_t::mValue -= base_t::convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator == (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue == base_t::convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator == (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue == base_t::convert(other).value(); - } - - template<typename STORAGE_T> - LL_FORCE_INLINE bool operator == (STORAGE_T other) const - { - return base_t::mValue == other; - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator != (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue != convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator != (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue != base_t::convert(other).value(); - } - - template<typename STORAGE_T> - LL_FORCE_INLINE bool operator != (STORAGE_T other) const - { - return base_t::mValue != other; - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator < (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue < base_t::convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator < (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue < base_t::convert(other).value(); - } - - template<typename STORAGE_T> - LL_FORCE_INLINE bool operator < (STORAGE_T other) const - { - return base_t::mValue < other; - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator <= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue <= base_t::convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator <= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue <= base_t::convert(other).value(); - } - - template<typename STORAGE_T> - LL_FORCE_INLINE bool operator <= (STORAGE_T other) const - { - return base_t::mValue <= other; - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator > (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue > base_t::convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator > (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue > base_t::convert(other).value(); - } - - template<typename STORAGE_T> - LL_FORCE_INLINE bool operator > (STORAGE_T other) const - { - return base_t::mValue > other; - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator >= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue >= base_t::convert(other).value(); - } - - template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator >= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const - { - return base_t::mValue >= base_t::convert(other).value(); - } - - template<typename STORAGE_T> - LL_FORCE_INLINE bool operator >= (STORAGE_T other) const - { - return base_t::mValue >= other; - } + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator == (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue == base_t::convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator == (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue == base_t::convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator == (STORAGE_T other) const + { + return base_t::mValue == other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator != (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue != convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator != (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue != base_t::convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator != (STORAGE_T other) const + { + return base_t::mValue != other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator < (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue < base_t::convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator < (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue < base_t::convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator < (STORAGE_T other) const + { + return base_t::mValue < other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator <= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue <= base_t::convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator <= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue <= base_t::convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator <= (STORAGE_T other) const + { + return base_t::mValue <= other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator > (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue > base_t::convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator > (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue > base_t::convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator > (STORAGE_T other) const + { + return base_t::mValue > other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator >= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue >= base_t::convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator >= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue >= base_t::convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator >= (STORAGE_T other) const + { + return base_t::mValue >= other; + } }; template<typename STORAGE_TYPE, typename UNITS> @@ -427,49 +427,49 @@ std::istream& operator >>(std::istream& s, LLUnitImplicit<STORAGE_TYPE, UNITS>& template<typename S1, typename T1, typename S2, typename T2> LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out) { - S2 divisor(1); - - LL_STATIC_ASSERT((LLIsSameType<T1, T2>::value - || !LLIsSameType<T1, typename T1::base_unit_t>::value - || !LLIsSameType<T2, typename T2::base_unit_t>::value), - "conversion requires compatible units"); - - if (LLIsSameType<T1, T2>::value) - { - // T1 and T2 same type, just assign - out.value((S2)in.value()); - } - else if (T1::sLevel > T2::sLevel) - { - // reduce T1 - LLUnit<S2, typename T1::base_unit_t> new_in; - divisor *= (S2)ll_convert_units(in, new_in); - divisor *= (S2)ll_convert_units(new_in, out); - } - else - { - // reduce T2 - LLUnit<S2, typename T2::base_unit_t> new_out; - divisor *= (S2)ll_convert_units(in, new_out); - divisor *= (S2)ll_convert_units(new_out, out); - } - return divisor; + S2 divisor(1); + + LL_STATIC_ASSERT((LLIsSameType<T1, T2>::value + || !LLIsSameType<T1, typename T1::base_unit_t>::value + || !LLIsSameType<T2, typename T2::base_unit_t>::value), + "conversion requires compatible units"); + + if (LLIsSameType<T1, T2>::value) + { + // T1 and T2 same type, just assign + out.value((S2)in.value()); + } + else if (T1::sLevel > T2::sLevel) + { + // reduce T1 + LLUnit<S2, typename T1::base_unit_t> new_in; + divisor *= (S2)ll_convert_units(in, new_in); + divisor *= (S2)ll_convert_units(new_in, out); + } + else + { + // reduce T2 + LLUnit<S2, typename T2::base_unit_t> new_out; + divisor *= (S2)ll_convert_units(in, new_out); + divisor *= (S2)ll_convert_units(new_out, out); + } + return divisor; } template<typename T> struct LLStorageType { - typedef T type_t; + typedef T type_t; }; template<typename STORAGE_TYPE, typename UNITS> struct LLStorageType<LLUnit<STORAGE_TYPE, UNITS> > { - typedef STORAGE_TYPE type_t; + typedef STORAGE_TYPE type_t; }; -// all of these operators need to perform type promotion on the storage type of the units, so they -// cannot be expressed as operations on identical types with implicit unit conversion +// all of these operators need to perform type promotion on the storage type of the units, so they +// cannot be expressed as operations on identical types with implicit unit conversion // e.g. typeof(S32Bytes(x) + F32Megabytes(y)) <==> F32Bytes // @@ -478,64 +478,64 @@ struct LLStorageType<LLUnit<STORAGE_TYPE, UNITS> > template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) { - LLUnit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result += second; - return result; + LLUnit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += second; + return result; } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> LLUnit<STORAGE_TYPE, UNITS> operator + (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit<STORAGE_TYPE, UNITS>(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> LLUnit<STORAGE_TYPE, UNITS> operator + (UNITLESS first, LLUnit<STORAGE_TYPE, UNITS> second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit<STORAGE_TYPE, UNITS>(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) { - LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result += second; - return result; + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += second; + return result; } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) { - LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result += second; - return result; + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += second; + return result; } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) { - LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result += LLUnitImplicit<STORAGE_TYPE1, UNITS1>(second); - return result; + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += LLUnitImplicit<STORAGE_TYPE1, UNITS1>(second); + return result; } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator + (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) { - LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> result(first); - result += second; - return result; + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> result(first); + result += second; + return result; } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>:: - type_t, UNITS> operator + (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNITS> second) + type_t, UNITS> operator + (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNITS> second) { - LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); - result += second; - return result; + LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result += second; + return result; } // @@ -544,63 +544,63 @@ LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<U template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) { - LLUnit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result -= second; - return result; + LLUnit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= second; + return result; } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> LLUnit<STORAGE_TYPE, UNITS> operator - (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit<STORAGE_TYPE, UNITS>(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> LLUnit<STORAGE_TYPE, UNITS> operator - (UNITLESS first, LLUnit<STORAGE_TYPE, UNITS> second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit<STORAGE_TYPE, UNITS>(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) { - LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result -= second; - return result; + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= second; + return result; } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) { - LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result -= second; - return result; + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= second; + return result; } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) { - LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); - result -= LLUnitImplicit<STORAGE_TYPE1, UNITS1>(second); - return result; + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= LLUnitImplicit<STORAGE_TYPE1, UNITS1>(second); + return result; } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator - (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) { - LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> result(first); - result -= second; - return result; + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> result(first); + result -= second; + return result; } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> operator - (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNITS> second) { - LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); - result -= second; - return result; + LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result -= second; + return result; } // @@ -609,41 +609,41 @@ LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageT template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LLUnit<STORAGE_TYPE1, UNITS1> operator * (LLUnit<STORAGE_TYPE1, UNITS1>, LLUnit<STORAGE_TYPE2, UNITS2>) { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); - return LLUnit<STORAGE_TYPE1, UNITS1>(); + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnit<STORAGE_TYPE1, UNITS1>(); } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator * (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) { - return LLUnit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() * second); + return LLUnit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() * second); } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnit<STORAGE_TYPE, UNITS> second) { - return LLUnit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); + return LLUnit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LLUnitImplicit<STORAGE_TYPE1, UNITS1> operator * (LLUnitImplicit<STORAGE_TYPE1, UNITS1>, LLUnitImplicit<STORAGE_TYPE2, UNITS2>) { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); - return LLUnitImplicit<STORAGE_TYPE1, UNITS1>(); + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit<STORAGE_TYPE1, UNITS1>(); } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator * (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) { - return LLUnitImplicit<typename LLResultTypeMultiply<STORAGE_TYPE, UNITLESS_TYPE>::type_t, UNITS>(first.value() * second); + return LLUnitImplicit<typename LLResultTypeMultiply<STORAGE_TYPE, UNITLESS_TYPE>::type_t, UNITS>(first.value() * second); } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNITS> second) { - return LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); + return LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); } @@ -654,196 +654,196 @@ LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageT template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator / (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) { - return LLUnit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() / second); + return LLUnit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() / second); } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) { - return first.value() / first.convert(second).value(); + return first.value() / first.convert(second).value(); } template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator / (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) { - return LLUnitImplicit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() / second); + return LLUnitImplicit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() / second); } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) { - return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) { - return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); } template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) { - return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); } -template<typename T> +template<typename T> struct LLGetUnitLabel { - static const char* getUnitLabel() { return ""; } + static const char* getUnitLabel() { return ""; } }; template<typename T, typename STORAGE_T> struct LLGetUnitLabel<LLUnit<STORAGE_T, T> > { - static const char* getUnitLabel() { return T::getUnitLabel(); } + static const char* getUnitLabel() { return T::getUnitLabel(); } }; template<typename T> struct LLUnitLinearOps { - typedef LLUnitLinearOps<T> self_t; - - LLUnitLinearOps(T val) - : mValue(val), - mDivisor(1) - {} - - template<typename OTHER_T> - self_t operator * (OTHER_T other) - { - return mValue * other; - } - - template<typename OTHER_T> - self_t operator / (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template<typename OTHER_T> - self_t operator + (OTHER_T other) - { - mValue += other * mDivisor; - return *this; - } - - template<typename OTHER_T> - self_t operator - (OTHER_T other) - { - mValue -= other * mDivisor; - return *this; - } - - T mValue; - T mDivisor; + typedef LLUnitLinearOps<T> self_t; + + LLUnitLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template<typename OTHER_T> + self_t operator * (OTHER_T other) + { + return mValue * other; + } + + template<typename OTHER_T> + self_t operator / (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator + (OTHER_T other) + { + mValue += other * mDivisor; + return *this; + } + + template<typename OTHER_T> + self_t operator - (OTHER_T other) + { + mValue -= other * mDivisor; + return *this; + } + + T mValue; + T mDivisor; }; template<typename T> struct LLUnitInverseLinearOps { - typedef LLUnitInverseLinearOps<T> self_t; - - LLUnitInverseLinearOps(T val) - : mValue(val), - mDivisor(1), - mMultiplicand(1) - {} - - template<typename OTHER_T> - self_t operator * (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template<typename OTHER_T> - self_t operator / (OTHER_T other) - { - mValue *= other; - mMultiplicand *= other; - return *this; - } - - template<typename OTHER_T> - self_t operator + (OTHER_T other) - { - mValue -= other * mMultiplicand; - return *this; - } - - template<typename OTHER_T> - self_t operator - (OTHER_T other) - { - mValue += other * mMultiplicand; - return *this; - } - - T mValue; - T mDivisor; - T mMultiplicand; + typedef LLUnitInverseLinearOps<T> self_t; + + LLUnitInverseLinearOps(T val) + : mValue(val), + mDivisor(1), + mMultiplicand(1) + {} + + template<typename OTHER_T> + self_t operator * (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator / (OTHER_T other) + { + mValue *= other; + mMultiplicand *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator + (OTHER_T other) + { + mValue -= other * mMultiplicand; + return *this; + } + + template<typename OTHER_T> + self_t operator - (OTHER_T other) + { + mValue += other * mMultiplicand; + return *this; + } + + T mValue; + T mDivisor; + T mMultiplicand; }; #define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ struct base_unit_name \ { \ - static const int sLevel = 0; \ - typedef base_unit_name base_unit_t; \ - static const char* getUnitLabel() { return unit_label; } \ - template<typename T> \ - static LLUnit<T, base_unit_name> fromValue(T value) { return LLUnit<T, base_unit_name>(value); } \ - template<typename STORAGE_T, typename UNIT_T> \ - static LLUnit<STORAGE_T, base_unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ - { return LLUnit<STORAGE_T, base_unit_name>(value); } \ + static const int sLevel = 0; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template<typename T> \ + static LLUnit<T, base_unit_name> fromValue(T value) { return LLUnit<T, base_unit_name>(value); } \ + template<typename STORAGE_T, typename UNIT_T> \ + static LLUnit<STORAGE_T, base_unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ + { return LLUnit<STORAGE_T, base_unit_name>(value); } \ } -#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ struct unit_name \ { \ - static const int sLevel = base_unit_name::sLevel + 1; \ - typedef base_unit_name base_unit_t; \ - static const char* getUnitLabel() { return unit_label; } \ - template<typename T> \ - static LLUnit<T, unit_name> fromValue(T value) { return LLUnit<T, unit_name>(value); } \ - template<typename STORAGE_T, typename UNIT_T> \ - static LLUnit<STORAGE_T, unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ - { return LLUnit<STORAGE_T, unit_name>(value); } \ + static const int sLevel = base_unit_name::sLevel + 1; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template<typename T> \ + static LLUnit<T, unit_name> fromValue(T value) { return LLUnit<T, unit_name>(value); } \ + template<typename STORAGE_T, typename UNIT_T> \ + static LLUnit<STORAGE_T, unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ + { return LLUnit<STORAGE_T, unit_name>(value); } \ }; \ - \ + \ template<typename S1, typename S2> \ LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out) \ { \ - typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ - LLUnitInverseLinearOps<result_storage_t> result = \ - LLUnitInverseLinearOps<result_storage_t>(in.value()) conversion_operation; \ - out = LLUnit<S2, base_unit_name>((S2)result.mValue); \ - return result.mDivisor; \ + typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ + LLUnitInverseLinearOps<result_storage_t> result = \ + LLUnitInverseLinearOps<result_storage_t>(in.value()) conversion_operation; \ + out = LLUnit<S2, base_unit_name>((S2)result.mValue); \ + return result.mDivisor; \ } \ \ template<typename S1, typename S2> \ LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out) \ { \ - typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ - LLUnitLinearOps<result_storage_t> result = \ - LLUnitLinearOps<result_storage_t>(in.value()) conversion_operation; \ - out = LLUnit<S2, unit_name>((S2)result.mValue); \ - return result.mDivisor; \ -} + typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ + LLUnitLinearOps<result_storage_t> result = \ + LLUnitLinearOps<result_storage_t>(in.value()) conversion_operation; \ + out = LLUnit<S2, unit_name>((S2)result.mValue); \ + return result.mDivisor; \ +} #define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ - typedef LLUnit<F32, ns::unit_name> F32##unit_name; \ - typedef LLUnitImplicit<F32, ns::unit_name> F32##unit_name##Implicit;\ - typedef LLUnit<F64, ns::unit_name> F64##unit_name; \ - typedef LLUnitImplicit<F64, ns::unit_name> F64##unit_name##Implicit;\ - typedef LLUnit<S32, ns::unit_name> S32##unit_name; \ - typedef LLUnitImplicit<S32, ns::unit_name> S32##unit_name##Implicit;\ - typedef LLUnit<S64, ns::unit_name> S64##unit_name; \ - typedef LLUnitImplicit<S64, ns::unit_name> S64##unit_name##Implicit;\ - typedef LLUnit<U32, ns::unit_name> U32##unit_name; \ - typedef LLUnitImplicit<U32, ns::unit_name> U32##unit_name##Implicit;\ - typedef LLUnit<U64, ns::unit_name> U64##unit_name; \ - typedef LLUnitImplicit<U64, ns::unit_name> U64##unit_name##Implicit + typedef LLUnit<F32, ns::unit_name> F32##unit_name; \ + typedef LLUnitImplicit<F32, ns::unit_name> F32##unit_name##Implicit;\ + typedef LLUnit<F64, ns::unit_name> F64##unit_name; \ + typedef LLUnitImplicit<F64, ns::unit_name> F64##unit_name##Implicit;\ + typedef LLUnit<S32, ns::unit_name> S32##unit_name; \ + typedef LLUnitImplicit<S32, ns::unit_name> S32##unit_name##Implicit;\ + typedef LLUnit<S64, ns::unit_name> S64##unit_name; \ + typedef LLUnitImplicit<S64, ns::unit_name> S64##unit_name##Implicit;\ + typedef LLUnit<U32, ns::unit_name> U32##unit_name; \ + typedef LLUnitImplicit<U32, ns::unit_name> U32##unit_name##Implicit;\ + typedef LLUnit<U64, ns::unit_name> U64##unit_name; \ + typedef LLUnitImplicit<U64, ns::unit_name> U64##unit_name##Implicit #endif //LL_UNITTYPE_H diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 4fb92a8f3e..e93238f0e9 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lluri.cpp * @author Phoenix * @date 2006-02-08 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #include "lluri.h" #include "llsd.h" #include <iomanip> - + #include "lluuid.h" // system includes @@ -43,182 +43,182 @@ // static void LLURI::encodeCharacter(std::ostream& ostr, std::string::value_type val) { - ostr << "%" + ostr << "%" - << std::uppercase - << std::hex - << std::setw(2) - << std::setfill('0') + << std::uppercase + << std::hex + << std::setw(2) + << std::setfill('0') - // VWR-4010 Cannot cast to U32 because sign-extension on - // chars > 128 will result in FFFFFFC3 instead of F3. - << static_cast<S32>(static_cast<U8>(val)) + // VWR-4010 Cannot cast to U32 because sign-extension on + // chars > 128 will result in FFFFFFC3 instead of F3. + << static_cast<S32>(static_cast<U8>(val)) - // reset stream state - << std::nouppercase - << std::dec - << std::setfill(' '); + // reset stream state + << std::nouppercase + << std::dec + << std::setfill(' '); } // static std::string LLURI::escape( - const std::string& str, - const std::string& allowed, - bool is_allowed_sorted) -{ - // *NOTE: This size determination feels like a good value to - // me. If someone wante to come up with a more precise heuristic - // with some data to back up the assertion that 'sort is good' - // then feel free to change this test a bit. - if(!is_allowed_sorted && (str.size() > 2 * allowed.size())) - { - // if it's already sorted, or if the url is quite long, we - // want to optimize this process. - std::string sorted_allowed(allowed); - std::sort(sorted_allowed.begin(), sorted_allowed.end()); - return escape(str, sorted_allowed, true); - } - - std::ostringstream ostr; - std::string::const_iterator it = str.begin(); - std::string::const_iterator end = str.end(); - std::string::value_type c; - if(is_allowed_sorted) - { - std::string::const_iterator allowed_begin(allowed.begin()); - std::string::const_iterator allowed_end(allowed.end()); - for(; it != end; ++it) - { - c = *it; - if(std::binary_search(allowed_begin, allowed_end, c)) - { - ostr << c; - } - else - { - encodeCharacter(ostr, c); - } - } - } - else - { - for(; it != end; ++it) - { - c = *it; - if(allowed.find(c) == std::string::npos) - { - encodeCharacter(ostr, c); - } - else - { - ostr << c; - } - } - } - return ostr.str(); + const std::string& str, + const std::string& allowed, + bool is_allowed_sorted) +{ + // *NOTE: This size determination feels like a good value to + // me. If someone wante to come up with a more precise heuristic + // with some data to back up the assertion that 'sort is good' + // then feel free to change this test a bit. + if(!is_allowed_sorted && (str.size() > 2 * allowed.size())) + { + // if it's already sorted, or if the url is quite long, we + // want to optimize this process. + std::string sorted_allowed(allowed); + std::sort(sorted_allowed.begin(), sorted_allowed.end()); + return escape(str, sorted_allowed, true); + } + + std::ostringstream ostr; + std::string::const_iterator it = str.begin(); + std::string::const_iterator end = str.end(); + std::string::value_type c; + if(is_allowed_sorted) + { + std::string::const_iterator allowed_begin(allowed.begin()); + std::string::const_iterator allowed_end(allowed.end()); + for(; it != end; ++it) + { + c = *it; + if(std::binary_search(allowed_begin, allowed_end, c)) + { + ostr << c; + } + else + { + encodeCharacter(ostr, c); + } + } + } + else + { + for(; it != end; ++it) + { + c = *it; + if(allowed.find(c) == std::string::npos) + { + encodeCharacter(ostr, c); + } + else + { + ostr << c; + } + } + } + return ostr.str(); } // static std::string LLURI::unescape(const std::string& str) { - std::ostringstream ostr; - std::string::const_iterator it = str.begin(); - std::string::const_iterator end = str.end(); - for(; it != end; ++it) - { - if((*it) == '%') - { - ++it; - if(it == end) break; - - if(is_char_hex(*it)) - { - U8 c = hex_as_nybble(*it++); - - c = c << 4; - if (it == end) break; - - if(is_char_hex(*it)) - { - c |= hex_as_nybble(*it); - ostr.put((char)c); - } - else - { - ostr.put((char)c); - ostr.put(*it); - } - } - else - { - ostr.put('%'); - ostr.put(*it); - } - } - else - { - ostr.put(*it); - } - } - return ostr.str(); + std::ostringstream ostr; + std::string::const_iterator it = str.begin(); + std::string::const_iterator end = str.end(); + for(; it != end; ++it) + { + if((*it) == '%') + { + ++it; + if(it == end) break; + + if(is_char_hex(*it)) + { + U8 c = hex_as_nybble(*it++); + + c = c << 4; + if (it == end) break; + + if(is_char_hex(*it)) + { + c |= hex_as_nybble(*it); + ostr.put((char)c); + } + else + { + ostr.put((char)c); + ostr.put(*it); + } + } + else + { + ostr.put('%'); + ostr.put(*it); + } + } + else + { + ostr.put(*it); + } + } + return ostr.str(); } namespace { - const std::string unreserved() - { - static const std::string s = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789" - "-._~"; - return s; - } - const std::string path() - { - static const std::string s = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "$-_.+" - "!*'()," - "{}|\\^~[]`" - "<>#%" - ";/?:@&="; - return s; - } - const std::string sub_delims() - { - static const std::string s = "!$&'()*+,;="; - return s; - } - - std::string escapeHostAndPort(const std::string& s) - { return LLURI::escape(s, unreserved() + sub_delims() +":"); } - std::string escapePathComponent(const std::string& s) - { return LLURI::escape(s, unreserved() + sub_delims() + ":@"); } - std::string escapeQueryVariable(const std::string& s) - { return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@" - std::string escapeQueryValue(const std::string& s) - { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@" - std::string escapeUriQuery(const std::string& s) - { return LLURI::escape(s, unreserved() + ":@?&$;*+=%/"); } - std::string escapeUriData(const std::string& s) - { return LLURI::escape(s, unreserved() + "%"); } - std::string escapeUriPath(const std::string& s) - { return LLURI::escape(s, path()); } + const std::string unreserved() + { + static const std::string s = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._~"; + return s; + } + const std::string path() + { + static const std::string s = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "$-_.+" + "!*'()," + "{}|\\^~[]`" + "<>#%" + ";/?:@&="; + return s; + } + const std::string sub_delims() + { + static const std::string s = "!$&'()*+,;="; + return s; + } + + std::string escapeHostAndPort(const std::string& s) + { return LLURI::escape(s, unreserved() + sub_delims() +":"); } + std::string escapePathComponent(const std::string& s) + { return LLURI::escape(s, unreserved() + sub_delims() + ":@"); } + std::string escapeQueryVariable(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@" + std::string escapeQueryValue(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@" + std::string escapeUriQuery(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@?&$;*+=%/"); } + std::string escapeUriData(const std::string& s) + { return LLURI::escape(s, unreserved() + "%"); } + std::string escapeUriPath(const std::string& s) + { return LLURI::escape(s, path()); } } //static std::string LLURI::escape(const std::string& str) { - static std::string default_allowed = unreserved(); - static bool initialized = false; - if(!initialized) - { - std::sort(default_allowed.begin(), default_allowed.end()); - initialized = true; - } - return escape(str, default_allowed, true); + static std::string default_allowed = unreserved(); + static bool initialized = false; + if(!initialized) + { + std::sort(default_allowed.begin(), default_allowed.end()); + initialized = true; + } + return escape(str, default_allowed, true); } //static @@ -306,126 +306,126 @@ LLURI::LLURI() LLURI::LLURI(const std::string& escaped_str) { - std::string::size_type delim_pos; - delim_pos = escaped_str.find(':'); - std::string temp; - if (delim_pos == std::string::npos) - { - mScheme = ""; - mEscapedOpaque = escaped_str; - } - else - { - mScheme = escaped_str.substr(0, delim_pos); - mEscapedOpaque = escaped_str.substr(delim_pos+1); - } - - parseAuthorityAndPathUsingOpaque(); - - delim_pos = mEscapedPath.find('?'); - if (delim_pos != std::string::npos) - { - mEscapedQuery = mEscapedPath.substr(delim_pos+1); - mEscapedPath = mEscapedPath.substr(0,delim_pos); - } + std::string::size_type delim_pos; + delim_pos = escaped_str.find(':'); + std::string temp; + if (delim_pos == std::string::npos) + { + mScheme = ""; + mEscapedOpaque = escaped_str; + } + else + { + mScheme = escaped_str.substr(0, delim_pos); + mEscapedOpaque = escaped_str.substr(delim_pos+1); + } + + parseAuthorityAndPathUsingOpaque(); + + delim_pos = mEscapedPath.find('?'); + if (delim_pos != std::string::npos) + { + mEscapedQuery = mEscapedPath.substr(delim_pos+1); + mEscapedPath = mEscapedPath.substr(0,delim_pos); + } } static BOOL isDefault(const std::string& scheme, U16 port) { - if (scheme == "http") - return port == 80; - if (scheme == "https") - return port == 443; - if (scheme == "ftp") - return port == 21; + if (scheme == "http") + return port == 80; + if (scheme == "https") + return port == 443; + if (scheme == "ftp") + return port == 21; - return FALSE; + return FALSE; } void LLURI::parseAuthorityAndPathUsingOpaque() { - if (mScheme == "http" || mScheme == "https" || - mScheme == "ftp" || mScheme == "secondlife" || - mScheme == "x-grid-location-info") - { - if (mEscapedOpaque.substr(0,2) != "//") - { - return; - } - - std::string::size_type delim_pos, delim_pos2; - delim_pos = mEscapedOpaque.find('/', 2); - delim_pos2 = mEscapedOpaque.find('?', 2); - // no path, no query - if (delim_pos == std::string::npos && - delim_pos2 == std::string::npos) - { - mEscapedAuthority = mEscapedOpaque.substr(2); - mEscapedPath = ""; - } - // path exist, no query - else if (delim_pos2 == std::string::npos) - { - mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); - mEscapedPath = mEscapedOpaque.substr(delim_pos); - } - // no path, only query - else if (delim_pos == std::string::npos || - delim_pos2 < delim_pos) - { - mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos2-2); - // query part will be broken out later - mEscapedPath = mEscapedOpaque.substr(delim_pos2); - } - // path and query - else - { - mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); - // query part will be broken out later - mEscapedPath = mEscapedOpaque.substr(delim_pos); - } - } - else if (mScheme == "about") - { - mEscapedPath = mEscapedOpaque; - } + if (mScheme == "http" || mScheme == "https" || + mScheme == "ftp" || mScheme == "secondlife" || + mScheme == "x-grid-location-info") + { + if (mEscapedOpaque.substr(0,2) != "//") + { + return; + } + + std::string::size_type delim_pos, delim_pos2; + delim_pos = mEscapedOpaque.find('/', 2); + delim_pos2 = mEscapedOpaque.find('?', 2); + // no path, no query + if (delim_pos == std::string::npos && + delim_pos2 == std::string::npos) + { + mEscapedAuthority = mEscapedOpaque.substr(2); + mEscapedPath = ""; + } + // path exist, no query + else if (delim_pos2 == std::string::npos) + { + mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); + mEscapedPath = mEscapedOpaque.substr(delim_pos); + } + // no path, only query + else if (delim_pos == std::string::npos || + delim_pos2 < delim_pos) + { + mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos2-2); + // query part will be broken out later + mEscapedPath = mEscapedOpaque.substr(delim_pos2); + } + // path and query + else + { + mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); + // query part will be broken out later + mEscapedPath = mEscapedOpaque.substr(delim_pos); + } + } + else if (mScheme == "about") + { + mEscapedPath = mEscapedOpaque; + } } LLURI::LLURI(const std::string& scheme, - const std::string& userName, - const std::string& password, - const std::string& hostName, - U16 port, - const std::string& escapedPath, - const std::string& escapedQuery) - : mScheme(scheme), - mEscapedPath(escapedPath), - mEscapedQuery(escapedQuery) -{ - std::ostringstream auth; - std::ostringstream opaque; - - opaque << "//"; - - if (!userName.empty()) - { - auth << escape(userName); - if (!password.empty()) - { - auth << ':' << escape(password); - } - auth << '@'; - } - auth << hostName; - if (!isDefault(scheme, port)) - { - auth << ':' << port; - } - mEscapedAuthority = auth.str(); - - opaque << mEscapedAuthority << escapedPath << escapedQuery; - - mEscapedOpaque = opaque.str(); + const std::string& userName, + const std::string& password, + const std::string& hostName, + U16 port, + const std::string& escapedPath, + const std::string& escapedQuery) + : mScheme(scheme), + mEscapedPath(escapedPath), + mEscapedQuery(escapedQuery) +{ + std::ostringstream auth; + std::ostringstream opaque; + + opaque << "//"; + + if (!userName.empty()) + { + auth << escape(userName); + if (!password.empty()) + { + auth << ':' << escape(password); + } + auth << '@'; + } + auth << hostName; + if (!isDefault(scheme, port)) + { + auth << ':' << port; + } + mEscapedAuthority = auth.str(); + + opaque << mEscapedAuthority << escapedPath << escapedQuery; + + mEscapedOpaque = opaque.str(); } LLURI::~LLURI() @@ -434,325 +434,325 @@ LLURI::~LLURI() // static LLURI LLURI::buildHTTP(const std::string& prefix, - const LLSD& path) -{ - LLURI result; - - // TODO: deal with '/' '?' '#' in host_port - if (prefix.find("://") != prefix.npos) - { - // it is a prefix - result = LLURI(prefix); - } - else - { - // it is just a host and optional port - result.mScheme = "http"; - result.mEscapedAuthority = escapeHostAndPort(prefix); - } - - if (path.isArray()) - { - // break out and escape each path component - for (LLSD::array_const_iterator it = path.beginArray(); - it != path.endArray(); - ++it) - { - LL_DEBUGS() << "PATH: inserting " << it->asString() << LL_ENDL; - result.mEscapedPath += "/" + escapePathComponent(it->asString()); - } - } - else if (path.isString()) - { - std::string pathstr(path); - // Trailing slash is significant in HTTP land. If caller specified, - // make a point of preserving. - std::string last_slash; - std::string::size_type len(pathstr.length()); - if (len && pathstr[len-1] == '/') - { - last_slash = "/"; - } - - // Escape every individual path component, recombining with slashes. - for (boost::split_iterator<std::string::const_iterator> - ti(pathstr, boost::first_finder("/")), tend; - ti != tend; ++ti) - { - // Eliminate a leading slash or duplicate slashes anywhere. (Extra - // slashes show up here as empty components.) This test also - // eliminates a trailing slash, hence last_slash above. - if (! ti->empty()) - { - result.mEscapedPath - += "/" + escapePathComponent(std::string(ti->begin(), ti->end())); - } - } - - // Reinstate trailing slash, if any. - result.mEscapedPath += last_slash; - } - else if(path.isUndefined()) - { - // do nothing - } - else - { - LL_WARNS() << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" - << path.type() << LL_ENDL; - } - result.mEscapedOpaque = "//" + result.mEscapedAuthority + - result.mEscapedPath; - return result; + const LLSD& path) +{ + LLURI result; + + // TODO: deal with '/' '?' '#' in host_port + if (prefix.find("://") != prefix.npos) + { + // it is a prefix + result = LLURI(prefix); + } + else + { + // it is just a host and optional port + result.mScheme = "http"; + result.mEscapedAuthority = escapeHostAndPort(prefix); + } + + if (path.isArray()) + { + // break out and escape each path component + for (LLSD::array_const_iterator it = path.beginArray(); + it != path.endArray(); + ++it) + { + LL_DEBUGS() << "PATH: inserting " << it->asString() << LL_ENDL; + result.mEscapedPath += "/" + escapePathComponent(it->asString()); + } + } + else if (path.isString()) + { + std::string pathstr(path); + // Trailing slash is significant in HTTP land. If caller specified, + // make a point of preserving. + std::string last_slash; + std::string::size_type len(pathstr.length()); + if (len && pathstr[len-1] == '/') + { + last_slash = "/"; + } + + // Escape every individual path component, recombining with slashes. + for (boost::split_iterator<std::string::const_iterator> + ti(pathstr, boost::first_finder("/")), tend; + ti != tend; ++ti) + { + // Eliminate a leading slash or duplicate slashes anywhere. (Extra + // slashes show up here as empty components.) This test also + // eliminates a trailing slash, hence last_slash above. + if (! ti->empty()) + { + result.mEscapedPath + += "/" + escapePathComponent(std::string(ti->begin(), ti->end())); + } + } + + // Reinstate trailing slash, if any. + result.mEscapedPath += last_slash; + } + else if(path.isUndefined()) + { + // do nothing + } + else + { + LL_WARNS() << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" + << path.type() << LL_ENDL; + } + result.mEscapedOpaque = "//" + result.mEscapedAuthority + + result.mEscapedPath; + return result; } // static LLURI LLURI::buildHTTP(const std::string& prefix, - const LLSD& path, - const LLSD& query) + const LLSD& path, + const LLSD& query) { - LLURI uri = buildHTTP(prefix, path); - // break out and escape each query component - uri.mEscapedQuery = mapToQueryString(query); - uri.mEscapedOpaque += uri.mEscapedQuery ; - uri.mEscapedQuery.erase(0,1); // trim the leading '?' - return uri; + LLURI uri = buildHTTP(prefix, path); + // break out and escape each query component + uri.mEscapedQuery = mapToQueryString(query); + uri.mEscapedOpaque += uri.mEscapedQuery ; + uri.mEscapedQuery.erase(0,1); // trim the leading '?' + return uri; } // static LLURI LLURI::buildHTTP(const std::string& host, - const U32& port, - const LLSD& path) + const U32& port, + const LLSD& path) { - return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path); + return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path); } // static LLURI LLURI::buildHTTP(const std::string& host, - const U32& port, - const LLSD& path, - const LLSD& query) + const U32& port, + const LLSD& path, + const LLSD& query) { - return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query); + return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query); } std::string LLURI::asString() const { - if (mScheme.empty()) - { - return mEscapedOpaque; - } - else - { - return mScheme + ":" + mEscapedOpaque; - } + if (mScheme.empty()) + { + return mEscapedOpaque; + } + else + { + return mScheme + ":" + mEscapedOpaque; + } } std::string LLURI::scheme() const { - return mScheme; + return mScheme; } std::string LLURI::opaque() const { - return unescape(mEscapedOpaque); + return unescape(mEscapedOpaque); } std::string LLURI::authority() const { - return unescape(mEscapedAuthority); + return unescape(mEscapedAuthority); } namespace { - void findAuthorityParts(const std::string& authority, - std::string& user, - std::string& host, - std::string& port) - { - std::string::size_type start_pos = authority.find('@'); - if (start_pos == std::string::npos) - { - user = ""; - start_pos = 0; - } - else - { - user = authority.substr(0, start_pos); - start_pos += 1; - } - - std::string::size_type end_pos = authority.find(':', start_pos); - if (end_pos == std::string::npos) - { - host = authority.substr(start_pos); - port = ""; - } - else - { - host = authority.substr(start_pos, end_pos - start_pos); - port = authority.substr(end_pos + 1); - } - } -} - + void findAuthorityParts(const std::string& authority, + std::string& user, + std::string& host, + std::string& port) + { + std::string::size_type start_pos = authority.find('@'); + if (start_pos == std::string::npos) + { + user = ""; + start_pos = 0; + } + else + { + user = authority.substr(0, start_pos); + start_pos += 1; + } + + std::string::size_type end_pos = authority.find(':', start_pos); + if (end_pos == std::string::npos) + { + host = authority.substr(start_pos); + port = ""; + } + else + { + host = authority.substr(start_pos, end_pos - start_pos); + port = authority.substr(end_pos + 1); + } + } +} + std::string LLURI::hostName() const { - std::string user, host, port; - findAuthorityParts(mEscapedAuthority, user, host, port); - return unescape(host); + std::string user, host, port; + findAuthorityParts(mEscapedAuthority, user, host, port); + return unescape(host); } std::string LLURI::userName() const { - std::string user, userPass, host, port; - findAuthorityParts(mEscapedAuthority, userPass, host, port); - std::string::size_type pos = userPass.find(':'); - if (pos != std::string::npos) - { - user = userPass.substr(0, pos); - } - return unescape(user); + std::string user, userPass, host, port; + findAuthorityParts(mEscapedAuthority, userPass, host, port); + std::string::size_type pos = userPass.find(':'); + if (pos != std::string::npos) + { + user = userPass.substr(0, pos); + } + return unescape(user); } std::string LLURI::password() const { - std::string pass, userPass, host, port; - findAuthorityParts(mEscapedAuthority, userPass, host, port); - std::string::size_type pos = userPass.find(':'); - if (pos != std::string::npos) - { - pass = userPass.substr(pos + 1); - } - return unescape(pass); + std::string pass, userPass, host, port; + findAuthorityParts(mEscapedAuthority, userPass, host, port); + std::string::size_type pos = userPass.find(':'); + if (pos != std::string::npos) + { + pass = userPass.substr(pos + 1); + } + return unescape(pass); } BOOL LLURI::defaultPort() const { - return isDefault(mScheme, hostPort()); + return isDefault(mScheme, hostPort()); } U16 LLURI::hostPort() const { - std::string user, host, port; - findAuthorityParts(mEscapedAuthority, user, host, port); - if (port.empty()) - { - if (mScheme == "http") - return 80; - if (mScheme == "https") - return 443; - if (mScheme == "ftp") - return 21; - return 0; - } - return atoi(port.c_str()); -} + std::string user, host, port; + findAuthorityParts(mEscapedAuthority, user, host, port); + if (port.empty()) + { + if (mScheme == "http") + return 80; + if (mScheme == "https") + return 443; + if (mScheme == "ftp") + return 21; + return 0; + } + return atoi(port.c_str()); +} std::string LLURI::path() const { - return unescape(mEscapedPath); + return unescape(mEscapedPath); } LLSD LLURI::pathArray() const { - typedef boost::tokenizer<boost::char_separator<char> > tokenizer; - boost::char_separator<char> sep("/", "", boost::drop_empty_tokens); - tokenizer tokens(mEscapedPath, sep); - tokenizer::iterator it = tokens.begin(); - tokenizer::iterator end = tokens.end(); + typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + boost::char_separator<char> sep("/", "", boost::drop_empty_tokens); + tokenizer tokens(mEscapedPath, sep); + tokenizer::iterator it = tokens.begin(); + tokenizer::iterator end = tokens.end(); - LLSD params; - for (const std::string& str : tokens) - { - params.append(str); - } - return params; + LLSD params; + for (const std::string& str : tokens) + { + params.append(str); + } + return params; } std::string LLURI::query() const { - return unescape(mEscapedQuery); + return unescape(mEscapedQuery); } LLSD LLURI::queryMap() const { - return queryMap(mEscapedQuery); + return queryMap(mEscapedQuery); } // static LLSD LLURI::queryMap(std::string escaped_query_string) { - LL_DEBUGS() << "LLURI::queryMap query params: " << escaped_query_string << LL_ENDL; - - LLSD result = LLSD::emptyArray(); - while(!escaped_query_string.empty()) - { - // get tuple first - std::string tuple; - std::string::size_type tuple_begin = escaped_query_string.find('&'); - if (tuple_begin != std::string::npos) - { - tuple = escaped_query_string.substr(0, tuple_begin); - escaped_query_string = escaped_query_string.substr(tuple_begin+1); - } - else - { - tuple = escaped_query_string; - escaped_query_string = ""; - } - if (tuple.empty()) continue; - - // parse tuple - std::string::size_type key_end = tuple.find('='); - if (key_end != std::string::npos) - { - std::string key = unescape(tuple.substr(0,key_end)); - std::string value = unescape(tuple.substr(key_end+1)); - LL_DEBUGS() << "inserting key " << key << " value " << value << LL_ENDL; - result[key] = value; - } - else - { - LL_DEBUGS() << "inserting key " << unescape(tuple) << " value true" << LL_ENDL; - result[unescape(tuple)] = true; - } - } - return result; + LL_DEBUGS() << "LLURI::queryMap query params: " << escaped_query_string << LL_ENDL; + + LLSD result = LLSD::emptyArray(); + while(!escaped_query_string.empty()) + { + // get tuple first + std::string tuple; + std::string::size_type tuple_begin = escaped_query_string.find('&'); + if (tuple_begin != std::string::npos) + { + tuple = escaped_query_string.substr(0, tuple_begin); + escaped_query_string = escaped_query_string.substr(tuple_begin+1); + } + else + { + tuple = escaped_query_string; + escaped_query_string = ""; + } + if (tuple.empty()) continue; + + // parse tuple + std::string::size_type key_end = tuple.find('='); + if (key_end != std::string::npos) + { + std::string key = unescape(tuple.substr(0,key_end)); + std::string value = unescape(tuple.substr(key_end+1)); + LL_DEBUGS() << "inserting key " << key << " value " << value << LL_ENDL; + result[key] = value; + } + else + { + LL_DEBUGS() << "inserting key " << unescape(tuple) << " value true" << LL_ENDL; + result[unescape(tuple)] = true; + } + } + return result; } std::string LLURI::mapToQueryString(const LLSD& queryMap) { - std::string query_string; - if (queryMap.isMap()) - { - bool first_element = true; - LLSD::map_const_iterator iter = queryMap.beginMap(); - LLSD::map_const_iterator end = queryMap.endMap(); - std::ostringstream ostr; - for (; iter != end; ++iter) - { - if(first_element) - { - ostr << "?"; - first_element = false; - } - else - { - ostr << "&"; - } - ostr << escapeQueryVariable(iter->first); - if(iter->second.isDefined()) - { - ostr << "=" << escapeQueryValue(iter->second.asString()); - } - } - query_string = ostr.str(); - } - return query_string; + std::string query_string; + if (queryMap.isMap()) + { + bool first_element = true; + LLSD::map_const_iterator iter = queryMap.beginMap(); + LLSD::map_const_iterator end = queryMap.endMap(); + std::ostringstream ostr; + for (; iter != end; ++iter) + { + if(first_element) + { + ostr << "?"; + first_element = false; + } + else + { + ostr << "&"; + } + ostr << escapeQueryVariable(iter->first); + if(iter->second.isDefined()) + { + ostr << "=" << escapeQueryValue(iter->second.asString()); + } + } + query_string = ostr.str(); + } + return query_string; } bool operator!=(const LLURI& first, const LLURI& second) { - return (first.asString() != second.asString()); + return (first.asString() != second.asString()); } diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h index b8fca0ca51..95c119dee9 100644 --- a/indra/llcommon/lluri.h +++ b/indra/llcommon/lluri.h @@ -1,4 +1,4 @@ -/** +/** * @file lluri.h * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ class LLSD; class LLUUID; class LLApp; -/** +/** * * LLURI instances are immutable * See: http://www.ietf.org/rfc/rfc3986.txt @@ -47,144 +47,144 @@ public: LLURI(); LLURI(const std::string& escaped_str); LLURI(const std::string& scheme, - const std::string& userName, - const std::string& password, - const std::string& hostName, - U16 hostPort, - const std::string& escapedPath, - const std::string& escapedQuery); - + const std::string& userName, + const std::string& password, + const std::string& hostName, + U16 hostPort, + const std::string& escapedPath, + const std::string& escapedQuery); + // construct from escaped string, as would be transmitted on the net - ~LLURI(); - - static LLURI buildHTTP( - const std::string& prefix, - const LLSD& path); - - static LLURI buildHTTP( - const std::string& prefix, - const LLSD& path, - const LLSD& query); - ///< prefix is either a full URL prefix of the form - /// "http://example.com:8080", or it can be simply a host and - /// optional port like "example.com" or "example.com:8080", in - /// these cases, the "http://" will be added - - static LLURI buildHTTP( - const std::string& host, - const U32& port, - const LLSD& path); - static LLURI buildHTTP( - const std::string& host, - const U32& port, - const LLSD& path, - const LLSD& query); - - std::string asString() const; - ///< the whole URI, escaped as needed - - /** @name Parts of a URI */ - //@{ - // These functions return parts of the decoded URI. The returned - // strings are un-escaped as needed - - // for all schemes - std::string scheme() const; ///< ex.: "http", note lack of colon - std::string opaque() const; ///< everything after the colon - + ~LLURI(); + + static LLURI buildHTTP( + const std::string& prefix, + const LLSD& path); + + static LLURI buildHTTP( + const std::string& prefix, + const LLSD& path, + const LLSD& query); + ///< prefix is either a full URL prefix of the form + /// "http://example.com:8080", or it can be simply a host and + /// optional port like "example.com" or "example.com:8080", in + /// these cases, the "http://" will be added + + static LLURI buildHTTP( + const std::string& host, + const U32& port, + const LLSD& path); + static LLURI buildHTTP( + const std::string& host, + const U32& port, + const LLSD& path, + const LLSD& query); + + std::string asString() const; + ///< the whole URI, escaped as needed + + /** @name Parts of a URI */ + //@{ + // These functions return parts of the decoded URI. The returned + // strings are un-escaped as needed + + // for all schemes + std::string scheme() const; ///< ex.: "http", note lack of colon + std::string opaque() const; ///< everything after the colon + // for schemes that follow path like syntax (http, https, ftp) - std::string authority() const; // ex.: "host.com:80" - std::string hostName() const; // ex.: "host.com" + std::string authority() const; // ex.: "host.com:80" + std::string hostName() const; // ex.: "host.com" std::string userName() const; std::string password() const; - U16 hostPort() const; // ex.: 80, will include implicit port - BOOL defaultPort() const; // true if port is default for scheme + U16 hostPort() const; // ex.: 80, will include implicit port + BOOL defaultPort() const; // true if port is default for scheme const std::string& escapedPath() const { return mEscapedPath; } - std::string path() const; // ex.: "/abc/def", includes leading slash - LLSD pathArray() const; // above decoded into an array of strings - std::string query() const; // ex.: "x=34", section after "?" + std::string path() const; // ex.: "/abc/def", includes leading slash + LLSD pathArray() const; // above decoded into an array of strings + std::string query() const; // ex.: "x=34", section after "?" const std::string& escapedQuery() const { return mEscapedQuery; } - LLSD queryMap() const; // above decoded into a map + LLSD queryMap() const; // above decoded into a map static LLSD queryMap(std::string escaped_query_string); - /** - * @brief given a name value map, return a serialized query string. - * - - * @param query_map a map of name value. every value must be - * representable as a string. - * @return Returns an url query string of '?n1=v1&n2=v2&...' - */ - static std::string mapToQueryString(const LLSD& query_map); - - /** @name Escaping Utilities */ - //@{ - /** - * @brief 'Escape' symbol into stream - * - * @param ostr Output stream. - * @param val Symbol to encode. - */ - static void encodeCharacter(std::ostream& ostr, std::string::value_type val); - - /** - * @brief Escape the string passed except for unreserved - * - * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz - * 0123456789 - * -._~ - * - * @see http://www.ietf.org/rfc/rfc1738.txt - * - * @param str The raw URI to escape. - * @return Returns the rfc 1738 escaped uri or an empty string. - */ - static std::string escape(const std::string& str); - - /** - * @brief Escape a string with a specified set of allowed characters. - * - * Escape a string by urlencoding all the characters that aren't - * in the allowed string. - * @param str The raw URI to escape. - * @param allowed Character array of allowed characters - * @param is_allowed_sorted Optimization hint if allowed array is sorted. - * @return Returns the escaped uri or an empty string. - */ - static std::string escape( - const std::string& str, - const std::string& allowed, - bool is_allowed_sorted = false); - - /** - * @brief Break string into data part and path or sheme - * and escape path (if present) and data. - * Data part is not allowed to have path related symbols - * @param str The raw URI to escape. - */ - static std::string escapePathAndData(const std::string &str); - - /** - * @brief unescape an escaped URI string. - * - * @param str The escped URI to unescape. - * @return Returns the unescaped uri or an empty string. - */ - static std::string unescape(const std::string& str); - //@} + /** + * @brief given a name value map, return a serialized query string. + * + + * @param query_map a map of name value. every value must be + * representable as a string. + * @return Returns an url query string of '?n1=v1&n2=v2&...' + */ + static std::string mapToQueryString(const LLSD& query_map); + + /** @name Escaping Utilities */ + //@{ + /** + * @brief 'Escape' symbol into stream + * + * @param ostr Output stream. + * @param val Symbol to encode. + */ + static void encodeCharacter(std::ostream& ostr, std::string::value_type val); + + /** + * @brief Escape the string passed except for unreserved + * + * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz + * 0123456789 + * -._~ + * + * @see http://www.ietf.org/rfc/rfc1738.txt + * + * @param str The raw URI to escape. + * @return Returns the rfc 1738 escaped uri or an empty string. + */ + static std::string escape(const std::string& str); + + /** + * @brief Escape a string with a specified set of allowed characters. + * + * Escape a string by urlencoding all the characters that aren't + * in the allowed string. + * @param str The raw URI to escape. + * @param allowed Character array of allowed characters + * @param is_allowed_sorted Optimization hint if allowed array is sorted. + * @return Returns the escaped uri or an empty string. + */ + static std::string escape( + const std::string& str, + const std::string& allowed, + bool is_allowed_sorted = false); + + /** + * @brief Break string into data part and path or sheme + * and escape path (if present) and data. + * Data part is not allowed to have path related symbols + * @param str The raw URI to escape. + */ + static std::string escapePathAndData(const std::string &str); + + /** + * @brief unescape an escaped URI string. + * + * @param str The escped URI to unescape. + * @return Returns the unescaped uri or an empty string. + */ + static std::string unescape(const std::string& str); + //@} private: - // only "http", "https", "ftp", and "secondlife" schemes are parsed - // secondlife scheme parses authority as "" and includes it as part of - // the path. See lluri_tut.cpp - // i.e. secondlife://app/login has mAuthority = "" and mPath = "/app/login" - void parseAuthorityAndPathUsingOpaque(); - std::string mScheme; - std::string mEscapedOpaque; - std::string mEscapedAuthority; - std::string mEscapedPath; - std::string mEscapedQuery; + // only "http", "https", "ftp", and "secondlife" schemes are parsed + // secondlife scheme parses authority as "" and includes it as part of + // the path. See lluri_tut.cpp + // i.e. secondlife://app/login has mAuthority = "" and mPath = "/app/login" + void parseAuthorityAndPathUsingOpaque(); + std::string mScheme; + std::string mEscapedOpaque; + std::string mEscapedAuthority; + std::string mEscapedPath; + std::string mEscapedQuery; }; // this operator required for tut diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index f79a98a56d..2ebb7fc742 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lluriparser.cpp * @author Protey * @date 2014-10-07 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2014&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,129 +36,129 @@ LLUriParser::LLUriParser(const std::string& u) : mTmpScheme(false), mNormalizedTmp(false), mRes(0) { - if (u.find("://") == std::string::npos) - { - mNormalizedUri = "http://"; - mTmpScheme = true; - } + if (u.find("://") == std::string::npos) + { + mNormalizedUri = "http://"; + mTmpScheme = true; + } - mNormalizedUri += u.c_str(); + mNormalizedUri += u.c_str(); - mRes = parse(); + mRes = parse(); } LLUriParser::~LLUriParser() { - uriFreeUriMembersA(&mUri); + uriFreeUriMembersA(&mUri); } S32 LLUriParser::parse() { - mRes = uriParseSingleUriA(&mUri, mNormalizedUri.c_str(), NULL); - return mRes; + mRes = uriParseSingleUriA(&mUri, mNormalizedUri.c_str(), NULL); + return mRes; } const char * LLUriParser::scheme() const { - return mScheme.c_str(); + return mScheme.c_str(); } void LLUriParser::sheme(const std::string& s) { - mTmpScheme = !s.size(); - mScheme = s; + mTmpScheme = !s.size(); + mScheme = s; } const char * LLUriParser::port() const { - return mPort.c_str(); + return mPort.c_str(); } void LLUriParser::port(const std::string& s) { - mPort = s; + mPort = s; } const char * LLUriParser::host() const { - return mHost.c_str(); + return mHost.c_str(); } void LLUriParser::host(const std::string& s) { - mHost = s; + mHost = s; } const char * LLUriParser::path() const { - return mPath.c_str(); + return mPath.c_str(); } void LLUriParser::path(const std::string& s) { - mPath = s; + mPath = s; } const char * LLUriParser::query() const { - return mQuery.c_str(); + return mQuery.c_str(); } void LLUriParser::query(const std::string& s) { - mQuery = s; + mQuery = s; } const char * LLUriParser::fragment() const { - return mFragment.c_str(); + return mFragment.c_str(); } void LLUriParser::fragment(const std::string& s) { - mFragment = s; + mFragment = s; } void LLUriParser::textRangeToString(UriTextRangeA& textRange, std::string& str) { - if (textRange.first != NULL && textRange.afterLast != NULL && textRange.first < textRange.afterLast) - { - const ptrdiff_t len = textRange.afterLast - textRange.first; - str.assign(textRange.first, static_cast<std::string::size_type>(len)); - } - else - { - str = LLStringUtil::null; - } + if (textRange.first != NULL && textRange.afterLast != NULL && textRange.first < textRange.afterLast) + { + const ptrdiff_t len = textRange.afterLast - textRange.first; + str.assign(textRange.first, static_cast<std::string::size_type>(len)); + } + else + { + str = LLStringUtil::null; + } } void LLUriParser::extractParts() { - if (mTmpScheme || mNormalizedTmp) - { - mScheme.clear(); - } - else - { - textRangeToString(mUri.scheme, mScheme); - } - - textRangeToString(mUri.hostText, mHost); - textRangeToString(mUri.portText, mPort); - textRangeToString(mUri.query, mQuery); - textRangeToString(mUri.fragment, mFragment); - - UriPathSegmentA * pathHead = mUri.pathHead; - while (pathHead) - { - std::string partOfPath; - textRangeToString(pathHead->text, partOfPath); - - mPath += '/'; - mPath += partOfPath; - - pathHead = pathHead->next; - } + if (mTmpScheme || mNormalizedTmp) + { + mScheme.clear(); + } + else + { + textRangeToString(mUri.scheme, mScheme); + } + + textRangeToString(mUri.hostText, mHost); + textRangeToString(mUri.portText, mPort); + textRangeToString(mUri.query, mQuery); + textRangeToString(mUri.fragment, mFragment); + + UriPathSegmentA * pathHead = mUri.pathHead; + while (pathHead) + { + std::string partOfPath; + textRangeToString(pathHead->text, partOfPath); + + mPath += '/'; + mPath += partOfPath; + + pathHead = pathHead->next; + } } #if LL_DARWIN @@ -177,14 +177,14 @@ void uri_signal_handler(int signal) S32 LLUriParser::normalize() { - mNormalizedTmp = mTmpScheme; - if (!mRes) - { + mNormalizedTmp = mTmpScheme; + if (!mRes) + { #if LL_DARWIN sighandler_t last_sigill_handler, last_sigbus_handler; - last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction + last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction last_sigbus_handler = signal(SIGBUS, &uri_signal_handler); - + if (setjmp(return_to_normalize)) { // Issue: external library crashed via signal @@ -230,79 +230,79 @@ S32 LLUriParser::normalize() } } } - } + } - if(mTmpScheme && mNormalizedUri.size() > 7) - { - mNormalizedUri = mNormalizedUri.substr(7); - mTmpScheme = false; - } + if(mTmpScheme && mNormalizedUri.size() > 7) + { + mNormalizedUri = mNormalizedUri.substr(7); + mTmpScheme = false; + } - return mRes; + return mRes; } void LLUriParser::glue(std::string& uri) const { - std::string first_part; - glueFirst(first_part); + std::string first_part; + glueFirst(first_part); - std::string second_part; - glueSecond(second_part); + std::string second_part; + glueSecond(second_part); - uri = first_part + second_part; + uri = first_part + second_part; } void LLUriParser::glueFirst(std::string& uri, bool use_scheme) const { - if (use_scheme && mScheme.size()) - { - uri = mScheme; - uri += "://"; - } - else - { - uri.clear(); - } - - uri += mHost; + if (use_scheme && mScheme.size()) + { + uri = mScheme; + uri += "://"; + } + else + { + uri.clear(); + } + + uri += mHost; } void LLUriParser::glueSecond(std::string& uri) const { - if (mPort.size()) - { - uri = ':'; - uri += mPort; - } - else - { - uri.clear(); - } - - uri += mPath; - - if (mQuery.size()) - { - uri += '?'; - uri += mQuery; - } - - if (mFragment.size()) - { - uri += '#'; - uri += mFragment; - } + if (mPort.size()) + { + uri = ':'; + uri += mPort; + } + else + { + uri.clear(); + } + + uri += mPath; + + if (mQuery.size()) + { + uri += '?'; + uri += mQuery; + } + + if (mFragment.size()) + { + uri += '#'; + uri += mFragment; + } } bool LLUriParser::test() const { - std::string uri; - glue(uri); + std::string uri; + glue(uri); - return uri == mNormalizedUri; + return uri == mNormalizedUri; } const char * LLUriParser::normalizedUri() const { - return mNormalizedUri.c_str(); + return mNormalizedUri.c_str(); } diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h index 92626b9054..77eb4031d5 100644 --- a/indra/llcommon/lluriparser.h +++ b/indra/llcommon/lluriparser.h @@ -1,4 +1,4 @@ -/** +/** * @file lluriparser.h * @author Protey * @date 20146-10-07 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2014&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,52 +35,52 @@ class LL_COMMON_API LLUriParser { public: - LLUriParser(const std::string& u); - ~LLUriParser(); + LLUriParser(const std::string& u); + ~LLUriParser(); - const char * scheme() const; - void sheme (const std::string& s); + const char * scheme() const; + void sheme (const std::string& s); - const char * port() const; - void port (const std::string& s); + const char * port() const; + void port (const std::string& s); - const char * host() const; - void host (const std::string& s); + const char * host() const; + void host (const std::string& s); - const char * path() const; - void path (const std::string& s); + const char * path() const; + void path (const std::string& s); - const char * query() const; - void query (const std::string& s); + const char * query() const; + void query (const std::string& s); - const char * fragment() const; - void fragment (const std::string& s); + const char * fragment() const; + void fragment (const std::string& s); - const char * normalizedUri() const; + const char * normalizedUri() const; - void extractParts(); - void glue(std::string& uri) const; - void glueFirst(std::string& uri, bool use_scheme = true) const; - void glueSecond(std::string& uri) const; - bool test() const; - S32 normalize(); + void extractParts(); + void glue(std::string& uri) const; + void glueFirst(std::string& uri, bool use_scheme = true) const; + void glueSecond(std::string& uri) const; + bool test() const; + S32 normalize(); private: - S32 parse(); - void textRangeToString(UriTextRangeA& textRange, std::string& str); - std::string mScheme; - std::string mHost; - std::string mPort; - std::string mPath; - std::string mQuery; - std::string mFragment; - std::string mNormalizedUri; + S32 parse(); + void textRangeToString(UriTextRangeA& textRange, std::string& str); + std::string mScheme; + std::string mHost; + std::string mPort; + std::string mPath; + std::string mQuery; + std::string mFragment; + std::string mNormalizedUri; - UriUriA mUri; + UriUriA mUri; - S32 mRes; - bool mTmpScheme; - bool mNormalizedTmp; + S32 mRes; + bool mTmpScheme; + bool mNormalizedTmp; }; #endif // LL_LLURIPARSER_H diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 200add404f..ab66fa6ddc 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -50,7 +50,7 @@ const LLUUID LLUUID::null; const LLTransactionID LLTransactionID::tnull; -// static +// static LLMutex* LLUUID::mMutex = NULL; @@ -187,7 +187,7 @@ void LLUUID::toString(char* out) const void LLUUID::toCompressedString(std::string& out) const { char bytes[UUID_BYTES + 1]; - memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */ + memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */ bytes[UUID_BYTES] = '\0'; out.assign(bytes, UUID_BYTES); } @@ -195,7 +195,7 @@ void LLUUID::toCompressedString(std::string& out) const // *TODO: deprecate void LLUUID::toCompressedString(char* out) const { - memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */ + memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */ out[UUID_BYTES] = '\0'; } @@ -227,11 +227,11 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) return TRUE; } - if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ + if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ { // I'm a moron. First implementation didn't have the right UUID format. // Shouldn't see any of these any more - if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ + if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ { if (emit) { @@ -323,10 +323,10 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) BOOL LLUUID::validate(const std::string& in_string) { BOOL broken_format = FALSE; - if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ + if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ { // I'm a moron. First implementation didn't have the right UUID format. - if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ + if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ { broken_format = TRUE; } @@ -431,7 +431,7 @@ std::ostream& operator<<(std::ostream& s, const LLUUID& uuid) std::istream& operator>>(std::istream& s, LLUUID& uuid) { U32 i; - char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */ + char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */ for (i = 0; i < UUID_STR_LENGTH - 1; i++) { s >> uuid_str[i]; @@ -459,7 +459,7 @@ static void get_random_bytes(void* buf, int nbytes) return; } -#if LL_WINDOWS +#if LL_WINDOWS typedef struct _ASTAT_ { @@ -468,7 +468,7 @@ typedef struct _ASTAT_ }ASTAT, * PASTAT; // static -S32 LLUUID::getNodeID(unsigned char* node_id) +S32 LLUUID::getNodeID(unsigned char* node_id) { ASTAT Adapter; NCB Ncb; @@ -495,14 +495,14 @@ S32 LLUUID::getNodeID(unsigned char* node_id) Ncb.ncb_command = NCBASTAT; Ncb.ncb_lana_num = lenum.lana[i]; - strcpy((char*)Ncb.ncb_callname, "* "); /* Flawfinder: ignore */ + strcpy((char*)Ncb.ncb_callname, "* "); /* Flawfinder: ignore */ Ncb.ncb_buffer = (unsigned char*)&Adapter; Ncb.ncb_length = sizeof(Adapter); uRetCode = Netbios(&Ncb); if (uRetCode == 0) { - memcpy(node_id, Adapter.adapt.adapter_address, 6); /* Flawfinder: ignore */ + memcpy(node_id, Adapter.adapt.adapter_address, 6); /* Flawfinder: ignore */ retval = 1; } } @@ -545,19 +545,19 @@ S32 LLUUID::getNodeID(unsigned char* node_id) for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { - // printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family); + // printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family); for (i = 0; i < ifa->ifa_addr->sa_len; i++) { - // printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]); + // printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]); } - // printf("\n"); + // printf("\n"); if (ifa->ifa_addr->sa_family == AF_LINK) { // This is a link-level address struct sockaddr_dl* lla = (struct sockaddr_dl*)ifa->ifa_addr; - // printf("\tLink level address, type %02X\n", lla->sdl_type); + // printf("\tLink level address, type %02X\n", lla->sdl_type); if (lla->sdl_type == IFT_ETHER) { @@ -614,11 +614,11 @@ S32 LLUUID::getNodeID(unsigned char* node_id) // static S32 LLUUID::getNodeID(unsigned char* node_id) { - int sd; - struct ifreq ifr, * ifrp; - struct ifconf ifc; + int sd; + struct ifreq ifr, * ifrp; + struct ifconf ifc; char buf[1024]; - int n, i; + int n, i; unsigned char* a; /* @@ -651,7 +651,7 @@ S32 LLUUID::getNodeID(unsigned char* node_id) n = ifc.ifc_len; for (i = 0; i < n; i += ifreq_size(*ifr)) { ifrp = (struct ifreq*)((char*)ifc.ifc_buf + i); - strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */ + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */ #ifdef SIOCGIFHWADDR if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) continue; @@ -673,7 +673,7 @@ S32 LLUUID::getNodeID(unsigned char* node_id) if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue; if (node_id) { - memcpy(node_id, a, 6); /* Flawfinder: ignore */ + memcpy(node_id, a, 6); /* Flawfinder: ignore */ close(sd); return 1; } @@ -784,7 +784,7 @@ void LLUUID::generate() // Create a UUID. uuid_time_t timestamp; - static unsigned char node_id[6]; /* Flawfinder: ignore */ + static unsigned char node_id[6]; /* Flawfinder: ignore */ static int has_init = 0; // Create a UUID. @@ -826,16 +826,16 @@ void LLUUID::generate() // if clock hasn't changed or went backward, change clockseq if (cmpTime(×tamp, &time_last) != 1) { - LLMutexLock lock(mMutex); + LLMutexLock lock(mMutex); clock_seq = (clock_seq + 1) & 0x3FFF; if (clock_seq == 0) clock_seq++; - our_clock_seq = clock_seq; // Ensure we're using a different clock_seq value from previous time + our_clock_seq = clock_seq; // Ensure we're using a different clock_seq value from previous time } time_last = timestamp; - memcpy(mData + 10, node_id, 6); /* Flawfinder: ignore */ + memcpy(mData + 10, node_id, 6); /* Flawfinder: ignore */ U32 tmp; tmp = timestamp.low; mData[3] = (unsigned char)tmp; @@ -872,7 +872,7 @@ void LLUUID::generate(const std::string& hash_string) U32 LLUUID::getRandomSeed() { - static unsigned char seed[16]; /* Flawfinder: ignore */ + static unsigned char seed[16]; /* Flawfinder: ignore */ getNodeID(&seed[0]); diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 80597fa186..eea5e39c61 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -1,24 +1,24 @@ -/** +/** * @file lluuid.h * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,104 +37,104 @@ class LLMutex; const S32 UUID_BYTES = 16; const S32 UUID_WORDS = 4; -const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below +const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below const S32 UUID_STR_SIZE = 37; const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL. struct uuid_time_t { - U32 high; - U32 low; - }; + U32 high; + U32 low; + }; class LL_COMMON_API LLUUID { public: - // - // CREATORS - // - LLUUID(); - explicit LLUUID(const char *in_string); // Convert from string. - explicit LLUUID(const std::string& in_string); // Convert from string. - ~LLUUID() = default; - - // - // MANIPULATORS - // - void generate(); // Generate a new UUID - void generate(const std::string& stream); //Generate a new UUID based on hash of input stream - - static LLUUID generateNewID(std::string stream = ""); //static version of above for use in initializer expressions such as constructor params, etc. - - BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings - BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings - void setNull(); // Faster than setting to LLUUID::null. + // + // CREATORS + // + LLUUID(); + explicit LLUUID(const char *in_string); // Convert from string. + explicit LLUUID(const std::string& in_string); // Convert from string. + ~LLUUID() = default; + + // + // MANIPULATORS + // + void generate(); // Generate a new UUID + void generate(const std::string& stream); //Generate a new UUID based on hash of input stream + + static LLUUID generateNewID(std::string stream = ""); //static version of above for use in initializer expressions such as constructor params, etc. + + BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings + BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings + void setNull(); // Faster than setting to LLUUID::null. S32 cmpTime(uuid_time_t *t1, uuid_time_t *t2); - static void getSystemTime(uuid_time_t *timestamp); - void getCurrentTime(uuid_time_t *timestamp); - - // - // ACCESSORS - // - BOOL isNull() const; // Faster than comparing to LLUUID::null. - BOOL notNull() const; // Faster than comparing to LLUUID::null. - // JC: This is dangerous. It allows UUIDs to be cast automatically - // to integers, among other things. Use isNull() or notNull(). - // operator bool() const; - - // JC: These must return real bool's (not BOOLs) or else use of the STL - // will generate bool-to-int performance warnings. - bool operator==(const LLUUID &rhs) const; - bool operator!=(const LLUUID &rhs) const; - bool operator<(const LLUUID &rhs) const; - bool operator>(const LLUUID &rhs) const; - - // xor functions. Useful since any two random uuids xored together - // will yield a determinate third random unique id that can be - // used as a key in a single uuid that represents 2. - const LLUUID& operator^=(const LLUUID& rhs); - LLUUID operator^(const LLUUID& rhs) const; - - // similar to functions above, but not invertible - // yields a third random UUID that can be reproduced from the two inputs - // but which, given the result and one of the inputs can't be used to - // deduce the other input - LLUUID combine(const LLUUID& other) const; - void combine(const LLUUID& other, LLUUID& result) const; - - friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); - friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid); - - void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0) - void toString(std::string& out) const; - void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0) - void toCompressedString(std::string& out) const; - - std::string asString() const; - std::string getString() const; - - U16 getCRC16() const; - U32 getCRC32() const; - - // Returns a 64 bits digest of the UUID, by XORing its two 64 bits long - // words. HB - inline U64 getDigest64() const - { - U64* tmp = (U64*)mData; - return tmp[0] ^ tmp[1]; - } - - static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. - - static const LLUUID null; - static LLMutex * mMutex; - - static U32 getRandomSeed(); - static S32 getNodeID(unsigned char * node_id); - - static BOOL parseUUID(const std::string& buf, LLUUID* value); - - U8 mData[UUID_BYTES]; + static void getSystemTime(uuid_time_t *timestamp); + void getCurrentTime(uuid_time_t *timestamp); + + // + // ACCESSORS + // + BOOL isNull() const; // Faster than comparing to LLUUID::null. + BOOL notNull() const; // Faster than comparing to LLUUID::null. + // JC: This is dangerous. It allows UUIDs to be cast automatically + // to integers, among other things. Use isNull() or notNull(). + // operator bool() const; + + // JC: These must return real bool's (not BOOLs) or else use of the STL + // will generate bool-to-int performance warnings. + bool operator==(const LLUUID &rhs) const; + bool operator!=(const LLUUID &rhs) const; + bool operator<(const LLUUID &rhs) const; + bool operator>(const LLUUID &rhs) const; + + // xor functions. Useful since any two random uuids xored together + // will yield a determinate third random unique id that can be + // used as a key in a single uuid that represents 2. + const LLUUID& operator^=(const LLUUID& rhs); + LLUUID operator^(const LLUUID& rhs) const; + + // similar to functions above, but not invertible + // yields a third random UUID that can be reproduced from the two inputs + // but which, given the result and one of the inputs can't be used to + // deduce the other input + LLUUID combine(const LLUUID& other) const; + void combine(const LLUUID& other, LLUUID& result) const; + + friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); + friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid); + + void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0) + void toString(std::string& out) const; + void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0) + void toCompressedString(std::string& out) const; + + std::string asString() const; + std::string getString() const; + + U16 getCRC16() const; + U32 getCRC32() const; + + // Returns a 64 bits digest of the UUID, by XORing its two 64 bits long + // words. HB + inline U64 getDigest64() const + { + U64* tmp = (U64*)mData; + return tmp[0] ^ tmp[1]; + } + + static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. + + static const LLUUID null; + static LLMutex * mMutex; + + static U32 getRandomSeed(); + static S32 getNodeID(unsigned char * node_id); + + static BOOL parseUUID(const std::string& buf, LLUUID* value); + + U8 mData[UUID_BYTES]; }; static_assert(std::is_trivially_copyable<LLUUID>::value, "LLUUID must be trivial copy"); static_assert(std::is_trivially_move_assignable<LLUUID>::value, "LLUUID must be trivial move"); @@ -151,10 +151,10 @@ typedef std::set<LLUUID> uuid_set_t; // verify.) struct lluuid_less { - bool operator()(const LLUUID& lhs, const LLUUID& rhs) const - { - return (lhs < rhs) ? true : false; - } + bool operator()(const LLUUID& lhs, const LLUUID& rhs) const + { + return (lhs < rhs) ? true : false; + } }; typedef std::set<LLUUID, lluuid_less> uuid_list_t; @@ -167,28 +167,28 @@ typedef LLUUID LLAssetID; class LL_COMMON_API LLTransactionID : public LLUUID { public: - LLTransactionID() : LLUUID() { } - - static const LLTransactionID tnull; - LLAssetID makeAssetID(const LLUUID& session) const; + LLTransactionID() : LLUUID() { } + + static const LLTransactionID tnull; + LLAssetID makeAssetID(const LLUUID& session) const; }; // std::hash implementation for LLUUID namespace std { - template<> struct hash<LLUUID> - { - inline size_t operator()(const LLUUID& id) const noexcept - { - return (size_t)id.getDigest64(); - } - }; + template<> struct hash<LLUUID> + { + inline size_t operator()(const LLUUID& id) const noexcept + { + return (size_t)id.getDigest64(); + } + }; } // For use with boost containers. inline size_t hash_value(const LLUUID& id) noexcept { - return (size_t)id.getDigest64(); + return (size_t)id.getDigest64(); } #endif // LL_LLUUID_H diff --git a/indra/llcommon/llwin32headers.h b/indra/llcommon/llwin32headers.h index 8cfa40ada8..f679adc200 100644 --- a/indra/llcommon/llwin32headers.h +++ b/indra/llcommon/llwin32headers.h @@ -1,25 +1,25 @@ -/** +/** * @file llwin32headers.h * @brief sanitized include of windows header files * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llwin32headerslean.h b/indra/llcommon/llwin32headerslean.h index 314e7a85d1..97c8edb8cf 100644 --- a/indra/llcommon/llwin32headerslean.h +++ b/indra/llcommon/llwin32headerslean.h @@ -1,25 +1,25 @@ -/** +/** * @file llwin32headerslean.h * @brief sanitized include of windows header files * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 06c74bdba0..67df2b5840 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llworkerthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,134 +35,134 @@ // Run on MAIN thread LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) : - LLQueuedThread(name, threaded, should_pause) + LLQueuedThread(name, threaded, should_pause) { - mDeleteMutex = new LLMutex(); + mDeleteMutex = new LLMutex(); - if(!mLocalAPRFilePoolp) - { - mLocalAPRFilePoolp = new LLVolatileAPRPool() ; - } + if(!mLocalAPRFilePoolp) + { + mLocalAPRFilePoolp = new LLVolatileAPRPool() ; + } } LLWorkerThread::~LLWorkerThread() { - // Delete any workers in the delete queue (should be safe - had better be!) - if (!mDeleteList.empty()) - { - LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << LL_ENDL; - } - - delete mDeleteMutex; - - // ~LLQueuedThread() will be called here + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) + { + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; + } + + delete mDeleteMutex; + + // ~LLQueuedThread() will be called here } //called only in destructor. void LLWorkerThread::clearDeleteList() { - // Delete any workers in the delete queue (should be safe - had better be!) - if (!mDeleteList.empty()) - { - LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << LL_ENDL; - - mDeleteMutex->lock(); - for (LLWorkerClass* worker : mDeleteList) - { - worker->mRequestHandle = LLWorkerThread::nullHandle(); - worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); - worker->clearFlags(LLWorkerClass::WCF_WORKING); - delete worker; - } - mDeleteList.clear() ; - mDeleteMutex->unlock() ; - } + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) + { + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; + + mDeleteMutex->lock(); + for (LLWorkerClass* worker : mDeleteList) + { + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + worker->clearFlags(LLWorkerClass::WCF_WORKING); + delete worker; + } + mDeleteList.clear() ; + mDeleteMutex->unlock() ; + } } // virtual size_t LLWorkerThread::update(F32 max_time_ms) { - auto res = LLQueuedThread::update(max_time_ms); - // Delete scheduled workers - std::vector<LLWorkerClass*> delete_list; - std::vector<LLWorkerClass*> abort_list; - mDeleteMutex->lock(); - for (delete_list_t::iterator iter = mDeleteList.begin(); - iter != mDeleteList.end(); ) - { - delete_list_t::iterator curiter = iter++; - LLWorkerClass* worker = *curiter; - if (worker->deleteOK()) - { - if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) - { + auto res = LLQueuedThread::update(max_time_ms); + // Delete scheduled workers + std::vector<LLWorkerClass*> delete_list; + std::vector<LLWorkerClass*> abort_list; + mDeleteMutex->lock(); + for (delete_list_t::iterator iter = mDeleteList.begin(); + iter != mDeleteList.end(); ) + { + delete_list_t::iterator curiter = iter++; + LLWorkerClass* worker = *curiter; + if (worker->deleteOK()) + { + if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) + { worker->setFlags(LLWorkerClass::WCF_DELETE_REQUESTED); - delete_list.push_back(worker); - mDeleteList.erase(curiter); - } - else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) - { - abort_list.push_back(worker); - } - } - } - mDeleteMutex->unlock(); - // abort and delete after releasing mutex - for (LLWorkerClass* worker : abort_list) - { - worker->abortWork(false); - } - for (LLWorkerClass* worker : delete_list) - { - if (worker->mRequestHandle) - { - // Finished but not completed - completeRequest(worker->mRequestHandle); - worker->mRequestHandle = LLWorkerThread::nullHandle(); - worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); - } - delete worker; - } - // delete and aborted entries mean there's still work to do - res += delete_list.size() + abort_list.size(); - return res; + delete_list.push_back(worker); + mDeleteList.erase(curiter); + } + else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) + { + abort_list.push_back(worker); + } + } + } + mDeleteMutex->unlock(); + // abort and delete after releasing mutex + for (LLWorkerClass* worker : abort_list) + { + worker->abortWork(false); + } + for (LLWorkerClass* worker : delete_list) + { + if (worker->mRequestHandle) + { + // Finished but not completed + completeRequest(worker->mRequestHandle); + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + } + delete worker; + } + // delete and aborted entries mean there's still work to do + res += delete_list.size() + abort_list.size(); + return res; } //---------------------------------------------------------------------------- LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param) { - handle_t handle = generateHandle(); - - WorkRequest* req = new WorkRequest(handle, workerclass, param); - - bool res = addRequest(req); - if (!res) - { - LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL; - req->deleteRequest(); - handle = nullHandle(); - } - - return handle; + handle_t handle = generateHandle(); + + WorkRequest* req = new WorkRequest(handle, workerclass, param); + + bool res = addRequest(req); + if (!res) + { + LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL; + req->deleteRequest(); + handle = nullHandle(); + } + + return handle; } void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass) { - mDeleteMutex->lock(); - mDeleteList.push_back(workerclass); - mDeleteMutex->unlock(); + mDeleteMutex->lock(); + mDeleteList.push_back(workerclass); + mDeleteMutex->unlock(); } //============================================================================ // Runs on its OWN thread LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param) : - LLQueuedThread::QueuedRequest(handle), - mWorkerClass(workerclass), - mParam(param) + LLQueuedThread::QueuedRequest(handle), + mWorkerClass(workerclass), + mParam(param) { } @@ -173,75 +173,75 @@ LLWorkerThread::WorkRequest::~WorkRequest() // virtual (required for access by LLWorkerThread) void LLWorkerThread::WorkRequest::deleteRequest() { - LLQueuedThread::QueuedRequest::deleteRequest(); -} + LLQueuedThread::QueuedRequest::deleteRequest(); +} // virtual bool LLWorkerThread::WorkRequest::processRequest() { LL_PROFILE_ZONE_SCOPED; - LLWorkerClass* workerclass = getWorkerClass(); - workerclass->setWorking(true); - bool complete = workerclass->doWork(getParam()); - workerclass->setWorking(false); - return complete; + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->setWorking(true); + bool complete = workerclass->doWork(getParam()); + workerclass->setWorking(false); + return complete; } // virtual void LLWorkerThread::WorkRequest::finishRequest(bool completed) { LL_PROFILE_ZONE_SCOPED; - LLWorkerClass* workerclass = getWorkerClass(); - workerclass->finishWork(getParam(), completed); - U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED); - workerclass->setFlags(flags); + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->finishWork(getParam(), completed); + U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED); + workerclass->setFlags(flags); } //============================================================================ // LLWorkerClass:: operates in main thread LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name) - : mWorkerThread(workerthread), - mWorkerClassName(name), - mRequestHandle(LLWorkerThread::nullHandle()), - mMutex(), - mWorkFlags(0) + : mWorkerThread(workerthread), + mWorkerClassName(name), + mRequestHandle(LLWorkerThread::nullHandle()), + mMutex(), + mWorkFlags(0) { - if (!mWorkerThread) - { - LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL; - } + if (!mWorkerThread) + { + LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL; + } } LLWorkerClass::~LLWorkerClass() { - llassert_always(!(mWorkFlags & WCF_WORKING)); - llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); - llassert_always(!mMutex.isLocked()); - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); - if (!workreq) - { - LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL; - } - if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && - workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) - { - LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL; - } - } + llassert_always(!(mWorkFlags & WCF_WORKING)); + llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); + llassert_always(!mMutex.isLocked()); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + if (!workreq) + { + LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL; + } + if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && + workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) + { + LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL; + } + } } void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) { - mMutex.lock(); - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL; - } - mWorkerThread = workerthread; - mMutex.unlock(); + mMutex.lock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL; + } + mWorkerThread = workerthread; + mMutex.unlock(); } //---------------------------------------------------------------------------- @@ -254,7 +254,7 @@ void LLWorkerClass::finishWork(S32 param, bool success) //virtual bool LLWorkerClass::deleteOK() { - return true; // default always OK + return true; // default always OK } //---------------------------------------------------------------------------- @@ -262,31 +262,31 @@ bool LLWorkerClass::deleteOK() // Called from worker thread void LLWorkerClass::setWorking(bool working) { - mMutex.lock(); - if (working) - { - llassert_always(!(mWorkFlags & WCF_WORKING)); - setFlags(WCF_WORKING); - } - else - { - llassert_always((mWorkFlags & WCF_WORKING)); - clearFlags(WCF_WORKING); - } - mMutex.unlock(); + mMutex.lock(); + if (working) + { + llassert_always(!(mWorkFlags & WCF_WORKING)); + setFlags(WCF_WORKING); + } + else + { + llassert_always((mWorkFlags & WCF_WORKING)); + clearFlags(WCF_WORKING); + } + mMutex.unlock(); } //---------------------------------------------------------------------------- bool LLWorkerClass::yield() { - LLThread::yield(); - mWorkerThread->checkPause(); - bool res; - mMutex.lock(); - res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false; - mMutex.unlock(); - return res; + LLThread::yield(); + mWorkerThread->checkPause(); + bool res; + mMutex.lock(); + res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false; + mMutex.unlock(); + return res; } //---------------------------------------------------------------------------- @@ -294,104 +294,104 @@ bool LLWorkerClass::yield() // calls startWork, adds doWork() to queue void LLWorkerClass::addWork(S32 param) { - mMutex.lock(); - llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL; - } + mMutex.lock(); + llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL; + } #if _DEBUG -// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL; +// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL; #endif - startWork(param); - clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); - setFlags(WCF_HAVE_WORK); - mRequestHandle = mWorkerThread->addWorkRequest(this, param); - mMutex.unlock(); + startWork(param); + clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); + setFlags(WCF_HAVE_WORK); + mRequestHandle = mWorkerThread->addWorkRequest(this, param); + mMutex.unlock(); } void LLWorkerClass::abortWork(bool autocomplete) { - mMutex.lock(); + mMutex.lock(); #if _DEBUG -// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); -// if (workreq) -// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL; +// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); +// if (workreq) +// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL; #endif - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - mWorkerThread->abortRequest(mRequestHandle, autocomplete); - setFlags(WCF_ABORT_REQUESTED); - } - mMutex.unlock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + mWorkerThread->abortRequest(mRequestHandle, autocomplete); + setFlags(WCF_ABORT_REQUESTED); + } + mMutex.unlock(); } // if doWork is complete or aborted, call endWork() and return true bool LLWorkerClass::checkWork(bool aborting) { - LLMutexLock lock(&mMutex); - bool complete = false, abort = false; - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); - if(!workreq) - { - if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running - { - mRequestHandle = LLWorkerThread::nullHandle(); - clearFlags(WCF_HAVE_WORK); - } - else - { - llassert_always(workreq); - } - return true ; - } - - LLQueuedThread::status_t status = workreq->getStatus(); - if (status == LLWorkerThread::STATUS_ABORTED) - { - complete = true; - abort = true; - } - else if (status == LLWorkerThread::STATUS_COMPLETE) - { - complete = true; - } - else - { - llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT)); - } - if (complete) - { - llassert_always(!(getFlags(WCF_WORKING))); - endWork(workreq->getParam(), abort); - mWorkerThread->completeRequest(mRequestHandle); - mRequestHandle = LLWorkerThread::nullHandle(); - clearFlags(WCF_HAVE_WORK); - } - } - else - { - complete = true; - } - return complete; + LLMutexLock lock(&mMutex); + bool complete = false, abort = false; + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + if(!workreq) + { + if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running + { + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } + else + { + llassert_always(workreq); + } + return true ; + } + + LLQueuedThread::status_t status = workreq->getStatus(); + if (status == LLWorkerThread::STATUS_ABORTED) + { + complete = true; + abort = true; + } + else if (status == LLWorkerThread::STATUS_COMPLETE) + { + complete = true; + } + else + { + llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT)); + } + if (complete) + { + llassert_always(!(getFlags(WCF_WORKING))); + endWork(workreq->getParam(), abort); + mWorkerThread->completeRequest(mRequestHandle); + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } + } + else + { + complete = true; + } + return complete; } void LLWorkerClass::scheduleDelete() { - bool do_delete = false; - mMutex.lock(); - if (!(getFlags(WCF_DELETE_REQUESTED))) - { - setFlags(WCF_DELETE_REQUESTED); - do_delete = true; - } - mMutex.unlock(); - if (do_delete) - { - mWorkerThread->deleteWorker(this); - } + bool do_delete = false; + mMutex.lock(); + if (!(getFlags(WCF_DELETE_REQUESTED))) + { + setFlags(WCF_DELETE_REQUESTED); + do_delete = true; + } + mMutex.unlock(); + if (do_delete) + { + mWorkerThread->deleteWorker(this); + } } //============================================================================ diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index bf94c84090..01c96852d3 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -1,24 +1,24 @@ -/** +/** * @file llworkerthread.h * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,55 +48,55 @@ class LLWorkerClass; class LL_COMMON_API LLWorkerThread : public LLQueuedThread { - friend class LLWorkerClass; + friend class LLWorkerClass; public: - class WorkRequest : public LLQueuedThread::QueuedRequest - { - protected: - virtual ~WorkRequest(); // use deleteRequest() - - public: - WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param); - - S32 getParam() - { - return mParam; - } - LLWorkerClass* getWorkerClass() - { - return mWorkerClass; - } - - /*virtual*/ bool processRequest(); - /*virtual*/ void finishRequest(bool completed); - /*virtual*/ void deleteRequest(); - - private: - LLWorkerClass* mWorkerClass; - S32 mParam; - }; + class WorkRequest : public LLQueuedThread::QueuedRequest + { + protected: + virtual ~WorkRequest(); // use deleteRequest() + + public: + WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param); + + S32 getParam() + { + return mParam; + } + LLWorkerClass* getWorkerClass() + { + return mWorkerClass; + } + + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); + /*virtual*/ void deleteRequest(); + + private: + LLWorkerClass* mWorkerClass; + S32 mParam; + }; protected: - void clearDeleteList() ; + void clearDeleteList() ; private: - typedef std::list<LLWorkerClass*> delete_list_t; - delete_list_t mDeleteList; - LLMutex* mDeleteMutex; - + typedef std::list<LLWorkerClass*> delete_list_t; + delete_list_t mDeleteList; + LLMutex* mDeleteMutex; + public: - LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false); - ~LLWorkerThread(); + LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false); + ~LLWorkerThread(); - /*virtual*/ size_t update(F32 max_time_ms); - - handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param); - - S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug + /*virtual*/ size_t update(F32 max_time_ms); + + handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param); + + S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug private: - void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion - + void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion + }; //============================================================================ @@ -118,81 +118,81 @@ private: class LL_COMMON_API LLWorkerClass { - friend class LLWorkerThread; - friend class LLWorkerThread::WorkRequest; + friend class LLWorkerThread; + friend class LLWorkerThread::WorkRequest; public: - typedef LLWorkerThread::handle_t handle_t; - enum FLAGS - { - WCF_HAVE_WORK = 0x01, - WCF_WORKING = 0x02, - WCF_WORK_FINISHED = 0x10, - WCF_WORK_ABORTED = 0x20, - WCF_DELETE_REQUESTED = 0x40, - WCF_ABORT_REQUESTED = 0x80 - }; - + typedef LLWorkerThread::handle_t handle_t; + enum FLAGS + { + WCF_HAVE_WORK = 0x01, + WCF_WORKING = 0x02, + WCF_WORK_FINISHED = 0x10, + WCF_WORK_ABORTED = 0x20, + WCF_DELETE_REQUESTED = 0x40, + WCF_ABORT_REQUESTED = 0x80 + }; + public: - LLWorkerClass(LLWorkerThread* workerthread, const std::string& name); - virtual ~LLWorkerClass(); - - // pure virtual, called from WORKER THREAD, returns TRUE if done - virtual bool doWork(S32 param)=0; // Called from WorkRequest::processRequest() - // virtual, called from finishRequest() after completed or aborted - virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) - // virtual, returns true if safe to delete the worker - virtual bool deleteOK(); // called from update() (WORK THREAD) - - // schedlueDelete(): schedules deletion once aborted or completed - void scheduleDelete(); - - bool haveWork() { return getFlags(WCF_HAVE_WORK); } // may still be true if aborted - bool isWorking() { return getFlags(WCF_WORKING); } - bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); } - - const std::string& getName() const { return mWorkerClassName; } + LLWorkerClass(LLWorkerThread* workerthread, const std::string& name); + virtual ~LLWorkerClass(); + + // pure virtual, called from WORKER THREAD, returns TRUE if done + virtual bool doWork(S32 param)=0; // Called from WorkRequest::processRequest() + // virtual, called from finishRequest() after completed or aborted + virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) + // virtual, returns true if safe to delete the worker + virtual bool deleteOK(); // called from update() (WORK THREAD) + + // schedlueDelete(): schedules deletion once aborted or completed + void scheduleDelete(); + + bool haveWork() { return getFlags(WCF_HAVE_WORK); } // may still be true if aborted + bool isWorking() { return getFlags(WCF_WORKING); } + bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); } + + const std::string& getName() const { return mWorkerClassName; } protected: - // called from WORKER THREAD - void setWorking(bool working); - - // Call from doWork only to avoid eating up cpu time. - // Returns true if work has been aborted - // yields the current thread and calls mWorkerThread->checkPause() - bool yield(); - - void setWorkerThread(LLWorkerThread* workerthread); - - // addWork(): calls startWork, adds doWork() to queue - void addWork(S32 param); - - // abortWork(): requests that work be aborted - void abortWork(bool autocomplete); - - // checkWork(): if doWork is complete or aborted, call endWork() and return true - bool checkWork(bool aborting = false); + // called from WORKER THREAD + void setWorking(bool working); + + // Call from doWork only to avoid eating up cpu time. + // Returns true if work has been aborted + // yields the current thread and calls mWorkerThread->checkPause() + bool yield(); + + void setWorkerThread(LLWorkerThread* workerthread); + + // addWork(): calls startWork, adds doWork() to queue + void addWork(S32 param); + + // abortWork(): requests that work be aborted + void abortWork(bool autocomplete); + + // checkWork(): if doWork is complete or aborted, call endWork() and return true + bool checkWork(bool aborting = false); private: - void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; } - void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; } - U32 getFlags() { return mWorkFlags; } + void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; } + void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; } + U32 getFlags() { return mWorkFlags; } public: - bool getFlags(U32 flags) { return mWorkFlags & flags ? true : false; } - + bool getFlags(U32 flags) { return mWorkFlags & flags ? true : false; } + private: - // pure virtuals - virtual void startWork(S32 param)=0; // called from addWork() (MAIN THREAD) - virtual void endWork(S32 param, bool aborted)=0; // called from doWork() (MAIN THREAD) - + // pure virtuals + virtual void startWork(S32 param)=0; // called from addWork() (MAIN THREAD) + virtual void endWork(S32 param, bool aborted)=0; // called from doWork() (MAIN THREAD) + protected: - LLWorkerThread* mWorkerThread; - std::string mWorkerClassName; - handle_t mRequestHandle; + LLWorkerThread* mWorkerThread; + std::string mWorkerClassName; + handle_t mRequestHandle; private: - LLMutex mMutex; - LLAtomicU32 mWorkFlags; + LLMutex mMutex; + LLAtomicU32 mWorkFlags; }; //============================================================================ diff --git a/indra/llcommon/lockstatic.h b/indra/llcommon/lockstatic.h index 96c53c6473..7cc9b7eec0 100644 --- a/indra/llcommon/lockstatic.h +++ b/indra/llcommon/lockstatic.h @@ -4,7 +4,7 @@ * @date 2019-12-03 * @brief LockStatic class provides mutex-guarded access to the specified * static data. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/mutex.h b/indra/llcommon/mutex.h index 90d0942270..82e46315e2 100644 --- a/indra/llcommon/mutex.h +++ b/indra/llcommon/mutex.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-12-03 * @brief Wrap <mutex> in odious boilerplate - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index 3aba9dda00..28e50b3d21 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -1,25 +1,25 @@ -/** +/** * @file stdtypes.h * @brief Basic type declarations for cross platform compatibility. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,12 +32,12 @@ #include <limits> #include <type_traits> -typedef signed char S8; -typedef unsigned char U8; -typedef signed short S16; -typedef unsigned short U16; -typedef signed int S32; -typedef unsigned int U32; +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; +typedef signed int S32; +typedef unsigned int U32; // to express an index that might go negative // (ssize_t is provided by SOME compilers, don't collide) @@ -52,9 +52,9 @@ typedef typename std::make_signed<std::size_t>::type llssize; // The version of clang available with VS 2019 also defines wchar_t as __wchar_t // which is also 16 bits. // In any case, llwchar should be a UTF-32 type. -typedef U32 llwchar; +typedef U32 llwchar; #else -typedef wchar_t llwchar; +typedef wchar_t llwchar; // What we'd actually want is a simple module-scope 'if constexpr' to test // std::is_same<wchar_t, llwchar>::value and use that to define, or not // define, string conversion specializations. Since we don't have that, we'll @@ -63,63 +63,63 @@ typedef wchar_t llwchar; #endif #if LL_WINDOWS -typedef signed __int64 S64; +typedef signed __int64 S64; // probably should be 'hyper' or similiar -#define S64L(a) (a) -typedef unsigned __int64 U64; -#define U64L(a) (a) +#define S64L(a) (a) +typedef unsigned __int64 U64; +#define U64L(a) (a) #else -typedef long long int S64; -typedef long long unsigned int U64; +typedef long long int S64; +typedef long long unsigned int U64; #if LL_DARWIN || LL_LINUX -#define S64L(a) (a##LL) -#define U64L(a) (a##ULL) +#define S64L(a) (a##LL) +#define U64L(a) (a##ULL) #endif #endif -typedef float F32; -typedef double F64; +typedef float F32; +typedef double F64; -typedef S32 BOOL; -typedef U8 KEY; -typedef U32 MASK; -typedef U32 TPACKETID; +typedef S32 BOOL; +typedef U8 KEY; +typedef U32 MASK; +typedef U32 TPACKETID; // Use #define instead of consts to avoid conversion headaches -#define S8_MAX (SCHAR_MAX) -#define U8_MAX (UCHAR_MAX) -#define S16_MAX (SHRT_MAX) -#define U16_MAX (USHRT_MAX) -#define S32_MAX (INT_MAX) -#define U32_MAX (UINT_MAX) -#define F32_MAX (FLT_MAX) -#define F64_MAX (DBL_MAX) - -#define S8_MIN (SCHAR_MIN) -#define U8_MIN (0) -#define S16_MIN (SHRT_MIN) -#define U16_MIN (0) -#define S32_MIN (INT_MIN) -#define U32_MIN (0) -#define F32_MIN (FLT_MIN) -#define F64_MIN (DBL_MIN) +#define S8_MAX (SCHAR_MAX) +#define U8_MAX (UCHAR_MAX) +#define S16_MAX (SHRT_MAX) +#define U16_MAX (USHRT_MAX) +#define S32_MAX (INT_MAX) +#define U32_MAX (UINT_MAX) +#define F32_MAX (FLT_MAX) +#define F64_MAX (DBL_MAX) + +#define S8_MIN (SCHAR_MIN) +#define U8_MIN (0) +#define S16_MIN (SHRT_MIN) +#define U16_MIN (0) +#define S32_MIN (INT_MIN) +#define U32_MIN (0) +#define F32_MIN (FLT_MIN) +#define F64_MIN (DBL_MIN) #ifndef TRUE -#define TRUE (1) +#define TRUE (1) #endif #ifndef FALSE -#define FALSE (0) +#define FALSE (0) #endif #ifndef NULL -#define NULL (0) +#define NULL (0) #endif typedef U8 LLPCode; -#define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) ) +#define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) ) #if LL_LINUX && __GNUC__ <= 2 typedef int intptr_t; diff --git a/indra/llcommon/string_table.h b/indra/llcommon/string_table.h index fe6416fb50..bb525f884b 100644 --- a/indra/llcommon/string_table.h +++ b/indra/llcommon/string_table.h @@ -1,25 +1,25 @@ -/** +/** * @file string_table.h * @brief Legacy wrapper header. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h index c0b13135f9..536a18abc1 100644 --- a/indra/llcommon/stringize.h +++ b/indra/llcommon/stringize.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-12-17 * @brief stringize(item) template function and STRINGIZE(expression) macro - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/StringVec.h b/indra/llcommon/tests/StringVec.h index a380b00a05..4311cba992 100644 --- a/indra/llcommon/tests/StringVec.h +++ b/indra/llcommon/tests/StringVec.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-24 * @brief Extend TUT ensure_equals() to handle std::vector<std::string> - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/apply_test.cpp b/indra/llcommon/tests/apply_test.cpp index 56b497e0c8..6d213c2db9 100644 --- a/indra/llcommon/tests/apply_test.cpp +++ b/indra/llcommon/tests/apply_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-12-19 * @brief Test for apply. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp index 9bfd567068..2810f926af 100644 --- a/indra/llcommon/tests/bitpack_test.cpp +++ b/indra/llcommon/tests/bitpack_test.cpp @@ -7,25 +7,25 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #include "linden_common.h" #include "../llbitpack.h" @@ -35,84 +35,84 @@ namespace tut { - struct bit_pack - { - }; - typedef test_group<bit_pack> bit_pack_t; - typedef bit_pack_t::object bit_pack_object_t; - tut::bit_pack_t tut_bit_pack("LLBitPack"); - - // pack -> unpack - template<> template<> - void bit_pack_object_t::test<1>() - { - U8 packbuffer[255]; - U8 unpackbuffer[255]; - int pack_bufsize = 0; - int unpack_bufsize = 0; - - LLBitPack bitpack(packbuffer, 255); - - char str[] = "SecondLife is a 3D virtual world"; - int len = sizeof(str); - pack_bufsize = bitpack.bitPack((U8*) str, len*8); - pack_bufsize = bitpack.flushBitPack(); - - LLBitPack bitunpack(packbuffer, pack_bufsize*8); - unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, len*8); - ensure("bitPack: unpack size should be same as string size prior to pack", len == unpack_bufsize); - ensure_memory_matches("str->bitPack->bitUnpack should be equal to string", str, len, unpackbuffer, unpack_bufsize); - } - - // pack large, unpack in individual bytes - template<> template<> - void bit_pack_object_t::test<2>() - { - U8 packbuffer[255]; - U8 unpackbuffer[255]; - int pack_bufsize = 0; - - LLBitPack bitpack(packbuffer, 255); - - char str[] = "SecondLife"; - int len = sizeof(str); - pack_bufsize = bitpack.bitPack((U8*) str, len*8); - pack_bufsize = bitpack.flushBitPack(); - - LLBitPack bitunpack(packbuffer, pack_bufsize*8); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 0", unpackbuffer[0] == (U8) str[0]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 1", unpackbuffer[0] == (U8) str[1]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 2", unpackbuffer[0] == (U8) str[2]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 3", unpackbuffer[0] == (U8) str[3]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 4", unpackbuffer[0] == (U8) str[4]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]); - bitunpack.bitUnpack(unpackbuffer, 8*4); // Life - ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4); - } - - // U32 packing - template<> template<> - void bit_pack_object_t::test<3>() - { - U8 packbuffer[255]; - int pack_bufsize = 0; - - LLBitPack bitpack(packbuffer, 255); - U32 num = 0x41fab67a; - pack_bufsize = bitpack.bitPack((U8*)&num, 8*sizeof(U32)); - pack_bufsize = bitpack.flushBitPack(); - - LLBitPack bitunpack(packbuffer, pack_bufsize*8); - U32 res = 0; - // since packing and unpacking is done on same machine in the unit test run, - // endianness should not matter - bitunpack.bitUnpack((U8*) &res, sizeof(res)*8); - ensure("U32->bitPack->bitUnpack->U32 should be equal", num == res); - } + struct bit_pack + { + }; + typedef test_group<bit_pack> bit_pack_t; + typedef bit_pack_t::object bit_pack_object_t; + tut::bit_pack_t tut_bit_pack("LLBitPack"); + + // pack -> unpack + template<> template<> + void bit_pack_object_t::test<1>() + { + U8 packbuffer[255]; + U8 unpackbuffer[255]; + int pack_bufsize = 0; + int unpack_bufsize = 0; + + LLBitPack bitpack(packbuffer, 255); + + char str[] = "SecondLife is a 3D virtual world"; + int len = sizeof(str); + pack_bufsize = bitpack.bitPack((U8*) str, len*8); + pack_bufsize = bitpack.flushBitPack(); + + LLBitPack bitunpack(packbuffer, pack_bufsize*8); + unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, len*8); + ensure("bitPack: unpack size should be same as string size prior to pack", len == unpack_bufsize); + ensure_memory_matches("str->bitPack->bitUnpack should be equal to string", str, len, unpackbuffer, unpack_bufsize); + } + + // pack large, unpack in individual bytes + template<> template<> + void bit_pack_object_t::test<2>() + { + U8 packbuffer[255]; + U8 unpackbuffer[255]; + int pack_bufsize = 0; + + LLBitPack bitpack(packbuffer, 255); + + char str[] = "SecondLife"; + int len = sizeof(str); + pack_bufsize = bitpack.bitPack((U8*) str, len*8); + pack_bufsize = bitpack.flushBitPack(); + + LLBitPack bitunpack(packbuffer, pack_bufsize*8); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 0", unpackbuffer[0] == (U8) str[0]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 1", unpackbuffer[0] == (U8) str[1]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 2", unpackbuffer[0] == (U8) str[2]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 3", unpackbuffer[0] == (U8) str[3]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 4", unpackbuffer[0] == (U8) str[4]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]); + bitunpack.bitUnpack(unpackbuffer, 8*4); // Life + ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4); + } + + // U32 packing + template<> template<> + void bit_pack_object_t::test<3>() + { + U8 packbuffer[255]; + int pack_bufsize = 0; + + LLBitPack bitpack(packbuffer, 255); + U32 num = 0x41fab67a; + pack_bufsize = bitpack.bitPack((U8*)&num, 8*sizeof(U32)); + pack_bufsize = bitpack.flushBitPack(); + + LLBitPack bitunpack(packbuffer, pack_bufsize*8); + U32 res = 0; + // since packing and unpacking is done on same machine in the unit test run, + // endianness should not matter + bitunpack.bitUnpack((U8*) &res, sizeof(res)*8); + ensure("U32->bitPack->bitUnpack->U32 should be equal", num == res); + } } diff --git a/indra/llcommon/tests/classic_callback_test.cpp b/indra/llcommon/tests/classic_callback_test.cpp index c060775c24..fe79179ce6 100644 --- a/indra/llcommon/tests/classic_callback_test.cpp +++ b/indra/llcommon/tests/classic_callback_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-09-22 * @brief Test ClassicCallback and HeapClassicCallback. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/commonmisc_test.cpp b/indra/llcommon/tests/commonmisc_test.cpp index 4b3e07fa75..3deb864c0c 100644 --- a/indra/llcommon/tests/commonmisc_test.cpp +++ b/indra/llcommon/tests/commonmisc_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file common.cpp * @author Phoenix * @date 2005-10-12 @@ -7,27 +7,27 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -/** - * +/** + * * THOROUGH_DESCRIPTION of common.cpp * */ @@ -54,388 +54,388 @@ namespace tut { - struct sd_data - { - }; - typedef test_group<sd_data> sd_test; - typedef sd_test::object sd_object; - tut::sd_test sd("LLSD"); - - template<> template<> - void sd_object::test<1>() - { - std::ostringstream resp; - resp << "{'connect':true, 'position':[r128,r128,r128], 'look_at':[r0,r1,r0], 'agent_access':'M', 'region_x':i8192, 'region_y':i8192}"; - std::string str = resp.str(); - LLMemoryStream mstr((U8*)str.c_str(), str.size()); - LLSD response; - S32 count = LLSDSerialize::fromNotation(response, mstr, str.size()); - ensure("stream parsed", response.isDefined()); - ensure_equals("stream parse count", count, 13); - ensure_equals("sd type", response.type(), LLSD::TypeMap); - ensure_equals("map element count", response.size(), 6); - ensure_equals("value connect", response["connect"].asBoolean(), true); - ensure_equals("value region_x", response["region_x"].asInteger(),8192); - ensure_equals("value region_y", response["region_y"].asInteger(),8192); - } - - template<> template<> - void sd_object::test<2>() - { - const std::string decoded("random"); - //const std::string encoded("cmFuZG9t\n"); - const std::string streamed("b(6)\"random\""); - typedef std::vector<U8> buf_t; - buf_t buf; - std::copy( - decoded.begin(), - decoded.end(), - std::back_insert_iterator<buf_t>(buf)); - LLSD sd; - sd = buf; - std::stringstream str; - S32 count = LLSDSerialize::toNotation(sd, str); - ensure_equals("output count", count, 1); - std::string actual(str.str()); - ensure_equals("formatted binary encoding", actual, streamed); - sd.clear(); - LLSDSerialize::fromNotation(sd, str, str.str().size()); - std::vector<U8> after; - after = sd.asBinary(); - ensure_equals("binary decoded size", after.size(), decoded.size()); - ensure("binary decoding", (0 == memcmp( - &after[0], - decoded.c_str(), - decoded.size()))); - } - - template<> template<> - void sd_object::test<3>() - { - for(S32 i = 0; i < 100; ++i) - { - // gen up a starting point - typedef std::vector<U8> buf_t; - buf_t source; - srand(i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 10; - std::generate_n( - std::back_insert_iterator<buf_t>(source), - size, - rand); - LLSD sd(source); - std::stringstream str; - S32 count = LLSDSerialize::toNotation(sd, str); - sd.clear(); - ensure_equals("format count", count, 1); - LLSD sd2; - count = LLSDSerialize::fromNotation(sd2, str, str.str().size()); - ensure_equals("parse count", count, 1); - buf_t dest = sd2.asBinary(); - str.str(""); - str << "binary encoding size " << i; - ensure_equals(str.str().c_str(), dest.size(), source.size()); - str.str(""); - str << "binary encoding " << i; - ensure(str.str().c_str(), (source == dest)); - } - } - - template<> template<> - void sd_object::test<4>() - { - std::ostringstream ostr; - ostr << "{'task_id':u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}\n" - << "{\n\tname\tObject|\n}\n"; - std::string expected = ostr.str(); - std::stringstream serialized; - serialized << "'" << LLSDNotationFormatter::escapeString(expected) - << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation( - sd, - serialized, - serialized.str().size()); - ensure_equals("parse count", count, 1); - ensure_equals("String streaming", sd.asString(), expected); - } - - template<> template<> - void sd_object::test<5>() - { - for(S32 i = 0; i < 100; ++i) - { - // gen up a starting point - typedef std::vector<U8> buf_t; - buf_t source; - srand(666 + i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 10; - std::generate_n( - std::back_insert_iterator<buf_t>(source), - size, - rand); - std::stringstream str; - str << "b(" << size << ")\""; - str.write((const char*)&source[0], size); - str << "\""; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("binary parse", count, 1); - buf_t actual = sd.asBinary(); - ensure_equals("binary size", actual.size(), (size_t)size); - ensure("binary data", (0 == memcmp(&source[0], &actual[0], size))); - } - } - - template<> template<> - void sd_object::test<6>() - { - std::string expected("'{\"task_id\":u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}'\t\n\t\t"); - std::stringstream str; - str << "s(" << expected.size() << ")'"; - str.write(expected.c_str(), expected.size()); - str << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("parse count", count, 1); - std::string actual = sd.asString(); - ensure_equals("string sizes", actual.size(), expected.size()); - ensure_equals("string content", actual, expected); - } - - template<> template<> - void sd_object::test<7>() - { - std::string msg("come on in"); - std::stringstream stream; - stream << "{'connect':1, 'message':'" << msg << "'," - << " 'position':[r45.65,r100.1,r25.5]," - << " 'look_at':[r0,r1,r0]," - << " 'agent_access':'PG'}"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation( - sd, - stream, - stream.str().size()); - ensure_equals("parse count", count, 12); - ensure_equals("bool value", sd["connect"].asBoolean(), true); - ensure_equals("message value", sd["message"].asString(), msg); - ensure_equals("pos x", sd["position"][0].asReal(), 45.65); - ensure_equals("pos y", sd["position"][1].asReal(), 100.1); - ensure_equals("pos z", sd["position"][2].asReal(), 25.5); - ensure_equals("look x", sd["look_at"][0].asReal(), 0.0); - ensure_equals("look y", sd["look_at"][1].asReal(), 1.0); - ensure_equals("look z", sd["look_at"][2].asReal(), 0.0); - } - - template<> template<> - void sd_object::test<8>() - { - std::stringstream resp; - resp << "{'label':'short string test', 'singlechar':'a', 'empty':'', 'endoftest':'end' }"; - LLSD response; - S32 count = LLSDSerialize::fromNotation( - response, - resp, - resp.str().size()); - ensure_equals("parse count", count, 5); - ensure_equals("sd type", response.type(), LLSD::TypeMap); - ensure_equals("map element count", response.size(), 4); - ensure_equals("singlechar", response["singlechar"].asString(), "a"); - ensure_equals("empty", response["empty"].asString(), ""); - } - - template<> template<> - void sd_object::test<9>() - { - std::ostringstream resp; - resp << "{'label':'short binary test', 'singlebinary':b(1)\"A\", 'singlerawstring':s(1)\"A\", 'endoftest':'end' }"; - std::string str = resp.str(); - LLSD sd; - LLMemoryStream mstr((U8*)str.c_str(), str.size()); - S32 count = LLSDSerialize::fromNotation(sd, mstr, str.size()); - ensure_equals("parse count", count, 5); - ensure("sd created", sd.isDefined()); - ensure_equals("sd type", sd.type(), LLSD::TypeMap); - ensure_equals("map element count", sd.size(), 4); - ensure_equals( - "label", - sd["label"].asString(), - "short binary test"); - std::vector<U8> bin = sd["singlebinary"].asBinary(); - std::vector<U8> expected; - expected.resize(1); - expected[0] = 'A'; - ensure("single binary", (0 == memcmp(&bin[0], &expected[0], 1))); - ensure_equals( - "single string", - sd["singlerawstring"].asString(), - std::string("A")); - ensure_equals("end", sd["endoftest"].asString(), "end"); - } - - template<> template<> - void sd_object::test<10>() - { - - std::string message("parcel '' is naughty."); - std::stringstream str; - str << "{'message':'" << LLSDNotationFormatter::escapeString(message) - << "'}"; - std::string expected_str("{'message':'parcel \\'\\' is naughty.'}"); - std::string actual_str = str.str(); - ensure_equals("stream contents", actual_str, expected_str); - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, actual_str.size()); - ensure_equals("parse count", count, 2); - ensure("valid parse", sd.isDefined()); - std::string actual = sd["message"].asString(); - ensure_equals("message contents", actual, message); - } - - template<> template<> - void sd_object::test<11>() - { - std::string expected("\"\"\"\"''''''\""); - std::stringstream str; - str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("parse count", count, 1); - ensure_equals("string value", sd.asString(), expected); - } - - template<> template<> - void sd_object::test<12>() - { - std::string expected("mytest\\"); - std::stringstream str; - str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("parse count", count, 1); - ensure_equals("string value", sd.asString(), expected); - } - - template<> template<> - void sd_object::test<13>() - { - for(S32 i = 0; i < 1000; ++i) - { - // gen up a starting point - std::string expected; - srand(1337 + i); /* Flawfinder: ignore */ - S32 size = rand() % 30 + 5; - std::generate_n( - std::back_insert_iterator<std::string>(expected), - size, - rand); - std::stringstream str; - str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, expected.size()); - ensure_equals("parse count", count, 1); - std::string actual = sd.asString(); + struct sd_data + { + }; + typedef test_group<sd_data> sd_test; + typedef sd_test::object sd_object; + tut::sd_test sd("LLSD"); + + template<> template<> + void sd_object::test<1>() + { + std::ostringstream resp; + resp << "{'connect':true, 'position':[r128,r128,r128], 'look_at':[r0,r1,r0], 'agent_access':'M', 'region_x':i8192, 'region_y':i8192}"; + std::string str = resp.str(); + LLMemoryStream mstr((U8*)str.c_str(), str.size()); + LLSD response; + S32 count = LLSDSerialize::fromNotation(response, mstr, str.size()); + ensure("stream parsed", response.isDefined()); + ensure_equals("stream parse count", count, 13); + ensure_equals("sd type", response.type(), LLSD::TypeMap); + ensure_equals("map element count", response.size(), 6); + ensure_equals("value connect", response["connect"].asBoolean(), true); + ensure_equals("value region_x", response["region_x"].asInteger(),8192); + ensure_equals("value region_y", response["region_y"].asInteger(),8192); + } + + template<> template<> + void sd_object::test<2>() + { + const std::string decoded("random"); + //const std::string encoded("cmFuZG9t\n"); + const std::string streamed("b(6)\"random\""); + typedef std::vector<U8> buf_t; + buf_t buf; + std::copy( + decoded.begin(), + decoded.end(), + std::back_insert_iterator<buf_t>(buf)); + LLSD sd; + sd = buf; + std::stringstream str; + S32 count = LLSDSerialize::toNotation(sd, str); + ensure_equals("output count", count, 1); + std::string actual(str.str()); + ensure_equals("formatted binary encoding", actual, streamed); + sd.clear(); + LLSDSerialize::fromNotation(sd, str, str.str().size()); + std::vector<U8> after; + after = sd.asBinary(); + ensure_equals("binary decoded size", after.size(), decoded.size()); + ensure("binary decoding", (0 == memcmp( + &after[0], + decoded.c_str(), + decoded.size()))); + } + + template<> template<> + void sd_object::test<3>() + { + for(S32 i = 0; i < 100; ++i) + { + // gen up a starting point + typedef std::vector<U8> buf_t; + buf_t source; + srand(i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 10; + std::generate_n( + std::back_insert_iterator<buf_t>(source), + size, + rand); + LLSD sd(source); + std::stringstream str; + S32 count = LLSDSerialize::toNotation(sd, str); + sd.clear(); + ensure_equals("format count", count, 1); + LLSD sd2; + count = LLSDSerialize::fromNotation(sd2, str, str.str().size()); + ensure_equals("parse count", count, 1); + buf_t dest = sd2.asBinary(); + str.str(""); + str << "binary encoding size " << i; + ensure_equals(str.str().c_str(), dest.size(), source.size()); + str.str(""); + str << "binary encoding " << i; + ensure(str.str().c_str(), (source == dest)); + } + } + + template<> template<> + void sd_object::test<4>() + { + std::ostringstream ostr; + ostr << "{'task_id':u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}\n" + << "{\n\tname\tObject|\n}\n"; + std::string expected = ostr.str(); + std::stringstream serialized; + serialized << "'" << LLSDNotationFormatter::escapeString(expected) + << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation( + sd, + serialized, + serialized.str().size()); + ensure_equals("parse count", count, 1); + ensure_equals("String streaming", sd.asString(), expected); + } + + template<> template<> + void sd_object::test<5>() + { + for(S32 i = 0; i < 100; ++i) + { + // gen up a starting point + typedef std::vector<U8> buf_t; + buf_t source; + srand(666 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 10; + std::generate_n( + std::back_insert_iterator<buf_t>(source), + size, + rand); + std::stringstream str; + str << "b(" << size << ")\""; + str.write((const char*)&source[0], size); + str << "\""; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("binary parse", count, 1); + buf_t actual = sd.asBinary(); + ensure_equals("binary size", actual.size(), (size_t)size); + ensure("binary data", (0 == memcmp(&source[0], &actual[0], size))); + } + } + + template<> template<> + void sd_object::test<6>() + { + std::string expected("'{\"task_id\":u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}'\t\n\t\t"); + std::stringstream str; + str << "s(" << expected.size() << ")'"; + str.write(expected.c_str(), expected.size()); + str << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("parse count", count, 1); + std::string actual = sd.asString(); + ensure_equals("string sizes", actual.size(), expected.size()); + ensure_equals("string content", actual, expected); + } + + template<> template<> + void sd_object::test<7>() + { + std::string msg("come on in"); + std::stringstream stream; + stream << "{'connect':1, 'message':'" << msg << "'," + << " 'position':[r45.65,r100.1,r25.5]," + << " 'look_at':[r0,r1,r0]," + << " 'agent_access':'PG'}"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation( + sd, + stream, + stream.str().size()); + ensure_equals("parse count", count, 12); + ensure_equals("bool value", sd["connect"].asBoolean(), true); + ensure_equals("message value", sd["message"].asString(), msg); + ensure_equals("pos x", sd["position"][0].asReal(), 45.65); + ensure_equals("pos y", sd["position"][1].asReal(), 100.1); + ensure_equals("pos z", sd["position"][2].asReal(), 25.5); + ensure_equals("look x", sd["look_at"][0].asReal(), 0.0); + ensure_equals("look y", sd["look_at"][1].asReal(), 1.0); + ensure_equals("look z", sd["look_at"][2].asReal(), 0.0); + } + + template<> template<> + void sd_object::test<8>() + { + std::stringstream resp; + resp << "{'label':'short string test', 'singlechar':'a', 'empty':'', 'endoftest':'end' }"; + LLSD response; + S32 count = LLSDSerialize::fromNotation( + response, + resp, + resp.str().size()); + ensure_equals("parse count", count, 5); + ensure_equals("sd type", response.type(), LLSD::TypeMap); + ensure_equals("map element count", response.size(), 4); + ensure_equals("singlechar", response["singlechar"].asString(), "a"); + ensure_equals("empty", response["empty"].asString(), ""); + } + + template<> template<> + void sd_object::test<9>() + { + std::ostringstream resp; + resp << "{'label':'short binary test', 'singlebinary':b(1)\"A\", 'singlerawstring':s(1)\"A\", 'endoftest':'end' }"; + std::string str = resp.str(); + LLSD sd; + LLMemoryStream mstr((U8*)str.c_str(), str.size()); + S32 count = LLSDSerialize::fromNotation(sd, mstr, str.size()); + ensure_equals("parse count", count, 5); + ensure("sd created", sd.isDefined()); + ensure_equals("sd type", sd.type(), LLSD::TypeMap); + ensure_equals("map element count", sd.size(), 4); + ensure_equals( + "label", + sd["label"].asString(), + "short binary test"); + std::vector<U8> bin = sd["singlebinary"].asBinary(); + std::vector<U8> expected; + expected.resize(1); + expected[0] = 'A'; + ensure("single binary", (0 == memcmp(&bin[0], &expected[0], 1))); + ensure_equals( + "single string", + sd["singlerawstring"].asString(), + std::string("A")); + ensure_equals("end", sd["endoftest"].asString(), "end"); + } + + template<> template<> + void sd_object::test<10>() + { + + std::string message("parcel '' is naughty."); + std::stringstream str; + str << "{'message':'" << LLSDNotationFormatter::escapeString(message) + << "'}"; + std::string expected_str("{'message':'parcel \\'\\' is naughty.'}"); + std::string actual_str = str.str(); + ensure_equals("stream contents", actual_str, expected_str); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, actual_str.size()); + ensure_equals("parse count", count, 2); + ensure("valid parse", sd.isDefined()); + std::string actual = sd["message"].asString(); + ensure_equals("message contents", actual, message); + } + + template<> template<> + void sd_object::test<11>() + { + std::string expected("\"\"\"\"''''''\""); + std::stringstream str; + str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("parse count", count, 1); + ensure_equals("string value", sd.asString(), expected); + } + + template<> template<> + void sd_object::test<12>() + { + std::string expected("mytest\\"); + std::stringstream str; + str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("parse count", count, 1); + ensure_equals("string value", sd.asString(), expected); + } + + template<> template<> + void sd_object::test<13>() + { + for(S32 i = 0; i < 1000; ++i) + { + // gen up a starting point + std::string expected; + srand(1337 + i); /* Flawfinder: ignore */ + S32 size = rand() % 30 + 5; + std::generate_n( + std::back_insert_iterator<std::string>(expected), + size, + rand); + std::stringstream str; + str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, expected.size()); + ensure_equals("parse count", count, 1); + std::string actual = sd.asString(); /* - if(actual != expected) - { - LL_WARNS() << "iteration " << i << LL_ENDL; - std::ostringstream e_str; - std::string::iterator iter = expected.begin(); - std::string::iterator end = expected.end(); - for(; iter != end; ++iter) - { - e_str << (S32)((U8)(*iter)) << " "; - } - e_str << std::endl; - llsd_serialize_string(e_str, expected); - LL_WARNS() << "expected size: " << expected.size() << LL_ENDL; - LL_WARNS() << "expected: " << e_str.str() << LL_ENDL; - - std::ostringstream a_str; - iter = actual.begin(); - end = actual.end(); - for(; iter != end; ++iter) - { - a_str << (S32)((U8)(*iter)) << " "; - } - a_str << std::endl; - llsd_serialize_string(a_str, actual); - LL_WARNS() << "actual size: " << actual.size() << LL_ENDL; - LL_WARNS() << "actual: " << a_str.str() << LL_ENDL; - } + if(actual != expected) + { + LL_WARNS() << "iteration " << i << LL_ENDL; + std::ostringstream e_str; + std::string::iterator iter = expected.begin(); + std::string::iterator end = expected.end(); + for(; iter != end; ++iter) + { + e_str << (S32)((U8)(*iter)) << " "; + } + e_str << std::endl; + llsd_serialize_string(e_str, expected); + LL_WARNS() << "expected size: " << expected.size() << LL_ENDL; + LL_WARNS() << "expected: " << e_str.str() << LL_ENDL; + + std::ostringstream a_str; + iter = actual.begin(); + end = actual.end(); + for(; iter != end; ++iter) + { + a_str << (S32)((U8)(*iter)) << " "; + } + a_str << std::endl; + llsd_serialize_string(a_str, actual); + LL_WARNS() << "actual size: " << actual.size() << LL_ENDL; + LL_WARNS() << "actual: " << a_str.str() << LL_ENDL; + } */ - ensure_equals("string value", actual, expected); - } - } + ensure_equals("string value", actual, expected); + } + } - template<> template<> - void sd_object::test<14>() - { + template<> template<> + void sd_object::test<14>() + { //#if LL_WINDOWS && _MSC_VER >= 1400 // skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); //#endif - std::string param = "[{'version':i1},{'data':{'binary_bucket':b(0)\"\"},'from_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'from_name':'Phoenix Linden','id':u004e45e5-5576-277a-fba7-859d6a4cb5c8,'message':'hey','offline':i0,'timestamp':i0,'to_id':u3c5f1bb4-5182-7546-6401-1d329b4ff2f8,'type':i0},{'agent_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'god_level':i0,'limited_to_estate':i1}]"; - std::istringstream istr; - istr.str(param); - LLSD param_sd; - LLSDSerialize::fromNotation(param_sd, istr, param.size()); - ensure_equals("parsed type", param_sd.type(), LLSD::TypeArray); - LLSD version_sd = param_sd[0]; - ensure_equals("version type", version_sd.type(), LLSD::TypeMap); - ensure("has version", version_sd.has("version")); - ensure_equals("version number", version_sd["version"].asInteger(), 1); - LLSD src_sd = param_sd[1]; - ensure_equals("src type", src_sd.type(), LLSD::TypeMap); - LLSD dst_sd = param_sd[2]; - ensure_equals("dst type", dst_sd.type(), LLSD::TypeMap); - } - - template<> template<> - void sd_object::test<15>() - { - std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]"; - std::istringstream istr; - istr.str(val); - LLSD sd; - LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parsed type", sd.type(), LLSD::TypeArray); - ensure_equals("parsed size", sd.size(), 1); - LLSD failures = sd[0]["failures"]; - ensure("no failures.", failures.isUndefined()); - LLSD success = sd[0]["successfuls"]; - ensure_equals("success type", success.type(), LLSD::TypeArray); - ensure_equals("success size", success.size(), 1); - ensure_equals("success instance type", success[0].type(), LLSD::TypeUUID); - } - - template<> template<> - void sd_object::test<16>() - { - std::string val = "[f,t,0,1,{'foo':t,'bar':f}]"; - std::istringstream istr; - istr.str(val); - LLSD sd; - LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parsed type", sd.type(), LLSD::TypeArray); - ensure_equals("parsed size", sd.size(), 5); - ensure_equals("element 0 false", sd[0].asBoolean(), false); - ensure_equals("element 1 true", sd[1].asBoolean(), true); - ensure_equals("element 2 false", sd[2].asBoolean(), false); - ensure_equals("element 3 true", sd[3].asBoolean(), true); - LLSD map = sd[4]; - ensure_equals("element 4 type", map.type(), LLSD::TypeMap); - ensure_equals("map foo type", map["foo"].type(), LLSD::TypeBoolean); - ensure_equals("map foo value", map["foo"].asBoolean(), true); - ensure_equals("map bar type", map["bar"].type(), LLSD::TypeBoolean); - ensure_equals("map bar value", map["bar"].asBoolean(), false); - } + std::string param = "[{'version':i1},{'data':{'binary_bucket':b(0)\"\"},'from_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'from_name':'Phoenix Linden','id':u004e45e5-5576-277a-fba7-859d6a4cb5c8,'message':'hey','offline':i0,'timestamp':i0,'to_id':u3c5f1bb4-5182-7546-6401-1d329b4ff2f8,'type':i0},{'agent_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'god_level':i0,'limited_to_estate':i1}]"; + std::istringstream istr; + istr.str(param); + LLSD param_sd; + LLSDSerialize::fromNotation(param_sd, istr, param.size()); + ensure_equals("parsed type", param_sd.type(), LLSD::TypeArray); + LLSD version_sd = param_sd[0]; + ensure_equals("version type", version_sd.type(), LLSD::TypeMap); + ensure("has version", version_sd.has("version")); + ensure_equals("version number", version_sd["version"].asInteger(), 1); + LLSD src_sd = param_sd[1]; + ensure_equals("src type", src_sd.type(), LLSD::TypeMap); + LLSD dst_sd = param_sd[2]; + ensure_equals("dst type", dst_sd.type(), LLSD::TypeMap); + } + + template<> template<> + void sd_object::test<15>() + { + std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]"; + std::istringstream istr; + istr.str(val); + LLSD sd; + LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parsed type", sd.type(), LLSD::TypeArray); + ensure_equals("parsed size", sd.size(), 1); + LLSD failures = sd[0]["failures"]; + ensure("no failures.", failures.isUndefined()); + LLSD success = sd[0]["successfuls"]; + ensure_equals("success type", success.type(), LLSD::TypeArray); + ensure_equals("success size", success.size(), 1); + ensure_equals("success instance type", success[0].type(), LLSD::TypeUUID); + } + + template<> template<> + void sd_object::test<16>() + { + std::string val = "[f,t,0,1,{'foo':t,'bar':f}]"; + std::istringstream istr; + istr.str(val); + LLSD sd; + LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parsed type", sd.type(), LLSD::TypeArray); + ensure_equals("parsed size", sd.size(), 5); + ensure_equals("element 0 false", sd[0].asBoolean(), false); + ensure_equals("element 1 true", sd[1].asBoolean(), true); + ensure_equals("element 2 false", sd[2].asBoolean(), false); + ensure_equals("element 3 true", sd[3].asBoolean(), true); + LLSD map = sd[4]; + ensure_equals("element 4 type", map.type(), LLSD::TypeMap); + ensure_equals("map foo type", map["foo"].type(), LLSD::TypeBoolean); + ensure_equals("map foo value", map["foo"].asBoolean(), true); + ensure_equals("map bar type", map["bar"].type(), LLSD::TypeBoolean); + ensure_equals("map bar value", map["bar"].asBoolean(), false); + } /* - template<> template<> - void sd_object::test<16>() - { - } + template<> template<> + void sd_object::test<16>() + { + } */ } @@ -445,227 +445,227 @@ namespace tut namespace tut { - struct mem_data - { - }; - typedef test_group<mem_data> mem_test; - typedef mem_test::object mem_object; - tut::mem_test mem_stream("LLMemoryStream"); - - template<> template<> - void mem_object::test<1>() - { - const char HELLO_WORLD[] = "hello world"; - LLMemoryStream mem((U8*)&HELLO_WORLD[0], strlen(HELLO_WORLD)); /* Flawfinder: ignore */ - std::string hello; - std::string world; - mem >> hello >> world; - ensure_equals("first word", hello, std::string("hello")); - ensure_equals("second word", world, std::string("world")); - } + struct mem_data + { + }; + typedef test_group<mem_data> mem_test; + typedef mem_test::object mem_object; + tut::mem_test mem_stream("LLMemoryStream"); + + template<> template<> + void mem_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + LLMemoryStream mem((U8*)&HELLO_WORLD[0], strlen(HELLO_WORLD)); /* Flawfinder: ignore */ + std::string hello; + std::string world; + mem >> hello >> world; + ensure_equals("first word", hello, std::string("hello")); + ensure_equals("second word", world, std::string("world")); + } } namespace tut { - struct U64_data - { - }; - typedef test_group<U64_data> U64_test; - typedef U64_test::object U64_object; - tut::U64_test U64_testcase("U64_conversion"); - - // U64_to_str - template<> template<> - void U64_object::test<1>() - { - U64 val; - std::string val_str; - char result[256]; - std::string result_str; - - val = U64L(18446744073709551610); // slightly less than MAX_U64 - val_str = "18446744073709551610"; - - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.1", val_str, result_str); - - val = 0; - val_str = "0"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.2", val_str, result_str); - - val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF - val_str = "18446744073709551615"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.3", val_str, result_str); - - // overflow - will result in warning at compile time - val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 - val_str = "0"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.4", val_str, result_str); - - val = U64L(-1); // 0xFFFFFFFFFFFFFFFF == 18446744073709551615 - val_str = "18446744073709551615"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.5", val_str, result_str); - - val = U64L(10000000000000000000); // testing preserving of 0s - val_str = "10000000000000000000"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.6", val_str, result_str); - - val = 1; // testing no leading 0s - val_str = "1"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.7", val_str, result_str); - - val = U64L(18446744073709551615); // testing exact sized buffer for result - val_str = "18446744073709551615"; - memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' - U64_to_str(val, result, sizeof("18446744073709551615")); //pass in the exact size - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.8", val_str, result_str); - - val = U64L(18446744073709551615); // testing smaller sized buffer for result - val_str = "1844"; - memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' - U64_to_str(val, result, 5); //pass in a size of 5. should only copy first 4 integers and add a null terminator - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.9", val_str, result_str); - } - - // str_to_U64 - template<> template<> - void U64_object::test<2>() - { - U64 val; - U64 result; - - val = U64L(18446744073709551610); // slightly less than MAX_U64 - result = str_to_U64("18446744073709551610"); - ensure_equals("str_to_U64 converted 2.1", val, result); - - val = U64L(0); // empty string - result = str_to_U64(LLStringUtil::null); - ensure_equals("str_to_U64 converted 2.2", val, result); - - val = U64L(0); // 0 - result = str_to_U64("0"); - ensure_equals("str_to_U64 converted 2.3", val, result); - - val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF - result = str_to_U64("18446744073709551615"); - ensure_equals("str_to_U64 converted 2.4", val, result); - - // overflow - will result in warning at compile time - val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 - result = str_to_U64("18446744073709551616"); - ensure_equals("str_to_U64 converted 2.5", val, result); - - val = U64L(1234); // process till first non-integral character - result = str_to_U64("1234A5678"); - ensure_equals("str_to_U64 converted 2.6", val, result); - - val = U64L(5678); // skip all non-integral characters - result = str_to_U64("ABCD5678"); - ensure_equals("str_to_U64 converted 2.7", val, result); - - // should it skip negative sign and process - // rest of string or return 0 - val = U64L(1234); // skip initial negative sign - result = str_to_U64("-1234"); - ensure_equals("str_to_U64 converted 2.8", val, result); - - val = U64L(5678); // stop at negative sign in the middle - result = str_to_U64("5678-1234"); - ensure_equals("str_to_U64 converted 2.9", val, result); - - val = U64L(0); // no integers - result = str_to_U64("AaCD"); - ensure_equals("str_to_U64 converted 2.10", val, result); - } - - // U64_to_F64 - template<> template<> - void U64_object::test<3>() - { - F64 val; - F64 result; - - result = 18446744073709551610.0; - val = U64_to_F64(U64L(18446744073709551610)); - ensure_equals("U64_to_F64 converted 3.1", val, result); - - result = 18446744073709551615.0; // 0xFFFFFFFFFFFFFFFF - val = U64_to_F64(U64L(18446744073709551615)); - ensure_equals("U64_to_F64 converted 3.2", val, result); - - result = 0.0; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 - // overflow - will result in warning at compile time - val = U64_to_F64(U64L(18446744073709551615)+1); - ensure_equals("U64_to_F64 converted 3.3", val, result); - - result = 0.0; // 0 - val = U64_to_F64(U64L(0)); - ensure_equals("U64_to_F64 converted 3.4", val, result); - - result = 1.0; // odd - val = U64_to_F64(U64L(1)); - ensure_equals("U64_to_F64 converted 3.5", val, result); - - result = 2.0; // even - val = U64_to_F64(U64L(2)); - ensure_equals("U64_to_F64 converted 3.6", val, result); - - result = U64L(0x7FFFFFFFFFFFFFFF) * 1.0L; // 0x7FFFFFFFFFFFFFFF - val = U64_to_F64(U64L(0x7FFFFFFFFFFFFFFF)); - ensure_equals("U64_to_F64 converted 3.7", val, result); - } - - // llstrtou64 - // seems to be deprecated - could not find it being used - // anywhere in the tarball - skipping unit tests for now + struct U64_data + { + }; + typedef test_group<U64_data> U64_test; + typedef U64_test::object U64_object; + tut::U64_test U64_testcase("U64_conversion"); + + // U64_to_str + template<> template<> + void U64_object::test<1>() + { + U64 val; + std::string val_str; + char result[256]; + std::string result_str; + + val = U64L(18446744073709551610); // slightly less than MAX_U64 + val_str = "18446744073709551610"; + + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.1", val_str, result_str); + + val = 0; + val_str = "0"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.2", val_str, result_str); + + val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF + val_str = "18446744073709551615"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.3", val_str, result_str); + + // overflow - will result in warning at compile time + val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 + val_str = "0"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.4", val_str, result_str); + + val = U64L(-1); // 0xFFFFFFFFFFFFFFFF == 18446744073709551615 + val_str = "18446744073709551615"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.5", val_str, result_str); + + val = U64L(10000000000000000000); // testing preserving of 0s + val_str = "10000000000000000000"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.6", val_str, result_str); + + val = 1; // testing no leading 0s + val_str = "1"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.7", val_str, result_str); + + val = U64L(18446744073709551615); // testing exact sized buffer for result + val_str = "18446744073709551615"; + memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' + U64_to_str(val, result, sizeof("18446744073709551615")); //pass in the exact size + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.8", val_str, result_str); + + val = U64L(18446744073709551615); // testing smaller sized buffer for result + val_str = "1844"; + memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' + U64_to_str(val, result, 5); //pass in a size of 5. should only copy first 4 integers and add a null terminator + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.9", val_str, result_str); + } + + // str_to_U64 + template<> template<> + void U64_object::test<2>() + { + U64 val; + U64 result; + + val = U64L(18446744073709551610); // slightly less than MAX_U64 + result = str_to_U64("18446744073709551610"); + ensure_equals("str_to_U64 converted 2.1", val, result); + + val = U64L(0); // empty string + result = str_to_U64(LLStringUtil::null); + ensure_equals("str_to_U64 converted 2.2", val, result); + + val = U64L(0); // 0 + result = str_to_U64("0"); + ensure_equals("str_to_U64 converted 2.3", val, result); + + val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF + result = str_to_U64("18446744073709551615"); + ensure_equals("str_to_U64 converted 2.4", val, result); + + // overflow - will result in warning at compile time + val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 + result = str_to_U64("18446744073709551616"); + ensure_equals("str_to_U64 converted 2.5", val, result); + + val = U64L(1234); // process till first non-integral character + result = str_to_U64("1234A5678"); + ensure_equals("str_to_U64 converted 2.6", val, result); + + val = U64L(5678); // skip all non-integral characters + result = str_to_U64("ABCD5678"); + ensure_equals("str_to_U64 converted 2.7", val, result); + + // should it skip negative sign and process + // rest of string or return 0 + val = U64L(1234); // skip initial negative sign + result = str_to_U64("-1234"); + ensure_equals("str_to_U64 converted 2.8", val, result); + + val = U64L(5678); // stop at negative sign in the middle + result = str_to_U64("5678-1234"); + ensure_equals("str_to_U64 converted 2.9", val, result); + + val = U64L(0); // no integers + result = str_to_U64("AaCD"); + ensure_equals("str_to_U64 converted 2.10", val, result); + } + + // U64_to_F64 + template<> template<> + void U64_object::test<3>() + { + F64 val; + F64 result; + + result = 18446744073709551610.0; + val = U64_to_F64(U64L(18446744073709551610)); + ensure_equals("U64_to_F64 converted 3.1", val, result); + + result = 18446744073709551615.0; // 0xFFFFFFFFFFFFFFFF + val = U64_to_F64(U64L(18446744073709551615)); + ensure_equals("U64_to_F64 converted 3.2", val, result); + + result = 0.0; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 + // overflow - will result in warning at compile time + val = U64_to_F64(U64L(18446744073709551615)+1); + ensure_equals("U64_to_F64 converted 3.3", val, result); + + result = 0.0; // 0 + val = U64_to_F64(U64L(0)); + ensure_equals("U64_to_F64 converted 3.4", val, result); + + result = 1.0; // odd + val = U64_to_F64(U64L(1)); + ensure_equals("U64_to_F64 converted 3.5", val, result); + + result = 2.0; // even + val = U64_to_F64(U64L(2)); + ensure_equals("U64_to_F64 converted 3.6", val, result); + + result = U64L(0x7FFFFFFFFFFFFFFF) * 1.0L; // 0x7FFFFFFFFFFFFFFF + val = U64_to_F64(U64L(0x7FFFFFFFFFFFFFFF)); + ensure_equals("U64_to_F64 converted 3.7", val, result); + } + + // llstrtou64 + // seems to be deprecated - could not find it being used + // anywhere in the tarball - skipping unit tests for now } namespace tut { - struct hash_data - { - }; - typedef test_group<hash_data> hash_test; - typedef hash_test::object hash_object; - tut::hash_test hash_tester("LLHash"); + struct hash_data + { + }; + typedef test_group<hash_data> hash_test; + typedef hash_test::object hash_object; + tut::hash_test hash_tester("LLHash"); + + template<> template<> + void hash_object::test<1>() + { + const char * str1 = "test string one"; + const char * same_as_str1 = "test string one"; + + size_t hash1 = llhash(str1); + size_t same_as_hash1 = llhash(same_as_str1); - template<> template<> - void hash_object::test<1>() - { - const char * str1 = "test string one"; - const char * same_as_str1 = "test string one"; - size_t hash1 = llhash(str1); - size_t same_as_hash1 = llhash(same_as_str1); + ensure("Hashes from identical strings should be equal", hash1 == same_as_hash1); + char str[100]; + strcpy( str, "Another test" ); - ensure("Hashes from identical strings should be equal", hash1 == same_as_hash1); - - char str[100]; - strcpy( str, "Another test" ); + size_t hash2 = llhash(str); - size_t hash2 = llhash(str); - - strcpy( str, "Different string, same pointer" ); + strcpy( str, "Different string, same pointer" ); - size_t hash3 = llhash(str); + size_t hash3 = llhash(str); - ensure("Hashes from same pointer but different string should not be equal", hash2 != hash3); - } + ensure("Hashes from same pointer but different string should not be equal", hash2 != hash3); + } } diff --git a/indra/llcommon/tests/lazyeventapi_test.cpp b/indra/llcommon/tests/lazyeventapi_test.cpp index 31b2d6d17f..f3fcf84e49 100644 --- a/indra/llcommon/tests/lazyeventapi_test.cpp +++ b/indra/llcommon/tests/lazyeventapi_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-18 * @brief Test for lazyeventapi. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/listener.h b/indra/llcommon/tests/listener.h index 6072060bb6..887a2c9082 100644 --- a/indra/llcommon/tests/listener.h +++ b/indra/llcommon/tests/listener.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-06 * @brief Useful for tests of the LLEventPump family of classes - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llallocator_heap_profile_test.cpp b/indra/llcommon/tests/llallocator_heap_profile_test.cpp index 44a9705803..da8b54ffc0 100644 --- a/indra/llcommon/tests/llallocator_heap_profile_test.cpp +++ b/indra/llcommon/tests/llallocator_heap_profile_test.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2008-02- * @brief Test for llallocator_heap_profile.cpp. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llallocator_test.cpp b/indra/llcommon/tests/llallocator_test.cpp index 4e62eaee67..a7573641c7 100644 --- a/indra/llcommon/tests/llallocator_test.cpp +++ b/indra/llcommon/tests/llallocator_test.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2008-02- * @brief Test for llallocator.cpp. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -71,7 +71,7 @@ namespace tut delete [] test_alloc; - llallocator.getProfile(); + llallocator.getProfile(); // *NOTE - this test isn't ensuring anything right now other than no // exceptions are thrown. diff --git a/indra/llcommon/tests/llbase64_test.cpp b/indra/llcommon/tests/llbase64_test.cpp index d0394150fa..69b062fc0c 100644 --- a/indra/llcommon/tests/llbase64_test.cpp +++ b/indra/llcommon/tests/llbase64_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbase64_test.cpp * @author James Cook * @date 2007-02-04 @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,42 +36,42 @@ namespace tut { - struct base64_data - { - }; - typedef test_group<base64_data> base64_test; - typedef base64_test::object base64_object; - tut::base64_test base64("LLBase64"); + struct base64_data + { + }; + typedef test_group<base64_data> base64_test; + typedef base64_test::object base64_object; + tut::base64_test base64("LLBase64"); - template<> template<> - void base64_object::test<1>() - { - std::string result; + template<> template<> + void base64_object::test<1>() + { + std::string result; - result = LLBase64::encode(NULL, 0); - ensure("encode nothing", (result == "") ); + result = LLBase64::encode(NULL, 0); + ensure("encode nothing", (result == "") ); - LLUUID nothing; - result = LLBase64::encode(¬hing.mData[0], UUID_BYTES); - ensure("encode blank uuid", - (result == "AAAAAAAAAAAAAAAAAAAAAA==") ); + LLUUID nothing; + result = LLBase64::encode(¬hing.mData[0], UUID_BYTES); + ensure("encode blank uuid", + (result == "AAAAAAAAAAAAAAAAAAAAAA==") ); - LLUUID id("526a1e07-a19d-baed-84c4-ff08a488d15e"); - result = LLBase64::encode(&id.mData[0], UUID_BYTES); - ensure("encode random uuid", - (result == "UmoeB6Gduu2ExP8IpIjRXg==") ); + LLUUID id("526a1e07-a19d-baed-84c4-ff08a488d15e"); + result = LLBase64::encode(&id.mData[0], UUID_BYTES); + ensure("encode random uuid", + (result == "UmoeB6Gduu2ExP8IpIjRXg==") ); - } + } - template<> template<> - void base64_object::test<2>() - { - std::string result; + template<> template<> + void base64_object::test<2>() + { + std::string result; - U8 blob[40] = { 115, 223, 172, 255, 140, 70, 49, 125, 236, 155, 45, 199, 101, 17, 164, 131, 230, 19, 80, 64, 112, 53, 135, 98, 237, 12, 26, 72, 126, 14, 145, 143, 118, 196, 11, 177, 132, 169, 195, 134 }; - result = LLBase64::encode(&blob[0], 40); - ensure("encode 40 bytes", - (result == "c9+s/4xGMX3smy3HZRGkg+YTUEBwNYdi7QwaSH4OkY92xAuxhKnDhg==") ); - } + U8 blob[40] = { 115, 223, 172, 255, 140, 70, 49, 125, 236, 155, 45, 199, 101, 17, 164, 131, 230, 19, 80, 64, 112, 53, 135, 98, 237, 12, 26, 72, 126, 14, 145, 143, 118, 196, 11, 177, 132, 169, 195, 134 }; + result = LLBase64::encode(&blob[0], 40); + ensure("encode 40 bytes", + (result == "c9+s/4xGMX3smy3HZRGkg+YTUEBwNYdi7QwaSH4OkY92xAuxhKnDhg==") ); + } } diff --git a/indra/llcommon/tests/llcond_test.cpp b/indra/llcommon/tests/llcond_test.cpp index 478149eacf..f2a302ed13 100644 --- a/indra/llcommon/tests/llcond_test.cpp +++ b/indra/llcommon/tests/llcond_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-07-18 * @brief Test for llcond. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ @@ -38,7 +38,7 @@ namespace tut { set_test_name("Immediate gratification"); cond.set_one(1); - ensure("wait_for_equal() failed", + ensure("wait_for_equal() failed", cond.wait_for_equal(F32Milliseconds(1), 1)); ensure("wait_for_unequal() should have failed", ! cond.wait_for_unequal(F32Milliseconds(1), 1)); diff --git a/indra/llcommon/tests/lldate_test.cpp b/indra/llcommon/tests/lldate_test.cpp index 7c95ccb91f..6d38b71649 100644 --- a/indra/llcommon/tests/lldate_test.cpp +++ b/indra/llcommon/tests/lldate_test.cpp @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,180 +34,180 @@ #include "../test/lltut.h" -#define VALID_DATE "2003-04-30T04:00:00Z" -#define VALID_DATE_LEAP "2004-02-29T04:00:00Z" -#define VALID_DATE_HOUR_BOUNDARY "2003-04-30T23:59:59Z" -#define VALID_DATE_FRACTIONAL_SECS "2007-09-26T20:31:33.70Z" +#define VALID_DATE "2003-04-30T04:00:00Z" +#define VALID_DATE_LEAP "2004-02-29T04:00:00Z" +#define VALID_DATE_HOUR_BOUNDARY "2003-04-30T23:59:59Z" +#define VALID_DATE_FRACTIONAL_SECS "2007-09-26T20:31:33.70Z" // invalid format -#define INVALID_DATE_MISSING_YEAR "-04-30T22:59:59Z" -#define INVALID_DATE_MISSING_MONTH "1900-0430T22:59:59Z" -#define INVALID_DATE_MISSING_DATE "1900-0430-T22:59:59Z" -#define INVALID_DATE_MISSING_T "1900-04-30-22:59:59Z" -#define INVALID_DATE_MISSING_HOUR "1900-04-30T:59:59Z" -#define INVALID_DATE_MISSING_MIN "1900-04-30T01::59Z" -#define INVALID_DATE_MISSING_SEC "1900-04-30T01:59Z" -#define INVALID_DATE_MISSING_Z "1900-04-30T01:59:23" -#define INVALID_DATE_EMPTY "" +#define INVALID_DATE_MISSING_YEAR "-04-30T22:59:59Z" +#define INVALID_DATE_MISSING_MONTH "1900-0430T22:59:59Z" +#define INVALID_DATE_MISSING_DATE "1900-0430-T22:59:59Z" +#define INVALID_DATE_MISSING_T "1900-04-30-22:59:59Z" +#define INVALID_DATE_MISSING_HOUR "1900-04-30T:59:59Z" +#define INVALID_DATE_MISSING_MIN "1900-04-30T01::59Z" +#define INVALID_DATE_MISSING_SEC "1900-04-30T01:59Z" +#define INVALID_DATE_MISSING_Z "1900-04-30T01:59:23" +#define INVALID_DATE_EMPTY "" // invalid values // apr 1.1.1 seems to not care about constraining the date to valid // dates. Put these back when the parser checks. #define LL_DATE_PARSER_CHECKS_BOUNDARY 0 -//#define INVALID_DATE_24HOUR_BOUNDARY "2003-04-30T24:00:00Z" -//#define INVALID_DATE_LEAP "2003-04-29T04:00:00Z" -//#define INVALID_DATE_HOUR "2003-04-30T24:59:59Z" -//#define INVALID_DATE_MIN "2003-04-30T22:69:59Z" -//#define INVALID_DATE_SEC "2003-04-30T22:59:69Z" -//#define INVALID_DATE_YEAR "0-04-30T22:59:59Z" -//#define INVALID_DATE_MONTH "2003-13-30T22:59:59Z" -//#define INVALID_DATE_DAY "2003-04-35T22:59:59Z" +//#define INVALID_DATE_24HOUR_BOUNDARY "2003-04-30T24:00:00Z" +//#define INVALID_DATE_LEAP "2003-04-29T04:00:00Z" +//#define INVALID_DATE_HOUR "2003-04-30T24:59:59Z" +//#define INVALID_DATE_MIN "2003-04-30T22:69:59Z" +//#define INVALID_DATE_SEC "2003-04-30T22:59:69Z" +//#define INVALID_DATE_YEAR "0-04-30T22:59:59Z" +//#define INVALID_DATE_MONTH "2003-13-30T22:59:59Z" +//#define INVALID_DATE_DAY "2003-04-35T22:59:59Z" namespace tut { - struct date_test - { + struct date_test + { - }; - typedef test_group<date_test> date_test_t; - typedef date_test_t::object date_test_object_t; - tut::date_test_t tut_date_test("LLDate"); + }; + typedef test_group<date_test> date_test_t; + typedef date_test_t::object date_test_object_t; + tut::date_test_t tut_date_test("LLDate"); - /* format validation */ - template<> template<> - void date_test_object_t::test<1>() - { - LLDate date(VALID_DATE); - std::string expected_string; - bool result; - expected_string = VALID_DATE; - ensure_equals("Valid Date failed" , expected_string, date.asString()); + /* format validation */ + template<> template<> + void date_test_object_t::test<1>() + { + LLDate date(VALID_DATE); + std::string expected_string; + bool result; + expected_string = VALID_DATE; + ensure_equals("Valid Date failed" , expected_string, date.asString()); - result = date.fromString(VALID_DATE_LEAP); - expected_string = VALID_DATE_LEAP; - ensure_equals("VALID_DATE_LEAP failed" , expected_string, date.asString()); + result = date.fromString(VALID_DATE_LEAP); + expected_string = VALID_DATE_LEAP; + ensure_equals("VALID_DATE_LEAP failed" , expected_string, date.asString()); - result = date.fromString(VALID_DATE_HOUR_BOUNDARY); - expected_string = VALID_DATE_HOUR_BOUNDARY; - ensure_equals("VALID_DATE_HOUR_BOUNDARY failed" , expected_string, date.asString()); + result = date.fromString(VALID_DATE_HOUR_BOUNDARY); + expected_string = VALID_DATE_HOUR_BOUNDARY; + ensure_equals("VALID_DATE_HOUR_BOUNDARY failed" , expected_string, date.asString()); - result = date.fromString(VALID_DATE_FRACTIONAL_SECS); - expected_string = VALID_DATE_FRACTIONAL_SECS; - ensure_equals("VALID_DATE_FRACTIONAL_SECS failed" , expected_string, date.asString()); + result = date.fromString(VALID_DATE_FRACTIONAL_SECS); + expected_string = VALID_DATE_FRACTIONAL_SECS; + ensure_equals("VALID_DATE_FRACTIONAL_SECS failed" , expected_string, date.asString()); - result = date.fromString(INVALID_DATE_MISSING_YEAR); - ensure_equals("INVALID_DATE_MISSING_YEAR should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_YEAR); + ensure_equals("INVALID_DATE_MISSING_YEAR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_MONTH); - ensure_equals("INVALID_DATE_MISSING_MONTH should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_MONTH); + ensure_equals("INVALID_DATE_MISSING_MONTH should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_DATE); - ensure_equals("INVALID_DATE_MISSING_DATE should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_DATE); + ensure_equals("INVALID_DATE_MISSING_DATE should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_T); - ensure_equals("INVALID_DATE_MISSING_T should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_T); + ensure_equals("INVALID_DATE_MISSING_T should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_HOUR); - ensure_equals("INVALID_DATE_MISSING_HOUR should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_HOUR); + ensure_equals("INVALID_DATE_MISSING_HOUR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_MIN); - ensure_equals("INVALID_DATE_MISSING_MIN should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_MIN); + ensure_equals("INVALID_DATE_MISSING_MIN should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_SEC); - ensure_equals("INVALID_DATE_MISSING_SEC should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_SEC); + ensure_equals("INVALID_DATE_MISSING_SEC should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_Z); - ensure_equals("INVALID_DATE_MISSING_Z should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_Z); + ensure_equals("INVALID_DATE_MISSING_Z should have failed" , result, false); - result = date.fromString(INVALID_DATE_EMPTY); - ensure_equals("INVALID_DATE_EMPTY should have failed" , result, false); - } + result = date.fromString(INVALID_DATE_EMPTY); + ensure_equals("INVALID_DATE_EMPTY should have failed" , result, false); + } - /* Invalid Value Handling */ - template<> template<> - void date_test_object_t::test<2>() - { + /* Invalid Value Handling */ + template<> template<> + void date_test_object_t::test<2>() + { #if LL_DATE_PARSER_CHECKS_BOUNDARY - LLDate date; - std::string expected_string; - bool result; + LLDate date; + std::string expected_string; + bool result; - result = date.fromString(INVALID_DATE_24HOUR_BOUNDARY); - ensure_equals("INVALID_DATE_24HOUR_BOUNDARY should have failed" , result, false); - ensure_equals("INVALID_DATE_24HOUR_BOUNDARY date still set to old value on failure!" , date.secondsSinceEpoch(), 0); + result = date.fromString(INVALID_DATE_24HOUR_BOUNDARY); + ensure_equals("INVALID_DATE_24HOUR_BOUNDARY should have failed" , result, false); + ensure_equals("INVALID_DATE_24HOUR_BOUNDARY date still set to old value on failure!" , date.secondsSinceEpoch(), 0); - result = date.fromString(INVALID_DATE_LEAP); - ensure_equals("INVALID_DATE_LEAP should have failed" , result, false); + result = date.fromString(INVALID_DATE_LEAP); + ensure_equals("INVALID_DATE_LEAP should have failed" , result, false); - result = date.fromString(INVALID_DATE_HOUR); - ensure_equals("INVALID_DATE_HOUR should have failed" , result, false); + result = date.fromString(INVALID_DATE_HOUR); + ensure_equals("INVALID_DATE_HOUR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MIN); - ensure_equals("INVALID_DATE_MIN should have failed" , result, false); + result = date.fromString(INVALID_DATE_MIN); + ensure_equals("INVALID_DATE_MIN should have failed" , result, false); - result = date.fromString(INVALID_DATE_SEC); - ensure_equals("INVALID_DATE_SEC should have failed" , result, false); + result = date.fromString(INVALID_DATE_SEC); + ensure_equals("INVALID_DATE_SEC should have failed" , result, false); - result = date.fromString(INVALID_DATE_YEAR); - ensure_equals("INVALID_DATE_YEAR should have failed" , result, false); + result = date.fromString(INVALID_DATE_YEAR); + ensure_equals("INVALID_DATE_YEAR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MONTH); - ensure_equals("INVALID_DATE_MONTH should have failed" , result, false); + result = date.fromString(INVALID_DATE_MONTH); + ensure_equals("INVALID_DATE_MONTH should have failed" , result, false); - result = date.fromString(INVALID_DATE_DAY); - ensure_equals("INVALID_DATE_DAY should have failed" , result, false); + result = date.fromString(INVALID_DATE_DAY); + ensure_equals("INVALID_DATE_DAY should have failed" , result, false); #endif - } - - /* API checks */ - template<> template<> - void date_test_object_t::test<3>() - { - LLDate date; - std::istringstream stream(VALID_DATE); - std::string expected_string = VALID_DATE; - date.fromStream(stream); - ensure_equals("fromStream failed", date.asString(), expected_string); - } - - template<> template<> - void date_test_object_t::test<4>() - { - LLDate date1(VALID_DATE); - LLDate date2(date1); - ensure_equals("LLDate(const LLDate& date) constructor failed", date1.asString(), date2.asString()); - } - - template<> template<> - void date_test_object_t::test<5>() - { - LLDate date1(VALID_DATE); - LLDate date2(date1.secondsSinceEpoch()); - ensure_equals("secondsSinceEpoch not equal",date1.secondsSinceEpoch(), date2.secondsSinceEpoch()); - ensure_equals("LLDate created using secondsSinceEpoch not equal", date1.asString(), date2.asString()); - } - - template<> template<> - void date_test_object_t::test<6>() - { - LLDate date(VALID_DATE); - std::ostringstream stream; - stream << date; - std::string expected_str = VALID_DATE; - ensure_equals("ostringstream failed", expected_str, stream.str()); - } - - template<> template<> - void date_test_object_t::test<7>() - { - LLDate date; - std::istringstream stream(VALID_DATE); - stream >> date; - std::string expected_str = VALID_DATE; - std::ostringstream out_stream; + } + + /* API checks */ + template<> template<> + void date_test_object_t::test<3>() + { + LLDate date; + std::istringstream stream(VALID_DATE); + std::string expected_string = VALID_DATE; + date.fromStream(stream); + ensure_equals("fromStream failed", date.asString(), expected_string); + } + + template<> template<> + void date_test_object_t::test<4>() + { + LLDate date1(VALID_DATE); + LLDate date2(date1); + ensure_equals("LLDate(const LLDate& date) constructor failed", date1.asString(), date2.asString()); + } + + template<> template<> + void date_test_object_t::test<5>() + { + LLDate date1(VALID_DATE); + LLDate date2(date1.secondsSinceEpoch()); + ensure_equals("secondsSinceEpoch not equal",date1.secondsSinceEpoch(), date2.secondsSinceEpoch()); + ensure_equals("LLDate created using secondsSinceEpoch not equal", date1.asString(), date2.asString()); + } + + template<> template<> + void date_test_object_t::test<6>() + { + LLDate date(VALID_DATE); + std::ostringstream stream; + stream << date; + std::string expected_str = VALID_DATE; + ensure_equals("ostringstream failed", expected_str, stream.str()); + } + + template<> template<> + void date_test_object_t::test<7>() + { + LLDate date; + std::istringstream stream(VALID_DATE); + stream >> date; + std::string expected_str = VALID_DATE; + std::ostringstream out_stream; out_stream << date; - ensure_equals("<< failed", date.asString(),expected_str); - ensure_equals("<< to >> failed", stream.str(),out_stream.str()); - } + ensure_equals("<< failed", date.asString(),expected_str); + ensure_equals("<< to >> failed", stream.str(),out_stream.str()); + } } diff --git a/indra/llcommon/tests/lldeadmantimer_test.cpp b/indra/llcommon/tests/lldeadmantimer_test.cpp index 23167762c3..01e6e8e2f7 100644 --- a/indra/llcommon/tests/lldeadmantimer_test.cpp +++ b/indra/llcommon/tests/lldeadmantimer_test.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldeadmantimer_test.cpp * @brief Tests for the LLDeadmanTimer class. * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2013, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,12 +37,12 @@ static LLDeadmanTimer::time_type float_time_to_u64(F64 delta) { - return LLDeadmanTimer::time_type(delta * get_timer_info().mClockFrequency); + return LLDeadmanTimer::time_type(delta * get_timer_info().mClockFrequency); } static F64 u64_time_to_float(LLDeadmanTimer::time_type delta) { - return delta * get_timer_info().mClockFrequencyInv; + return delta * get_timer_info().mClockFrequencyInv; } @@ -51,11 +51,11 @@ namespace tut struct deadmantimer_test { - deadmantimer_test() - { - // LLTimer internals updating - get_timer_info().update(); - } + deadmantimer_test() + { + // LLTimer internals updating + get_timer_info().update(); + } }; typedef test_group<deadmantimer_test> deadmantimer_group_t; @@ -66,31 +66,31 @@ tut::deadmantimer_group_t deadmantimer_instance("LLDeadmanTimer"); template<> template<> void deadmantimer_object_t::test<1>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - ensure_equals("WOCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count), false); - ensure_approximately_equals("WOCM t1 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t1 - isExpired() does not modify count", count, U64L(8)); - } - - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - ensure_equals("WCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); - ensure_approximately_equals("WCM t1 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WCM t1 - isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t1 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t1 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + ensure_equals("WOCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count), false); + ensure_approximately_equals("WOCM t1 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t1 - isExpired() does not modify count", count, U64L(8)); + } + + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + ensure_equals("WCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); + ensure_approximately_equals("WCM t1 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WCM t1 - isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t1 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t1 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -98,25 +98,25 @@ void deadmantimer_object_t::test<1>() template<> template<> void deadmantimer_object_t::test<2>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(0.0, false); // Zero is pre-expired - - ensure_equals("WOCM isExpired() still returns false with 0.0 time ctor()", - timer.isExpired(0, started, stopped, count), false); - } - - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(0.0, true); // Zero is pre-expired - - ensure_equals("WCM isExpired() still returns false with 0.0 time ctor()", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(0.0, false); // Zero is pre-expired + + ensure_equals("WOCM isExpired() still returns false with 0.0 time ctor()", + timer.isExpired(0, started, stopped, count), false); + } + + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(0.0, true); // Zero is pre-expired + + ensure_equals("WCM isExpired() still returns false with 0.0 time ctor()", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); + } } @@ -125,28 +125,28 @@ void deadmantimer_object_t::test<2>() template<> template<> void deadmantimer_object_t::test<3>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(0.0, false); - - timer.start(0); - ensure_equals("WOCM isExpired() returns true with 0.0 horizon time", - timer.isExpired(0, started, stopped, count), true); - ensure_approximately_equals("WOCM expired timer with no bell ringing has stopped == started", started, stopped, 8); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(0.0, true); - - timer.start(0); - ensure_equals("WCM isExpired() returns true with 0.0 horizon time", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM expired timer with no bell ringing has stopped == started", started, stopped, 8); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(0.0, false); + + timer.start(0); + ensure_equals("WOCM isExpired() returns true with 0.0 horizon time", + timer.isExpired(0, started, stopped, count), true); + ensure_approximately_equals("WOCM expired timer with no bell ringing has stopped == started", started, stopped, 8); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(0.0, true); + + timer.start(0); + ensure_equals("WCM isExpired() returns true with 0.0 horizon time", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM expired timer with no bell ringing has stopped == started", started, stopped, 8); + } } @@ -154,30 +154,30 @@ void deadmantimer_object_t::test<3>() template<> template<> void deadmantimer_object_t::test<4>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(0.0, false); - - timer.start(0); - timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); - ensure_equals("WOCM isExpired() returns true with 0.0 horizon time after bell ring", - timer.isExpired(0, started, stopped, count), true); - ensure_approximately_equals("WOCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(0.0, true); - - timer.start(0); - timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); - ensure_equals("WCM isExpired() returns true with 0.0 horizon time after bell ring", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(0.0, false); + + timer.start(0); + timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); + ensure_equals("WOCM isExpired() returns true with 0.0 horizon time after bell ring", + timer.isExpired(0, started, stopped, count), true); + ensure_approximately_equals("WOCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(0.0, true); + + timer.start(0); + timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); + ensure_equals("WCM isExpired() returns true with 0.0 horizon time after bell ring", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); + } } @@ -185,34 +185,34 @@ void deadmantimer_object_t::test<4>() template<> template<> void deadmantimer_object_t::test<5>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - timer.start(0); - ensure_equals("WOCM isExpired() returns false after starting with 10.0 horizon time", - timer.isExpired(0, started, stopped, count), false); - ensure_approximately_equals("WOCM t5 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t5 - isExpired() does not modify count", count, U64L(8)); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - timer.start(0); - ensure_equals("WCM isExpired() returns false after starting with 10.0 horizon time", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); - ensure_approximately_equals("WCM t5 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WCM t5 - isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t5 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t5 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + timer.start(0); + ensure_equals("WOCM isExpired() returns false after starting with 10.0 horizon time", + timer.isExpired(0, started, stopped, count), false); + ensure_approximately_equals("WOCM t5 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t5 - isExpired() does not modify count", count, U64L(8)); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + timer.start(0); + ensure_equals("WCM isExpired() returns false after starting with 10.0 horizon time", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); + ensure_approximately_equals("WCM t5 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WCM t5 - isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t5 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t5 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -220,46 +220,46 @@ void deadmantimer_object_t::test<5>() template<> template<> void deadmantimer_object_t::test<6>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); - timer.start(the_past); - ensure_equals("WOCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", - timer.isExpired(now, started, stopped, count), false); - ensure_approximately_equals("WOCM t6 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t6 - isExpired() does not modify count", count, U64L(8)); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); - timer.start(the_past); - ensure_equals("WCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - ensure_approximately_equals("WCM t6 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("t6 - isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t6 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t6 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); + timer.start(the_past); + ensure_equals("WOCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", + timer.isExpired(now, started, stopped, count), false); + ensure_approximately_equals("WOCM t6 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t6 - isExpired() does not modify count", count, U64L(8)); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); + timer.start(the_past); + ensure_equals("WCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + ensure_approximately_equals("WCM t6 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("t6 - isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t6 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t6 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -267,40 +267,40 @@ void deadmantimer_object_t::test<6>() template<> template<> void deadmantimer_object_t::test<7>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WOCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now,started, stopped, count), true); - ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now,started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WOCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now,started, stopped, count), true); + ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now,started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); + } } @@ -308,60 +308,60 @@ void deadmantimer_object_t::test<7>() template<> template<> void deadmantimer_object_t::test<8>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WOCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now, started, stopped, count), true); - - started = 42.0; - stopped = 97.0; - count = U64L(8); - ensure_equals("WOCM t8 - second isExpired() returns false after true", - timer.isExpired(now, started, stopped, count), false); - ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - - started = 42.0; - stopped = 97.0; - count = U64L(8); - user_cpu = 29000; - sys_cpu = 57000; - ensure_equals("WCM t8 - second isExpired() returns false after true", - timer.isExpired(now, started, stopped, count), false); - ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t8 - 2nd isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t8 - 2nd isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WOCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now, started, stopped, count), true); + + started = 42.0; + stopped = 97.0; + count = U64L(8); + ensure_equals("WOCM t8 - second isExpired() returns false after true", + timer.isExpired(now, started, stopped, count), false); + ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + + started = 42.0; + stopped = 97.0; + count = U64L(8); + user_cpu = 29000; + sys_cpu = 57000; + ensure_equals("WCM t8 - second isExpired() returns false after true", + timer.isExpired(now, started, stopped, count), false); + ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t8 - 2nd isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t8 - 2nd isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -369,92 +369,92 @@ void deadmantimer_object_t::test<8>() template<> template<> void deadmantimer_object_t::test<9>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(5.0, false); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WOCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WOCM t9 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count), true); - ensure_approximately_equals("WOCM t9 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WOCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WOCM t9 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WOCM t9 - single read only", timer.isExpired(now, started, stopped, count), false); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(5.0, true); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WCM t9 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM t9 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WCM t9 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WCM t9 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(5.0, false); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WOCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WOCM t9 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count), true); + ensure_approximately_equals("WOCM t9 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WOCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WOCM t9 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WOCM t9 - single read only", timer.isExpired(now, started, stopped, count), false); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(5.0, true); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WCM t9 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM t9 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WCM t9 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WCM t9 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + } } @@ -462,165 +462,165 @@ void deadmantimer_object_t::test<9>() template<> template<> void deadmantimer_object_t::test<10>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(5.0, false); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WOCM t10 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count), true); - ensure_approximately_equals("WOCM t10 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WOCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WOCM t10 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WOCM t10 - single read only", timer.isExpired(now, started, stopped, count), false); - - // Jump forward and restart - now += float_time_to_u64(1.0); - real_start = u64_time_to_float(now); - timer.start(now); - - // Run a modified bell ring sequence - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", - timer.isExpired(now, started, stopped, count), false); - last_good_ring = u64_time_to_float(now); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WOCM t10 - 5.0 horizon timer expires on 8-second jump", - timer.isExpired(now, started, stopped, count), true); - ensure_approximately_equals("WOCM t10 - 2nd started matches start() time", started, real_start, 4); - ensure_approximately_equals("WOCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WOCM t10 - 8 good ringBell()s", count, U64L(8)); - ensure_equals("WOCM t10 - single read only - 2nd start", - timer.isExpired(now, started, stopped, count), false); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - - LLDeadmanTimer timer(5.0, true); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WCM t10 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM t10 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WCM t10 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WCM t10 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - - // Jump forward and restart - now += float_time_to_u64(1.0); - real_start = u64_time_to_float(now); - timer.start(now); - - // Run a modified bell ring sequence - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - last_good_ring = u64_time_to_float(now); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WCM t10 - 5.0 horizon timer expires on 8-second jump", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM t10 - 2nd started matches start() time", started, real_start, 4); - ensure_approximately_equals("WCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WCM t10 - 8 good ringBell()s", count, U64L(8)); - ensure_equals("WCM t10 - single read only - 2nd start", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(5.0, false); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WOCM t10 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count), true); + ensure_approximately_equals("WOCM t10 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WOCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WOCM t10 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WOCM t10 - single read only", timer.isExpired(now, started, stopped, count), false); + + // Jump forward and restart + now += float_time_to_u64(1.0); + real_start = u64_time_to_float(now); + timer.start(now); + + // Run a modified bell ring sequence + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", + timer.isExpired(now, started, stopped, count), false); + last_good_ring = u64_time_to_float(now); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WOCM t10 - 5.0 horizon timer expires on 8-second jump", + timer.isExpired(now, started, stopped, count), true); + ensure_approximately_equals("WOCM t10 - 2nd started matches start() time", started, real_start, 4); + ensure_approximately_equals("WOCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WOCM t10 - 8 good ringBell()s", count, U64L(8)); + ensure_equals("WOCM t10 - single read only - 2nd start", + timer.isExpired(now, started, stopped, count), false); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + + LLDeadmanTimer timer(5.0, true); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WCM t10 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM t10 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WCM t10 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WCM t10 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + + // Jump forward and restart + now += float_time_to_u64(1.0); + real_start = u64_time_to_float(now); + timer.start(now); + + // Run a modified bell ring sequence + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + last_good_ring = u64_time_to_float(now); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WCM t10 - 5.0 horizon timer expires on 8-second jump", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM t10 - 2nd started matches start() time", started, real_start, 4); + ensure_approximately_equals("WCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WCM t10 - 8 good ringBell()s", count, U64L(8)); + ensure_equals("WCM t10 - single read only - 2nd start", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + } } diff --git a/indra/llcommon/tests/lldependencies_test.cpp b/indra/llcommon/tests/lldependencies_test.cpp index b5e189a465..84eb41b5fe 100644 --- a/indra/llcommon/tests/lldependencies_test.cpp +++ b/indra/llcommon/tests/lldependencies_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-17 * @brief Test of lldependencies.h - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index b4cdbdc6bf..3ec429530c 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -47,7 +47,7 @@ enum LogFieldIndex MSG_FIELD }; -static const char* FieldName[] = +static const char* FieldName[] = { "TIME", "LEVEL", @@ -62,15 +62,15 @@ namespace #ifdef __clang__ # pragma clang diagnostic ignored "-Wunused-function" #endif - void test_that_error_h_includes_enough_things_to_compile_a_message() - { - LL_INFOS() << "!" << LL_ENDL; - } + void test_that_error_h_includes_enough_things_to_compile_a_message() + { + LL_INFOS() << "!" << LL_ENDL; + } } namespace { - static bool fatalWasCalled = false; + static bool fatalWasCalled = false; struct FatalWasCalled: public std::runtime_error { FatalWasCalled(const std::string& what): std::runtime_error(what) {} @@ -96,95 +96,95 @@ namespace namespace tut { - class TestRecorder : public LLError::Recorder - { - public: - TestRecorder() - { - showTime(false); - } - virtual ~TestRecorder() - {} - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) - { - mMessages.push_back(message); - } - - int countMessages() { return (int) mMessages.size(); } - void clearMessages() { mMessages.clear(); } - - std::string message(int n) - { - std::ostringstream test_name; - test_name << "testing message " << n << ", not enough messages"; - - tut::ensure(test_name.str(), n < countMessages()); - return mMessages[n]; - } - - private: - typedef std::vector<std::string> MessageVector; - MessageVector mMessages; - }; - - struct ErrorTestData - { - LLError::RecorderPtr mRecorder; - LLError::SettingsStoragePtr mPriorErrorSettings; - - ErrorTestData(): - mRecorder(new TestRecorder()) - { - fatalWasCalled = false; - - mPriorErrorSettings = LLError::saveAndResetSettings(); - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setFatalFunction(fatalCall); - LLError::addRecorder(mRecorder); - } - - ~ErrorTestData() - { - LLError::removeRecorder(mRecorder); - LLError::restoreSettings(mPriorErrorSettings); - } - - int countMessages() - { - return std::dynamic_pointer_cast<TestRecorder>(mRecorder)->countMessages(); - } - - void clearMessages() - { - std::dynamic_pointer_cast<TestRecorder>(mRecorder)->clearMessages(); - } - - void setWantsTime(bool t) + class TestRecorder : public LLError::Recorder + { + public: + TestRecorder() + { + showTime(false); + } + virtual ~TestRecorder() + {} + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + mMessages.push_back(message); + } + + int countMessages() { return (int) mMessages.size(); } + void clearMessages() { mMessages.clear(); } + + std::string message(int n) + { + std::ostringstream test_name; + test_name << "testing message " << n << ", not enough messages"; + + tut::ensure(test_name.str(), n < countMessages()); + return mMessages[n]; + } + + private: + typedef std::vector<std::string> MessageVector; + MessageVector mMessages; + }; + + struct ErrorTestData + { + LLError::RecorderPtr mRecorder; + LLError::SettingsStoragePtr mPriorErrorSettings; + + ErrorTestData(): + mRecorder(new TestRecorder()) + { + fatalWasCalled = false; + + mPriorErrorSettings = LLError::saveAndResetSettings(); + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setFatalFunction(fatalCall); + LLError::addRecorder(mRecorder); + } + + ~ErrorTestData() + { + LLError::removeRecorder(mRecorder); + LLError::restoreSettings(mPriorErrorSettings); + } + + int countMessages() + { + return std::dynamic_pointer_cast<TestRecorder>(mRecorder)->countMessages(); + } + + void clearMessages() + { + std::dynamic_pointer_cast<TestRecorder>(mRecorder)->clearMessages(); + } + + void setWantsTime(bool t) { std::dynamic_pointer_cast<TestRecorder>(mRecorder)->showTime(t); } - void setWantsMultiline(bool t) + void setWantsMultiline(bool t) { std::dynamic_pointer_cast<TestRecorder>(mRecorder)->showMultiline(t); } - std::string message(int n) - { - return std::dynamic_pointer_cast<TestRecorder>(mRecorder)->message(n); - } + std::string message(int n) + { + return std::dynamic_pointer_cast<TestRecorder>(mRecorder)->message(n); + } - void ensure_message_count(int expectedCount) - { - ensure_equals("message count", countMessages(), expectedCount); - } + void ensure_message_count(int expectedCount) + { + ensure_equals("message count", countMessages(), expectedCount); + } std::string message_field(int msgnum, LogFieldIndex fieldnum) { std::ostringstream test_name; - test_name << "testing message " << msgnum << ", not enough messages"; + test_name << "testing message " << msgnum << ", not enough messages"; tut::ensure(test_name.str(), msgnum < countMessages()); std::string msg(message(msgnum)); @@ -204,7 +204,7 @@ namespace tut on_field++; } // except function, which may have embedded spaces so ends with " : " - else if ( ( on_field == FUNCTION_FIELD ) + else if ( ( on_field == FUNCTION_FIELD ) && ( ':' == msg[scan+1] && ' ' == msg[scan+2] ) ) { @@ -220,9 +220,9 @@ namespace tut { fieldlen = msg.find(' ', start_field) - start_field; } - else if ( fieldnum == FUNCTION_FIELD ) + else if ( fieldnum == FUNCTION_FIELD ) { - fieldlen = msg.find(" : ", start_field) - start_field; + fieldlen = msg.find(" : ", start_field) - start_field; } else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end { @@ -231,8 +231,8 @@ namespace tut return msg.substr(start_field, fieldlen); } - - void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText) + + void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText) { std::ostringstream test_name; test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n message: \"" << message(msgnum) << "\"\n "; @@ -240,105 +240,105 @@ namespace tut ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText); } - void ensure_message_does_not_contain(int n, const std::string& expectedText) - { - std::ostringstream test_name; - test_name << "testing message " << n; + void ensure_message_does_not_contain(int n, const std::string& expectedText) + { + std::ostringstream test_name; + test_name << "testing message " << n; - ensure_does_not_contain(test_name.str(), message(n), expectedText); - } - }; + ensure_does_not_contain(test_name.str(), message(n), expectedText); + } + }; - typedef test_group<ErrorTestData> ErrorTestGroup; - typedef ErrorTestGroup::object ErrorTestObject; + typedef test_group<ErrorTestData> ErrorTestGroup; + typedef ErrorTestGroup::object ErrorTestObject; - ErrorTestGroup errorTestGroup("error"); + ErrorTestGroup errorTestGroup("error"); - template<> template<> - void ErrorTestObject::test<1>() - // basic test of output - { - LL_INFOS() << "test" << LL_ENDL; - LL_INFOS() << "bob" << LL_ENDL; + template<> template<> + void ErrorTestObject::test<1>() + // basic test of output + { + LL_INFOS() << "test" << LL_ENDL; + LL_INFOS() << "bob" << LL_ENDL; - ensure_message_field_equals(0, MSG_FIELD, "test"); - ensure_message_field_equals(1, MSG_FIELD, "bob"); - } + ensure_message_field_equals(0, MSG_FIELD, "test"); + ensure_message_field_equals(1, MSG_FIELD, "bob"); + } } namespace { - void writeSome() - { - LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL; - LL_INFOS("WriteTag") << "two" << LL_ENDL; - LL_WARNS("WriteTag") << "three" << LL_ENDL; - CATCH(LL_ERRS("WriteTag"), "four"); - } + void writeSome() + { + LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL; + LL_INFOS("WriteTag") << "two" << LL_ENDL; + LL_WARNS("WriteTag") << "three" << LL_ENDL; + CATCH(LL_ERRS("WriteTag"), "four"); + } }; namespace tut { - template<> template<> - void ErrorTestObject::test<2>() - // messages are filtered based on default level - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - writeSome(); - ensure_message_field_equals(0, MSG_FIELD, "one"); - ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); - ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#"); - ensure_message_field_equals(1, MSG_FIELD, "two"); - ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); - ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#"); - ensure_message_field_equals(2, MSG_FIELD, "three"); - ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); - ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#"); - ensure_message_field_equals(3, MSG_FIELD, "four"); - ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); - ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#"); - ensure_message_count(4); - - LLError::setDefaultLevel(LLError::LEVEL_INFO); - writeSome(); - ensure_message_field_equals(4, MSG_FIELD, "two"); - ensure_message_field_equals(5, MSG_FIELD, "three"); - ensure_message_field_equals(6, MSG_FIELD, "four"); - ensure_message_count(7); - - LLError::setDefaultLevel(LLError::LEVEL_WARN); - writeSome(); - ensure_message_field_equals(7, MSG_FIELD, "three"); - ensure_message_field_equals(8, MSG_FIELD, "four"); - ensure_message_count(9); - - LLError::setDefaultLevel(LLError::LEVEL_ERROR); - writeSome(); - ensure_message_field_equals(9, MSG_FIELD, "four"); - ensure_message_count(10); - - LLError::setDefaultLevel(LLError::LEVEL_NONE); - writeSome(); - ensure_message_count(10); - } - - template<> template<> - void ErrorTestObject::test<3>() - // error type string in output - { - writeSome(); - ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); - ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); - ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); - ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); - ensure_message_count(4); - } - - template<> template<> - void ErrorTestObject::test<4>() - // file abbreviation - { - std::string prev, abbreviateFile = __FILE__; + template<> template<> + void ErrorTestObject::test<2>() + // messages are filtered based on default level + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + writeSome(); + ensure_message_field_equals(0, MSG_FIELD, "one"); + ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); + ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#"); + ensure_message_field_equals(1, MSG_FIELD, "two"); + ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); + ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#"); + ensure_message_field_equals(2, MSG_FIELD, "three"); + ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); + ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#"); + ensure_message_field_equals(3, MSG_FIELD, "four"); + ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); + ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#"); + ensure_message_count(4); + + LLError::setDefaultLevel(LLError::LEVEL_INFO); + writeSome(); + ensure_message_field_equals(4, MSG_FIELD, "two"); + ensure_message_field_equals(5, MSG_FIELD, "three"); + ensure_message_field_equals(6, MSG_FIELD, "four"); + ensure_message_count(7); + + LLError::setDefaultLevel(LLError::LEVEL_WARN); + writeSome(); + ensure_message_field_equals(7, MSG_FIELD, "three"); + ensure_message_field_equals(8, MSG_FIELD, "four"); + ensure_message_count(9); + + LLError::setDefaultLevel(LLError::LEVEL_ERROR); + writeSome(); + ensure_message_field_equals(9, MSG_FIELD, "four"); + ensure_message_count(10); + + LLError::setDefaultLevel(LLError::LEVEL_NONE); + writeSome(); + ensure_message_count(10); + } + + template<> template<> + void ErrorTestObject::test<3>() + // error type string in output + { + writeSome(); + ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); + ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); + ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); + ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); + ensure_message_count(4); + } + + template<> template<> + void ErrorTestObject::test<4>() + // file abbreviation + { + std::string prev, abbreviateFile = __FILE__; do { prev = abbreviateFile; @@ -354,169 +354,169 @@ namespace tut // argument unchanged, THEN check. } while (abbreviateFile != prev); - ensure_ends_with("file name abbreviation", - abbreviateFile, - "llcommon/tests/llerror_test.cpp" - ); - ensure_does_not_contain("file name abbreviation", - abbreviateFile, "indra"); + ensure_ends_with("file name abbreviation", + abbreviateFile, + "llcommon/tests/llerror_test.cpp" + ); + ensure_does_not_contain("file name abbreviation", + abbreviateFile, "indra"); - std::string someFile = + std::string someFile = #if LL_WINDOWS - "C:/amy/bob/cam.cpp" + "C:/amy/bob/cam.cpp" #else - "/amy/bob/cam.cpp" + "/amy/bob/cam.cpp" #endif - ; - std::string someAbbreviation = LLError::abbreviateFile(someFile); + ; + std::string someAbbreviation = LLError::abbreviateFile(someFile); - ensure_equals("non-indra file abbreviation", - someAbbreviation, someFile); - } + ensure_equals("non-indra file abbreviation", + someAbbreviation, someFile); + } } namespace { - std::string locationString(int line) - { - std::ostringstream location; - location << LLError::abbreviateFile(__FILE__) - << "(" << line << ")"; - - return location.str(); - } - - std::string writeReturningLocation() - { - LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; - return locationString(this_line); - } - - void writeReturningLocationAndFunction(std::string& location, std::string& function) - { - LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; - location = locationString(this_line); - function = __FUNCTION__; - } - - std::string errorReturningLocation() - { - int this_line = __LINE__; CATCH(LL_ERRS(), "die"); - return locationString(this_line); - } + std::string locationString(int line) + { + std::ostringstream location; + location << LLError::abbreviateFile(__FILE__) + << "(" << line << ")"; + + return location.str(); + } + + std::string writeReturningLocation() + { + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; + return locationString(this_line); + } + + void writeReturningLocationAndFunction(std::string& location, std::string& function) + { + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; + location = locationString(this_line); + function = __FUNCTION__; + } + + std::string errorReturningLocation() + { + int this_line = __LINE__; CATCH(LL_ERRS(), "die"); + return locationString(this_line); + } } /* The following helper functions and class members all log a simple message - from some particular function scope. Each function takes a bool argument - that indicates if it should log its own name or not (in the manner that - existing log messages often do.) The functions all return their C++ - name so that test can be substantial mechanized. + from some particular function scope. Each function takes a bool argument + that indicates if it should log its own name or not (in the manner that + existing log messages often do.) The functions all return their C++ + name so that test can be substantial mechanized. */ std::string logFromGlobal(bool id) { - LL_INFOS() << (id ? "logFromGlobal: " : "") << "hi" << LL_ENDL; - return "logFromGlobal"; + LL_INFOS() << (id ? "logFromGlobal: " : "") << "hi" << LL_ENDL; + return "logFromGlobal"; } static std::string logFromStatic(bool id) { - LL_INFOS() << (id ? "logFromStatic: " : "") << "hi" << LL_ENDL; - return "logFromStatic"; + LL_INFOS() << (id ? "logFromStatic: " : "") << "hi" << LL_ENDL; + return "logFromStatic"; } namespace { - std::string logFromAnon(bool id) - { - LL_INFOS() << (id ? "logFromAnon: " : "") << "hi" << LL_ENDL; - return "logFromAnon"; - } + std::string logFromAnon(bool id) + { + LL_INFOS() << (id ? "logFromAnon: " : "") << "hi" << LL_ENDL; + return "logFromAnon"; + } } namespace Foo { - std::string logFromNamespace(bool id) - { - LL_INFOS() << (id ? "Foo::logFromNamespace: " : "") << "hi" << LL_ENDL; - //return "Foo::logFromNamespace"; - // there is no standard way to get the namespace name, hence - // we won't be testing for it - return "logFromNamespace"; - } + std::string logFromNamespace(bool id) + { + LL_INFOS() << (id ? "Foo::logFromNamespace: " : "") << "hi" << LL_ENDL; + //return "Foo::logFromNamespace"; + // there is no standard way to get the namespace name, hence + // we won't be testing for it + return "logFromNamespace"; + } } namespace { - class ClassWithNoLogType { - public: - std::string logFromMember(bool id) - { - LL_INFOS() << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << LL_ENDL; - return "ClassWithNoLogType::logFromMember"; - } - static std::string logFromStatic(bool id) - { - LL_INFOS() << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << LL_ENDL; - return "ClassWithNoLogType::logFromStatic"; - } - }; - - class ClassWithLogType { - LOG_CLASS(ClassWithLogType); - public: - std::string logFromMember(bool id) - { - LL_INFOS() << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << LL_ENDL; - return "ClassWithLogType::logFromMember"; - } - static std::string logFromStatic(bool id) - { - LL_INFOS() << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << LL_ENDL; - return "ClassWithLogType::logFromStatic"; - } - }; - - std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); } - std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); } - std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); } - - void ensure_has(const std::string& message, - const std::string& actual, const std::string& expected) - { - std::string::size_type n1 = actual.find(expected); - if (n1 == std::string::npos) - { - std::stringstream ss; - ss << message << ": " << "expected to find a copy of '" << expected - << "' in actual '" << actual << "'"; - throw tut::failure(ss.str().c_str()); - } - } - - typedef std::string (*LogFromFunction)(bool); - void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, - const std::string& class_name = "") - { - std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->clearMessages(); - std::string name = f(false); - f(true); - - std::string messageWithoutName = std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(0); - std::string messageWithName = std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(1); - - ensure_has(name + " logged without name", - messageWithoutName, name); - ensure_has(name + " logged with name", - messageWithName, name); - - if (!class_name.empty()) - { - ensure_has(name + "logged without name", - messageWithoutName, class_name); - ensure_has(name + "logged with name", - messageWithName, class_name); - } - } + class ClassWithNoLogType { + public: + std::string logFromMember(bool id) + { + LL_INFOS() << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << LL_ENDL; + return "ClassWithNoLogType::logFromMember"; + } + static std::string logFromStatic(bool id) + { + LL_INFOS() << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << LL_ENDL; + return "ClassWithNoLogType::logFromStatic"; + } + }; + + class ClassWithLogType { + LOG_CLASS(ClassWithLogType); + public: + std::string logFromMember(bool id) + { + LL_INFOS() << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << LL_ENDL; + return "ClassWithLogType::logFromMember"; + } + static std::string logFromStatic(bool id) + { + LL_INFOS() << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << LL_ENDL; + return "ClassWithLogType::logFromStatic"; + } + }; + + std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); } + std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); } + std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); } + + void ensure_has(const std::string& message, + const std::string& actual, const std::string& expected) + { + std::string::size_type n1 = actual.find(expected); + if (n1 == std::string::npos) + { + std::stringstream ss; + ss << message << ": " << "expected to find a copy of '" << expected + << "' in actual '" << actual << "'"; + throw tut::failure(ss.str().c_str()); + } + } + + typedef std::string (*LogFromFunction)(bool); + void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, + const std::string& class_name = "") + { + std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->clearMessages(); + std::string name = f(false); + f(true); + + std::string messageWithoutName = std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(0); + std::string messageWithName = std::dynamic_pointer_cast<tut::TestRecorder>(recorder)->message(1); + + ensure_has(name + " logged without name", + messageWithoutName, name); + ensure_has(name + " logged with name", + messageWithName, name); + + if (!class_name.empty()) + { + ensure_has(name + "logged without name", + messageWithoutName, class_name); + ensure_has(name + "logged with name", + messageWithName, class_name); + } + } } namespace @@ -540,7 +540,7 @@ namespace tut // backslash, return, and newline are not escaped with backslashes { LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - setWantsMultiline(true); + setWantsMultiline(true); writeMsgNeedsEscaping(); // but should not be now ensure_message_field_equals(0, MSG_FIELD, "backslash\\"); ensure_message_field_equals(1, MSG_FIELD, "newline\nafternewline"); @@ -554,324 +554,324 @@ namespace tut namespace tut { - template<> template<> - // class/function information in output - void ErrorTestObject::test<6>() - { - testLogName(mRecorder, logFromGlobal); - testLogName(mRecorder, logFromStatic); - testLogName(mRecorder, logFromAnon); - testLogName(mRecorder, logFromNamespace); - testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType"); - testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType"); - } + template<> template<> + // class/function information in output + void ErrorTestObject::test<6>() + { + testLogName(mRecorder, logFromGlobal); + testLogName(mRecorder, logFromStatic); + testLogName(mRecorder, logFromAnon); + testLogName(mRecorder, logFromNamespace); + testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType"); + testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType"); + } } namespace { - std::string innerLogger() - { - LL_INFOS() << "inside" << LL_ENDL; - return "moo"; - } - - std::string outerLogger() - { - LL_INFOS() << "outside(" << innerLogger() << ")" << LL_ENDL; - return "bar"; - } - - class LogWhileLogging - { - public: - void print(std::ostream& out) const - { - LL_INFOS() << "logging" << LL_ENDL; - out << "baz"; - } - }; - - std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l) - { l.print(out); return out; } - - void metaLogger() - { - LogWhileLogging l; - LL_INFOS() << "meta(" << l << ")" << LL_ENDL; - } + std::string innerLogger() + { + LL_INFOS() << "inside" << LL_ENDL; + return "moo"; + } + + std::string outerLogger() + { + LL_INFOS() << "outside(" << innerLogger() << ")" << LL_ENDL; + return "bar"; + } + + class LogWhileLogging + { + public: + void print(std::ostream& out) const + { + LL_INFOS() << "logging" << LL_ENDL; + out << "baz"; + } + }; + + std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l) + { l.print(out); return out; } + + void metaLogger() + { + LogWhileLogging l; + LL_INFOS() << "meta(" << l << ")" << LL_ENDL; + } } namespace tut { - template<> template<> - // handle nested logging - void ErrorTestObject::test<7>() - { - outerLogger(); - ensure_message_field_equals(0, MSG_FIELD, "inside"); - ensure_message_field_equals(1, MSG_FIELD, "outside(moo)"); - ensure_message_count(2); - - metaLogger(); - ensure_message_field_equals(2, MSG_FIELD, "logging"); - ensure_message_field_equals(3, MSG_FIELD, "meta(baz)"); - ensure_message_count(4); - } - - template<> template<> - // special handling of LL_ERRS() calls - void ErrorTestObject::test<8>() - { - std::string location = errorReturningLocation(); - - ensure_message_field_equals(0, LOCATION_FIELD, location); - ensure_message_field_equals(0, MSG_FIELD, "die"); - ensure_message_count(1); - - ensure("fatal callback called", fatalWasCalled); - } + template<> template<> + // handle nested logging + void ErrorTestObject::test<7>() + { + outerLogger(); + ensure_message_field_equals(0, MSG_FIELD, "inside"); + ensure_message_field_equals(1, MSG_FIELD, "outside(moo)"); + ensure_message_count(2); + + metaLogger(); + ensure_message_field_equals(2, MSG_FIELD, "logging"); + ensure_message_field_equals(3, MSG_FIELD, "meta(baz)"); + ensure_message_count(4); + } + + template<> template<> + // special handling of LL_ERRS() calls + void ErrorTestObject::test<8>() + { + std::string location = errorReturningLocation(); + + ensure_message_field_equals(0, LOCATION_FIELD, location); + ensure_message_field_equals(0, MSG_FIELD, "die"); + ensure_message_count(1); + + ensure("fatal callback called", fatalWasCalled); + } } namespace { - std::string roswell() - { - return "1947-07-08T03:04:05Z"; - } - - void ufoSighting() - { - LL_INFOS() << "ufo" << LL_ENDL; - } + std::string roswell() + { + return "1947-07-08T03:04:05Z"; + } + + void ufoSighting() + { + LL_INFOS() << "ufo" << LL_ENDL; + } } namespace tut { - template<> template<> - // time in output (for recorders that need it) - void ErrorTestObject::test<9>() - { - LLError::setTimeFunction(roswell); - - setWantsTime(false); - ufoSighting(); - ensure_message_field_equals(0, MSG_FIELD, "ufo"); - ensure_message_does_not_contain(0, roswell()); - - setWantsTime(true); - ufoSighting(); - ensure_message_field_equals(1, MSG_FIELD, "ufo"); - ensure_message_field_equals(1, TIME_FIELD, roswell()); - } - - template<> template<> - // output order - void ErrorTestObject::test<10>() - { - LLError::setTimeFunction(roswell); - setWantsTime(true); - - std::string location, - function; - writeReturningLocationAndFunction(location, function); - - ensure_equals("order is time level tags location function message", + template<> template<> + // time in output (for recorders that need it) + void ErrorTestObject::test<9>() + { + LLError::setTimeFunction(roswell); + + setWantsTime(false); + ufoSighting(); + ensure_message_field_equals(0, MSG_FIELD, "ufo"); + ensure_message_does_not_contain(0, roswell()); + + setWantsTime(true); + ufoSighting(); + ensure_message_field_equals(1, MSG_FIELD, "ufo"); + ensure_message_field_equals(1, TIME_FIELD, roswell()); + } + + template<> template<> + // output order + void ErrorTestObject::test<10>() + { + LLError::setTimeFunction(roswell); + setWantsTime(true); + + std::string location, + function; + writeReturningLocationAndFunction(location, function); + + ensure_equals("order is time level tags location function message", message(0), roswell() + " INFO " + "# " /* no tag */ + location + " " + function + " : " + "apple"); - } + } - template<> template<> - // multiple recorders - void ErrorTestObject::test<11>() - { - LLError::RecorderPtr altRecorder(new TestRecorder()); - LLError::addRecorder(altRecorder); + template<> template<> + // multiple recorders + void ErrorTestObject::test<11>() + { + LLError::RecorderPtr altRecorder(new TestRecorder()); + LLError::addRecorder(altRecorder); - LL_INFOS() << "boo" << LL_ENDL; + LL_INFOS() << "boo" << LL_ENDL; - ensure_message_field_equals(0, MSG_FIELD, "boo"); - ensure_equals("alt recorder count", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1); - ensure_contains("alt recorder message 0", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo"); + ensure_message_field_equals(0, MSG_FIELD, "boo"); + ensure_equals("alt recorder count", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 1); + ensure_contains("alt recorder message 0", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(0), "boo"); - LLError::setTimeFunction(roswell); + LLError::setTimeFunction(roswell); - LLError::RecorderPtr anotherRecorder(new TestRecorder()); - std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->showTime(true); - LLError::addRecorder(anotherRecorder); + LLError::RecorderPtr anotherRecorder(new TestRecorder()); + std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->showTime(true); + LLError::addRecorder(anotherRecorder); - LL_INFOS() << "baz" << LL_ENDL; + LL_INFOS() << "baz" << LL_ENDL; - std::string when = roswell(); + std::string when = roswell(); - ensure_message_does_not_contain(1, when); - ensure_equals("alt recorder count", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 2); - ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(1), when); - ensure_equals("another recorder count", std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->countMessages(), 1); - ensure_contains("another recorder message 0", std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->message(0), when); + ensure_message_does_not_contain(1, when); + ensure_equals("alt recorder count", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->countMessages(), 2); + ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast<TestRecorder>(altRecorder)->message(1), when); + ensure_equals("another recorder count", std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->countMessages(), 1); + ensure_contains("another recorder message 0", std::dynamic_pointer_cast<TestRecorder>(anotherRecorder)->message(0), when); - LLError::removeRecorder(altRecorder); - LLError::removeRecorder(anotherRecorder); - } + LLError::removeRecorder(altRecorder); + LLError::removeRecorder(anotherRecorder); + } } class TestAlpha { - LOG_CLASS(TestAlpha); + LOG_CLASS(TestAlpha); public: - static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } - static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } - static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } - static void doError() { CATCH(LL_ERRS(), "ate eels"); } - static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } + static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "ate eels"); } + static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; class TestBeta { - LOG_CLASS(TestBeta); + LOG_CLASS(TestBeta); public: - static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } - static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } - static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } - static void doError() { CATCH(LL_ERRS(), "big easy"); } - static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } + static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "big easy"); } + static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; namespace tut { - template<> template<> - // filtering by class - void ErrorTestObject::test<12>() - { - LLError::setDefaultLevel(LLError::LEVEL_WARN); - LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO); - - TestAlpha::doAll(); - TestBeta::doAll(); - - ensure_message_field_equals(0, MSG_FIELD, "aim west"); - ensure_message_field_equals(1, MSG_FIELD, "ate eels"); - ensure_message_field_equals(2, MSG_FIELD, "buy iron"); - ensure_message_field_equals(3, MSG_FIELD, "bad word"); - ensure_message_field_equals(4, MSG_FIELD, "big easy"); - ensure_message_count(5); - } - - template<> template<> - // filtering by function, and that it will override class filtering - void ErrorTestObject::test<13>() - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN); - LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG); - LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE); - - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "buy iron"); - ensure_message_field_equals(1, MSG_FIELD, "bad word"); - ensure_message_count(2); - } - - template<> template<> - // filtering by file - // and that it is overridden by both class and function filtering - void ErrorTestObject::test<14>() - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setFileLevel(LLError::abbreviateFile(__FILE__), - LLError::LEVEL_WARN); - LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO); - LLError::setFunctionLevel("TestAlpha::doError", - LLError::LEVEL_NONE); - LLError::setFunctionLevel("TestBeta::doError", - LLError::LEVEL_NONE); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "any idea"); - ensure_message_field_equals(1, MSG_FIELD, "aim west"); - ensure_message_field_equals(2, MSG_FIELD, "bad word"); - ensure_message_count(3); - } - - template<> template<> - // proper cached, efficient lookup of filtering - void ErrorTestObject::test<15>() - { - LLError::setDefaultLevel(LLError::LEVEL_NONE); - - TestAlpha::doInfo(); - ensure_message_count(0); - ensure_equals("first check", LLError::shouldLogCallCount(), 1); - TestAlpha::doInfo(); - ensure_message_count(0); - ensure_equals("second check", LLError::shouldLogCallCount(), 1); - - LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG); - TestAlpha::doInfo(); - ensure_message_count(1); - ensure_equals("third check", LLError::shouldLogCallCount(), 2); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); - - LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); - } - - template<> template<> - // configuration from LLSD - void ErrorTestObject::test<16>() - { - LLSD config; - config["print-location"] = true; - config["default-level"] = "DEBUG"; - - LLSD set1; - set1["level"] = "WARN"; + template<> template<> + // filtering by class + void ErrorTestObject::test<12>() + { + LLError::setDefaultLevel(LLError::LEVEL_WARN); + LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO); + + TestAlpha::doAll(); + TestBeta::doAll(); + + ensure_message_field_equals(0, MSG_FIELD, "aim west"); + ensure_message_field_equals(1, MSG_FIELD, "ate eels"); + ensure_message_field_equals(2, MSG_FIELD, "buy iron"); + ensure_message_field_equals(3, MSG_FIELD, "bad word"); + ensure_message_field_equals(4, MSG_FIELD, "big easy"); + ensure_message_count(5); + } + + template<> template<> + // filtering by function, and that it will override class filtering + void ErrorTestObject::test<13>() + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN); + LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG); + LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE); + + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "buy iron"); + ensure_message_field_equals(1, MSG_FIELD, "bad word"); + ensure_message_count(2); + } + + template<> template<> + // filtering by file + // and that it is overridden by both class and function filtering + void ErrorTestObject::test<14>() + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setFileLevel(LLError::abbreviateFile(__FILE__), + LLError::LEVEL_WARN); + LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO); + LLError::setFunctionLevel("TestAlpha::doError", + LLError::LEVEL_NONE); + LLError::setFunctionLevel("TestBeta::doError", + LLError::LEVEL_NONE); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "any idea"); + ensure_message_field_equals(1, MSG_FIELD, "aim west"); + ensure_message_field_equals(2, MSG_FIELD, "bad word"); + ensure_message_count(3); + } + + template<> template<> + // proper cached, efficient lookup of filtering + void ErrorTestObject::test<15>() + { + LLError::setDefaultLevel(LLError::LEVEL_NONE); + + TestAlpha::doInfo(); + ensure_message_count(0); + ensure_equals("first check", LLError::shouldLogCallCount(), 1); + TestAlpha::doInfo(); + ensure_message_count(0); + ensure_equals("second check", LLError::shouldLogCallCount(), 1); + + LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG); + TestAlpha::doInfo(); + ensure_message_count(1); + ensure_equals("third check", LLError::shouldLogCallCount(), 2); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); + + LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); + } + + template<> template<> + // configuration from LLSD + void ErrorTestObject::test<16>() + { + LLSD config; + config["print-location"] = true; + config["default-level"] = "DEBUG"; + + LLSD set1; + set1["level"] = "WARN"; set1["files"][0] = LLError::abbreviateFile(__FILE__); - LLSD set2; - set2["level"] = "INFO"; - set2["classes"][0] = "TestAlpha"; - - LLSD set3; - set3["level"] = "NONE"; - set3["functions"][0] = "TestAlpha::doError"; - set3["functions"][1] = "TestBeta::doError"; - - config["settings"][0] = set1; - config["settings"][1] = set2; - config["settings"][2] = set3; - - LLError::configure(config); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "any idea"); - ensure_message_field_equals(1, MSG_FIELD, "aim west"); - ensure_message_field_equals(2, MSG_FIELD, "bad word"); - ensure_message_count(3); - - // make sure reconfiguring works - LLSD config2; - config2["default-level"] = "WARN"; - - LLError::configure(config2); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(3, MSG_FIELD, "aim west"); - ensure_message_field_equals(4, MSG_FIELD, "ate eels"); - ensure_message_field_equals(5, MSG_FIELD, "bad word"); - ensure_message_field_equals(6, MSG_FIELD, "big easy"); - ensure_message_count(7); - } + LLSD set2; + set2["level"] = "INFO"; + set2["classes"][0] = "TestAlpha"; + + LLSD set3; + set3["level"] = "NONE"; + set3["functions"][0] = "TestAlpha::doError"; + set3["functions"][1] = "TestBeta::doError"; + + config["settings"][0] = set1; + config["settings"][1] = set2; + config["settings"][2] = set3; + + LLError::configure(config); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "any idea"); + ensure_message_field_equals(1, MSG_FIELD, "aim west"); + ensure_message_field_equals(2, MSG_FIELD, "bad word"); + ensure_message_count(3); + + // make sure reconfiguring works + LLSD config2; + config2["default-level"] = "WARN"; + + LLError::configure(config2); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(3, MSG_FIELD, "aim west"); + ensure_message_field_equals(4, MSG_FIELD, "ate eels"); + ensure_message_field_equals(5, MSG_FIELD, "bad word"); + ensure_message_field_equals(6, MSG_FIELD, "big easy"); + ensure_message_count(7); + } } namespace tut @@ -919,16 +919,16 @@ namespace tut } /* Tests left: - handling of classes without LOG_CLASS + handling of classes without LOG_CLASS - live update of filtering from file + live update of filtering from file - syslog recorder - file recorder - cerr/stderr recorder - fixed buffer recorder - windows recorder + syslog recorder + file recorder + cerr/stderr recorder + fixed buffer recorder + windows recorder - mutex use when logging (?) - strange careful about to crash handling (?) + mutex use when logging (?) + strange careful about to crash handling (?) */ diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index 01104545c6..a3c54ffaa2 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-22 * @brief Test for coroutine. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index b0c532887c..a99acba848 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-01-20 * @brief Test for lleventdispatcher. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ @@ -470,7 +470,7 @@ namespace tut params["a"], "\n" "params[\"b\"]:\n", params["b"]); - // default LLSD::Binary value + // default LLSD::Binary value std::vector<U8> binary; for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11) { diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index fa2cb03e95..a01d7fe415 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-06 * @brief Test for lleventfilter. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llframetimer_test.cpp b/indra/llcommon/tests/llframetimer_test.cpp index be372bb855..b9a8c91abf 100644 --- a/indra/llcommon/tests/llframetimer_test.cpp +++ b/indra/llcommon/tests/llframetimer_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lltiming_test.cpp * @date 2006-07-23 * @brief Tests the timers. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,88 +34,88 @@ namespace tut { - struct frametimer_test - { - frametimer_test() - { - LLFrameTimer::updateFrameTime(); - } - }; - typedef test_group<frametimer_test> frametimer_group_t; - typedef frametimer_group_t::object frametimer_object_t; - tut::frametimer_group_t frametimer_instance("LLFrameTimer"); + struct frametimer_test + { + frametimer_test() + { + LLFrameTimer::updateFrameTime(); + } + }; + typedef test_group<frametimer_test> frametimer_group_t; + typedef frametimer_group_t::object frametimer_object_t; + tut::frametimer_group_t frametimer_instance("LLFrameTimer"); + + template<> template<> + void frametimer_object_t::test<1>() + { + F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); + LLFrameTimer timer; + timer.setExpiryAt(seconds_since_epoch); + F64 expires_at = timer.expiresAt(); + ensure_distance( + "set expiry matches get expiry", + expires_at, + seconds_since_epoch, + 0.001); + } - template<> template<> - void frametimer_object_t::test<1>() - { - F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); - LLFrameTimer timer; - timer.setExpiryAt(seconds_since_epoch); - F64 expires_at = timer.expiresAt(); - ensure_distance( - "set expiry matches get expiry", - expires_at, - seconds_since_epoch, - 0.001); - } + template<> template<> + void frametimer_object_t::test<2>() + { + F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); + seconds_since_epoch += 10.0; + LLFrameTimer timer; + timer.setExpiryAt(seconds_since_epoch); + F64 expires_at = timer.expiresAt(); + ensure_distance( + "set expiry matches get expiry 1", + expires_at, + seconds_since_epoch, + 0.001); + seconds_since_epoch += 10.0; + timer.setExpiryAt(seconds_since_epoch); + expires_at = timer.expiresAt(); + ensure_distance( + "set expiry matches get expiry 2", + expires_at, + seconds_since_epoch, + 0.001); + } + template<> template<> + void frametimer_object_t::test<3>() + { + clock_t t1 = clock(); + ms_sleep(200); + clock_t t2 = clock(); + clock_t elapsed = t2 - t1 + 1; + std::cout << "Note: using clock(), ms_sleep() actually took " << (long)elapsed << "ms" << std::endl; - template<> template<> - void frametimer_object_t::test<2>() - { - F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); - seconds_since_epoch += 10.0; - LLFrameTimer timer; - timer.setExpiryAt(seconds_since_epoch); - F64 expires_at = timer.expiresAt(); - ensure_distance( - "set expiry matches get expiry 1", - expires_at, - seconds_since_epoch, - 0.001); - seconds_since_epoch += 10.0; - timer.setExpiryAt(seconds_since_epoch); - expires_at = timer.expiresAt(); - ensure_distance( - "set expiry matches get expiry 2", - expires_at, - seconds_since_epoch, - 0.001); - } - template<> template<> - void frametimer_object_t::test<3>() - { - clock_t t1 = clock(); - ms_sleep(200); - clock_t t2 = clock(); - clock_t elapsed = t2 - t1 + 1; - std::cout << "Note: using clock(), ms_sleep() actually took " << (long)elapsed << "ms" << std::endl; + F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); + seconds_since_epoch += 2.0; + LLFrameTimer timer; + timer.setExpiryAt(seconds_since_epoch); + /* + * Note that the ms_sleep(200) below is only guaranteed to return + * in 200ms _or_more_, so it should be true that by the 10th + * iteration we've gotten to the 2 seconds requested above + * and the timer should expire, but it can expire in fewer iterations + * if one or more of the ms_sleep calls takes longer. + * (as it did when we moved to Mac OS X 10.10) + */ + int iterations_until_expiration = 0; + while ( !timer.hasExpired() ) + { + ms_sleep(200); + LLFrameTimer::updateFrameTime(); + iterations_until_expiration++; + } + ensure("timer took too long to expire", iterations_until_expiration <= 10); + } - F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); - seconds_since_epoch += 2.0; - LLFrameTimer timer; - timer.setExpiryAt(seconds_since_epoch); - /* - * Note that the ms_sleep(200) below is only guaranteed to return - * in 200ms _or_more_, so it should be true that by the 10th - * iteration we've gotten to the 2 seconds requested above - * and the timer should expire, but it can expire in fewer iterations - * if one or more of the ms_sleep calls takes longer. - * (as it did when we moved to Mac OS X 10.10) - */ - int iterations_until_expiration = 0; - while ( !timer.hasExpired() ) - { - ms_sleep(200); - LLFrameTimer::updateFrameTime(); - iterations_until_expiration++; - } - ensure("timer took too long to expire", iterations_until_expiration <= 10); - } - /* - template<> template<> - void frametimer_object_t::test<4>() - { - } + template<> template<> + void frametimer_object_t::test<4>() + { + } */ } diff --git a/indra/llcommon/tests/llheteromap_test.cpp b/indra/llcommon/tests/llheteromap_test.cpp index 686bffb878..cabfb91593 100644 --- a/indra/llcommon/tests/llheteromap_test.cpp +++ b/indra/llcommon/tests/llheteromap_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-10-12 * @brief Test for llheteromap. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 95af9c2a50..c6eb0fdf75 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-11-10 * @brief Test for llinstancetracker. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -170,7 +170,7 @@ namespace tut { Unkeyed one, two, three; typedef std::set<Unkeyed*> KeySet; - + KeySet instances; instances.insert(&one); instances.insert(&two); diff --git a/indra/llcommon/tests/lllazy_test.cpp b/indra/llcommon/tests/lllazy_test.cpp index 542306ee22..923fe952a9 100644 --- a/indra/llcommon/tests/lllazy_test.cpp +++ b/indra/llcommon/tests/lllazy_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-01-28 * @brief Tests of lllazy.h. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 7197dedfbf..fa48bcdefd 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-21 * @brief Test for llleap. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llmainthreadtask_test.cpp b/indra/llcommon/tests/llmainthreadtask_test.cpp index 69b11ccafb..9ccf391327 100644 --- a/indra/llcommon/tests/llmainthreadtask_test.cpp +++ b/indra/llcommon/tests/llmainthreadtask_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-12-05 * @brief Test for llmainthreadtask. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llmemtype_test.cpp b/indra/llcommon/tests/llmemtype_test.cpp index 1f050d6dc7..2d64d342ae 100644 --- a/indra/llcommon/tests/llmemtype_test.cpp +++ b/indra/llcommon/tests/llmemtype_test.cpp @@ -3,25 +3,25 @@ * @author Palmer Truelson * @date 2008-03- * @brief Test for llmemtype.cpp. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,14 +37,14 @@ std::stack<S32> memTypeStack; void LLAllocator::pushMemType(S32 i) { - memTypeStack.push(i); + memTypeStack.push(i); } S32 LLAllocator::popMemType(void) { - S32 ret = memTypeStack.top(); - memTypeStack.pop(); - return ret; + S32 ret = memTypeStack.top(); + memTypeStack.pop(); + return ret; } namespace tut @@ -69,49 +69,49 @@ namespace tut ensure("Simplest test ever", true); } - // test with no scripts - template<> template<> - void object::test<2>() - { - { - LLMemType m1(LLMemType::MTYPE_INIT); - } - ensure("Test that you can construct and destruct the mem type"); - } - - // test creation and stack testing - template<> template<> - void object::test<3>() - { - { - ensure("Test that creation and destruction properly inc/dec the stack"); - ensure_equals(memTypeStack.size(), 0); - { - LLMemType m1(LLMemType::MTYPE_INIT); - ensure_equals(memTypeStack.size(), 1); - LLMemType m2(LLMemType::MTYPE_STARTUP); - ensure_equals(memTypeStack.size(), 2); - } - ensure_equals(memTypeStack.size(), 0); - } - } - - // test with no scripts - template<> template<> - void object::test<4>() - { - // catch the begining and end - std::string test_name = LLMemType::getNameFromID(LLMemType::MTYPE_INIT.mID); - ensure_equals("Init name", test_name, "Init"); - - std::string test_name2 = LLMemType::getNameFromID(LLMemType::MTYPE_VOLUME.mID); - ensure_equals("Volume name", test_name2, "Volume"); - - std::string test_name3 = LLMemType::getNameFromID(LLMemType::MTYPE_OTHER.mID); - ensure_equals("Other name", test_name3, "Other"); + // test with no scripts + template<> template<> + void object::test<2>() + { + { + LLMemType m1(LLMemType::MTYPE_INIT); + } + ensure("Test that you can construct and destruct the mem type"); + } + + // test creation and stack testing + template<> template<> + void object::test<3>() + { + { + ensure("Test that creation and destruction properly inc/dec the stack"); + ensure_equals(memTypeStack.size(), 0); + { + LLMemType m1(LLMemType::MTYPE_INIT); + ensure_equals(memTypeStack.size(), 1); + LLMemType m2(LLMemType::MTYPE_STARTUP); + ensure_equals(memTypeStack.size(), 2); + } + ensure_equals(memTypeStack.size(), 0); + } + } + + // test with no scripts + template<> template<> + void object::test<4>() + { + // catch the begining and end + std::string test_name = LLMemType::getNameFromID(LLMemType::MTYPE_INIT.mID); + ensure_equals("Init name", test_name, "Init"); + + std::string test_name2 = LLMemType::getNameFromID(LLMemType::MTYPE_VOLUME.mID); + ensure_equals("Volume name", test_name2, "Volume"); + + std::string test_name3 = LLMemType::getNameFromID(LLMemType::MTYPE_OTHER.mID); + ensure_equals("Other name", test_name3, "Other"); std::string test_name4 = LLMemType::getNameFromID(-1); ensure_equals("Invalid name", test_name4, "INVALID"); - } + } }; diff --git a/indra/llcommon/tests/llpounceable_test.cpp b/indra/llcommon/tests/llpounceable_test.cpp index 2f4915ce11..b3024966c5 100644 --- a/indra/llcommon/tests/llpounceable_test.cpp +++ b/indra/llcommon/tests/llpounceable_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2015-05-22 * @brief Test for llpounceable. - * + * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Copyright (c) 2015, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 628f046f55..6e8422ca0c 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-12-19 * @brief Test for llprocess. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ @@ -1075,7 +1075,7 @@ namespace tut { EventListener(LLEventPump& pump) { - mConnection = + mConnection = pump.listen("EventListener", boost::bind(&EventListener::tick, this, _1)); } diff --git a/indra/llcommon/tests/llprocessor_test.cpp b/indra/llcommon/tests/llprocessor_test.cpp index 884e1b5e5b..a2467d9205 100644 --- a/indra/llcommon/tests/llprocessor_test.cpp +++ b/indra/llcommon/tests/llprocessor_test.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocessor_test.cpp * @date 2010-06-01 * * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,30 +32,30 @@ namespace tut { - struct processor - { - }; - - typedef test_group<processor> processor_t; - typedef processor_t::object processor_object_t; - tut::processor_t tut_processor("LLProcessor"); - - template<> template<> - void processor_object_t::test<1>() - { - set_test_name("LLProcessorInfo regression test"); - - LLProcessorInfo pi; - F64 freq = pi.getCPUFrequency(); - //bool sse = pi.hasSSE(); - //bool sse2 = pi.hasSSE2(); - //bool alitvec = pi.hasAltivec(); - std::string family = pi.getCPUFamilyName(); - std::string brand = pi.getCPUBrandName(); - //std::string steam = pi.getCPUFeatureDescription(); - - ensure_not_equals("Unknown Brand name", brand, "Unknown"); - ensure_not_equals("Unknown Family name", family, "Unknown"); - ensure("Reasonable CPU Frequency > 100 && < 10000", freq > 100 && freq < 10000); - } + struct processor + { + }; + + typedef test_group<processor> processor_t; + typedef processor_t::object processor_object_t; + tut::processor_t tut_processor("LLProcessor"); + + template<> template<> + void processor_object_t::test<1>() + { + set_test_name("LLProcessorInfo regression test"); + + LLProcessorInfo pi; + F64 freq = pi.getCPUFrequency(); + //bool sse = pi.hasSSE(); + //bool sse2 = pi.hasSSE2(); + //bool alitvec = pi.hasAltivec(); + std::string family = pi.getCPUFamilyName(); + std::string brand = pi.getCPUBrandName(); + //std::string steam = pi.getCPUFeatureDescription(); + + ensure_not_equals("Unknown Brand name", brand, "Unknown"); + ensure_not_equals("Unknown Family name", family, "Unknown"); + ensure("Reasonable CPU Frequency > 100 && < 10000", freq > 100 && freq < 10000); + } } diff --git a/indra/llcommon/tests/llprocinfo_test.cpp b/indra/llcommon/tests/llprocinfo_test.cpp index 12d5a695ee..6a151048c2 100644 --- a/indra/llcommon/tests/llprocinfo_test.cpp +++ b/indra/llcommon/tests/llprocinfo_test.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocinfo_test.cpp * @brief Tests for the LLProcInfo class. * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2013, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,9 +40,9 @@ namespace tut struct procinfo_test { - procinfo_test() - { - } + procinfo_test() + { + } }; typedef test_group<procinfo_test> procinfo_group_t; @@ -54,14 +54,14 @@ tut::procinfo_group_t procinfo_instance("LLProcInfo"); template<> template<> void procinfo_object_t::test<1>() { - LLProcInfo::time_type user(bad_user), system(bad_system); + LLProcInfo::time_type user(bad_user), system(bad_system); + + set_test_name("getCPUUsage() basic function"); - set_test_name("getCPUUsage() basic function"); + LLProcInfo::getCPUUsage(user, system); - LLProcInfo::getCPUUsage(user, system); - - ensure_not_equals("getCPUUsage() writes to its user argument", user, bad_user); - ensure_not_equals("getCPUUsage() writes to its system argument", system, bad_system); + ensure_not_equals("getCPUUsage() writes to its user argument", user, bad_user); + ensure_not_equals("getCPUUsage() writes to its system argument", system, bad_system); } @@ -69,22 +69,22 @@ void procinfo_object_t::test<1>() template<> template<> void procinfo_object_t::test<2>() { - LLProcInfo::time_type user(bad_user), system(bad_system); - LLProcInfo::time_type user2(bad_user), system2(bad_system); - - set_test_name("getCPUUsage() increases over time"); - - LLProcInfo::getCPUUsage(user, system); - - for (int i(0); i < 100000; ++i) - { - ms_sleep(0); - } - - LLProcInfo::getCPUUsage(user2, system2); - - ensure_equals("getCPUUsage() user value doesn't decrease over time", user2 >= user, true); - ensure_equals("getCPUUsage() system value doesn't decrease over time", system2 >= system, true); + LLProcInfo::time_type user(bad_user), system(bad_system); + LLProcInfo::time_type user2(bad_user), system2(bad_system); + + set_test_name("getCPUUsage() increases over time"); + + LLProcInfo::getCPUUsage(user, system); + + for (int i(0); i < 100000; ++i) + { + ms_sleep(0); + } + + LLProcInfo::getCPUUsage(user2, system2); + + ensure_equals("getCPUUsage() user value doesn't decrease over time", user2 >= user, true); + ensure_equals("getCPUUsage() system value doesn't decrease over time", system2 >= system, true); } diff --git a/indra/llcommon/tests/llrand_test.cpp b/indra/llcommon/tests/llrand_test.cpp index ac5a33d0ba..a0dd4ef576 100644 --- a/indra/llcommon/tests/llrand_test.cpp +++ b/indra/llcommon/tests/llrand_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llrandom_test.cpp * @author Phoenix * @date 2007-01-25 @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,76 +49,76 @@ void ensure_in_range(const std::string_view& name, namespace tut { - struct random - { - }; + struct random + { + }; - typedef test_group<random> random_t; - typedef random_t::object random_object_t; - tut::random_t tut_random("LLSeedRand"); + typedef test_group<random> random_t; + typedef random_t::object random_object_t; + tut::random_t tut_random("LLSeedRand"); - template<> template<> - void random_object_t::test<1>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("frand", ll_frand(), 0.0f, 1.0f); - } - } + template<> template<> + void random_object_t::test<1>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("frand", ll_frand(), 0.0f, 1.0f); + } + } - template<> template<> - void random_object_t::test<2>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("drand", ll_drand(), 0.0, 1.0); - } - } + template<> template<> + void random_object_t::test<2>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("drand", ll_drand(), 0.0, 1.0); + } + } - template<> template<> - void random_object_t::test<3>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("frand(2.0f)", ll_frand(2.0f) - 1.0f, -1.0f, 1.0f); - } - } + template<> template<> + void random_object_t::test<3>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("frand(2.0f)", ll_frand(2.0f) - 1.0f, -1.0f, 1.0f); + } + } - template<> template<> - void random_object_t::test<4>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - // Negate the result so we don't have to allow a templated low-end - // comparison as well. - ensure_in_range("-frand(-7.0)", -ll_frand(-7.0), 0.0f, 7.0f); - } - } + template<> template<> + void random_object_t::test<4>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + // Negate the result so we don't have to allow a templated low-end + // comparison as well. + ensure_in_range("-frand(-7.0)", -ll_frand(-7.0), 0.0f, 7.0f); + } + } - template<> template<> - void random_object_t::test<5>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("-drand(-2.0)", -ll_drand(-2.0), 0.0, 2.0); - } - } + template<> template<> + void random_object_t::test<5>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("-drand(-2.0)", -ll_drand(-2.0), 0.0, 2.0); + } + } - template<> template<> - void random_object_t::test<6>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("rand(100)", ll_rand(100), 0, 100); - } - } + template<> template<> + void random_object_t::test<6>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("rand(100)", ll_rand(100), 0, 100); + } + } - template<> template<> - void random_object_t::test<7>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("-rand(-127)", -ll_rand(-127), 0, 127); - } - } + template<> template<> + void random_object_t::test<7>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("-rand(-127)", -ll_rand(-127), 0, 127); + } + } } diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index ac40125f75..56fdc51e82 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize_test.cpp * @date 2006-04 * @brief LLSDSerialize unit tests @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -64,313 +64,313 @@ typedef std::function<bool(std::istream& istr, LLSD& data, llssize max_bytes)> P std::vector<U8> string_to_vector(const std::string& str) { - return std::vector<U8>(str.begin(), str.end()); + return std::vector<U8>(str.begin(), str.end()); } namespace tut { - struct sd_xml_data - { - sd_xml_data() - { - mFormatter = new LLSDXMLFormatter; - } - LLSD mSD; - LLPointer<LLSDXMLFormatter> mFormatter; - void xml_test(const char* name, const std::string& expected) - { - std::ostringstream ostr; - mFormatter->format(mSD, ostr); - ensure_equals(name, ostr.str(), expected); - } - }; - - typedef test_group<sd_xml_data> sd_xml_test; - typedef sd_xml_test::object sd_xml_object; - tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); - - template<> template<> - void sd_xml_object::test<1>() - { - // random atomic tests - std::string expected; - - expected = "<llsd><undef /></llsd>\n"; - xml_test("undef", expected); - - mSD = 3463; - expected = "<llsd><integer>3463</integer></llsd>\n"; - xml_test("integer", expected); - - mSD = ""; - expected = "<llsd><string /></llsd>\n"; - xml_test("empty string", expected); - - mSD = "foobar"; - expected = "<llsd><string>foobar</string></llsd>\n"; - xml_test("string", expected); - - mSD = LLUUID::null; - expected = "<llsd><uuid /></llsd>\n"; - xml_test("null uuid", expected); - - mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); - expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n"; - xml_test("uuid", expected); - - mSD = LLURI("https://secondlife.com/login"); - expected = "<llsd><uri>https://secondlife.com/login</uri></llsd>\n"; - xml_test("uri", expected); - - mSD = LLDate("2006-04-24T16:11:33Z"); - expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n"; - xml_test("date", expected); - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - std::vector<U8> hello; - hello.push_back('h'); - hello.push_back('e'); - hello.push_back('l'); - hello.push_back('l'); - hello.push_back('o'); - mSD = hello; - expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; - xml_test("binary", expected); - } - - template<> template<> - void sd_xml_object::test<2>() - { - // tests with boolean values. - std::string expected; - - mFormatter->boolalpha(true); - mSD = true; - expected = "<llsd><boolean>true</boolean></llsd>\n"; - xml_test("bool alpha true", expected); - mSD = false; - expected = "<llsd><boolean>false</boolean></llsd>\n"; - xml_test("bool alpha false", expected); - - mFormatter->boolalpha(false); - mSD = true; - expected = "<llsd><boolean>1</boolean></llsd>\n"; - xml_test("bool true", expected); - mSD = false; - expected = "<llsd><boolean>0</boolean></llsd>\n"; - xml_test("bool false", expected); - } - - - template<> template<> - void sd_xml_object::test<3>() - { - // tests with real values. - std::string expected; - - mFormatter->realFormat("%.2f"); - mSD = 1.0; - expected = "<llsd><real>1.00</real></llsd>\n"; - xml_test("real 1", expected); - - mSD = -34379.0438; - expected = "<llsd><real>-34379.04</real></llsd>\n"; - xml_test("real reduced precision", expected); - mFormatter->realFormat("%.4f"); - expected = "<llsd><real>-34379.0438</real></llsd>\n"; - xml_test("higher precision", expected); - - mFormatter->realFormat("%.0f"); - mSD = 0.0; - expected = "<llsd><real>0</real></llsd>\n"; - xml_test("no decimal 0", expected); - mSD = 3287.4387; - expected = "<llsd><real>3287</real></llsd>\n"; - xml_test("no decimal real number", expected); - } - - template<> template<> - void sd_xml_object::test<4>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyArray(); - expected = "<llsd><array /></llsd>\n"; - xml_test("empty array", expected); - - mSD.append(LLSD()); - expected = "<llsd><array><undef /></array></llsd>\n"; - xml_test("1 element array", expected); - - mSD.append(1); - expected = "<llsd><array><undef /><integer>1</integer></array></llsd>\n"; - xml_test("2 element array", expected); - } - - template<> template<> - void sd_xml_object::test<5>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyMap(); - expected = "<llsd><map /></llsd>\n"; - xml_test("empty map", expected); - - mSD["foo"] = "bar"; - expected = "<llsd><map><key>foo</key><string>bar</string></map></llsd>\n"; - xml_test("1 element map", expected); - - mSD["baz"] = LLSD(); - expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n"; - xml_test("2 element map", expected); - } - - template<> template<> - void sd_xml_object::test<6>() - { - // tests with binary - std::string expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - mSD = string_to_vector("hello"); - expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; - xml_test("binary", expected); - - mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; - xml_test("binary", expected); - } - - class TestLLSDSerializeData - { - public: - TestLLSDSerializeData(); - ~TestLLSDSerializeData(); - - void doRoundTripTests(const std::string&); - void checkRoundTrip(const std::string&, const LLSD& v); - - void setFormatterParser(LLPointer<LLSDFormatter> formatter, LLPointer<LLSDParser> parser) - { - mFormatter = [formatter](const LLSD& data, std::ostream& str) - { - formatter->format(data, str); - }; - // this lambda must be mutable since otherwise the bound 'parser' - // is assumed to point to a const LLSDParser - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable - { - // reset() call is needed since test code re-uses parser object - parser->reset(); - return (parser->parse(istr, data, max_bytes) > 0); - }; - } - - void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) - { - // why does LLSDSerialize::deserialize() reverse the parse() params?? - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) - { - return parser(data, istr, max_bytes); - }; - } - - FormatterFunction mFormatter; - ParserFunction mParser; - }; - - TestLLSDSerializeData::TestLLSDSerializeData() - { - } - - TestLLSDSerializeData::~TestLLSDSerializeData() - { - } - - void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) - { - std::stringstream stream; - mFormatter(v, stream); - //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; - LLSD w; - mParser(stream, w, stream.str().size()); - - try - { - ensure_equals(msg, w, v); - } - catch (...) - { - std::cerr << "the serialized string was:" << std::endl; - std::cerr << stream.str() << std::endl; - throw; - } - } - - static void fillmap(LLSD& root, U32 width, U32 depth) - { - if(depth == 0) - { - root["foo"] = "bar"; - return; - } - - for(U32 i = 0; i < width; ++i) - { - std::string key = llformat("child %d", i); - root[key] = LLSD::emptyMap(); - fillmap(root[key], width, depth - 1); - } - } - - void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) - { - LLSD v; - checkRoundTrip(msg + " undefined", v); - - v = true; - checkRoundTrip(msg + " true bool", v); - - v = false; - checkRoundTrip(msg + " false bool", v); - - v = 1; - checkRoundTrip(msg + " positive int", v); - - v = 0; - checkRoundTrip(msg + " zero int", v); - - v = -1; - checkRoundTrip(msg + " negative int", v); - - v = 1234.5f; - checkRoundTrip(msg + " positive float", v); - - v = 0.0f; - checkRoundTrip(msg + " zero float", v); - - v = -1234.5f; - checkRoundTrip(msg + " negative float", v); - - // FIXME: need a NaN test - - v = LLUUID::null; - checkRoundTrip(msg + " null uuid", v); - - LLUUID newUUID; - newUUID.generate(); - v = newUUID; - checkRoundTrip(msg + " new uuid", v); - - v = ""; - checkRoundTrip(msg + " empty string", v); - - v = "some string"; - checkRoundTrip(msg + " non-empty string", v); - - v = + struct sd_xml_data + { + sd_xml_data() + { + mFormatter = new LLSDXMLFormatter; + } + LLSD mSD; + LLPointer<LLSDXMLFormatter> mFormatter; + void xml_test(const char* name, const std::string& expected) + { + std::ostringstream ostr; + mFormatter->format(mSD, ostr); + ensure_equals(name, ostr.str(), expected); + } + }; + + typedef test_group<sd_xml_data> sd_xml_test; + typedef sd_xml_test::object sd_xml_object; + tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); + + template<> template<> + void sd_xml_object::test<1>() + { + // random atomic tests + std::string expected; + + expected = "<llsd><undef /></llsd>\n"; + xml_test("undef", expected); + + mSD = 3463; + expected = "<llsd><integer>3463</integer></llsd>\n"; + xml_test("integer", expected); + + mSD = ""; + expected = "<llsd><string /></llsd>\n"; + xml_test("empty string", expected); + + mSD = "foobar"; + expected = "<llsd><string>foobar</string></llsd>\n"; + xml_test("string", expected); + + mSD = LLUUID::null; + expected = "<llsd><uuid /></llsd>\n"; + xml_test("null uuid", expected); + + mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); + expected = "<llsd><uuid>c96f9b1e-f589-4100-9774-d98643ce0bed</uuid></llsd>\n"; + xml_test("uuid", expected); + + mSD = LLURI("https://secondlife.com/login"); + expected = "<llsd><uri>https://secondlife.com/login</uri></llsd>\n"; + xml_test("uri", expected); + + mSD = LLDate("2006-04-24T16:11:33Z"); + expected = "<llsd><date>2006-04-24T16:11:33Z</date></llsd>\n"; + xml_test("date", expected); + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + std::vector<U8> hello; + hello.push_back('h'); + hello.push_back('e'); + hello.push_back('l'); + hello.push_back('l'); + hello.push_back('o'); + mSD = hello; + expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; + xml_test("binary", expected); + } + + template<> template<> + void sd_xml_object::test<2>() + { + // tests with boolean values. + std::string expected; + + mFormatter->boolalpha(true); + mSD = true; + expected = "<llsd><boolean>true</boolean></llsd>\n"; + xml_test("bool alpha true", expected); + mSD = false; + expected = "<llsd><boolean>false</boolean></llsd>\n"; + xml_test("bool alpha false", expected); + + mFormatter->boolalpha(false); + mSD = true; + expected = "<llsd><boolean>1</boolean></llsd>\n"; + xml_test("bool true", expected); + mSD = false; + expected = "<llsd><boolean>0</boolean></llsd>\n"; + xml_test("bool false", expected); + } + + + template<> template<> + void sd_xml_object::test<3>() + { + // tests with real values. + std::string expected; + + mFormatter->realFormat("%.2f"); + mSD = 1.0; + expected = "<llsd><real>1.00</real></llsd>\n"; + xml_test("real 1", expected); + + mSD = -34379.0438; + expected = "<llsd><real>-34379.04</real></llsd>\n"; + xml_test("real reduced precision", expected); + mFormatter->realFormat("%.4f"); + expected = "<llsd><real>-34379.0438</real></llsd>\n"; + xml_test("higher precision", expected); + + mFormatter->realFormat("%.0f"); + mSD = 0.0; + expected = "<llsd><real>0</real></llsd>\n"; + xml_test("no decimal 0", expected); + mSD = 3287.4387; + expected = "<llsd><real>3287</real></llsd>\n"; + xml_test("no decimal real number", expected); + } + + template<> template<> + void sd_xml_object::test<4>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyArray(); + expected = "<llsd><array /></llsd>\n"; + xml_test("empty array", expected); + + mSD.append(LLSD()); + expected = "<llsd><array><undef /></array></llsd>\n"; + xml_test("1 element array", expected); + + mSD.append(1); + expected = "<llsd><array><undef /><integer>1</integer></array></llsd>\n"; + xml_test("2 element array", expected); + } + + template<> template<> + void sd_xml_object::test<5>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyMap(); + expected = "<llsd><map /></llsd>\n"; + xml_test("empty map", expected); + + mSD["foo"] = "bar"; + expected = "<llsd><map><key>foo</key><string>bar</string></map></llsd>\n"; + xml_test("1 element map", expected); + + mSD["baz"] = LLSD(); + expected = "<llsd><map><key>baz</key><undef /><key>foo</key><string>bar</string></map></llsd>\n"; + xml_test("2 element map", expected); + } + + template<> template<> + void sd_xml_object::test<6>() + { + // tests with binary + std::string expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + mSD = string_to_vector("hello"); + expected = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; + xml_test("binary", expected); + + mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + expected = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; + xml_test("binary", expected); + } + + class TestLLSDSerializeData + { + public: + TestLLSDSerializeData(); + ~TestLLSDSerializeData(); + + void doRoundTripTests(const std::string&); + void checkRoundTrip(const std::string&, const LLSD& v); + + void setFormatterParser(LLPointer<LLSDFormatter> formatter, LLPointer<LLSDParser> parser) + { + mFormatter = [formatter](const LLSD& data, std::ostream& str) + { + formatter->format(data, str); + }; + // this lambda must be mutable since otherwise the bound 'parser' + // is assumed to point to a const LLSDParser + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable + { + // reset() call is needed since test code re-uses parser object + parser->reset(); + return (parser->parse(istr, data, max_bytes) > 0); + }; + } + + void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) + { + // why does LLSDSerialize::deserialize() reverse the parse() params?? + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) + { + return parser(data, istr, max_bytes); + }; + } + + FormatterFunction mFormatter; + ParserFunction mParser; + }; + + TestLLSDSerializeData::TestLLSDSerializeData() + { + } + + TestLLSDSerializeData::~TestLLSDSerializeData() + { + } + + void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) + { + std::stringstream stream; + mFormatter(v, stream); + //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; + LLSD w; + mParser(stream, w, stream.str().size()); + + try + { + ensure_equals(msg, w, v); + } + catch (...) + { + std::cerr << "the serialized string was:" << std::endl; + std::cerr << stream.str() << std::endl; + throw; + } + } + + static void fillmap(LLSD& root, U32 width, U32 depth) + { + if(depth == 0) + { + root["foo"] = "bar"; + return; + } + + for(U32 i = 0; i < width; ++i) + { + std::string key = llformat("child %d", i); + root[key] = LLSD::emptyMap(); + fillmap(root[key], width, depth - 1); + } + } + + void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) + { + LLSD v; + checkRoundTrip(msg + " undefined", v); + + v = true; + checkRoundTrip(msg + " true bool", v); + + v = false; + checkRoundTrip(msg + " false bool", v); + + v = 1; + checkRoundTrip(msg + " positive int", v); + + v = 0; + checkRoundTrip(msg + " zero int", v); + + v = -1; + checkRoundTrip(msg + " negative int", v); + + v = 1234.5f; + checkRoundTrip(msg + " positive float", v); + + v = 0.0f; + checkRoundTrip(msg + " zero float", v); + + v = -1234.5f; + checkRoundTrip(msg + " negative float", v); + + // FIXME: need a NaN test + + v = LLUUID::null; + checkRoundTrip(msg + " null uuid", v); + + LLUUID newUUID; + newUUID.generate(); + v = newUUID; + checkRoundTrip(msg + " new uuid", v); + + v = ""; + checkRoundTrip(msg + " empty string", v); + + v = "some string"; + checkRoundTrip(msg + " non-empty string", v); + + v = "Second Life is a 3-D virtual world entirely built and owned by its residents. " "Since opening to the public in 2003, it has grown explosively and today is " "inhabited by nearly 100,000 people from around the globe.\n" @@ -390,437 +390,437 @@ namespace tut "currency exchanges.\n" "\n" "Welcome to Second Life. We look forward to seeing you in-world!\n" - ; - checkRoundTrip(msg + " long string", v); - - static const U32 block_size = 0x000020; - for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) - { - std::ostringstream out; - - for (U32 c = block; c < block + block_size; ++c) - { - if (c <= 0x000001f - && c != 0x000009 - && c != 0x00000a) - { - // see XML standard, sections 2.2 and 4.1 - continue; - } - if (0x00d800 <= c && c <= 0x00dfff) { continue; } - if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } - if ((c & 0x00fffe) == 0x00fffe) { continue; } - // see Unicode standard, section 15.8 - - if (c <= 0x00007f) - { - out << (char)(c & 0x7f); - } - else if (c <= 0x0007ff) - { - out << (char)(0xc0 | ((c >> 6) & 0x1f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else if (c <= 0x00ffff) - { - out << (char)(0xe0 | ((c >> 12) & 0x0f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else - { - out << (char)(0xf0 | ((c >> 18) & 0x07)); - out << (char)(0x80 | ((c >> 12) & 0x3f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - } - - v = out.str(); - - std::ostringstream blockmsg; - blockmsg << msg << " unicode string block 0x" << std::hex << block; - checkRoundTrip(blockmsg.str(), v); - } - - LLDate epoch; - v = epoch; - checkRoundTrip(msg + " epoch date", v); - - LLDate aDay("2002-12-07T05:07:15.00Z"); - v = aDay; - checkRoundTrip(msg + " date", v); - - LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); - v = path; - checkRoundTrip(msg + " url", v); - - const char source[] = "it must be a blue moon again"; - std::vector<U8> data; - // note, includes terminating '\0' - copy(&source[0], &source[sizeof(source)], back_inserter(data)); - - v = data; - checkRoundTrip(msg + " binary", v); - - v = LLSD::emptyMap(); - checkRoundTrip(msg + " empty map", v); - - v = LLSD::emptyMap(); - v["name"] = "luke"; //v.insert("name", "luke"); - v["age"] = 3; //v.insert("age", 3); - checkRoundTrip(msg + " map", v); - - v.clear(); - v["a"]["1"] = true; - v["b"]["0"] = false; - checkRoundTrip(msg + " nested maps", v); - - v = LLSD::emptyArray(); - checkRoundTrip(msg + " empty array", v); - - v = LLSD::emptyArray(); - v.append("ali"); - v.append(28); - checkRoundTrip(msg + " array", v); - - v.clear(); - v[0][0] = true; - v[1][0] = false; - checkRoundTrip(msg + " nested arrays", v); - - v = LLSD::emptyMap(); - fillmap(v, 10, 3); // 10^6 maps - checkRoundTrip(msg + " many nested maps", v); - } - - typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerializeGroup; - typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; - TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); - - template<> template<> - void TestLLSDSerializeObject::test<1>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), - new LLSDNotationParser()); - doRoundTripTests("pretty binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<2>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - doRoundTripTests("raw binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<3>() - { - setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); - doRoundTripTests("xml serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<4>() - { - setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); - doRoundTripTests("binary serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<5>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_BINARY)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<6>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_XML)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<7>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); - }; - setParser(LLSDSerialize::deserialize); - // In this test, serialize(LLSD_NOTATION) emits a header recognized by - // deserialize(). - doRoundTripTests("serialize(LLSD_NOTATION)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<8>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDNotationFormatter does not - // emit an llsd/notation header. - doRoundTripTests("LLSDNotationFormatter -> deserialize"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<9>() - { - setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDXMLParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDXMLFormatter does not - // emit an LLSD/XML header. - doRoundTripTests("LLSDXMLFormatter -> deserialize"); - }; + ; + checkRoundTrip(msg + " long string", v); + + static const U32 block_size = 0x000020; + for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) + { + std::ostringstream out; + + for (U32 c = block; c < block + block_size; ++c) + { + if (c <= 0x000001f + && c != 0x000009 + && c != 0x00000a) + { + // see XML standard, sections 2.2 and 4.1 + continue; + } + if (0x00d800 <= c && c <= 0x00dfff) { continue; } + if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } + if ((c & 0x00fffe) == 0x00fffe) { continue; } + // see Unicode standard, section 15.8 + + if (c <= 0x00007f) + { + out << (char)(c & 0x7f); + } + else if (c <= 0x0007ff) + { + out << (char)(0xc0 | ((c >> 6) & 0x1f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else if (c <= 0x00ffff) + { + out << (char)(0xe0 | ((c >> 12) & 0x0f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else + { + out << (char)(0xf0 | ((c >> 18) & 0x07)); + out << (char)(0x80 | ((c >> 12) & 0x3f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + } + + v = out.str(); + + std::ostringstream blockmsg; + blockmsg << msg << " unicode string block 0x" << std::hex << block; + checkRoundTrip(blockmsg.str(), v); + } + + LLDate epoch; + v = epoch; + checkRoundTrip(msg + " epoch date", v); + + LLDate aDay("2002-12-07T05:07:15.00Z"); + v = aDay; + checkRoundTrip(msg + " date", v); + + LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); + v = path; + checkRoundTrip(msg + " url", v); + + const char source[] = "it must be a blue moon again"; + std::vector<U8> data; + // note, includes terminating '\0' + copy(&source[0], &source[sizeof(source)], back_inserter(data)); + + v = data; + checkRoundTrip(msg + " binary", v); + + v = LLSD::emptyMap(); + checkRoundTrip(msg + " empty map", v); + + v = LLSD::emptyMap(); + v["name"] = "luke"; //v.insert("name", "luke"); + v["age"] = 3; //v.insert("age", 3); + checkRoundTrip(msg + " map", v); + + v.clear(); + v["a"]["1"] = true; + v["b"]["0"] = false; + checkRoundTrip(msg + " nested maps", v); + + v = LLSD::emptyArray(); + checkRoundTrip(msg + " empty array", v); + + v = LLSD::emptyArray(); + v.append("ali"); + v.append(28); + checkRoundTrip(msg + " array", v); + + v.clear(); + v[0][0] = true; + v[1][0] = false; + checkRoundTrip(msg + " nested arrays", v); + + v = LLSD::emptyMap(); + fillmap(v, 10, 3); // 10^6 maps + checkRoundTrip(msg + " many nested maps", v); + } + + typedef tut::test_group<TestLLSDSerializeData> TestLLSDSerializeGroup; + typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; + TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); + + template<> template<> + void TestLLSDSerializeObject::test<1>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), + new LLSDNotationParser()); + doRoundTripTests("pretty binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<2>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + doRoundTripTests("raw binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<3>() + { + setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); + doRoundTripTests("xml serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<4>() + { + setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); + doRoundTripTests("binary serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<5>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_BINARY)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<6>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_XML)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<7>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); + }; + setParser(LLSDSerialize::deserialize); + // In this test, serialize(LLSD_NOTATION) emits a header recognized by + // deserialize(). + doRoundTripTests("serialize(LLSD_NOTATION)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<8>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDNotationFormatter does not + // emit an llsd/notation header. + doRoundTripTests("LLSDNotationFormatter -> deserialize"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<9>() + { + setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDXMLParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDXMLFormatter does not + // emit an LLSD/XML header. + doRoundTripTests("LLSDXMLFormatter -> deserialize"); + }; /*==========================================================================*| - // We do not expect this test to succeed. Without a header, neither - // notation LLSD nor binary LLSD reliably start with a distinct character, - // the way XML LLSD starts with '<'. By convention, we default to notation - // rather than binary. - template<> template<> - void TestLLSDSerializeObject::test<10>() - { - setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDBinaryParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDBinaryFormatter does not - // emit an LLSD/Binary header. - doRoundTripTests("LLSDBinaryFormatter -> deserialize"); - }; + // We do not expect this test to succeed. Without a header, neither + // notation LLSD nor binary LLSD reliably start with a distinct character, + // the way XML LLSD starts with '<'. By convention, we default to notation + // rather than binary. + template<> template<> + void TestLLSDSerializeObject::test<10>() + { + setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDBinaryParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDBinaryFormatter does not + // emit an LLSD/Binary header. + doRoundTripTests("LLSDBinaryFormatter -> deserialize"); + }; |*==========================================================================*/ - /** - * @class TestLLSDParsing - * @brief Base class for of a parse tester. - */ - template <class parser_t> - class TestLLSDParsing - { - public: - TestLLSDParsing() - { - mParser = new parser_t; - } - - void ensureParse( - const std::string& msg, - const std::string& in, - const LLSD& expected_value, - S32 expected_count, - S32 depth_limit = -1) - { - std::stringstream input; - input.str(in); - - LLSD parsed_result; - mParser->reset(); // reset() call is needed since test code re-uses mParser - S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); - ensure_equals(msg.c_str(), parsed_result, expected_value); - - // This count check is really only useful for expected - // parse failures, since the ensures equal will already - // require equality. - std::string count_msg(msg); - count_msg += " (count)"; - ensure_equals(count_msg, parsed_count, expected_count); - } - - LLPointer<parser_t> mParser; - }; - - - /** - * @class TestLLSDXMLParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDXMLParsing : public TestLLSDParsing<LLSDXMLParser> - { - public: - TestLLSDXMLParsing() {} - }; - - typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup; - typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; - TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); - - template<> template<> - void TestLLSDXMLParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed xml", - "<llsd><string>ha ha</string>", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "not llsd", - "<html><body><p>ha ha</p></body></html>", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "value without llsd", - "<string>ha ha</string>", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "key without llsd", - "<key>ha ha</key>", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - - template<> template<> - void TestLLSDXMLParsingObject::test<2>() - { - // test handling of unrecognized or unparseable llsd values - LLSD v; - v["amy"] = 23; - v["bob"] = LLSD(); - v["cam"] = 1.23; - - ensureParse( - "unknown data type", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<key>bob</key><bigint>99999999999999999</bigint>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<3>() - { - // test handling of nested bad data - - LLSD v; - v["amy"] = 23; - v["cam"] = 1.23; - - ensureParse( - "map with html", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<html><body>ha ha</body></html>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["cam"] = 1.23; - ensureParse( - "map with value for key", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<string>ha ha</string>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["bob"] = LLSD::emptyMap(); - v["cam"] = 1.23; - ensureParse( - "map with map of html", - "<llsd><map>" - "<key>amy</key><integer>23</integer>" - "<key>bob</key>" - "<map>" - "<html><body>ha ha</body></html>" - "</map>" - "<key>cam</key><real>1.23</real>" - "</map></llsd>", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD(); - v[2] = 1.23; - - ensureParse( - "array value of html", - "<llsd><array>" - "<integer>23</integer>" - "<html><body>ha ha</body></html>" - "<real>1.23</real>" - "</array></llsd>", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD::emptyMap(); - v[2] = 1.23; - ensureParse( - "array with map of html", - "<llsd><array>" - "<integer>23</integer>" - "<map>" - "<html><body>ha ha</body></html>" - "</map>" - "<real>1.23</real>" - "</array></llsd>", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<4>() - { - // test handling of binary object in XML - std::string xml; - LLSD expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - expected = string_to_vector("hello"); - xml = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; - ensureParse( - "the word 'hello' packed in binary encoded base64", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; - xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; - xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; - xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; - xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - } + /** + * @class TestLLSDParsing + * @brief Base class for of a parse tester. + */ + template <class parser_t> + class TestLLSDParsing + { + public: + TestLLSDParsing() + { + mParser = new parser_t; + } + + void ensureParse( + const std::string& msg, + const std::string& in, + const LLSD& expected_value, + S32 expected_count, + S32 depth_limit = -1) + { + std::stringstream input; + input.str(in); + + LLSD parsed_result; + mParser->reset(); // reset() call is needed since test code re-uses mParser + S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); + ensure_equals(msg.c_str(), parsed_result, expected_value); + + // This count check is really only useful for expected + // parse failures, since the ensures equal will already + // require equality. + std::string count_msg(msg); + count_msg += " (count)"; + ensure_equals(count_msg, parsed_count, expected_count); + } + + LLPointer<parser_t> mParser; + }; + + + /** + * @class TestLLSDXMLParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDXMLParsing : public TestLLSDParsing<LLSDXMLParser> + { + public: + TestLLSDXMLParsing() {} + }; + + typedef tut::test_group<TestLLSDXMLParsing> TestLLSDXMLParsingGroup; + typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; + TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); + + template<> template<> + void TestLLSDXMLParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed xml", + "<llsd><string>ha ha</string>", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "not llsd", + "<html><body><p>ha ha</p></body></html>", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "value without llsd", + "<string>ha ha</string>", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "key without llsd", + "<key>ha ha</key>", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + + template<> template<> + void TestLLSDXMLParsingObject::test<2>() + { + // test handling of unrecognized or unparseable llsd values + LLSD v; + v["amy"] = 23; + v["bob"] = LLSD(); + v["cam"] = 1.23; + + ensureParse( + "unknown data type", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<key>bob</key><bigint>99999999999999999</bigint>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<3>() + { + // test handling of nested bad data + + LLSD v; + v["amy"] = 23; + v["cam"] = 1.23; + + ensureParse( + "map with html", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<html><body>ha ha</body></html>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["cam"] = 1.23; + ensureParse( + "map with value for key", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<string>ha ha</string>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["bob"] = LLSD::emptyMap(); + v["cam"] = 1.23; + ensureParse( + "map with map of html", + "<llsd><map>" + "<key>amy</key><integer>23</integer>" + "<key>bob</key>" + "<map>" + "<html><body>ha ha</body></html>" + "</map>" + "<key>cam</key><real>1.23</real>" + "</map></llsd>", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD(); + v[2] = 1.23; + + ensureParse( + "array value of html", + "<llsd><array>" + "<integer>23</integer>" + "<html><body>ha ha</body></html>" + "<real>1.23</real>" + "</array></llsd>", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD::emptyMap(); + v[2] = 1.23; + ensureParse( + "array with map of html", + "<llsd><array>" + "<integer>23</integer>" + "<map>" + "<html><body>ha ha</body></html>" + "</map>" + "<real>1.23</real>" + "</array></llsd>", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<4>() + { + // test handling of binary object in XML + std::string xml; + LLSD expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + expected = string_to_vector("hello"); + xml = "<llsd><binary encoding=\"base64\">aGVsbG8=</binary></llsd>\n"; + ensureParse( + "the word 'hello' packed in binary encoded base64", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "<llsd><binary encoding=\"base64\">Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; + xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; + xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; + xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; + xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==</binary></llsd>\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + } template<> template<> void TestLLSDXMLParsingObject::test<5>() @@ -858,272 +858,272 @@ namespace tut } - /* - TODO: - test XML parsing - binary with unrecognized encoding - nested LLSD tags - multiple values inside an LLSD - */ - - - /** - * @class TestLLSDNotationParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDNotationParsing : public TestLLSDParsing<LLSDNotationParser> - { - public: - TestLLSDNotationParsing() {} - }; - - typedef tut::test_group<TestLLSDNotationParsing> TestLLSDNotationParsingGroup; - typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; - TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( - "llsd notation parsing"); - - template<> template<> - void TestLLSDNotationParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed notation map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad notation noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<2>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<3>() - { - LLSD val = false; - ensureParse("valid boolean false 0", "false", val, 1); - ensureParse("valid boolean false 1", "f", val, 1); - ensureParse("valid boolean false 2", "0", val, 1); - ensureParse("valid boolean false 3", "F", val, 1); - ensureParse("valid boolean false 4", "FALSE", val, 1); - val = true; - ensureParse("valid boolean true 0", "true", val, 1); - ensureParse("valid boolean true 1", "t", val, 1); - ensureParse("valid boolean true 2", "1", val, 1); - ensureParse("valid boolean true 3", "T", val, 1); - ensureParse("valid boolean true 4", "TRUE", val, 1); - - val.clear(); - ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<4>() - { - LLSD val = 123; - ensureParse("valid integer", "i123", val, 1); - val.clear(); - ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<5>() - { - LLSD val = 456.7; - ensureParse("valid real", "r456.7", val, 1); - val.clear(); - ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<6>() - { - LLUUID id; - LLSD val = id; - ensureParse( - "unparseable uuid", - "u123", - LLSD(), - LLSDParser::PARSE_FAILURE); - id.generate(); - val = id; - std::string uuid_str("u"); - uuid_str += id.asString(); - ensureParse("valid uuid", uuid_str.c_str(), val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<7>() - { - LLSD val = std::string("foolish"); - ensureParse("valid string 1", "\"foolish\"", val, 1); - val = std::string("g'day"); - ensureParse("valid string 2", "\"g'day\"", val, 1); - val = std::string("have a \"nice\" day"); - ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); - val = std::string("whatever"); - ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<8>() - { - ensureParse( - "invalid string 1", - "s(7)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid string 2", - "s(9)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<9>() - { - LLSD val = LLURI("http://www.google.com"); - ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<10>() - { - LLSD val = LLDate("2007-12-28T09:22:53.10Z"); - ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<11>() - { - std::vector<U8> vec; - vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); - vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); - LLSD val = vec; - ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); - ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); - ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<12>() - { - ensureParse( - "invalid -- binary length specified too long", - "b(7)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid -- binary length specified way too long", - "b(1000000)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<13>() - { - LLSD val; - val["amy"] = 23; - val["bob"] = LLSD(); - val["cam"] = 1.23; - ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); - - val["bob"] = LLSD::emptyMap(); - val["bob"]["vehicle"] = std::string("bicycle"); - ensureParse( - "nested map", - "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", - val, - 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<14>() - { - LLSD val; - val.append(23); - val.append(LLSD()); - val.append(1.23); - ensureParse("simple array", "[i23,!,r1.23]", val, 4); - val[1] = LLSD::emptyArray(); - val[1].append("bicycle"); - ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<15>() - { - LLSD val; - val["amy"] = 23; - val["bob"]["dogs"] = LLSD::emptyArray(); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][0]["name"] = std::string("groove"); - val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][1]["name"] = std::string("greyley"); - val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); - val["cam"] = 1.23; - ensureParse( - "nested notation", - "{'amy':i23," - " 'bob':{'dogs':[" - "{'name':'groove', 'breed':'samoyed'}," - "{'name':'greyley', 'breed':'chow/husky'}]}," - " 'cam':r1.23}", - val, - 11); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<16>() - { - // text to make sure that incorrect sizes bail because - std::string bad_str("s(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_str, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<17>() - { - // text to make sure that incorrect sizes bail because - std::string bad_bin("b(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_bin, - LLSD(), - LLSDParser::PARSE_FAILURE); - } + /* + TODO: + test XML parsing + binary with unrecognized encoding + nested LLSD tags + multiple values inside an LLSD + */ + + + /** + * @class TestLLSDNotationParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDNotationParsing : public TestLLSDParsing<LLSDNotationParser> + { + public: + TestLLSDNotationParsing() {} + }; + + typedef tut::test_group<TestLLSDNotationParsing> TestLLSDNotationParsingGroup; + typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; + TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( + "llsd notation parsing"); + + template<> template<> + void TestLLSDNotationParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed notation map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad notation noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<2>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<3>() + { + LLSD val = false; + ensureParse("valid boolean false 0", "false", val, 1); + ensureParse("valid boolean false 1", "f", val, 1); + ensureParse("valid boolean false 2", "0", val, 1); + ensureParse("valid boolean false 3", "F", val, 1); + ensureParse("valid boolean false 4", "FALSE", val, 1); + val = true; + ensureParse("valid boolean true 0", "true", val, 1); + ensureParse("valid boolean true 1", "t", val, 1); + ensureParse("valid boolean true 2", "1", val, 1); + ensureParse("valid boolean true 3", "T", val, 1); + ensureParse("valid boolean true 4", "TRUE", val, 1); + + val.clear(); + ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<4>() + { + LLSD val = 123; + ensureParse("valid integer", "i123", val, 1); + val.clear(); + ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<5>() + { + LLSD val = 456.7; + ensureParse("valid real", "r456.7", val, 1); + val.clear(); + ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<6>() + { + LLUUID id; + LLSD val = id; + ensureParse( + "unparseable uuid", + "u123", + LLSD(), + LLSDParser::PARSE_FAILURE); + id.generate(); + val = id; + std::string uuid_str("u"); + uuid_str += id.asString(); + ensureParse("valid uuid", uuid_str.c_str(), val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<7>() + { + LLSD val = std::string("foolish"); + ensureParse("valid string 1", "\"foolish\"", val, 1); + val = std::string("g'day"); + ensureParse("valid string 2", "\"g'day\"", val, 1); + val = std::string("have a \"nice\" day"); + ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); + val = std::string("whatever"); + ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<8>() + { + ensureParse( + "invalid string 1", + "s(7)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid string 2", + "s(9)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<9>() + { + LLSD val = LLURI("http://www.google.com"); + ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<10>() + { + LLSD val = LLDate("2007-12-28T09:22:53.10Z"); + ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<11>() + { + std::vector<U8> vec; + vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); + vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); + LLSD val = vec; + ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); + ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); + ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<12>() + { + ensureParse( + "invalid -- binary length specified too long", + "b(7)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid -- binary length specified way too long", + "b(1000000)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<13>() + { + LLSD val; + val["amy"] = 23; + val["bob"] = LLSD(); + val["cam"] = 1.23; + ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); + + val["bob"] = LLSD::emptyMap(); + val["bob"]["vehicle"] = std::string("bicycle"); + ensureParse( + "nested map", + "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", + val, + 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<14>() + { + LLSD val; + val.append(23); + val.append(LLSD()); + val.append(1.23); + ensureParse("simple array", "[i23,!,r1.23]", val, 4); + val[1] = LLSD::emptyArray(); + val[1].append("bicycle"); + ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<15>() + { + LLSD val; + val["amy"] = 23; + val["bob"]["dogs"] = LLSD::emptyArray(); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][0]["name"] = std::string("groove"); + val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][1]["name"] = std::string("greyley"); + val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); + val["cam"] = 1.23; + ensureParse( + "nested notation", + "{'amy':i23," + " 'bob':{'dogs':[" + "{'name':'groove', 'breed':'samoyed'}," + "{'name':'greyley', 'breed':'chow/husky'}]}," + " 'cam':r1.23}", + val, + 11); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<16>() + { + // text to make sure that incorrect sizes bail because + std::string bad_str("s(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_str, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<17>() + { + // text to make sure that incorrect sizes bail because + std::string bad_bin("b(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_bin, + LLSD(), + LLSDParser::PARSE_FAILURE); + } template<> template<> void TestLLSDNotationParsingObject::test<18>() { - LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; - LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; + LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; + LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; LLSD deep = LLSD::emptyMap(); deep["level_0"] = level_0; @@ -1168,7 +1168,7 @@ namespace tut template<> template<> void TestLLSDNotationParsingObject::test<20>() { - LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; + LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; LLSD level_49 = LLSD::emptyMap(); level_49["level_49"] = end; LLSD level_48 = LLSD::emptyMap(); level_48["level_48"] = level_49; @@ -1259,536 +1259,536 @@ namespace tut 9); } - /** - * @class TestLLSDBinaryParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDBinaryParsing : public TestLLSDParsing<LLSDBinaryParser> - { - public: - TestLLSDBinaryParsing() {} - }; - - typedef tut::test_group<TestLLSDBinaryParsing> TestLLSDBinaryParsingGroup; - typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; - TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( - "llsd binary parsing"); - - template<> template<> - void TestLLSDBinaryParsingObject::test<1>() - { - std::vector<U8> vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - std::string string_expected((char*)&vec[0], vec.size()); - LLSD value = string_expected; - - vec.resize(11); - vec[0] = 's'; // for string - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct string parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<2>() - { - std::vector<U8> vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - LLSD value = vec; - - vec.resize(11); - vec[0] = 'b'; // for binary - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct binary parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 1", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 2", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<3>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed binary map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - template<> template<> - void TestLLSDBinaryParsingObject::test<4>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<5>() - { - LLSD val = false; - ensureParse("valid boolean false 2", "0", val, 1); - val = true; - ensureParse("valid boolean true 2", "1", val, 1); - - val.clear(); - ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<6>() - { - std::vector<U8> vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('k'); - int key_size_loc = vec.size(); - size = htonl(1); // 1 too short - vec.resize(vec.size() + 4); - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); - vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid key size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing '}') - size = htonl(3); // correct size - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "valid key size, unterminated map", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val["amy"] = 23; - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid map", - str_good, - val, - 2); - - // check w/ incorrect sizes and correct map termination - size = htonl(0); // 1 too few (for the map entry) - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too long", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(2); // 1 too many - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_4((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too short", - str_bad_4, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<7>() - { - std::vector<U8> vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); // 1 too short - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); - vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid array size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing ']') - size = htonl(2); // correct size - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "unterminated array", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val.append("amy"); - val.append(23); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid array", - str_good, - val, - 3); - - // check with too many elements - size = htonl(3); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "array too short", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<8>() - { - std::vector<U8> vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyMap(); - ensureParse( - "empty map", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<9>() - { - std::vector<U8> vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyArray(); - ensureParse( - "empty array", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<10>() - { - std::vector<U8> vec; - vec.push_back('l'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(14); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); - vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); - vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); - vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); - vec.push_back('m'); - std::string str_bad((char*)&vec[0], vec.size()); - ensureParse( - "invalid uri length size", - str_bad, - LLSD(), - LLSDParser::PARSE_FAILURE); - - LLSD val; - val = LLURI("http://sl.com"); - size = htonl(13); // correct length - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid key size", - str_good, - val, - 1); - } + /** + * @class TestLLSDBinaryParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDBinaryParsing : public TestLLSDParsing<LLSDBinaryParser> + { + public: + TestLLSDBinaryParsing() {} + }; + + typedef tut::test_group<TestLLSDBinaryParsing> TestLLSDBinaryParsingGroup; + typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; + TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( + "llsd binary parsing"); + + template<> template<> + void TestLLSDBinaryParsingObject::test<1>() + { + std::vector<U8> vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + std::string string_expected((char*)&vec[0], vec.size()); + LLSD value = string_expected; + + vec.resize(11); + vec[0] = 's'; // for string + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct string parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<2>() + { + std::vector<U8> vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + LLSD value = vec; + + vec.resize(11); + vec[0] = 'b'; // for binary + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct binary parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 1", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 2", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<3>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed binary map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + template<> template<> + void TestLLSDBinaryParsingObject::test<4>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<5>() + { + LLSD val = false; + ensureParse("valid boolean false 2", "0", val, 1); + val = true; + ensureParse("valid boolean true 2", "1", val, 1); + + val.clear(); + ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<6>() + { + std::vector<U8> vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('k'); + int key_size_loc = vec.size(); + size = htonl(1); // 1 too short + vec.resize(vec.size() + 4); + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); + vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid key size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing '}') + size = htonl(3); // correct size + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "valid key size, unterminated map", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val["amy"] = 23; + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid map", + str_good, + val, + 2); + + // check w/ incorrect sizes and correct map termination + size = htonl(0); // 1 too few (for the map entry) + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too long", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(2); // 1 too many + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_4((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too short", + str_bad_4, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<7>() + { + std::vector<U8> vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); // 1 too short + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); + vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid array size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing ']') + size = htonl(2); // correct size + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "unterminated array", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val.append("amy"); + val.append(23); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid array", + str_good, + val, + 3); + + // check with too many elements + size = htonl(3); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "array too short", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<8>() + { + std::vector<U8> vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyMap(); + ensureParse( + "empty map", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<9>() + { + std::vector<U8> vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyArray(); + ensureParse( + "empty array", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<10>() + { + std::vector<U8> vec; + vec.push_back('l'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(14); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); + vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); + vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); + vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); + vec.push_back('m'); + std::string str_bad((char*)&vec[0], vec.size()); + ensureParse( + "invalid uri length size", + str_bad, + LLSD(), + LLSDParser::PARSE_FAILURE); + + LLSD val; + val = LLURI("http://sl.com"); + size = htonl(13); // correct length + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid key size", + str_good, + val, + 1); + } /* - template<> template<> - void TestLLSDBinaryParsingObject::test<11>() - { - } + template<> template<> + void TestLLSDBinaryParsingObject::test<11>() + { + } */ /** - * @class TestLLSDCrossCompatible - * @brief Miscellaneous serialization and parsing tests - */ - class TestLLSDCrossCompatible - { - public: - TestLLSDCrossCompatible() {} - - void ensureBinaryAndNotation( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation binary count", - count2, - count1); - - // to notation and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndNotation notation count1", - count3, - count2); - LLSD actual_value_notation; - S32 count4 = LLSDSerialize::fromNotation( - actual_value_notation, - str2, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation notation count2", - count4, - count3); - ensure_equals( - (msg + " (binaryandnotation)").c_str(), - actual_value_notation, - input); - } - - void ensureBinaryAndXML( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndXML binary count", - count2, - count1); - - // to xml and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndXML xml count1", - count3, - count2); - LLSD actual_value_xml; - S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); - ensure_equals( - "ensureBinaryAndXML xml count2", - count4, - count3); - ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); - } - }; - - typedef tut::test_group<TestLLSDCrossCompatible> TestLLSDCompatibleGroup; - typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; - TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( - "llsd serialize compatible"); - - template<> template<> - void TestLLSDCompatibleObject::test<1>() - { - LLSD test; - ensureBinaryAndNotation("undef", test); - ensureBinaryAndXML("undef", test); - test = true; - ensureBinaryAndNotation("boolean true", test); - ensureBinaryAndXML("boolean true", test); - test = false; - ensureBinaryAndNotation("boolean false", test); - ensureBinaryAndXML("boolean false", test); - test = 0; - ensureBinaryAndNotation("integer zero", test); - ensureBinaryAndXML("integer zero", test); - test = 1; - ensureBinaryAndNotation("integer positive", test); - ensureBinaryAndXML("integer positive", test); - test = -234567; - ensureBinaryAndNotation("integer negative", test); - ensureBinaryAndXML("integer negative", test); - test = 0.0; - ensureBinaryAndNotation("real zero", test); - ensureBinaryAndXML("real zero", test); - test = 1.0; - ensureBinaryAndNotation("real positive", test); - ensureBinaryAndXML("real positive", test); - test = -1.0; - ensureBinaryAndNotation("real negative", test); - ensureBinaryAndXML("real negative", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<2>() - { - LLSD test; - test = "foobar"; - ensureBinaryAndNotation("string", test); - ensureBinaryAndXML("string", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<3>() - { - LLSD test; - LLUUID id; - id.generate(); - test = id; - ensureBinaryAndNotation("uuid", test); - ensureBinaryAndXML("uuid", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<4>() - { - LLSD test; - test = LLDate(12345.0); - ensureBinaryAndNotation("date", test); - ensureBinaryAndXML("date", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<5>() - { - LLSD test; - test = LLURI("http://www.secondlife.com/"); - ensureBinaryAndNotation("uri", test); - ensureBinaryAndXML("uri", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<6>() - { - LLSD test; - typedef std::vector<U8> buf_t; - buf_t val; - for(int ii = 0; ii < 100; ++ii) - { - srand(ii); /* Flawfinder: ignore */ - S32 size = rand() % 100 + 10; - std::generate_n( - std::back_insert_iterator<buf_t>(val), - size, - rand); - } - test = val; - ensureBinaryAndNotation("binary", test); - ensureBinaryAndXML("binary", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<7>() - { - LLSD test; - test = LLSD::emptyArray(); - test.append(1); - test.append("hello"); - ensureBinaryAndNotation("array", test); - ensureBinaryAndXML("array", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<8>() - { - LLSD test; - test = LLSD::emptyArray(); - test["foo"] = "bar"; - test["baz"] = 100; - ensureBinaryAndNotation("map", test); - ensureBinaryAndXML("map", test); - } + * @class TestLLSDCrossCompatible + * @brief Miscellaneous serialization and parsing tests + */ + class TestLLSDCrossCompatible + { + public: + TestLLSDCrossCompatible() {} + + void ensureBinaryAndNotation( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation binary count", + count2, + count1); + + // to notation and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndNotation notation count1", + count3, + count2); + LLSD actual_value_notation; + S32 count4 = LLSDSerialize::fromNotation( + actual_value_notation, + str2, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation notation count2", + count4, + count3); + ensure_equals( + (msg + " (binaryandnotation)").c_str(), + actual_value_notation, + input); + } + + void ensureBinaryAndXML( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndXML binary count", + count2, + count1); + + // to xml and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndXML xml count1", + count3, + count2); + LLSD actual_value_xml; + S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); + ensure_equals( + "ensureBinaryAndXML xml count2", + count4, + count3); + ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); + } + }; + + typedef tut::test_group<TestLLSDCrossCompatible> TestLLSDCompatibleGroup; + typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; + TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( + "llsd serialize compatible"); + + template<> template<> + void TestLLSDCompatibleObject::test<1>() + { + LLSD test; + ensureBinaryAndNotation("undef", test); + ensureBinaryAndXML("undef", test); + test = true; + ensureBinaryAndNotation("boolean true", test); + ensureBinaryAndXML("boolean true", test); + test = false; + ensureBinaryAndNotation("boolean false", test); + ensureBinaryAndXML("boolean false", test); + test = 0; + ensureBinaryAndNotation("integer zero", test); + ensureBinaryAndXML("integer zero", test); + test = 1; + ensureBinaryAndNotation("integer positive", test); + ensureBinaryAndXML("integer positive", test); + test = -234567; + ensureBinaryAndNotation("integer negative", test); + ensureBinaryAndXML("integer negative", test); + test = 0.0; + ensureBinaryAndNotation("real zero", test); + ensureBinaryAndXML("real zero", test); + test = 1.0; + ensureBinaryAndNotation("real positive", test); + ensureBinaryAndXML("real positive", test); + test = -1.0; + ensureBinaryAndNotation("real negative", test); + ensureBinaryAndXML("real negative", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<2>() + { + LLSD test; + test = "foobar"; + ensureBinaryAndNotation("string", test); + ensureBinaryAndXML("string", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<3>() + { + LLSD test; + LLUUID id; + id.generate(); + test = id; + ensureBinaryAndNotation("uuid", test); + ensureBinaryAndXML("uuid", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<4>() + { + LLSD test; + test = LLDate(12345.0); + ensureBinaryAndNotation("date", test); + ensureBinaryAndXML("date", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<5>() + { + LLSD test; + test = LLURI("http://www.secondlife.com/"); + ensureBinaryAndNotation("uri", test); + ensureBinaryAndXML("uri", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<6>() + { + LLSD test; + typedef std::vector<U8> buf_t; + buf_t val; + for(int ii = 0; ii < 100; ++ii) + { + srand(ii); /* Flawfinder: ignore */ + S32 size = rand() % 100 + 10; + std::generate_n( + std::back_insert_iterator<buf_t>(val), + size, + rand); + } + test = val; + ensureBinaryAndNotation("binary", test); + ensureBinaryAndXML("binary", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<7>() + { + LLSD test; + test = LLSD::emptyArray(); + test.append(1); + test.append("hello"); + ensureBinaryAndNotation("array", test); + ensureBinaryAndXML("array", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<8>() + { + LLSD test; + test = LLSD::emptyArray(); + test["foo"] = "bar"; + test["baz"] = 100; + ensureBinaryAndNotation("map", test); + ensureBinaryAndXML("map", test); + } // helper for TestPythonCompatible static std::string import_llsd("import os.path\n" @@ -2130,7 +2130,7 @@ namespace tut item.asReal(), 3.14, 7); // 7 bits ~= 0.01 ensure("Failed to read LLSD::String from Python", itemFromStream(inf, item, parse)); - ensure_equals(item.asString(), + ensure_equals(item.asString(), "This string\n" "has several\n" "lines."); diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 6f8aaaa0cb..adf5804272 100644 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsingleton_test.cpp * @date 2011-08-11 * @brief Unit test for the LLSingleton class diff --git a/indra/llcommon/tests/llstreamqueue_test.cpp b/indra/llcommon/tests/llstreamqueue_test.cpp index 8af057328b..82b451119e 100644 --- a/indra/llcommon/tests/llstreamqueue_test.cpp +++ b/indra/llcommon/tests/llstreamqueue_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-01-05 * @brief Test for llstreamqueue. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp index a7aa347222..3fadfa5334 100644 --- a/indra/llcommon/tests/llstring_test.cpp +++ b/indra/llcommon/tests/llstring_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llstring_test.cpp * @author Adroit, Steve Linden, Tofu Linden * @date 2006-12-24 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,835 +37,835 @@ using boost::assign::list_of; namespace tut { - struct string_index - { - }; - typedef test_group<string_index> string_index_t; - typedef string_index_t::object string_index_object_t; - tut::string_index_t tut_string_index("LLString"); - - template<> template<> - void string_index_object_t::test<1>() - { - std::string llstr1; - ensure("Empty std::string", (llstr1.size() == 0) && llstr1.empty()); - - std::string llstr2("Hello"); - ensure("std::string = Hello", (!strcmp(llstr2.c_str(), "Hello")) && (llstr2.size() == 5) && !llstr2.empty()); - - std::string llstr3(llstr2); - ensure("std::string = std::string(std::string)", (!strcmp(llstr3.c_str(), "Hello")) && (llstr3.size() == 5) && !llstr3.empty()); - - std::string str("Hello World"); - std::string llstr4(str, 6); - ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (!strcmp(llstr4.c_str(), "World")) && (llstr4.size() == 5) && !llstr4.empty()); - - std::string llstr5(str, str.size()); - ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (llstr5.size() == 0) && llstr5.empty()); - - std::string llstr6(5, 'A'); - ensure("std::string = std::string(count, c)", (!strcmp(llstr6.c_str(), "AAAAA")) && (llstr6.size() == 5) && !llstr6.empty()); - - std::string llstr7("Hello World", 5); - ensure("std::string(s, n)", (!strcmp(llstr7.c_str(), "Hello")) && (llstr7.size() == 5) && !llstr7.empty()); - - std::string llstr8("Hello World", 6, 5); - ensure("std::string(s, n, count)", (!strcmp(llstr8.c_str(), "World")) && (llstr8.size() == 5) && !llstr8.empty()); - - std::string llstr9("Hello World", sizeof("Hello World")-1, 5); // go past end - ensure("std::string(s, n, count) goes past end", (llstr9.size() == 0) && llstr9.empty()); - } - - template<> template<> - void string_index_object_t::test<3>() - { - std::string str("Len=5"); - ensure("isValidIndex failed", LLStringUtil::isValidIndex(str, 0) == TRUE && - LLStringUtil::isValidIndex(str, 5) == TRUE && - LLStringUtil::isValidIndex(str, 6) == FALSE); - - std::string str1; - ensure("isValidIndex failed fo rempty string", LLStringUtil::isValidIndex(str1, 0) == FALSE); - } - - template<> template<> - void string_index_object_t::test<4>() - { - std::string str_val(" Testing the extra whitespaces "); - LLStringUtil::trimHead(str_val); - ensure_equals("1: trimHead failed", str_val, "Testing the extra whitespaces "); - - std::string str_val1("\n\t\r\n Testing the extra whitespaces "); - LLStringUtil::trimHead(str_val1); - ensure_equals("2: trimHead failed", str_val1, "Testing the extra whitespaces "); - } - - template<> template<> - void string_index_object_t::test<5>() - { - std::string str_val(" Testing the extra whitespaces "); - LLStringUtil::trimTail(str_val); - ensure_equals("1: trimTail failed", str_val, " Testing the extra whitespaces"); - - std::string str_val1("\n Testing the extra whitespaces \n\t\r\n "); - LLStringUtil::trimTail(str_val1); - ensure_equals("2: trimTail failed", str_val1, "\n Testing the extra whitespaces"); - } - - - template<> template<> - void string_index_object_t::test<6>() - { - std::string str_val(" \t \r Testing the extra \r\n whitespaces \n \t "); - LLStringUtil::trim(str_val); - ensure_equals("1: trim failed", str_val, "Testing the extra \r\n whitespaces"); - } - - template<> template<> - void string_index_object_t::test<7>() - { - std::string str("Second LindenLabs"); - LLStringUtil::truncate(str, 6); - ensure_equals("1: truncate", str, "Second"); - - // further truncate more than the length - LLStringUtil::truncate(str, 0); - ensure_equals("2: truncate", str, ""); - } - - template<> template<> - void string_index_object_t::test<8>() - { - std::string str_val("SecondLife Source"); - LLStringUtil::toUpper(str_val); - ensure_equals("toUpper failed", str_val, "SECONDLIFE SOURCE"); - } - - template<> template<> - void string_index_object_t::test<9>() - { - std::string str_val("SecondLife Source"); - LLStringUtil::toLower(str_val); - ensure_equals("toLower failed", str_val, "secondlife source"); - } - - template<> template<> - void string_index_object_t::test<10>() - { - std::string str_val("Second"); - ensure("1. isHead failed", LLStringUtil::isHead(str_val, "SecondLife Source") == TRUE); - ensure("2. isHead failed", LLStringUtil::isHead(str_val, " SecondLife Source") == FALSE); - std::string str_val2(""); - ensure("3. isHead failed", LLStringUtil::isHead(str_val2, "") == FALSE); - } - - template<> template<> - void string_index_object_t::test<11>() - { - std::string str_val("Hello.\n\n Lindenlabs. \n This is \na simple test.\n"); - std::string orig_str_val(str_val); - LLStringUtil::addCRLF(str_val); - ensure_equals("addCRLF failed", str_val, "Hello.\r\n\r\n Lindenlabs. \r\n This is \r\na simple test.\r\n"); - LLStringUtil::removeCRLF(str_val); - ensure_equals("removeCRLF failed", str_val, orig_str_val); - } - - template<> template<> - void string_index_object_t::test<12>() - { - std::string str_val("Hello.\n\n\t \t Lindenlabs. \t\t"); - std::string orig_str_val(str_val); - LLStringUtil::replaceTabsWithSpaces(str_val, 1); - ensure_equals("replaceTabsWithSpaces failed", str_val, "Hello.\n\n Lindenlabs. "); - LLStringUtil::replaceTabsWithSpaces(orig_str_val, 0); - ensure_equals("replaceTabsWithSpaces failed for 0", orig_str_val, "Hello.\n\n Lindenlabs. "); - - str_val = "\t\t\t\t"; - LLStringUtil::replaceTabsWithSpaces(str_val, 0); - ensure_equals("replaceTabsWithSpaces failed for all tabs", str_val, ""); - } - - template<> template<> - void string_index_object_t::test<13>() - { - std::string str_val("Hello.\n\n\t\t\r\nLindenlabsX."); - LLStringUtil::replaceNonstandardASCII(str_val, 'X'); - ensure_equals("replaceNonstandardASCII failed", str_val, "Hello.\n\nXXX\nLindenlabsX."); - } - - template<> template<> - void string_index_object_t::test<14>() - { - std::string str_val("Hello.\n\t\r\nABCDEFGHIABABAB"); - LLStringUtil::replaceChar(str_val, 'A', 'X'); - ensure_equals("1: replaceChar failed", str_val, "Hello.\n\t\r\nXBCDEFGHIXBXBXB"); - std::string str_val1("Hello.\n\t\r\nABCDEFGHIABABAB"); - } - - template<> template<> - void string_index_object_t::test<15>() - { - std::string str_val("Hello.\n\r\t"); - ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == TRUE); - - str_val = "ABC "; - ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == FALSE); - } - - template<> template<> - void string_index_object_t::test<16>() - { - std::string str_val("Hello.\n\r\t Again!"); - LLStringUtil::stripNonprintable(str_val); - ensure_equals("stripNonprintable failed", str_val, "Hello. Again!"); - - str_val = "\r\n\t\t"; - LLStringUtil::stripNonprintable(str_val); - ensure_equals("stripNonprintable resulting in empty string failed", str_val, ""); - - str_val = ""; - LLStringUtil::stripNonprintable(str_val); - ensure_equals("stripNonprintable of empty string resulting in empty string failed", str_val, ""); - } - - template<> template<> - void string_index_object_t::test<17>() - { - BOOL value; - std::string str_val("1"); - ensure("convertToBOOL 1 failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "T"; - ensure("convertToBOOL T failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "t"; - ensure("convertToBOOL t failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "TRUE"; - ensure("convertToBOOL TRUE failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "True"; - ensure("convertToBOOL True failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "true"; - ensure("convertToBOOL true failed", LLStringUtil::convertToBOOL(str_val, value) && value); - - str_val = "0"; - ensure("convertToBOOL 0 failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "F"; - ensure("convertToBOOL F failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "f"; - ensure("convertToBOOL f failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "FALSE"; - ensure("convertToBOOL FASLE failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "False"; - ensure("convertToBOOL False failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "false"; - ensure("convertToBOOL false failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - - str_val = "Tblah"; - ensure("convertToBOOL false failed", !LLStringUtil::convertToBOOL(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<18>() - { - U8 value; - std::string str_val("255"); - ensure("1: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 255); - - str_val = "0"; - ensure("2: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 0); - - str_val = "-1"; - ensure("3: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); - - str_val = "256"; // bigger than MAX_U8 - ensure("4: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<19>() - { - S8 value; - std::string str_val("127"); - ensure("1: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 127); - - str_val = "0"; - ensure("2: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 0); - - str_val = "-128"; - ensure("3: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == -128); - - str_val = "128"; // bigger than MAX_S8 - ensure("4: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); - - str_val = "-129"; - ensure("5: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<20>() - { - S16 value; - std::string str_val("32767"); - ensure("1: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 32767); - - str_val = "0"; - ensure("2: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 0); - - str_val = "-32768"; - ensure("3: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == -32768); - - str_val = "32768"; - ensure("4: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); - - str_val = "-32769"; - ensure("5: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<21>() - { - U16 value; - std::string str_val("65535"); //0xFFFF - ensure("1: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 65535); - - str_val = "0"; - ensure("2: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 0); - - str_val = "-1"; - ensure("3: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); - - str_val = "65536"; - ensure("4: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<22>() - { - U32 value; - std::string str_val("4294967295"); //0xFFFFFFFF - ensure("1: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 4294967295UL); - - str_val = "0"; - ensure("2: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 0); - - str_val = "4294967296"; - ensure("3: convertToU32 failed", !LLStringUtil::convertToU32(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<23>() - { - S32 value; - std::string str_val("2147483647"); //0x7FFFFFFF - ensure("1: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 2147483647); - - str_val = "0"; - ensure("2: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 0); - - // Avoid "unary minus operator applied to unsigned type" warning on VC++. JC - S32 min_val = -2147483647 - 1; - str_val = "-2147483648"; - ensure("3: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == min_val); - - str_val = "2147483648"; - ensure("4: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); - - str_val = "-2147483649"; - ensure("5: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<24>() - { - F32 value; - std::string str_val("2147483647"); //0x7FFFFFFF - ensure("1: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 2147483647); - - str_val = "0"; - ensure("2: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 0); - - /* Need to find max/min F32 values - str_val = "-2147483648"; - ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); - - str_val = "2147483648"; - ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - - str_val = "-2147483649"; - ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - */ - } - - template<> template<> - void string_index_object_t::test<25>() - { - F64 value; - std::string str_val("9223372036854775807"); //0x7FFFFFFFFFFFFFFF - ensure("1: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 9223372036854775807LL); - - str_val = "0"; - ensure("2: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 0.0F); - - /* Need to find max/min F64 values - str_val = "-2147483648"; - ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); - - str_val = "2147483648"; - ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - - str_val = "-2147483649"; - ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - */ - } - - template<> template<> - void string_index_object_t::test<26>() - { - const char* str1 = NULL; - const char* str2 = NULL; - - ensure("1: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); - str2 = "A"; - ensure("2: compareStrings failed", LLStringUtil::compareStrings(str1, str2) > 0); - ensure("3: compareStrings failed", LLStringUtil::compareStrings(str2, str1) < 0); - - str1 = "A is smaller than B"; - str2 = "B is greater than A"; - ensure("4: compareStrings failed", LLStringUtil::compareStrings(str1, str2) < 0); - - str2 = "A is smaller than B"; - ensure("5: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); - } - - template<> template<> - void string_index_object_t::test<27>() - { - const char* str1 = NULL; - const char* str2 = NULL; - - ensure("1: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); - str2 = "A"; - ensure("2: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) > 0); - ensure("3: compareInsensitive failed", LLStringUtil::compareInsensitive(str2, str1) < 0); - - str1 = "A is equal to a"; - str2 = "a is EQUAL to A"; - ensure("4: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); - } - - template<> template<> - void string_index_object_t::test<28>() - { - std::string lhs_str("PROgraM12files"); - std::string rhs_str("PROgram12Files"); - ensure("compareDict 1 failed", LLStringUtil::compareDict(lhs_str, rhs_str) < 0); - ensure("precedesDict 1 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == TRUE); - - lhs_str = "PROgram12Files"; - rhs_str = "PROgram12Files"; - ensure("compareDict 2 failed", LLStringUtil::compareDict(lhs_str, rhs_str) == 0); - ensure("precedesDict 2 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); - - lhs_str = "PROgram12Files"; - rhs_str = "PROgRAM12FILES"; - ensure("compareDict 3 failed", LLStringUtil::compareDict(lhs_str, rhs_str) > 0); - ensure("precedesDict 3 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); - } - - template<> template<> - void string_index_object_t::test<29>() - { - char str1[] = "First String..."; - char str2[100]; - - LLStringUtil::copy(str2, str1, 100); - ensure("LLStringUtil::copy with enough dest length failed", strcmp(str2, str1) == 0); - LLStringUtil::copy(str2, str1, sizeof("First")); - ensure("LLStringUtil::copy with less dest length failed", strcmp(str2, "First") == 0); - } - - template<> template<> - void string_index_object_t::test<30>() - { - std::string str1 = "This is the sentence..."; - std::string str2 = "This is the "; - std::string str3 = "first "; - std::string str4 = "This is the first sentence..."; - std::string str5 = "This is the sentence...first "; - std::string dest; - - dest = str1; - LLStringUtil::copyInto(dest, str3, str2.length()); - ensure("LLStringUtil::copyInto insert failed", dest == str4); - - dest = str1; - LLStringUtil::copyInto(dest, str3, dest.length()); - ensure("LLStringUtil::copyInto append failed", dest == str5); - } - - template<> template<> - void string_index_object_t::test<31>() - { - std::string stripped; - - // Plain US ASCII text, including spaces and punctuation, - // should not be altered. - std::string simple_text = "Hello, world!"; - stripped = LLStringFn::strip_invalid_xml(simple_text); - ensure("Simple text passed unchanged", stripped == simple_text); - - // Control characters should be removed - // except for 0x09, 0x0a, 0x0d - std::string control_chars; - for (char c = 0x01; c < 0x20; c++) - { - control_chars.push_back(c); - } - std::string allowed_control_chars; - allowed_control_chars.push_back( (char)0x09 ); - allowed_control_chars.push_back( (char)0x0a ); - allowed_control_chars.push_back( (char)0x0d ); - - stripped = LLStringFn::strip_invalid_xml(control_chars); - ensure("Only tab, LF, CR control characters allowed", - stripped == allowed_control_chars); - - // UTF-8 should be passed intact, including high byte - // characters. Try Francais (with C squiggle cedilla) - std::string french = "Fran"; - french.push_back( (char)0xC3 ); - french.push_back( (char)0xA7 ); - french += "ais"; - stripped = LLStringFn::strip_invalid_xml( french ); - ensure("UTF-8 high byte text is allowed", french == stripped ); - } - - template<> template<> - void string_index_object_t::test<32>() - { - // Test LLStringUtil::format() string interpolation - LLStringUtil::format_map_t fmt_map; - std::string s; - int subcount; - - fmt_map["[TRICK1]"] = "[A]"; - fmt_map["[A]"] = "a"; - fmt_map["[B]"] = "b"; - fmt_map["[AAA]"] = "aaa"; - fmt_map["[BBB]"] = "bbb"; - fmt_map["[TRICK2]"] = "[A]"; - fmt_map["[EXPLOIT]"] = "!!!!!!!!!!!![EXPLOIT]!!!!!!!!!!!!"; - fmt_map["[KEYLONGER]"] = "short"; - fmt_map["[KEYSHORTER]"] = "Am I not a long string?"; - fmt_map["?"] = "?"; - fmt_map["[DELETE]"] = ""; - fmt_map["[]"] = "[]"; // doesn't do a substitution, but shouldn't crash either - - for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) - { - // Test when source string is entirely one key - std::string s1 = (std::string)iter->first; - std::string s2 = (std::string)iter->second; - subcount = LLStringUtil::format(s1, fmt_map); - ensure_equals("LLStringUtil::format: Raw interpolation result", s1, s2); - if (s1 == "?" || s1 == "[]") // no interp expected - { - ensure_equals("LLStringUtil::format: Raw interpolation result count", 0, subcount); - } - else - { - ensure_equals("LLStringUtil::format: Raw interpolation result count", 1, subcount); - } - } - - for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) - { - // Test when source string is one key, duplicated - std::string s1 = (std::string)iter->first; - std::string s2 = (std::string)iter->second; - s = s1 + s1 + s1 + s1; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Rawx4 interpolation result", s, s2 + s2 + s2 + s2); - if (s1 == "?" || s1 == "[]") // no interp expected - { - ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 0, subcount); - } - else - { - ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 4, subcount); - } - } - - // Test when source string has no keys - std::string srcs = "!!!!!!!!!!!!!!!!"; - s = srcs; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: No key test result", s, srcs); - ensure_equals("LLStringUtil::format: No key test result count", 0, subcount); - - // Test when source string has no keys and is empty - std::string srcs3; - s = srcs3; - subcount = LLStringUtil::format(s, fmt_map); - ensure("LLStringUtil::format: No key test3 result", s.empty()); - ensure_equals("LLStringUtil::format: No key test3 result count", 0, subcount); - - // Test a substitution where a key is substituted with blankness - std::string srcs2 = "[DELETE]"; - s = srcs2; - subcount = LLStringUtil::format(s, fmt_map); - ensure("LLStringUtil::format: Delete key test2 result", s.empty()); - ensure_equals("LLStringUtil::format: Delete key test2 result count", 1, subcount); - - // Test an assorted substitution - std::string srcs4 = "[TRICK1][A][B][AAA][BBB][TRICK2][KEYLONGER][KEYSHORTER]?[DELETE]"; - s = srcs4; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test1 result", s, "[A]abaaabbb[A]shortAm I not a long string??"); - ensure_equals("LLStringUtil::format: Assorted Test1 result count", 9, subcount); - - // Test an assorted substitution - std::string srcs5 = "[DELETE]?[KEYSHORTER][KEYLONGER][TRICK2][BBB][AAA][B][A][TRICK1]"; - s = srcs5; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]"); - ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); - - // Test on nested brackets - std::string srcs6 = "[[TRICK1]][[A]][[B]][[AAA]][[BBB]][[TRICK2]][[KEYLONGER]][[KEYSHORTER]]?[[DELETE]]"; - s = srcs6; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "[[A]][a][b][aaa][bbb][[A]][short][Am I not a long string?]?[]"); - ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); - - - // Test an assorted substitution - std::string srcs8 = "foo[DELETE]bar?"; - s = srcs8; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test3 result", s, "foobar?"); - ensure_equals("LLStringUtil::format: Assorted Test3 result count", 1, subcount); - } - - template<> template<> - void string_index_object_t::test<33>() - { - // Test LLStringUtil::format() string interpolation - LLStringUtil::format_map_t blank_fmt_map; - std::string s; - int subcount; - - // Test substituting out of a blank format_map - std::string srcs6 = "12345"; - s = srcs6; - subcount = LLStringUtil::format(s, blank_fmt_map); - ensure_equals("LLStringUtil::format: Blankfmt Test1 result", s, "12345"); - ensure_equals("LLStringUtil::format: Blankfmt Test1 result count", 0, subcount); - - // Test substituting a blank string out of a blank format_map - std::string srcs7; - s = srcs7; - subcount = LLStringUtil::format(s, blank_fmt_map); - ensure("LLStringUtil::format: Blankfmt Test2 result", s.empty()); - ensure_equals("LLStringUtil::format: Blankfmt Test2 result count", 0, subcount); - } - - template<> template<> - void string_index_object_t::test<34>() - { - // Test that incorrect LLStringUtil::format() use does not explode. - LLStringUtil::format_map_t nasty_fmt_map; - std::string s; - int subcount; - - nasty_fmt_map[""] = "never used"; // see, this is nasty. - - // Test substituting out of a nasty format_map - std::string srcs6 = "12345"; - s = srcs6; - subcount = LLStringUtil::format(s, nasty_fmt_map); - ensure_equals("LLStringUtil::format: Nastyfmt Test1 result", s, "12345"); - ensure_equals("LLStringUtil::format: Nastyfmt Test1 result count", 0, subcount); - - // Test substituting a blank string out of a nasty format_map - std::string srcs7; - s = srcs7; - subcount = LLStringUtil::format(s, nasty_fmt_map); - ensure("LLStringUtil::format: Nastyfmt Test2 result", s.empty()); - ensure_equals("LLStringUtil::format: Nastyfmt Test2 result count", 0, subcount); - } - - template<> template<> - void string_index_object_t::test<35>() - { - // Make sure startsWith works - std::string string("anybody in there?"); - std::string substr("anybody"); - ensure("startsWith works.", LLStringUtil::startsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<36>() - { - // Make sure startsWith correctly fails - std::string string("anybody in there?"); - std::string substr("there"); - ensure("startsWith fails.", !LLStringUtil::startsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<37>() - { - // startsWith fails on empty strings - std::string value("anybody in there?"); - std::string empty; - ensure("empty string.", !LLStringUtil::startsWith(value, empty)); - ensure("empty substr.", !LLStringUtil::startsWith(empty, value)); - ensure("empty everything.", !LLStringUtil::startsWith(empty, empty)); - } - - template<> template<> - void string_index_object_t::test<38>() - { - // Make sure endsWith works correctly - std::string string("anybody in there?"); - std::string substr("there?"); - ensure("endsWith works.", LLStringUtil::endsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<39>() - { - // Make sure endsWith correctly fails - std::string string("anybody in there?"); - std::string substr("anybody"); - ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); - substr = "there"; - ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); - substr = "ther?"; - ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<40>() - { - // endsWith fails on empty strings - std::string value("anybody in there?"); - std::string empty; - ensure("empty string.", !LLStringUtil::endsWith(value, empty)); - ensure("empty substr.", !LLStringUtil::endsWith(empty, value)); - ensure("empty everything.", !LLStringUtil::endsWith(empty, empty)); - } - - template<> template<> - void string_index_object_t::test<41>() - { - set_test_name("getTokens(\"delims\")"); - ensure_equals("empty string", LLStringUtil::getTokens("", " "), StringVec()); - ensure_equals("only delims", - LLStringUtil::getTokens(" \r\n ", " \r\n"), StringVec()); - ensure_equals("sequence of delims", - LLStringUtil::getTokens(",,, one ,,,", ","), list_of("one")); - // nat considers this a dubious implementation side effect, but I'd - // hate to change it now... - ensure_equals("noncontiguous tokens", - LLStringUtil::getTokens(", ,, , one ,,,", ","), list_of("")("")("one")); - ensure_equals("space-padded tokens", - LLStringUtil::getTokens(", one , two ,", ","), list_of("one")("two")); - ensure_equals("no delims", LLStringUtil::getTokens("one", ","), list_of("one")); - } - - // Shorthand for verifying that getTokens() behaves the same when you - // don't pass a string of escape characters, when you pass an empty string - // (different overloads), and when you pass a string of characters that - // aren't actually present. - void ensure_getTokens(const std::string& desc, - const std::string& string, - const std::string& drop_delims, - const std::string& keep_delims, - const std::string& quotes, - const std::vector<std::string>& expect) - { - ensure_equals(desc + " - no esc", - LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes), - expect); - ensure_equals(desc + " - empty esc", - LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, ""), - expect); - ensure_equals(desc + " - unused esc", - LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, "!"), - expect); - } - - void ensure_getTokens(const std::string& desc, - const std::string& string, - const std::string& drop_delims, - const std::string& keep_delims, - const std::vector<std::string>& expect) - { - ensure_getTokens(desc, string, drop_delims, keep_delims, "", expect); - } - - template<> template<> - void string_index_object_t::test<42>() - { - set_test_name("getTokens(\"delims\", etc.)"); - // Signatures to test in this method: - // getTokens(string, drop_delims, keep_delims [, quotes [, escapes]]) - // If you omit keep_delims, you get the older function (test above). - - // cases like the getTokens(string, delims) tests above - ensure_getTokens("empty string", "", " ", "", StringVec()); - ensure_getTokens("only delims", - " \r\n ", " \r\n", "", StringVec()); - ensure_getTokens("sequence of delims", - ",,, one ,,,", ", ", "", list_of("one")); - // Note contrast with the case in the previous method - ensure_getTokens("noncontiguous tokens", - ", ,, , one ,,,", ", ", "", list_of("one")); - ensure_getTokens("space-padded tokens", - ", one , two ,", ", ", "", + struct string_index + { + }; + typedef test_group<string_index> string_index_t; + typedef string_index_t::object string_index_object_t; + tut::string_index_t tut_string_index("LLString"); + + template<> template<> + void string_index_object_t::test<1>() + { + std::string llstr1; + ensure("Empty std::string", (llstr1.size() == 0) && llstr1.empty()); + + std::string llstr2("Hello"); + ensure("std::string = Hello", (!strcmp(llstr2.c_str(), "Hello")) && (llstr2.size() == 5) && !llstr2.empty()); + + std::string llstr3(llstr2); + ensure("std::string = std::string(std::string)", (!strcmp(llstr3.c_str(), "Hello")) && (llstr3.size() == 5) && !llstr3.empty()); + + std::string str("Hello World"); + std::string llstr4(str, 6); + ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (!strcmp(llstr4.c_str(), "World")) && (llstr4.size() == 5) && !llstr4.empty()); + + std::string llstr5(str, str.size()); + ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (llstr5.size() == 0) && llstr5.empty()); + + std::string llstr6(5, 'A'); + ensure("std::string = std::string(count, c)", (!strcmp(llstr6.c_str(), "AAAAA")) && (llstr6.size() == 5) && !llstr6.empty()); + + std::string llstr7("Hello World", 5); + ensure("std::string(s, n)", (!strcmp(llstr7.c_str(), "Hello")) && (llstr7.size() == 5) && !llstr7.empty()); + + std::string llstr8("Hello World", 6, 5); + ensure("std::string(s, n, count)", (!strcmp(llstr8.c_str(), "World")) && (llstr8.size() == 5) && !llstr8.empty()); + + std::string llstr9("Hello World", sizeof("Hello World")-1, 5); // go past end + ensure("std::string(s, n, count) goes past end", (llstr9.size() == 0) && llstr9.empty()); + } + + template<> template<> + void string_index_object_t::test<3>() + { + std::string str("Len=5"); + ensure("isValidIndex failed", LLStringUtil::isValidIndex(str, 0) == TRUE && + LLStringUtil::isValidIndex(str, 5) == TRUE && + LLStringUtil::isValidIndex(str, 6) == FALSE); + + std::string str1; + ensure("isValidIndex failed fo rempty string", LLStringUtil::isValidIndex(str1, 0) == FALSE); + } + + template<> template<> + void string_index_object_t::test<4>() + { + std::string str_val(" Testing the extra whitespaces "); + LLStringUtil::trimHead(str_val); + ensure_equals("1: trimHead failed", str_val, "Testing the extra whitespaces "); + + std::string str_val1("\n\t\r\n Testing the extra whitespaces "); + LLStringUtil::trimHead(str_val1); + ensure_equals("2: trimHead failed", str_val1, "Testing the extra whitespaces "); + } + + template<> template<> + void string_index_object_t::test<5>() + { + std::string str_val(" Testing the extra whitespaces "); + LLStringUtil::trimTail(str_val); + ensure_equals("1: trimTail failed", str_val, " Testing the extra whitespaces"); + + std::string str_val1("\n Testing the extra whitespaces \n\t\r\n "); + LLStringUtil::trimTail(str_val1); + ensure_equals("2: trimTail failed", str_val1, "\n Testing the extra whitespaces"); + } + + + template<> template<> + void string_index_object_t::test<6>() + { + std::string str_val(" \t \r Testing the extra \r\n whitespaces \n \t "); + LLStringUtil::trim(str_val); + ensure_equals("1: trim failed", str_val, "Testing the extra \r\n whitespaces"); + } + + template<> template<> + void string_index_object_t::test<7>() + { + std::string str("Second LindenLabs"); + LLStringUtil::truncate(str, 6); + ensure_equals("1: truncate", str, "Second"); + + // further truncate more than the length + LLStringUtil::truncate(str, 0); + ensure_equals("2: truncate", str, ""); + } + + template<> template<> + void string_index_object_t::test<8>() + { + std::string str_val("SecondLife Source"); + LLStringUtil::toUpper(str_val); + ensure_equals("toUpper failed", str_val, "SECONDLIFE SOURCE"); + } + + template<> template<> + void string_index_object_t::test<9>() + { + std::string str_val("SecondLife Source"); + LLStringUtil::toLower(str_val); + ensure_equals("toLower failed", str_val, "secondlife source"); + } + + template<> template<> + void string_index_object_t::test<10>() + { + std::string str_val("Second"); + ensure("1. isHead failed", LLStringUtil::isHead(str_val, "SecondLife Source") == TRUE); + ensure("2. isHead failed", LLStringUtil::isHead(str_val, " SecondLife Source") == FALSE); + std::string str_val2(""); + ensure("3. isHead failed", LLStringUtil::isHead(str_val2, "") == FALSE); + } + + template<> template<> + void string_index_object_t::test<11>() + { + std::string str_val("Hello.\n\n Lindenlabs. \n This is \na simple test.\n"); + std::string orig_str_val(str_val); + LLStringUtil::addCRLF(str_val); + ensure_equals("addCRLF failed", str_val, "Hello.\r\n\r\n Lindenlabs. \r\n This is \r\na simple test.\r\n"); + LLStringUtil::removeCRLF(str_val); + ensure_equals("removeCRLF failed", str_val, orig_str_val); + } + + template<> template<> + void string_index_object_t::test<12>() + { + std::string str_val("Hello.\n\n\t \t Lindenlabs. \t\t"); + std::string orig_str_val(str_val); + LLStringUtil::replaceTabsWithSpaces(str_val, 1); + ensure_equals("replaceTabsWithSpaces failed", str_val, "Hello.\n\n Lindenlabs. "); + LLStringUtil::replaceTabsWithSpaces(orig_str_val, 0); + ensure_equals("replaceTabsWithSpaces failed for 0", orig_str_val, "Hello.\n\n Lindenlabs. "); + + str_val = "\t\t\t\t"; + LLStringUtil::replaceTabsWithSpaces(str_val, 0); + ensure_equals("replaceTabsWithSpaces failed for all tabs", str_val, ""); + } + + template<> template<> + void string_index_object_t::test<13>() + { + std::string str_val("Hello.\n\n\t\t\r\nLindenlabsX."); + LLStringUtil::replaceNonstandardASCII(str_val, 'X'); + ensure_equals("replaceNonstandardASCII failed", str_val, "Hello.\n\nXXX\nLindenlabsX."); + } + + template<> template<> + void string_index_object_t::test<14>() + { + std::string str_val("Hello.\n\t\r\nABCDEFGHIABABAB"); + LLStringUtil::replaceChar(str_val, 'A', 'X'); + ensure_equals("1: replaceChar failed", str_val, "Hello.\n\t\r\nXBCDEFGHIXBXBXB"); + std::string str_val1("Hello.\n\t\r\nABCDEFGHIABABAB"); + } + + template<> template<> + void string_index_object_t::test<15>() + { + std::string str_val("Hello.\n\r\t"); + ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == TRUE); + + str_val = "ABC "; + ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == FALSE); + } + + template<> template<> + void string_index_object_t::test<16>() + { + std::string str_val("Hello.\n\r\t Again!"); + LLStringUtil::stripNonprintable(str_val); + ensure_equals("stripNonprintable failed", str_val, "Hello. Again!"); + + str_val = "\r\n\t\t"; + LLStringUtil::stripNonprintable(str_val); + ensure_equals("stripNonprintable resulting in empty string failed", str_val, ""); + + str_val = ""; + LLStringUtil::stripNonprintable(str_val); + ensure_equals("stripNonprintable of empty string resulting in empty string failed", str_val, ""); + } + + template<> template<> + void string_index_object_t::test<17>() + { + BOOL value; + std::string str_val("1"); + ensure("convertToBOOL 1 failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "T"; + ensure("convertToBOOL T failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "t"; + ensure("convertToBOOL t failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "TRUE"; + ensure("convertToBOOL TRUE failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "True"; + ensure("convertToBOOL True failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "true"; + ensure("convertToBOOL true failed", LLStringUtil::convertToBOOL(str_val, value) && value); + + str_val = "0"; + ensure("convertToBOOL 0 failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "F"; + ensure("convertToBOOL F failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "f"; + ensure("convertToBOOL f failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "FALSE"; + ensure("convertToBOOL FASLE failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "False"; + ensure("convertToBOOL False failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "false"; + ensure("convertToBOOL false failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + + str_val = "Tblah"; + ensure("convertToBOOL false failed", !LLStringUtil::convertToBOOL(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<18>() + { + U8 value; + std::string str_val("255"); + ensure("1: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 255); + + str_val = "0"; + ensure("2: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 0); + + str_val = "-1"; + ensure("3: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); + + str_val = "256"; // bigger than MAX_U8 + ensure("4: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<19>() + { + S8 value; + std::string str_val("127"); + ensure("1: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 127); + + str_val = "0"; + ensure("2: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 0); + + str_val = "-128"; + ensure("3: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == -128); + + str_val = "128"; // bigger than MAX_S8 + ensure("4: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); + + str_val = "-129"; + ensure("5: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<20>() + { + S16 value; + std::string str_val("32767"); + ensure("1: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 32767); + + str_val = "0"; + ensure("2: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 0); + + str_val = "-32768"; + ensure("3: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == -32768); + + str_val = "32768"; + ensure("4: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); + + str_val = "-32769"; + ensure("5: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<21>() + { + U16 value; + std::string str_val("65535"); //0xFFFF + ensure("1: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 65535); + + str_val = "0"; + ensure("2: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 0); + + str_val = "-1"; + ensure("3: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); + + str_val = "65536"; + ensure("4: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<22>() + { + U32 value; + std::string str_val("4294967295"); //0xFFFFFFFF + ensure("1: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 4294967295UL); + + str_val = "0"; + ensure("2: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 0); + + str_val = "4294967296"; + ensure("3: convertToU32 failed", !LLStringUtil::convertToU32(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<23>() + { + S32 value; + std::string str_val("2147483647"); //0x7FFFFFFF + ensure("1: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 2147483647); + + str_val = "0"; + ensure("2: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 0); + + // Avoid "unary minus operator applied to unsigned type" warning on VC++. JC + S32 min_val = -2147483647 - 1; + str_val = "-2147483648"; + ensure("3: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == min_val); + + str_val = "2147483648"; + ensure("4: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); + + str_val = "-2147483649"; + ensure("5: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<24>() + { + F32 value; + std::string str_val("2147483647"); //0x7FFFFFFF + ensure("1: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 2147483647); + + str_val = "0"; + ensure("2: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 0); + + /* Need to find max/min F32 values + str_val = "-2147483648"; + ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); + + str_val = "2147483648"; + ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + + str_val = "-2147483649"; + ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + */ + } + + template<> template<> + void string_index_object_t::test<25>() + { + F64 value; + std::string str_val("9223372036854775807"); //0x7FFFFFFFFFFFFFFF + ensure("1: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 9223372036854775807LL); + + str_val = "0"; + ensure("2: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 0.0F); + + /* Need to find max/min F64 values + str_val = "-2147483648"; + ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); + + str_val = "2147483648"; + ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + + str_val = "-2147483649"; + ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + */ + } + + template<> template<> + void string_index_object_t::test<26>() + { + const char* str1 = NULL; + const char* str2 = NULL; + + ensure("1: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); + str2 = "A"; + ensure("2: compareStrings failed", LLStringUtil::compareStrings(str1, str2) > 0); + ensure("3: compareStrings failed", LLStringUtil::compareStrings(str2, str1) < 0); + + str1 = "A is smaller than B"; + str2 = "B is greater than A"; + ensure("4: compareStrings failed", LLStringUtil::compareStrings(str1, str2) < 0); + + str2 = "A is smaller than B"; + ensure("5: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); + } + + template<> template<> + void string_index_object_t::test<27>() + { + const char* str1 = NULL; + const char* str2 = NULL; + + ensure("1: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); + str2 = "A"; + ensure("2: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) > 0); + ensure("3: compareInsensitive failed", LLStringUtil::compareInsensitive(str2, str1) < 0); + + str1 = "A is equal to a"; + str2 = "a is EQUAL to A"; + ensure("4: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); + } + + template<> template<> + void string_index_object_t::test<28>() + { + std::string lhs_str("PROgraM12files"); + std::string rhs_str("PROgram12Files"); + ensure("compareDict 1 failed", LLStringUtil::compareDict(lhs_str, rhs_str) < 0); + ensure("precedesDict 1 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == TRUE); + + lhs_str = "PROgram12Files"; + rhs_str = "PROgram12Files"; + ensure("compareDict 2 failed", LLStringUtil::compareDict(lhs_str, rhs_str) == 0); + ensure("precedesDict 2 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); + + lhs_str = "PROgram12Files"; + rhs_str = "PROgRAM12FILES"; + ensure("compareDict 3 failed", LLStringUtil::compareDict(lhs_str, rhs_str) > 0); + ensure("precedesDict 3 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); + } + + template<> template<> + void string_index_object_t::test<29>() + { + char str1[] = "First String..."; + char str2[100]; + + LLStringUtil::copy(str2, str1, 100); + ensure("LLStringUtil::copy with enough dest length failed", strcmp(str2, str1) == 0); + LLStringUtil::copy(str2, str1, sizeof("First")); + ensure("LLStringUtil::copy with less dest length failed", strcmp(str2, "First") == 0); + } + + template<> template<> + void string_index_object_t::test<30>() + { + std::string str1 = "This is the sentence..."; + std::string str2 = "This is the "; + std::string str3 = "first "; + std::string str4 = "This is the first sentence..."; + std::string str5 = "This is the sentence...first "; + std::string dest; + + dest = str1; + LLStringUtil::copyInto(dest, str3, str2.length()); + ensure("LLStringUtil::copyInto insert failed", dest == str4); + + dest = str1; + LLStringUtil::copyInto(dest, str3, dest.length()); + ensure("LLStringUtil::copyInto append failed", dest == str5); + } + + template<> template<> + void string_index_object_t::test<31>() + { + std::string stripped; + + // Plain US ASCII text, including spaces and punctuation, + // should not be altered. + std::string simple_text = "Hello, world!"; + stripped = LLStringFn::strip_invalid_xml(simple_text); + ensure("Simple text passed unchanged", stripped == simple_text); + + // Control characters should be removed + // except for 0x09, 0x0a, 0x0d + std::string control_chars; + for (char c = 0x01; c < 0x20; c++) + { + control_chars.push_back(c); + } + std::string allowed_control_chars; + allowed_control_chars.push_back( (char)0x09 ); + allowed_control_chars.push_back( (char)0x0a ); + allowed_control_chars.push_back( (char)0x0d ); + + stripped = LLStringFn::strip_invalid_xml(control_chars); + ensure("Only tab, LF, CR control characters allowed", + stripped == allowed_control_chars); + + // UTF-8 should be passed intact, including high byte + // characters. Try Francais (with C squiggle cedilla) + std::string french = "Fran"; + french.push_back( (char)0xC3 ); + french.push_back( (char)0xA7 ); + french += "ais"; + stripped = LLStringFn::strip_invalid_xml( french ); + ensure("UTF-8 high byte text is allowed", french == stripped ); + } + + template<> template<> + void string_index_object_t::test<32>() + { + // Test LLStringUtil::format() string interpolation + LLStringUtil::format_map_t fmt_map; + std::string s; + int subcount; + + fmt_map["[TRICK1]"] = "[A]"; + fmt_map["[A]"] = "a"; + fmt_map["[B]"] = "b"; + fmt_map["[AAA]"] = "aaa"; + fmt_map["[BBB]"] = "bbb"; + fmt_map["[TRICK2]"] = "[A]"; + fmt_map["[EXPLOIT]"] = "!!!!!!!!!!!![EXPLOIT]!!!!!!!!!!!!"; + fmt_map["[KEYLONGER]"] = "short"; + fmt_map["[KEYSHORTER]"] = "Am I not a long string?"; + fmt_map["?"] = "?"; + fmt_map["[DELETE]"] = ""; + fmt_map["[]"] = "[]"; // doesn't do a substitution, but shouldn't crash either + + for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) + { + // Test when source string is entirely one key + std::string s1 = (std::string)iter->first; + std::string s2 = (std::string)iter->second; + subcount = LLStringUtil::format(s1, fmt_map); + ensure_equals("LLStringUtil::format: Raw interpolation result", s1, s2); + if (s1 == "?" || s1 == "[]") // no interp expected + { + ensure_equals("LLStringUtil::format: Raw interpolation result count", 0, subcount); + } + else + { + ensure_equals("LLStringUtil::format: Raw interpolation result count", 1, subcount); + } + } + + for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) + { + // Test when source string is one key, duplicated + std::string s1 = (std::string)iter->first; + std::string s2 = (std::string)iter->second; + s = s1 + s1 + s1 + s1; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Rawx4 interpolation result", s, s2 + s2 + s2 + s2); + if (s1 == "?" || s1 == "[]") // no interp expected + { + ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 0, subcount); + } + else + { + ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 4, subcount); + } + } + + // Test when source string has no keys + std::string srcs = "!!!!!!!!!!!!!!!!"; + s = srcs; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: No key test result", s, srcs); + ensure_equals("LLStringUtil::format: No key test result count", 0, subcount); + + // Test when source string has no keys and is empty + std::string srcs3; + s = srcs3; + subcount = LLStringUtil::format(s, fmt_map); + ensure("LLStringUtil::format: No key test3 result", s.empty()); + ensure_equals("LLStringUtil::format: No key test3 result count", 0, subcount); + + // Test a substitution where a key is substituted with blankness + std::string srcs2 = "[DELETE]"; + s = srcs2; + subcount = LLStringUtil::format(s, fmt_map); + ensure("LLStringUtil::format: Delete key test2 result", s.empty()); + ensure_equals("LLStringUtil::format: Delete key test2 result count", 1, subcount); + + // Test an assorted substitution + std::string srcs4 = "[TRICK1][A][B][AAA][BBB][TRICK2][KEYLONGER][KEYSHORTER]?[DELETE]"; + s = srcs4; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test1 result", s, "[A]abaaabbb[A]shortAm I not a long string??"); + ensure_equals("LLStringUtil::format: Assorted Test1 result count", 9, subcount); + + // Test an assorted substitution + std::string srcs5 = "[DELETE]?[KEYSHORTER][KEYLONGER][TRICK2][BBB][AAA][B][A][TRICK1]"; + s = srcs5; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]"); + ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); + + // Test on nested brackets + std::string srcs6 = "[[TRICK1]][[A]][[B]][[AAA]][[BBB]][[TRICK2]][[KEYLONGER]][[KEYSHORTER]]?[[DELETE]]"; + s = srcs6; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "[[A]][a][b][aaa][bbb][[A]][short][Am I not a long string?]?[]"); + ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); + + + // Test an assorted substitution + std::string srcs8 = "foo[DELETE]bar?"; + s = srcs8; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test3 result", s, "foobar?"); + ensure_equals("LLStringUtil::format: Assorted Test3 result count", 1, subcount); + } + + template<> template<> + void string_index_object_t::test<33>() + { + // Test LLStringUtil::format() string interpolation + LLStringUtil::format_map_t blank_fmt_map; + std::string s; + int subcount; + + // Test substituting out of a blank format_map + std::string srcs6 = "12345"; + s = srcs6; + subcount = LLStringUtil::format(s, blank_fmt_map); + ensure_equals("LLStringUtil::format: Blankfmt Test1 result", s, "12345"); + ensure_equals("LLStringUtil::format: Blankfmt Test1 result count", 0, subcount); + + // Test substituting a blank string out of a blank format_map + std::string srcs7; + s = srcs7; + subcount = LLStringUtil::format(s, blank_fmt_map); + ensure("LLStringUtil::format: Blankfmt Test2 result", s.empty()); + ensure_equals("LLStringUtil::format: Blankfmt Test2 result count", 0, subcount); + } + + template<> template<> + void string_index_object_t::test<34>() + { + // Test that incorrect LLStringUtil::format() use does not explode. + LLStringUtil::format_map_t nasty_fmt_map; + std::string s; + int subcount; + + nasty_fmt_map[""] = "never used"; // see, this is nasty. + + // Test substituting out of a nasty format_map + std::string srcs6 = "12345"; + s = srcs6; + subcount = LLStringUtil::format(s, nasty_fmt_map); + ensure_equals("LLStringUtil::format: Nastyfmt Test1 result", s, "12345"); + ensure_equals("LLStringUtil::format: Nastyfmt Test1 result count", 0, subcount); + + // Test substituting a blank string out of a nasty format_map + std::string srcs7; + s = srcs7; + subcount = LLStringUtil::format(s, nasty_fmt_map); + ensure("LLStringUtil::format: Nastyfmt Test2 result", s.empty()); + ensure_equals("LLStringUtil::format: Nastyfmt Test2 result count", 0, subcount); + } + + template<> template<> + void string_index_object_t::test<35>() + { + // Make sure startsWith works + std::string string("anybody in there?"); + std::string substr("anybody"); + ensure("startsWith works.", LLStringUtil::startsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<36>() + { + // Make sure startsWith correctly fails + std::string string("anybody in there?"); + std::string substr("there"); + ensure("startsWith fails.", !LLStringUtil::startsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<37>() + { + // startsWith fails on empty strings + std::string value("anybody in there?"); + std::string empty; + ensure("empty string.", !LLStringUtil::startsWith(value, empty)); + ensure("empty substr.", !LLStringUtil::startsWith(empty, value)); + ensure("empty everything.", !LLStringUtil::startsWith(empty, empty)); + } + + template<> template<> + void string_index_object_t::test<38>() + { + // Make sure endsWith works correctly + std::string string("anybody in there?"); + std::string substr("there?"); + ensure("endsWith works.", LLStringUtil::endsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<39>() + { + // Make sure endsWith correctly fails + std::string string("anybody in there?"); + std::string substr("anybody"); + ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); + substr = "there"; + ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); + substr = "ther?"; + ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<40>() + { + // endsWith fails on empty strings + std::string value("anybody in there?"); + std::string empty; + ensure("empty string.", !LLStringUtil::endsWith(value, empty)); + ensure("empty substr.", !LLStringUtil::endsWith(empty, value)); + ensure("empty everything.", !LLStringUtil::endsWith(empty, empty)); + } + + template<> template<> + void string_index_object_t::test<41>() + { + set_test_name("getTokens(\"delims\")"); + ensure_equals("empty string", LLStringUtil::getTokens("", " "), StringVec()); + ensure_equals("only delims", + LLStringUtil::getTokens(" \r\n ", " \r\n"), StringVec()); + ensure_equals("sequence of delims", + LLStringUtil::getTokens(",,, one ,,,", ","), list_of("one")); + // nat considers this a dubious implementation side effect, but I'd + // hate to change it now... + ensure_equals("noncontiguous tokens", + LLStringUtil::getTokens(", ,, , one ,,,", ","), list_of("")("")("one")); + ensure_equals("space-padded tokens", + LLStringUtil::getTokens(", one , two ,", ","), list_of("one")("two")); + ensure_equals("no delims", LLStringUtil::getTokens("one", ","), list_of("one")); + } + + // Shorthand for verifying that getTokens() behaves the same when you + // don't pass a string of escape characters, when you pass an empty string + // (different overloads), and when you pass a string of characters that + // aren't actually present. + void ensure_getTokens(const std::string& desc, + const std::string& string, + const std::string& drop_delims, + const std::string& keep_delims, + const std::string& quotes, + const std::vector<std::string>& expect) + { + ensure_equals(desc + " - no esc", + LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes), + expect); + ensure_equals(desc + " - empty esc", + LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, ""), + expect); + ensure_equals(desc + " - unused esc", + LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, "!"), + expect); + } + + void ensure_getTokens(const std::string& desc, + const std::string& string, + const std::string& drop_delims, + const std::string& keep_delims, + const std::vector<std::string>& expect) + { + ensure_getTokens(desc, string, drop_delims, keep_delims, "", expect); + } + + template<> template<> + void string_index_object_t::test<42>() + { + set_test_name("getTokens(\"delims\", etc.)"); + // Signatures to test in this method: + // getTokens(string, drop_delims, keep_delims [, quotes [, escapes]]) + // If you omit keep_delims, you get the older function (test above). + + // cases like the getTokens(string, delims) tests above + ensure_getTokens("empty string", "", " ", "", StringVec()); + ensure_getTokens("only delims", + " \r\n ", " \r\n", "", StringVec()); + ensure_getTokens("sequence of delims", + ",,, one ,,,", ", ", "", list_of("one")); + // Note contrast with the case in the previous method + ensure_getTokens("noncontiguous tokens", + ", ,, , one ,,,", ", ", "", list_of("one")); + ensure_getTokens("space-padded tokens", + ", one , two ,", ", ", "", list_of("one")("two")); - ensure_getTokens("no delims", "one", ",", "", list_of("one")); - - // drop_delims vs. keep_delims - ensure_getTokens("arithmetic", - " ab+def / xx* yy ", " ", "+-*/", - list_of("ab")("+")("def")("/")("xx")("*")("yy")); - - // quotes - ensure_getTokens("no quotes", - "She said, \"Don't go.\"", " ", ",", "", - list_of("She")("said")(",")("\"Don't")("go.\"")); - ensure_getTokens("quotes", - "She said, \"Don't go.\"", " ", ",", "\"", - list_of("She")("said")(",")("Don't go.")); - ensure_getTokens("quotes and delims", - "run c:/'Documents and Settings'/someone", " ", "", "'", - list_of("run")("c:/Documents and Settings/someone")); - ensure_getTokens("unmatched quote", - "baby don't leave", " ", "", "'", - list_of("baby")("don't")("leave")); - ensure_getTokens("adjacent quoted", - "abc'def \"ghi'\"jkl' mno\"pqr", " ", "", "\"'", - list_of("abcdef \"ghijkl' mnopqr")); - ensure_getTokens("quoted empty string", - "--set SomeVar ''", " ", "", "'", - list_of("--set")("SomeVar")("")); - - // escapes - // Don't use backslash as an escape for these tests -- you'll go nuts - // between the C++ string scanner and getTokens() escapes. Test with - // something else! - ensure_equals("escaped delims", - LLStringUtil::getTokens("^ a - dog^-gone^ phrase", " ", "-", "", "^"), - list_of(" a")("-")("dog-gone phrase")); - ensure_equals("escaped quotes", - LLStringUtil::getTokens("say: 'this isn^'t w^orking'.", " ", "", "'", "^"), - list_of("say:")("this isn't working.")); - ensure_equals("escaped escape", - LLStringUtil::getTokens("want x^^2", " ", "", "", "^"), - list_of("want")("x^2")); - ensure_equals("escape at end", - LLStringUtil::getTokens("it's^ up there^", " ", "", "'", "^"), - list_of("it's up")("there^")); + ensure_getTokens("no delims", "one", ",", "", list_of("one")); + + // drop_delims vs. keep_delims + ensure_getTokens("arithmetic", + " ab+def / xx* yy ", " ", "+-*/", + list_of("ab")("+")("def")("/")("xx")("*")("yy")); + + // quotes + ensure_getTokens("no quotes", + "She said, \"Don't go.\"", " ", ",", "", + list_of("She")("said")(",")("\"Don't")("go.\"")); + ensure_getTokens("quotes", + "She said, \"Don't go.\"", " ", ",", "\"", + list_of("She")("said")(",")("Don't go.")); + ensure_getTokens("quotes and delims", + "run c:/'Documents and Settings'/someone", " ", "", "'", + list_of("run")("c:/Documents and Settings/someone")); + ensure_getTokens("unmatched quote", + "baby don't leave", " ", "", "'", + list_of("baby")("don't")("leave")); + ensure_getTokens("adjacent quoted", + "abc'def \"ghi'\"jkl' mno\"pqr", " ", "", "\"'", + list_of("abcdef \"ghijkl' mnopqr")); + ensure_getTokens("quoted empty string", + "--set SomeVar ''", " ", "", "'", + list_of("--set")("SomeVar")("")); + + // escapes + // Don't use backslash as an escape for these tests -- you'll go nuts + // between the C++ string scanner and getTokens() escapes. Test with + // something else! + ensure_equals("escaped delims", + LLStringUtil::getTokens("^ a - dog^-gone^ phrase", " ", "-", "", "^"), + list_of(" a")("-")("dog-gone phrase")); + ensure_equals("escaped quotes", + LLStringUtil::getTokens("say: 'this isn^'t w^orking'.", " ", "", "'", "^"), + list_of("say:")("this isn't working.")); + ensure_equals("escaped escape", + LLStringUtil::getTokens("want x^^2", " ", "", "", "^"), + list_of("want")("x^2")); + ensure_equals("escape at end", + LLStringUtil::getTokens("it's^ up there^", " ", "", "'", "^"), + list_of("it's up")("there^")); } } diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp index 0a9d85ad00..8851f87b91 100644 --- a/indra/llcommon/tests/lltrace_test.cpp +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsingleton_test.cpp * @date 2011-08-11 * @brief Unit test for the LLSingleton class @@ -34,14 +34,14 @@ namespace LLUnits { - // using powers of 2 to allow strict floating point equality - LL_DECLARE_BASE_UNIT(Ounces, "oz"); - LL_DECLARE_DERIVED_UNIT(TallCup, "", Ounces, / 12); - LL_DECLARE_DERIVED_UNIT(GrandeCup, "", Ounces, / 16); - LL_DECLARE_DERIVED_UNIT(VentiCup, "", Ounces, / 20); - - LL_DECLARE_BASE_UNIT(Grams, "g"); - LL_DECLARE_DERIVED_UNIT(Milligrams, "mg", Grams, * 1000); + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Ounces, "oz"); + LL_DECLARE_DERIVED_UNIT(TallCup, "", Ounces, / 12); + LL_DECLARE_DERIVED_UNIT(GrandeCup, "", Ounces, / 16); + LL_DECLARE_DERIVED_UNIT(VentiCup, "", Ounces, / 20); + + LL_DECLARE_BASE_UNIT(Grams, "g"); + LL_DECLARE_DERIVED_UNIT(Milligrams, "mg", Grams, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ounces); @@ -54,89 +54,89 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milligrams); namespace tut { - using namespace LLTrace; - struct trace - { - ThreadRecorder mRecorder; - }; - - typedef test_group<trace> trace_t; - typedef trace_t::object trace_object_t; - tut::trace_t tut_singleton("LLTrace"); - - static CountStatHandle<S32> sCupsOfCoffeeConsumed("coffeeconsumed", "Delicious cup of dark roast."); - static SampleStatHandle<F32Milligrams> sCaffeineLevelStat("caffeinelevel", "Coffee buzz quotient"); - static EventStatHandle<S32Ounces> sOuncesPerCup("cupsize", "Large, huge, or ginormous"); - - static F32 sCaffeineLevel(0.f); - const F32Milligrams sCaffeinePerOz(18.f); - - void drink_coffee(S32 num_cups, S32Ounces cup_size) - { - add(sCupsOfCoffeeConsumed, num_cups); - for (S32 i = 0; i < num_cups; i++) - { - record(sOuncesPerCup, cup_size); - } - - sCaffeineLevel += F32Ounces(num_cups * cup_size).value() * sCaffeinePerOz.value(); - sample(sCaffeineLevelStat, sCaffeineLevel); - } - - // basic data collection - template<> template<> - void trace_object_t::test<1>() - { - sample(sCaffeineLevelStat, sCaffeineLevel); - - Recording all_day; - Recording at_work; - Recording after_3pm; - - all_day.start(); - { - // warm up with one grande cup - drink_coffee(1, S32TallCup(1)); - - // go to work - at_work.start(); - { - // drink 3 tall cups, 1 after 3 pm - drink_coffee(2, S32GrandeCup(1)); - after_3pm.start(); - drink_coffee(1, S32GrandeCup(1)); - } - at_work.stop(); - drink_coffee(1, S32VentiCup(1)); - } - // don't need to stop recordings to get accurate values out of them - //after_3pm.stop(); - //all_day.stop(); - - ensure("count stats are counted when recording is active", - at_work.getSum(sCupsOfCoffeeConsumed) == 3 - && all_day.getSum(sCupsOfCoffeeConsumed) == 5 - && after_3pm.getSum(sCupsOfCoffeeConsumed) == 2); - ensure("measurement sums are counted when recording is active", - at_work.getSum(sOuncesPerCup) == S32Ounces(48) - && all_day.getSum(sOuncesPerCup) == S32Ounces(80) - && after_3pm.getSum(sOuncesPerCup) == S32Ounces(36)); - ensure("measurement min is specific to when recording is active", - at_work.getMin(sOuncesPerCup) == S32GrandeCup(1) - && all_day.getMin(sOuncesPerCup) == S32TallCup(1) - && after_3pm.getMin(sOuncesPerCup) == S32GrandeCup(1)); - ensure("measurement max is specific to when recording is active", - at_work.getMax(sOuncesPerCup) == S32GrandeCup(1) - && all_day.getMax(sOuncesPerCup) == S32VentiCup(1) - && after_3pm.getMax(sOuncesPerCup) == S32VentiCup(1)); - ensure("sample min is specific to when recording is active", - at_work.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1)).value() - && all_day.getMin(sCaffeineLevelStat) == F32Milligrams(0.f) - && after_3pm.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(2)).value()); - ensure("sample max is specific to when recording is active", - at_work.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3)).value() - && all_day.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value() - && after_3pm.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value()); - } + using namespace LLTrace; + struct trace + { + ThreadRecorder mRecorder; + }; + + typedef test_group<trace> trace_t; + typedef trace_t::object trace_object_t; + tut::trace_t tut_singleton("LLTrace"); + + static CountStatHandle<S32> sCupsOfCoffeeConsumed("coffeeconsumed", "Delicious cup of dark roast."); + static SampleStatHandle<F32Milligrams> sCaffeineLevelStat("caffeinelevel", "Coffee buzz quotient"); + static EventStatHandle<S32Ounces> sOuncesPerCup("cupsize", "Large, huge, or ginormous"); + + static F32 sCaffeineLevel(0.f); + const F32Milligrams sCaffeinePerOz(18.f); + + void drink_coffee(S32 num_cups, S32Ounces cup_size) + { + add(sCupsOfCoffeeConsumed, num_cups); + for (S32 i = 0; i < num_cups; i++) + { + record(sOuncesPerCup, cup_size); + } + + sCaffeineLevel += F32Ounces(num_cups * cup_size).value() * sCaffeinePerOz.value(); + sample(sCaffeineLevelStat, sCaffeineLevel); + } + + // basic data collection + template<> template<> + void trace_object_t::test<1>() + { + sample(sCaffeineLevelStat, sCaffeineLevel); + + Recording all_day; + Recording at_work; + Recording after_3pm; + + all_day.start(); + { + // warm up with one grande cup + drink_coffee(1, S32TallCup(1)); + + // go to work + at_work.start(); + { + // drink 3 tall cups, 1 after 3 pm + drink_coffee(2, S32GrandeCup(1)); + after_3pm.start(); + drink_coffee(1, S32GrandeCup(1)); + } + at_work.stop(); + drink_coffee(1, S32VentiCup(1)); + } + // don't need to stop recordings to get accurate values out of them + //after_3pm.stop(); + //all_day.stop(); + + ensure("count stats are counted when recording is active", + at_work.getSum(sCupsOfCoffeeConsumed) == 3 + && all_day.getSum(sCupsOfCoffeeConsumed) == 5 + && after_3pm.getSum(sCupsOfCoffeeConsumed) == 2); + ensure("measurement sums are counted when recording is active", + at_work.getSum(sOuncesPerCup) == S32Ounces(48) + && all_day.getSum(sOuncesPerCup) == S32Ounces(80) + && after_3pm.getSum(sOuncesPerCup) == S32Ounces(36)); + ensure("measurement min is specific to when recording is active", + at_work.getMin(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMin(sOuncesPerCup) == S32TallCup(1) + && after_3pm.getMin(sOuncesPerCup) == S32GrandeCup(1)); + ensure("measurement max is specific to when recording is active", + at_work.getMax(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMax(sOuncesPerCup) == S32VentiCup(1) + && after_3pm.getMax(sOuncesPerCup) == S32VentiCup(1)); + ensure("sample min is specific to when recording is active", + at_work.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1)).value() + && all_day.getMin(sCaffeineLevelStat) == F32Milligrams(0.f) + && after_3pm.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(2)).value()); + ensure("sample max is specific to when recording is active", + at_work.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3)).value() + && all_day.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value() + && after_3pm.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value()); + } } diff --git a/indra/llcommon/tests/lltreeiterators_test.cpp b/indra/llcommon/tests/lltreeiterators_test.cpp index b9c7a70c07..7a2adfd8ba 100644 --- a/indra/llcommon/tests/lltreeiterators_test.cpp +++ b/indra/llcommon/tests/lltreeiterators_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-08-20 * @brief Test of lltreeiterators.h - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -1045,7 +1045,7 @@ bool LLTreeWalkIter_test(const std::string& itername, const std::string& nodenam { std::cout << itername << '<' << nodename << ">(NULL)\n"; return false; - } + } return true; } @@ -1107,7 +1107,7 @@ namespace tut TreeNodePtr tnroot(example_tree<TreeNode>()); TreeNodePtr tnB2b(get_B2b<TreeNode, TreeNode::child_iterator> (tnroot, boost::bind(&TreeNode::child_begin, _1))); - + std::string desc1("for (TreeNodePr : getRootRange<LLTreeIter::UP>(tnB2b))"); // std::cout << desc1 << "\n"; // Although we've commented out the output statement, ensure that the diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp index 57cf9810af..49f2d3085a 100644 --- a/indra/llcommon/tests/llunits_test.cpp +++ b/indra/llcommon/tests/llunits_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsingleton_test.cpp * @date 2011-08-11 * @brief Unit test for the LLSingleton class @@ -32,10 +32,10 @@ namespace LLUnits { - // using powers of 2 to allow strict floating point equality - LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); - LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); - LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); + LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); + LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Quatloos); @@ -44,9 +44,9 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Solari); namespace LLUnits { - LL_DECLARE_BASE_UNIT(Celcius, "c"); - LL_DECLARE_DERIVED_UNIT(Fahrenheit, "f", Celcius, * 9 / 5 + 32); - LL_DECLARE_DERIVED_UNIT(Kelvin, "k", Celcius, + 273.15f); + LL_DECLARE_BASE_UNIT(Celcius, "c"); + LL_DECLARE_DERIVED_UNIT(Fahrenheit, "f", Celcius, * 9 / 5 + 32); + LL_DECLARE_DERIVED_UNIT(Kelvin, "k", Celcius, + 273.15f); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Celcius); @@ -56,333 +56,333 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kelvin); namespace tut { - using namespace LLUnits; - struct units - { - }; - - typedef test_group<units> units_t; - typedef units_t::object units_object_t; - tut::units_t tut_singleton("LLUnit"); - - // storage type conversions - template<> template<> - void units_object_t::test<1>() - { - LLUnit<F32, Quatloos> float_quatloos; - ensure("default float unit is zero", float_quatloos == F32Quatloos(0.f)); - - LLUnit<F32, Quatloos> float_initialize_quatloos(1); - ensure("non-zero initialized unit", float_initialize_quatloos == F32Quatloos(1.f)); - - LLUnit<S32, Quatloos> int_quatloos; - ensure("default int unit is zero", int_quatloos == S32Quatloos(0)); - - int_quatloos = S32Quatloos(42); - ensure("int assignment is preserved", int_quatloos == S32Quatloos(42)); - float_quatloos = int_quatloos; - ensure("float assignment from int preserves value", float_quatloos == F32Quatloos(42.f)); - - int_quatloos = float_quatloos; - ensure("int assignment from float preserves value", int_quatloos == S32Quatloos(42)); - - float_quatloos = F32Quatloos(42.1f); - int_quatloos = float_quatloos; - ensure("int units truncate float units on assignment", int_quatloos == S32Quatloos(42)); - - LLUnit<U32, Quatloos> unsigned_int_quatloos(float_quatloos); - ensure("unsigned int can be initialized from signed int", unsigned_int_quatloos == S32Quatloos(42)); - - S32Solari int_solari(1); - - float_quatloos = int_solari; - ensure("fractional units are preserved in conversion from integer to float type", float_quatloos == F32Quatloos(0.25f)); - - int_quatloos = S32Quatloos(1); - F32Solari float_solari = int_quatloos; - ensure("can convert with fractional intermediates from integer to float type", float_solari == F32Solari(4.f)); - } - - // conversions to/from base unit - template<> template<> - void units_object_t::test<2>() - { - LLUnit<F32, Quatloos> quatloos(1.f); - LLUnit<F32, Latinum> latinum_bars(quatloos); - ensure("conversion between units is automatic via initialization", latinum_bars == F32Latinum(1.f / 4.f)); - - latinum_bars = S32Latinum(256); - quatloos = latinum_bars; - ensure("conversion between units is automatic via assignment, and bidirectional", quatloos == S32Quatloos(1024)); - - LLUnit<S32, Quatloos> single_quatloo(1); - LLUnit<F32, Latinum> quarter_latinum = single_quatloo; - ensure("division of integer unit preserves fractional values when converted to float unit", quarter_latinum == F32Latinum(0.25f)); - } - - // conversions across non-base units - template<> template<> - void units_object_t::test<3>() - { - LLUnit<F32, Quatloos> quatloos(1024); - LLUnit<F32, Solari> solari(quatloos); - ensure("conversions can work between indirectly related units: Quatloos -> Latinum -> Solari", solari == S32Solari(4096)); - - LLUnit<F32, Latinum> latinum_bars = solari; - ensure("Non base units can be converted between each other", latinum_bars == S32Latinum(256)); - } - - // math operations - template<> template<> - void units_object_t::test<4>() - { - // exercise math operations - LLUnit<F32, Quatloos> quatloos(1.f); - quatloos *= 4.f; - ensure(quatloos == S32Quatloos(4)); - quatloos = quatloos * 2; - ensure(quatloos == S32Quatloos(8)); - quatloos = 2.f * quatloos; - ensure(quatloos == S32Quatloos(16)); - - quatloos += F32Quatloos(4.f); - ensure(quatloos == S32Quatloos(20)); - quatloos += S32Quatloos(4); - ensure(quatloos == S32Quatloos(24)); - quatloos = quatloos + S32Quatloos(4); - ensure(quatloos == S32Quatloos(28)); - quatloos = S32Quatloos(4) + quatloos; - ensure(quatloos == S32Quatloos(32)); - quatloos += quatloos * 3; - ensure(quatloos == S32Quatloos(128)); - - quatloos -= quatloos / 4 * 3; - ensure(quatloos == S32Quatloos(32)); - quatloos = quatloos - S32Quatloos(8); - ensure(quatloos == S32Quatloos(24)); - quatloos -= S32Quatloos(4); - ensure(quatloos == S32Quatloos(20)); - quatloos -= F32Quatloos(4.f); - ensure(quatloos == S32Quatloos(16)); - - quatloos /= 2.f; - ensure(quatloos == S32Quatloos(8)); - quatloos = quatloos / 4; - ensure(quatloos == S32Quatloos(2)); - - F32 ratio = quatloos / LLUnit<F32, Quatloos>(2.f); - ensure(ratio == 1); - ratio = quatloos / LLUnit<F32, Solari>(8.f); - ensure(ratio == 1); - - quatloos += LLUnit<F32, Solari>(8.f); - ensure(quatloos == S32Quatloos(4)); - quatloos -= LLUnit<F32, Latinum>(1.f); - ensure(quatloos == S32Quatloos(0)); - } - - // comparison operators - template<> template<> - void units_object_t::test<5>() - { - LLUnit<S32, Quatloos> quatloos(1); - ensure("can perform less than comparison against same type", quatloos < S32Quatloos(2)); - ensure("can perform less than comparison against different storage type", quatloos < F32Quatloos(2.f)); - ensure("can perform less than comparison against different units", quatloos < S32Latinum(5)); - ensure("can perform less than comparison against different storage type and units", quatloos < F32Latinum(5.f)); - - ensure("can perform greater than comparison against same type", quatloos > S32Quatloos(0)); - ensure("can perform greater than comparison against different storage type", quatloos > F32Quatloos(0.f)); - ensure("can perform greater than comparison against different units", quatloos > S32Latinum(0)); - ensure("can perform greater than comparison against different storage type and units", quatloos > F32Latinum(0.f)); - - } - - bool accept_explicit_quatloos(S32Quatloos q) - { - return true; - } - - bool accept_implicit_quatloos(S32Quatloos q) - { - return true; - } - - // signature compatibility - template<> template<> - void units_object_t::test<6>() - { - S32Quatloos quatloos(1); - ensure("can pass unit values as argument", accept_explicit_quatloos(S32Quatloos(1))); - ensure("can pass unit values as argument", accept_explicit_quatloos(quatloos)); - } - - // implicit units - template<> template<> - void units_object_t::test<7>() - { - LLUnit<F32, Quatloos> quatloos; - LLUnitImplicit<F32, Quatloos> quatloos_implicit = quatloos + S32Quatloos(1); - ensure("can initialize implicit unit from explicit", quatloos_implicit == 1); - - quatloos = quatloos_implicit; - ensure("can assign implicit unit to explicit unit", quatloos == S32Quatloos(1)); - quatloos += quatloos_implicit; - ensure("can perform math operation using mixture of implicit and explicit units", quatloos == S32Quatloos(2)); - - // math operations on implicits - quatloos_implicit = 1; - ensure(quatloos_implicit == 1); - - quatloos_implicit += 2; - ensure(quatloos_implicit == 3); - - quatloos_implicit *= 2; - ensure(quatloos_implicit == 6); - - quatloos_implicit -= 1; - ensure(quatloos_implicit == 5); - - quatloos_implicit /= 5; - ensure(quatloos_implicit == 1); - - quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit; - ensure(quatloos_implicit == 5); - - quatloos_implicit = 10 - quatloos_implicit - 1; - ensure(quatloos_implicit == 4); - - quatloos_implicit = 2 * quatloos_implicit * 2; - ensure(quatloos_implicit == 16); - - F32 one_half = quatloos_implicit / (quatloos_implicit * 2); - ensure(one_half == 0.5f); - - // implicit conversion to POD - F32 float_val = quatloos_implicit; - ensure("implicit units convert implicitly to regular values", float_val == 16); - - S32 int_val = quatloos_implicit; - ensure("implicit units convert implicitly to regular values", int_val == 16); - - // conversion of implicits - LLUnitImplicit<F32, Latinum> latinum_implicit(2); - ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); - - quatloos_implicit += F32Quatloos(10); - ensure("can add-assign explicit units", quatloos_implicit == 26); - - quatloos_implicit -= F32Quatloos(10); - ensure("can subtract-assign explicit units", quatloos_implicit == 16); - - // comparisons - ensure("can compare greater than implicit unit", quatloos_implicit > F32QuatloosImplicit(0.f)); - ensure("can compare greater than non-implicit unit", quatloos_implicit > F32Quatloos(0.f)); - ensure("can compare greater than or equal to implicit unit", quatloos_implicit >= F32QuatloosImplicit(0.f)); - ensure("can compare greater than or equal to non-implicit unit", quatloos_implicit >= F32Quatloos(0.f)); - ensure("can compare less than implicit unit", quatloos_implicit < F32QuatloosImplicit(20.f)); - ensure("can compare less than non-implicit unit", quatloos_implicit < F32Quatloos(20.f)); - ensure("can compare less than or equal to implicit unit", quatloos_implicit <= F32QuatloosImplicit(20.f)); - ensure("can compare less than or equal to non-implicit unit", quatloos_implicit <= F32Quatloos(20.f)); - } - - // precision tests - template<> template<> - void units_object_t::test<8>() - { - U32Bytes max_bytes(U32_MAX); - S32Megabytes mega_bytes = max_bytes; - ensure("max available precision is used when converting units", mega_bytes == (S32Megabytes)4095); - - mega_bytes = (S32Megabytes)-5 + (U32Megabytes)1; - ensure("can mix signed and unsigned in units addition", mega_bytes == (S32Megabytes)-4); - - mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; - ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); - } - - // default units - template<> template<> - void units_object_t::test<9>() - { - U32Gigabytes GB(1); - U32Megabytes MB(GB); - U32Kilobytes KB(GB); - U32Bytes B(GB); - - ensure("GB -> MB conversion", MB.value() == 1024); - ensure("GB -> KB conversion", KB.value() == 1024 * 1024); - ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); - - KB = U32Kilobytes(1); - U32Kilobits Kb(KB); - U32Bits b(KB); - ensure("KB -> Kb conversion", Kb.value() == 8); - ensure("KB -> b conversion", b.value() == 8 * 1024); - - U32Days days(1); - U32Hours hours(days); - U32Minutes minutes(days); - U32Seconds seconds(days); - U32Milliseconds ms(days); - - ensure("days -> hours conversion", hours.value() == 24); - ensure("days -> minutes conversion", minutes.value() == 24 * 60); - ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); - ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); - - U32Kilometers km(1); - U32Meters m(km); - U32Centimeters cm(km); - U32Millimeters mm(km); - - ensure("km -> m conversion", m.value() == 1000); - ensure("km -> cm conversion", cm.value() == 1000 * 100); - ensure("km -> mm conversion", mm.value() == 1000 * 1000); - - U32Gigahertz GHz(1); - U32Megahertz MHz(GHz); - U32Kilohertz KHz(GHz); - U32Hertz Hz(GHz); - - ensure("GHz -> MHz conversion", MHz.value() == 1000); - ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); - ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); - - F32Radians rad(6.2831853071795f); - S32Degrees deg(rad); - ensure("radians -> degrees conversion", deg.value() == 360); - - F32Percent percent(50); - F32Ratio ratio(percent); - ensure("percent -> ratio conversion", ratio.value() == 0.5f); - - U32Kilotriangles ktris(1); - U32Triangles tris(ktris); - ensure("kilotriangles -> triangles conversion", tris.value() == 1000); - } - - bool value_near(F32 value, F32 target, F32 threshold) - { - return fabsf(value - target) < threshold; - } - - // linear transforms - template<> template<> - void units_object_t::test<10>() - { - F32Celcius float_celcius(100); - F32Fahrenheit float_fahrenheit(float_celcius); - ensure("floating point celcius -> fahrenheit conversion using linear transform", value_near(float_fahrenheit.value(), 212, 0.1f) ); - - float_celcius = float_fahrenheit; - ensure("floating point fahrenheit -> celcius conversion using linear transform (round trip)", value_near(float_celcius.value(), 100.f, 0.1f) ); - - S32Celcius int_celcius(100); - S32Fahrenheit int_fahrenheit(int_celcius); - ensure("integer celcius -> fahrenheit conversion using linear transform", int_fahrenheit.value() == 212); - - int_celcius = int_fahrenheit; - ensure("integer fahrenheit -> celcius conversion using linear transform (round trip)", int_celcius.value() == 100); - } + using namespace LLUnits; + struct units + { + }; + + typedef test_group<units> units_t; + typedef units_t::object units_object_t; + tut::units_t tut_singleton("LLUnit"); + + // storage type conversions + template<> template<> + void units_object_t::test<1>() + { + LLUnit<F32, Quatloos> float_quatloos; + ensure("default float unit is zero", float_quatloos == F32Quatloos(0.f)); + + LLUnit<F32, Quatloos> float_initialize_quatloos(1); + ensure("non-zero initialized unit", float_initialize_quatloos == F32Quatloos(1.f)); + + LLUnit<S32, Quatloos> int_quatloos; + ensure("default int unit is zero", int_quatloos == S32Quatloos(0)); + + int_quatloos = S32Quatloos(42); + ensure("int assignment is preserved", int_quatloos == S32Quatloos(42)); + float_quatloos = int_quatloos; + ensure("float assignment from int preserves value", float_quatloos == F32Quatloos(42.f)); + + int_quatloos = float_quatloos; + ensure("int assignment from float preserves value", int_quatloos == S32Quatloos(42)); + + float_quatloos = F32Quatloos(42.1f); + int_quatloos = float_quatloos; + ensure("int units truncate float units on assignment", int_quatloos == S32Quatloos(42)); + + LLUnit<U32, Quatloos> unsigned_int_quatloos(float_quatloos); + ensure("unsigned int can be initialized from signed int", unsigned_int_quatloos == S32Quatloos(42)); + + S32Solari int_solari(1); + + float_quatloos = int_solari; + ensure("fractional units are preserved in conversion from integer to float type", float_quatloos == F32Quatloos(0.25f)); + + int_quatloos = S32Quatloos(1); + F32Solari float_solari = int_quatloos; + ensure("can convert with fractional intermediates from integer to float type", float_solari == F32Solari(4.f)); + } + + // conversions to/from base unit + template<> template<> + void units_object_t::test<2>() + { + LLUnit<F32, Quatloos> quatloos(1.f); + LLUnit<F32, Latinum> latinum_bars(quatloos); + ensure("conversion between units is automatic via initialization", latinum_bars == F32Latinum(1.f / 4.f)); + + latinum_bars = S32Latinum(256); + quatloos = latinum_bars; + ensure("conversion between units is automatic via assignment, and bidirectional", quatloos == S32Quatloos(1024)); + + LLUnit<S32, Quatloos> single_quatloo(1); + LLUnit<F32, Latinum> quarter_latinum = single_quatloo; + ensure("division of integer unit preserves fractional values when converted to float unit", quarter_latinum == F32Latinum(0.25f)); + } + + // conversions across non-base units + template<> template<> + void units_object_t::test<3>() + { + LLUnit<F32, Quatloos> quatloos(1024); + LLUnit<F32, Solari> solari(quatloos); + ensure("conversions can work between indirectly related units: Quatloos -> Latinum -> Solari", solari == S32Solari(4096)); + + LLUnit<F32, Latinum> latinum_bars = solari; + ensure("Non base units can be converted between each other", latinum_bars == S32Latinum(256)); + } + + // math operations + template<> template<> + void units_object_t::test<4>() + { + // exercise math operations + LLUnit<F32, Quatloos> quatloos(1.f); + quatloos *= 4.f; + ensure(quatloos == S32Quatloos(4)); + quatloos = quatloos * 2; + ensure(quatloos == S32Quatloos(8)); + quatloos = 2.f * quatloos; + ensure(quatloos == S32Quatloos(16)); + + quatloos += F32Quatloos(4.f); + ensure(quatloos == S32Quatloos(20)); + quatloos += S32Quatloos(4); + ensure(quatloos == S32Quatloos(24)); + quatloos = quatloos + S32Quatloos(4); + ensure(quatloos == S32Quatloos(28)); + quatloos = S32Quatloos(4) + quatloos; + ensure(quatloos == S32Quatloos(32)); + quatloos += quatloos * 3; + ensure(quatloos == S32Quatloos(128)); + + quatloos -= quatloos / 4 * 3; + ensure(quatloos == S32Quatloos(32)); + quatloos = quatloos - S32Quatloos(8); + ensure(quatloos == S32Quatloos(24)); + quatloos -= S32Quatloos(4); + ensure(quatloos == S32Quatloos(20)); + quatloos -= F32Quatloos(4.f); + ensure(quatloos == S32Quatloos(16)); + + quatloos /= 2.f; + ensure(quatloos == S32Quatloos(8)); + quatloos = quatloos / 4; + ensure(quatloos == S32Quatloos(2)); + + F32 ratio = quatloos / LLUnit<F32, Quatloos>(2.f); + ensure(ratio == 1); + ratio = quatloos / LLUnit<F32, Solari>(8.f); + ensure(ratio == 1); + + quatloos += LLUnit<F32, Solari>(8.f); + ensure(quatloos == S32Quatloos(4)); + quatloos -= LLUnit<F32, Latinum>(1.f); + ensure(quatloos == S32Quatloos(0)); + } + + // comparison operators + template<> template<> + void units_object_t::test<5>() + { + LLUnit<S32, Quatloos> quatloos(1); + ensure("can perform less than comparison against same type", quatloos < S32Quatloos(2)); + ensure("can perform less than comparison against different storage type", quatloos < F32Quatloos(2.f)); + ensure("can perform less than comparison against different units", quatloos < S32Latinum(5)); + ensure("can perform less than comparison against different storage type and units", quatloos < F32Latinum(5.f)); + + ensure("can perform greater than comparison against same type", quatloos > S32Quatloos(0)); + ensure("can perform greater than comparison against different storage type", quatloos > F32Quatloos(0.f)); + ensure("can perform greater than comparison against different units", quatloos > S32Latinum(0)); + ensure("can perform greater than comparison against different storage type and units", quatloos > F32Latinum(0.f)); + + } + + bool accept_explicit_quatloos(S32Quatloos q) + { + return true; + } + + bool accept_implicit_quatloos(S32Quatloos q) + { + return true; + } + + // signature compatibility + template<> template<> + void units_object_t::test<6>() + { + S32Quatloos quatloos(1); + ensure("can pass unit values as argument", accept_explicit_quatloos(S32Quatloos(1))); + ensure("can pass unit values as argument", accept_explicit_quatloos(quatloos)); + } + + // implicit units + template<> template<> + void units_object_t::test<7>() + { + LLUnit<F32, Quatloos> quatloos; + LLUnitImplicit<F32, Quatloos> quatloos_implicit = quatloos + S32Quatloos(1); + ensure("can initialize implicit unit from explicit", quatloos_implicit == 1); + + quatloos = quatloos_implicit; + ensure("can assign implicit unit to explicit unit", quatloos == S32Quatloos(1)); + quatloos += quatloos_implicit; + ensure("can perform math operation using mixture of implicit and explicit units", quatloos == S32Quatloos(2)); + + // math operations on implicits + quatloos_implicit = 1; + ensure(quatloos_implicit == 1); + + quatloos_implicit += 2; + ensure(quatloos_implicit == 3); + + quatloos_implicit *= 2; + ensure(quatloos_implicit == 6); + + quatloos_implicit -= 1; + ensure(quatloos_implicit == 5); + + quatloos_implicit /= 5; + ensure(quatloos_implicit == 1); + + quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit; + ensure(quatloos_implicit == 5); + + quatloos_implicit = 10 - quatloos_implicit - 1; + ensure(quatloos_implicit == 4); + + quatloos_implicit = 2 * quatloos_implicit * 2; + ensure(quatloos_implicit == 16); + + F32 one_half = quatloos_implicit / (quatloos_implicit * 2); + ensure(one_half == 0.5f); + + // implicit conversion to POD + F32 float_val = quatloos_implicit; + ensure("implicit units convert implicitly to regular values", float_val == 16); + + S32 int_val = quatloos_implicit; + ensure("implicit units convert implicitly to regular values", int_val == 16); + + // conversion of implicits + LLUnitImplicit<F32, Latinum> latinum_implicit(2); + ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); + + quatloos_implicit += F32Quatloos(10); + ensure("can add-assign explicit units", quatloos_implicit == 26); + + quatloos_implicit -= F32Quatloos(10); + ensure("can subtract-assign explicit units", quatloos_implicit == 16); + + // comparisons + ensure("can compare greater than implicit unit", quatloos_implicit > F32QuatloosImplicit(0.f)); + ensure("can compare greater than non-implicit unit", quatloos_implicit > F32Quatloos(0.f)); + ensure("can compare greater than or equal to implicit unit", quatloos_implicit >= F32QuatloosImplicit(0.f)); + ensure("can compare greater than or equal to non-implicit unit", quatloos_implicit >= F32Quatloos(0.f)); + ensure("can compare less than implicit unit", quatloos_implicit < F32QuatloosImplicit(20.f)); + ensure("can compare less than non-implicit unit", quatloos_implicit < F32Quatloos(20.f)); + ensure("can compare less than or equal to implicit unit", quatloos_implicit <= F32QuatloosImplicit(20.f)); + ensure("can compare less than or equal to non-implicit unit", quatloos_implicit <= F32Quatloos(20.f)); + } + + // precision tests + template<> template<> + void units_object_t::test<8>() + { + U32Bytes max_bytes(U32_MAX); + S32Megabytes mega_bytes = max_bytes; + ensure("max available precision is used when converting units", mega_bytes == (S32Megabytes)4095); + + mega_bytes = (S32Megabytes)-5 + (U32Megabytes)1; + ensure("can mix signed and unsigned in units addition", mega_bytes == (S32Megabytes)-4); + + mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; + ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); + } + + // default units + template<> template<> + void units_object_t::test<9>() + { + U32Gigabytes GB(1); + U32Megabytes MB(GB); + U32Kilobytes KB(GB); + U32Bytes B(GB); + + ensure("GB -> MB conversion", MB.value() == 1024); + ensure("GB -> KB conversion", KB.value() == 1024 * 1024); + ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); + + KB = U32Kilobytes(1); + U32Kilobits Kb(KB); + U32Bits b(KB); + ensure("KB -> Kb conversion", Kb.value() == 8); + ensure("KB -> b conversion", b.value() == 8 * 1024); + + U32Days days(1); + U32Hours hours(days); + U32Minutes minutes(days); + U32Seconds seconds(days); + U32Milliseconds ms(days); + + ensure("days -> hours conversion", hours.value() == 24); + ensure("days -> minutes conversion", minutes.value() == 24 * 60); + ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); + ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); + + U32Kilometers km(1); + U32Meters m(km); + U32Centimeters cm(km); + U32Millimeters mm(km); + + ensure("km -> m conversion", m.value() == 1000); + ensure("km -> cm conversion", cm.value() == 1000 * 100); + ensure("km -> mm conversion", mm.value() == 1000 * 1000); + + U32Gigahertz GHz(1); + U32Megahertz MHz(GHz); + U32Kilohertz KHz(GHz); + U32Hertz Hz(GHz); + + ensure("GHz -> MHz conversion", MHz.value() == 1000); + ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); + ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); + + F32Radians rad(6.2831853071795f); + S32Degrees deg(rad); + ensure("radians -> degrees conversion", deg.value() == 360); + + F32Percent percent(50); + F32Ratio ratio(percent); + ensure("percent -> ratio conversion", ratio.value() == 0.5f); + + U32Kilotriangles ktris(1); + U32Triangles tris(ktris); + ensure("kilotriangles -> triangles conversion", tris.value() == 1000); + } + + bool value_near(F32 value, F32 target, F32 threshold) + { + return fabsf(value - target) < threshold; + } + + // linear transforms + template<> template<> + void units_object_t::test<10>() + { + F32Celcius float_celcius(100); + F32Fahrenheit float_fahrenheit(float_celcius); + ensure("floating point celcius -> fahrenheit conversion using linear transform", value_near(float_fahrenheit.value(), 212, 0.1f) ); + + float_celcius = float_fahrenheit; + ensure("floating point fahrenheit -> celcius conversion using linear transform (round trip)", value_near(float_celcius.value(), 100.f, 0.1f) ); + + S32Celcius int_celcius(100); + S32Fahrenheit int_fahrenheit(int_celcius); + ensure("integer celcius -> fahrenheit conversion using linear transform", int_fahrenheit.value() == 212); + + int_celcius = int_fahrenheit; + ensure("integer fahrenheit -> celcius conversion using linear transform (round trip)", int_celcius.value() == 100); + } } diff --git a/indra/llcommon/tests/lluri_test.cpp b/indra/llcommon/tests/lluri_test.cpp index 1a4c6641b9..b48dd3ef1b 100644 --- a/indra/llcommon/tests/lluri_test.cpp +++ b/indra/llcommon/tests/lluri_test.cpp @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,359 +34,359 @@ namespace tut { - struct URITestData { - void checkParts(const LLURI& u, - const char* expectedScheme, - const char* expectedOpaque, - const char* expectedAuthority, - const char* expectedPath, - const char* expectedQuery = "") - { - ensure_equals("scheme", u.scheme(), expectedScheme); - ensure_equals("opaque", u.opaque(), expectedOpaque); - ensure_equals("authority", u.authority(), expectedAuthority); - ensure_equals("path", u.path(), expectedPath); - ensure_equals("query", u.query(), expectedQuery); - } - - void escapeRoundTrip(const std::string& uri_raw_1) - { - std::string uri_esc_1(LLURI::escape(uri_raw_1)); - std::string uri_raw_2(LLURI::unescape(uri_esc_1)); - ensure_equals("escape/unescape raw", uri_raw_2, uri_raw_1); - std::string uri_esc_2(LLURI::escape(uri_raw_2)); - ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1); - } - }; - - typedef test_group<URITestData> URITestGroup; - typedef URITestGroup::object URITestObject; - - URITestGroup uriTestGroup("LLURI"); - - template<> template<> - void URITestObject::test<1>() - { - LLURI u("http://abc.com/def/ghi?x=37&y=hello"); - - ensure_equals("scheme", u.scheme(), "http"); - ensure_equals("authority", u.authority(), "abc.com"); - ensure_equals("path", u.path(), "/def/ghi"); - ensure_equals("query", u.query(), "x=37&y=hello"); - - ensure_equals("host name", u.hostName(), "abc.com"); - ensure_equals("host port", u.hostPort(), 80); - - LLSD query = u.queryMap(); - ensure_equals("query x", query["x"].asInteger(), 37); - ensure_equals("query y", query["y"].asString(), "hello"); - - query = LLURI::queryMap("x=22.23&y=https://lindenlab.com/"); - ensure_equals("query x", query["x"].asReal(), 22.23); - ensure_equals("query y", query["y"].asURI().asString(), "https://lindenlab.com/"); - } - - template<> template<> - void URITestObject::test<2>() - { - set_test_name("empty string"); - checkParts(LLURI(""), "", "", "", ""); - } - - template<> template<> - void URITestObject::test<3>() - { - set_test_name("no scheme"); - checkParts(LLURI("foo"), "", "foo", "", ""); - checkParts(LLURI("foo%3A"), "", "foo:", "", ""); - } - - template<> template<> - void URITestObject::test<4>() - { - set_test_name("scheme w/o paths"); - checkParts(LLURI("mailto:zero@ll.com"), - "mailto", "zero@ll.com", "", ""); - checkParts(LLURI("silly://abc/def?foo"), - "silly", "//abc/def?foo", "", ""); - } - - template<> template<> - void URITestObject::test<5>() - { - set_test_name("authority section"); - checkParts(LLURI("http:///"), - "http", "///", "", "/"); - - checkParts(LLURI("http://abc"), - "http", "//abc", "abc", ""); - - checkParts(LLURI("http://a%2Fb/cd"), - "http", "//a/b/cd", "a/b", "/cd"); - - checkParts(LLURI("http://host?"), - "http", "//host?", "host", ""); - } - - template<> template<> - void URITestObject::test<6>() - { - set_test_name("path section"); - checkParts(LLURI("http://host/a/b/"), - "http", "//host/a/b/", "host", "/a/b/"); - - checkParts(LLURI("http://host/a%3Fb/"), - "http", "//host/a?b/", "host", "/a?b/"); - - checkParts(LLURI("http://host/a:b/"), - "http", "//host/a:b/", "host", "/a:b/"); - } - - template<> template<> - void URITestObject::test<7>() - { - set_test_name("query string"); - checkParts(LLURI("http://host/?"), - "http", "//host/?", "host", "/", ""); - - checkParts(LLURI("http://host/?x"), - "http", "//host/?x", "host", "/", "x"); - - checkParts(LLURI("http://host/??"), - "http", "//host/??", "host", "/", "?"); - - checkParts(LLURI("http://host/?%3F"), - "http", "//host/??", "host", "/", "?"); - } - - template<> template<> - void URITestObject::test<8>() - { - LLSD path; - path.append("x"); - path.append("123"); - checkParts(LLURI::buildHTTP("host", path), - "http", "//host/x/123", "host", "/x/123"); - - LLSD query; - query["123"] = "12"; - query["abcd"] = "abc"; - checkParts(LLURI::buildHTTP("host", path, query), - "http", "//host/x/123?123=12&abcd=abc", - "host", "/x/123", "123=12&abcd=abc"); - - ensure_equals(LLURI::buildHTTP("host", "").asString(), - "http://host"); - ensure_equals(LLURI::buildHTTP("host", "/").asString(), - "http://host/"); - ensure_equals(LLURI::buildHTTP("host", "//").asString(), - "http://host/"); - ensure_equals(LLURI::buildHTTP("host", "dir name").asString(), - "http://host/dir%20name"); - ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(), - "http://host/dir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(), - "http://host/dir%20name"); - ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(), - "http://host/dir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(), - "http://host/dir%20name/subdir%20name"); - ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(), - "http://host/dir%20name/subdir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(), - "http://host/dir%20name/subdir%20name"); - ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(), - "http://host/dir%20name/subdir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(), - "http://host/dir%20name/subdir%20name/"); - } - - template<> template<> - void URITestObject::test<9>() - { - set_test_name("test unescaped path components"); - LLSD path; - path.append("x@*//*$&^"); - path.append("123"); - checkParts(LLURI::buildHTTP("host", path), - "http", "//host/x@*//*$&^/123", "host", "/x@*//*$&^/123"); - } - - template<> template<> - void URITestObject::test<10>() - { - set_test_name("test unescaped query components"); - LLSD path; - path.append("x"); - path.append("123"); - LLSD query; - query["123"] = "?&*#//"; - query["**@&?//"] = "abc"; - checkParts(LLURI::buildHTTP("host", path, query), - "http", "//host/x/123?**@&?//=abc&123=?&*#//", - "host", "/x/123", "**@&?//=abc&123=?&*#//"); - } - - template<> template<> - void URITestObject::test<11>() - { - set_test_name("test unescaped host components"); - LLSD path; - path.append("x"); - path.append("123"); - LLSD query; - query["123"] = "12"; - query["abcd"] = "abc"; - checkParts(LLURI::buildHTTP("hi123*33--}{:portstuffs", path, query), - "http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc", - "hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc"); - } - - template<> template<> - void URITestObject::test<12>() - { - set_test_name("test funky host_port values that are actually prefixes"); - - checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()), - "http", "//example.com:8080", - "example.com:8080", ""); - - checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()), - "http", "//example.com:8080/", - "example.com:8080", "/"); - - checkParts(LLURI::buildHTTP("http://example.com:8080/a/b", LLSD()), - "http", "//example.com:8080/a/b", - "example.com:8080", "/a/b"); - } - - template<> template<> - void URITestObject::test<13>() - { - const std::string unreserved = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789" - "-._~"; - set_test_name("test escape"); - ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67"); - ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40"); - ensure_equals("escaping as query variable", - LLURI::escape("http://10.0.1.4:12032/agent/god/agent-id/map/layer/?resume=http://station3.ll.com:12032/agent/203ad6df-b522-491d-ba48-4e24eb57aeff/send-postcard", unreserved + ":@!$'()*+,="), - "http:%2F%2F10.0.1.4:12032%2Fagent%2Fgod%2Fagent-id%2Fmap%2Flayer%2F%3Fresume=http:%2F%2Fstation3.ll.com:12032%2Fagent%2F203ad6df-b522-491d-ba48-4e24eb57aeff%2Fsend-postcard"); - // French cedilla (C with squiggle, like in the word Francais) is UTF-8 C3 A7 + struct URITestData { + void checkParts(const LLURI& u, + const char* expectedScheme, + const char* expectedOpaque, + const char* expectedAuthority, + const char* expectedPath, + const char* expectedQuery = "") + { + ensure_equals("scheme", u.scheme(), expectedScheme); + ensure_equals("opaque", u.opaque(), expectedOpaque); + ensure_equals("authority", u.authority(), expectedAuthority); + ensure_equals("path", u.path(), expectedPath); + ensure_equals("query", u.query(), expectedQuery); + } + + void escapeRoundTrip(const std::string& uri_raw_1) + { + std::string uri_esc_1(LLURI::escape(uri_raw_1)); + std::string uri_raw_2(LLURI::unescape(uri_esc_1)); + ensure_equals("escape/unescape raw", uri_raw_2, uri_raw_1); + std::string uri_esc_2(LLURI::escape(uri_raw_2)); + ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1); + } + }; + + typedef test_group<URITestData> URITestGroup; + typedef URITestGroup::object URITestObject; + + URITestGroup uriTestGroup("LLURI"); + + template<> template<> + void URITestObject::test<1>() + { + LLURI u("http://abc.com/def/ghi?x=37&y=hello"); + + ensure_equals("scheme", u.scheme(), "http"); + ensure_equals("authority", u.authority(), "abc.com"); + ensure_equals("path", u.path(), "/def/ghi"); + ensure_equals("query", u.query(), "x=37&y=hello"); + + ensure_equals("host name", u.hostName(), "abc.com"); + ensure_equals("host port", u.hostPort(), 80); + + LLSD query = u.queryMap(); + ensure_equals("query x", query["x"].asInteger(), 37); + ensure_equals("query y", query["y"].asString(), "hello"); + + query = LLURI::queryMap("x=22.23&y=https://lindenlab.com/"); + ensure_equals("query x", query["x"].asReal(), 22.23); + ensure_equals("query y", query["y"].asURI().asString(), "https://lindenlab.com/"); + } + + template<> template<> + void URITestObject::test<2>() + { + set_test_name("empty string"); + checkParts(LLURI(""), "", "", "", ""); + } + + template<> template<> + void URITestObject::test<3>() + { + set_test_name("no scheme"); + checkParts(LLURI("foo"), "", "foo", "", ""); + checkParts(LLURI("foo%3A"), "", "foo:", "", ""); + } + + template<> template<> + void URITestObject::test<4>() + { + set_test_name("scheme w/o paths"); + checkParts(LLURI("mailto:zero@ll.com"), + "mailto", "zero@ll.com", "", ""); + checkParts(LLURI("silly://abc/def?foo"), + "silly", "//abc/def?foo", "", ""); + } + + template<> template<> + void URITestObject::test<5>() + { + set_test_name("authority section"); + checkParts(LLURI("http:///"), + "http", "///", "", "/"); + + checkParts(LLURI("http://abc"), + "http", "//abc", "abc", ""); + + checkParts(LLURI("http://a%2Fb/cd"), + "http", "//a/b/cd", "a/b", "/cd"); + + checkParts(LLURI("http://host?"), + "http", "//host?", "host", ""); + } + + template<> template<> + void URITestObject::test<6>() + { + set_test_name("path section"); + checkParts(LLURI("http://host/a/b/"), + "http", "//host/a/b/", "host", "/a/b/"); + + checkParts(LLURI("http://host/a%3Fb/"), + "http", "//host/a?b/", "host", "/a?b/"); + + checkParts(LLURI("http://host/a:b/"), + "http", "//host/a:b/", "host", "/a:b/"); + } + + template<> template<> + void URITestObject::test<7>() + { + set_test_name("query string"); + checkParts(LLURI("http://host/?"), + "http", "//host/?", "host", "/", ""); + + checkParts(LLURI("http://host/?x"), + "http", "//host/?x", "host", "/", "x"); + + checkParts(LLURI("http://host/??"), + "http", "//host/??", "host", "/", "?"); + + checkParts(LLURI("http://host/?%3F"), + "http", "//host/??", "host", "/", "?"); + } + + template<> template<> + void URITestObject::test<8>() + { + LLSD path; + path.append("x"); + path.append("123"); + checkParts(LLURI::buildHTTP("host", path), + "http", "//host/x/123", "host", "/x/123"); + + LLSD query; + query["123"] = "12"; + query["abcd"] = "abc"; + checkParts(LLURI::buildHTTP("host", path, query), + "http", "//host/x/123?123=12&abcd=abc", + "host", "/x/123", "123=12&abcd=abc"); + + ensure_equals(LLURI::buildHTTP("host", "").asString(), + "http://host"); + ensure_equals(LLURI::buildHTTP("host", "/").asString(), + "http://host/"); + ensure_equals(LLURI::buildHTTP("host", "//").asString(), + "http://host/"); + ensure_equals(LLURI::buildHTTP("host", "dir name").asString(), + "http://host/dir%20name"); + ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(), + "http://host/dir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(), + "http://host/dir%20name"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(), + "http://host/dir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(), + "http://host/dir%20name/subdir%20name"); + ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(), + "http://host/dir%20name/subdir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(), + "http://host/dir%20name/subdir%20name"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(), + "http://host/dir%20name/subdir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(), + "http://host/dir%20name/subdir%20name/"); + } + + template<> template<> + void URITestObject::test<9>() + { + set_test_name("test unescaped path components"); + LLSD path; + path.append("x@*//*$&^"); + path.append("123"); + checkParts(LLURI::buildHTTP("host", path), + "http", "//host/x@*//*$&^/123", "host", "/x@*//*$&^/123"); + } + + template<> template<> + void URITestObject::test<10>() + { + set_test_name("test unescaped query components"); + LLSD path; + path.append("x"); + path.append("123"); + LLSD query; + query["123"] = "?&*#//"; + query["**@&?//"] = "abc"; + checkParts(LLURI::buildHTTP("host", path, query), + "http", "//host/x/123?**@&?//=abc&123=?&*#//", + "host", "/x/123", "**@&?//=abc&123=?&*#//"); + } + + template<> template<> + void URITestObject::test<11>() + { + set_test_name("test unescaped host components"); + LLSD path; + path.append("x"); + path.append("123"); + LLSD query; + query["123"] = "12"; + query["abcd"] = "abc"; + checkParts(LLURI::buildHTTP("hi123*33--}{:portstuffs", path, query), + "http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc", + "hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc"); + } + + template<> template<> + void URITestObject::test<12>() + { + set_test_name("test funky host_port values that are actually prefixes"); + + checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()), + "http", "//example.com:8080", + "example.com:8080", ""); + + checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()), + "http", "//example.com:8080/", + "example.com:8080", "/"); + + checkParts(LLURI::buildHTTP("http://example.com:8080/a/b", LLSD()), + "http", "//example.com:8080/a/b", + "example.com:8080", "/a/b"); + } + + template<> template<> + void URITestObject::test<13>() + { + const std::string unreserved = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._~"; + set_test_name("test escape"); + ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67"); + ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40"); + ensure_equals("escaping as query variable", + LLURI::escape("http://10.0.1.4:12032/agent/god/agent-id/map/layer/?resume=http://station3.ll.com:12032/agent/203ad6df-b522-491d-ba48-4e24eb57aeff/send-postcard", unreserved + ":@!$'()*+,="), + "http:%2F%2F10.0.1.4:12032%2Fagent%2Fgod%2Fagent-id%2Fmap%2Flayer%2F%3Fresume=http:%2F%2Fstation3.ll.com:12032%2Fagent%2F203ad6df-b522-491d-ba48-4e24eb57aeff%2Fsend-postcard"); + // French cedilla (C with squiggle, like in the word Francais) is UTF-8 C3 A7 #if LL_WINDOWS #pragma warning(disable: 4309) #endif - std::string cedilla; - cedilla.push_back( (char)0xC3 ); - cedilla.push_back( (char)0xA7 ); - ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7"); - } - - - template<> template<> - void URITestObject::test<14>() - { - set_test_name("make sure escape and unescape of empty strings return empty strings."); - std::string uri_esc(LLURI::escape("")); - ensure("escape string empty", uri_esc.empty()); - std::string uri_raw(LLURI::unescape("")); - ensure("unescape string empty", uri_raw.empty()); - } - - template<> template<> - void URITestObject::test<15>() - { - set_test_name("do some round-trip tests"); - escapeRoundTrip("http://secondlife.com"); - escapeRoundTrip("http://secondlife.com/url with spaces"); - escapeRoundTrip("http://bad[domain]name.com/"); - escapeRoundTrip("ftp://bill.gates@ms/micro$oft.com/c:\\autoexec.bat"); - escapeRoundTrip(""); - } - - template<> template<> - void URITestObject::test<16>() - { - set_test_name("Test the default escaping"); - // yes -- this mangles the url. This is expected behavior - std::string simple("http://secondlife.com"); - ensure_equals( - "simple http", - LLURI::escape(simple), - "http%3A%2F%2Fsecondlife.com"); - ensure_equals( - "needs escape", - LLURI::escape("http://get.secondlife.com/windows viewer"), - "http%3A%2F%2Fget.secondlife.com%2Fwindows%20viewer"); - } - - template<> template<> - void URITestObject::test<17>() - { - set_test_name("do some round-trip tests with very long strings."); - escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six"); - escapeRoundTrip( - "'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale" - "\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tf" - "aces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204" - "\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffff" - "ff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t" - "0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t" - "\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t" - "\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreat" - "or_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundra" - "dius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0" - "\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f" - "25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000" - "000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1" - ".57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemI" - "D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"); - } - - - template<> template<> - void URITestObject::test<18>() - { - LLURI u("secondlife:///app/login?first_name=Testert4&last_name=Tester&web_login_key=test"); - // if secondlife is the scheme, LLURI should parse /app/login as path, with no authority - ensure_equals("scheme", u.scheme(), "secondlife"); - ensure_equals("authority", u.authority(), ""); - ensure_equals("path", u.path(), "/app/login"); - ensure_equals("pathmap", u.pathArray()[0].asString(), "app"); - ensure_equals("pathmap", u.pathArray()[1].asString(), "login"); - ensure_equals("query", u.query(), "first_name=Testert4&last_name=Tester&web_login_key=test"); - ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester"); - - u = LLURI("secondlife://Da Boom/128/128/128"); - // if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority - ensure_equals("scheme", u.scheme(), "secondlife"); - ensure_equals("authority", u.authority(), "Da Boom"); - ensure_equals("path", u.path(), "/128/128/128"); - ensure_equals("pathmap", u.pathArray()[0].asString(), "128"); - ensure_equals("pathmap", u.pathArray()[1].asString(), "128"); - ensure_equals("pathmap", u.pathArray()[2].asString(), "128"); - ensure_equals("query", u.query(), ""); - } - - template<> template<> - void URITestObject::test<19>() - { - set_test_name("Parse about: schemes"); - LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78"); - ensure_equals("scheme", u.scheme(), "about"); - ensure_equals("authority", u.authority(), ""); - ensure_equals("path", u.path(), "blank"); - ensure_equals("pathmap", u.pathArray()[0].asString(), "blank"); - ensure_equals("query", u.query(), "redirect-http-hack=secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); - ensure_equals("query map element", u.queryMap()["redirect-http-hack"].asString(), "secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); - } - - template<> template<> - void URITestObject::test<20>() - { + std::string cedilla; + cedilla.push_back( (char)0xC3 ); + cedilla.push_back( (char)0xA7 ); + ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7"); + } + + + template<> template<> + void URITestObject::test<14>() + { + set_test_name("make sure escape and unescape of empty strings return empty strings."); + std::string uri_esc(LLURI::escape("")); + ensure("escape string empty", uri_esc.empty()); + std::string uri_raw(LLURI::unescape("")); + ensure("unescape string empty", uri_raw.empty()); + } + + template<> template<> + void URITestObject::test<15>() + { + set_test_name("do some round-trip tests"); + escapeRoundTrip("http://secondlife.com"); + escapeRoundTrip("http://secondlife.com/url with spaces"); + escapeRoundTrip("http://bad[domain]name.com/"); + escapeRoundTrip("ftp://bill.gates@ms/micro$oft.com/c:\\autoexec.bat"); + escapeRoundTrip(""); + } + + template<> template<> + void URITestObject::test<16>() + { + set_test_name("Test the default escaping"); + // yes -- this mangles the url. This is expected behavior + std::string simple("http://secondlife.com"); + ensure_equals( + "simple http", + LLURI::escape(simple), + "http%3A%2F%2Fsecondlife.com"); + ensure_equals( + "needs escape", + LLURI::escape("http://get.secondlife.com/windows viewer"), + "http%3A%2F%2Fget.secondlife.com%2Fwindows%20viewer"); + } + + template<> template<> + void URITestObject::test<17>() + { + set_test_name("do some round-trip tests with very long strings."); + escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six"); + escapeRoundTrip( + "'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale" + "\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tf" + "aces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204" + "\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffff" + "ff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t" + "0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t" + "\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t" + "\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreat" + "or_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundra" + "dius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0" + "\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f" + "25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000" + "000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1" + ".57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemI" + "D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"); + } + + + template<> template<> + void URITestObject::test<18>() + { + LLURI u("secondlife:///app/login?first_name=Testert4&last_name=Tester&web_login_key=test"); + // if secondlife is the scheme, LLURI should parse /app/login as path, with no authority + ensure_equals("scheme", u.scheme(), "secondlife"); + ensure_equals("authority", u.authority(), ""); + ensure_equals("path", u.path(), "/app/login"); + ensure_equals("pathmap", u.pathArray()[0].asString(), "app"); + ensure_equals("pathmap", u.pathArray()[1].asString(), "login"); + ensure_equals("query", u.query(), "first_name=Testert4&last_name=Tester&web_login_key=test"); + ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester"); + + u = LLURI("secondlife://Da Boom/128/128/128"); + // if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority + ensure_equals("scheme", u.scheme(), "secondlife"); + ensure_equals("authority", u.authority(), "Da Boom"); + ensure_equals("path", u.path(), "/128/128/128"); + ensure_equals("pathmap", u.pathArray()[0].asString(), "128"); + ensure_equals("pathmap", u.pathArray()[1].asString(), "128"); + ensure_equals("pathmap", u.pathArray()[2].asString(), "128"); + ensure_equals("query", u.query(), ""); + } + + template<> template<> + void URITestObject::test<19>() + { + set_test_name("Parse about: schemes"); + LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78"); + ensure_equals("scheme", u.scheme(), "about"); + ensure_equals("authority", u.authority(), ""); + ensure_equals("path", u.path(), "blank"); + ensure_equals("pathmap", u.pathArray()[0].asString(), "blank"); + ensure_equals("query", u.query(), "redirect-http-hack=secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); + ensure_equals("query map element", u.queryMap()["redirect-http-hack"].asString(), "secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); + } + + template<> template<> + void URITestObject::test<20>() + { set_test_name("escapePathAndData uri test"); // Basics scheme:[//authority]path[?query][#fragment] diff --git a/indra/llcommon/tests/stringize_test.cpp b/indra/llcommon/tests/stringize_test.cpp index 2a4ed44a67..a3ce7f8e3d 100644 --- a/indra/llcommon/tests/stringize_test.cpp +++ b/indra/llcommon/tests/stringize_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-12 * @brief Test of stringize.h - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -78,7 +78,7 @@ namespace tut float f; double d; std::string abc; - std::wstring def; + std::wstring def; LLSD llsd; }; typedef test_group<stringize_data> stringize_group; diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp index 8851590189..f2f17dd2e6 100644 --- a/indra/llcommon/tests/threadsafeschedule_test.cpp +++ b/indra/llcommon/tests/threadsafeschedule_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-04 * @brief Test for threadsafeschedule. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/tuple_test.cpp b/indra/llcommon/tests/tuple_test.cpp index af94e2086c..aff129753f 100644 --- a/indra/llcommon/tests/tuple_test.cpp +++ b/indra/llcommon/tests/tuple_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-04 * @brief Test for tuple. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp index df16f4a46e..209b6b868c 100644 --- a/indra/llcommon/tests/workqueue_test.cpp +++ b/indra/llcommon/tests/workqueue_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-07 * @brief Test for workqueue. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 6978c296b3..9cd2c69b11 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-11 * @brief Define a class useful for unit tests that engage llerrs (LL_ERRS) functionality - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -117,9 +117,9 @@ class CaptureLogRecorder : public LLError::Recorder, public boost::noncopyable { public: CaptureLogRecorder() - : LLError::Recorder(), - boost::noncopyable(), - mMessages() + : LLError::Recorder(), + boost::noncopyable(), + mMessages() { } diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index c48989358e..302bbe6f8d 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-21 * @brief Implementation for threadpool. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index 74056aea17..0eb1891754 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -4,7 +4,7 @@ * @date 2021-10-21 * @brief ThreadPool configures a WorkQueue along with a pool of threads to * service it. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/threadpool_fwd.h b/indra/llcommon/threadpool_fwd.h index 1aa3c4a0e2..50e212ef05 100644 --- a/indra/llcommon/threadpool_fwd.h +++ b/indra/llcommon/threadpool_fwd.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-12-09 * @brief Forward declarations for ThreadPool et al. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h index 92bc7da940..0c7f583819 100644 --- a/indra/llcommon/threadsafeschedule.h +++ b/indra/llcommon/threadsafeschedule.h @@ -4,7 +4,7 @@ * @date 2021-10-02 * @brief ThreadSafeSchedule is an ordered queue in which every item has an * associated timestamp. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ @@ -18,7 +18,7 @@ #include "llthreadsafequeue.h" #include "tuple.h" #include <chrono> -#include <tuple> +#include <tuple> namespace LL { diff --git a/indra/llcommon/timer.h b/indra/llcommon/timer.h index 82d19c2d32..aaa0cf0775 100644 --- a/indra/llcommon/timer.h +++ b/indra/llcommon/timer.h @@ -1,25 +1,25 @@ -/** +/** * @file timer.h * @brief Legacy wrapper header. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tuple.h b/indra/llcommon/tuple.h index bfe7e3c2ba..21337650ef 100644 --- a/indra/llcommon/tuple.h +++ b/indra/llcommon/tuple.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-04 * @brief A couple tuple utilities - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/u64.cpp b/indra/llcommon/u64.cpp index 02c2c15d26..1d39d3c3e5 100644 --- a/indra/llcommon/u64.cpp +++ b/indra/llcommon/u64.cpp @@ -1,25 +1,25 @@ -/** +/** * @file u64.cpp * @brief Utilities to deal with U64s. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,75 +31,75 @@ U64 str_to_U64(const std::string& str) { - U64 result = 0; - const char *aptr = strpbrk(str.c_str(),"0123456789"); + U64 result = 0; + const char *aptr = strpbrk(str.c_str(),"0123456789"); - if (!aptr) - { - LL_WARNS() << "str_to_U64: Bad string to U64 conversion attempt: format\n" << LL_ENDL; - } - else - { - while ((*aptr >= '0') && (*aptr <= '9')) - { - result = result*10 + (*aptr++ - '0'); - } - } - return (result); + if (!aptr) + { + LL_WARNS() << "str_to_U64: Bad string to U64 conversion attempt: format\n" << LL_ENDL; + } + else + { + while ((*aptr >= '0') && (*aptr <= '9')) + { + result = result*10 + (*aptr++ - '0'); + } + } + return (result); } -std::string U64_to_str(U64 value) +std::string U64_to_str(U64 value) { - std::string res; - U32 part1,part2,part3; - - part3 = (U32)(value % (U64)10000000); - - value /= 10000000; - part2 = (U32)(value % (U64)10000000); - - value /= 10000000; - part1 = (U32)(value % (U64)10000000); - - // three cases to avoid leading zeroes unless necessary - - if (part1) - { - res = llformat("%u%07u%07u",part1,part2,part3); - } - else if (part2) - { - res = llformat("%u%07u",part2,part3); - } - else - { - res = llformat("%u",part3); - } - return res; -} + std::string res; + U32 part1,part2,part3; + + part3 = (U32)(value % (U64)10000000); + + value /= 10000000; + part2 = (U32)(value % (U64)10000000); + + value /= 10000000; + part1 = (U32)(value % (U64)10000000); + + // three cases to avoid leading zeroes unless necessary + + if (part1) + { + res = llformat("%u%07u%07u",part1,part2,part3); + } + else if (part2) + { + res = llformat("%u%07u",part2,part3); + } + else + { + res = llformat("%u",part3); + } + return res; +} -char* U64_to_str(U64 value, char* result, S32 result_size) +char* U64_to_str(U64 value, char* result, S32 result_size) { - std::string res = U64_to_str(value); - LLStringUtil::copy(result, res.c_str(), result_size); - return result; + std::string res = U64_to_str(value); + LLStringUtil::copy(result, res.c_str(), result_size); + return result; } F64 U64_to_F64(const U64 value) { - S64 top_bits = (S64)(value >> 1); - F64 result = (F64)top_bits; - result *= 2.f; - result += (U32)(value & 0x01); - return result; + S64 top_bits = (S64)(value >> 1); + F64 result = (F64)top_bits; + result *= 2.f; + result += (U32)(value & 0x01); + return result; } -U64 llstrtou64(const char* str, char** end, S32 base) +U64 llstrtou64(const char* str, char** end, S32 base) { #ifdef LL_WINDOWS - return _strtoui64(str,end,base); + return _strtoui64(str,end,base); #else - return strtoull(str,end,base); + return strtoull(str,end,base); #endif } diff --git a/indra/llcommon/u64.h b/indra/llcommon/u64.h index 75c8a59136..d70477feb0 100644 --- a/indra/llcommon/u64.h +++ b/indra/llcommon/u64.h @@ -1,25 +1,25 @@ -/** +/** * @file u64.h * @brief Utilities to deal with U64s. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index cf80ce0656..6066e74fb5 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-06 * @brief Implementation for WorkQueue. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index ec0700a718..9d7bbfbf7a 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-09-30 * @brief Queue used for inter-thread work passing. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ |