From f6da5ba9d31e2273e5f66a4a02350b3e1548d41c Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Mon, 17 Jun 2013 06:42:49 -0700 Subject: [PATCH] Add beast_basics module --- .../Builds/VisualStudio2012/beast.vcxproj | 160 ++++ .../VisualStudio2012/beast.vcxproj.filters | 264 +++++ Subtrees/beast/ReadMe.md | 2 +- .../modules/beast_basics/beast_basics.cpp | 89 ++ .../beast/modules/beast_basics/beast_basics.h | 497 ++++++++++ .../beast_basics/containers/beast_List.h | 809 ++++++++++++++++ .../containers/beast_LockFreeQueue.h | 239 +++++ .../containers/beast_LockFreeStack.h | 179 ++++ .../containers/beast_SharedTable.h | 226 +++++ .../containers/beast_SortedLookupTable.h | 169 ++++ .../diagnostic/beast_CatchAny.cpp | 289 ++++++ .../beast_basics/diagnostic/beast_CatchAny.h | 69 ++ .../beast_basics/diagnostic/beast_Debug.cpp | 268 ++++++ .../beast_basics/diagnostic/beast_Debug.h | 69 ++ .../beast_basics/diagnostic/beast_Error.cpp | 256 +++++ .../beast_basics/diagnostic/beast_Error.h | 139 +++ .../diagnostic/beast_FPUFlags.cpp | 53 ++ .../beast_basics/diagnostic/beast_FPUFlags.h | 348 +++++++ .../diagnostic/beast_LeakChecked.cpp | 104 ++ .../diagnostic/beast_LeakChecked.h | 184 ++++ .../beast_basics/diagnostic/beast_SafeBool.h | 104 ++ .../beast_basics/diagnostic/beast_Throw.h | 51 + .../events/beast_OncePerSecond.cpp | 124 +++ .../beast_basics/events/beast_OncePerSecond.h | 77 ++ .../events/beast_PerformedAtExit.cpp | 79 ++ .../events/beast_PerformedAtExit.h | 63 ++ .../modules/beast_basics/functor/beast_Bind.h | 109 +++ .../beast_basics/functor/beast_Function.h | 279 ++++++ .../beast_basics/math/beast_Interval.h | 400 ++++++++ .../modules/beast_basics/math/beast_Math.h | 97 ++ .../beast_basics/math/beast_MurmurHash.cpp | 506 ++++++++++ .../beast_basics/math/beast_MurmurHash.h | 79 ++ .../beast_basics/memory/beast_AllocatedBy.h | 76 ++ .../beast_basics/memory/beast_AtomicCounter.h | 96 ++ .../beast_basics/memory/beast_AtomicFlag.h | 115 +++ .../beast_basics/memory/beast_AtomicPointer.h | 146 +++ .../beast_basics/memory/beast_AtomicState.h | 114 +++ .../beast_basics/memory/beast_CacheLine.h | 491 ++++++++++ .../beast_basics/memory/beast_FifoFreeStore.h | 54 ++ .../memory/beast_FifoFreeStoreWithTLS.cpp | 207 ++++ .../memory/beast_FifoFreeStoreWithTLS.h | 80 ++ .../memory/beast_FifoFreeStoreWithoutTLS.cpp | 254 +++++ .../memory/beast_FifoFreeStoreWithoutTLS.h | 80 ++ .../memory/beast_GlobalFifoFreeStore.h | 78 ++ .../memory/beast_GlobalPagedFreeStore.cpp | 55 ++ .../memory/beast_GlobalPagedFreeStore.h | 74 ++ .../memory/beast_MemoryAlignment.h | 73 ++ .../memory/beast_PagedFreeStore.cpp | 239 +++++ .../memory/beast_PagedFreeStore.h | 106 +++ .../memory/beast_RefCountedSingleton.h | 212 +++++ .../beast_basics/memory/beast_StaticObject.h | 200 ++++ .../beast_basics/memory/beast_Uncopyable.h | 51 + .../native/beast_posix_FPUFlags.cpp | 13 + .../native/beast_posix_Threads.cpp | 31 + .../native/beast_win32_FPUFlags.cpp | 189 ++++ .../native/beast_win32_Threads.cpp | 31 + .../beast_basics/threads/beast_CallQueue.cpp | 166 ++++ .../beast_basics/threads/beast_CallQueue.h | 555 +++++++++++ .../threads/beast_ConcurrentObject.cpp | 89 ++ .../threads/beast_ConcurrentObject.h | 92 ++ .../threads/beast_ConcurrentState.h | 311 ++++++ .../threads/beast_GlobalThreadGroup.h | 62 ++ .../threads/beast_InterruptibleThread.cpp | 238 +++++ .../threads/beast_InterruptibleThread.h | 201 ++++ .../beast_basics/threads/beast_Listeners.cpp | 778 +++++++++++++++ .../beast_basics/threads/beast_Listeners.h | 900 ++++++++++++++++++ .../threads/beast_ManualCallQueue.cpp | 54 ++ .../threads/beast_ManualCallQueue.h | 108 +++ .../threads/beast_ParallelFor.cpp | 76 ++ .../beast_basics/threads/beast_ParallelFor.h | 504 ++++++++++ .../threads/beast_ReadWriteMutex.cpp | 111 +++ .../threads/beast_ReadWriteMutex.h | 159 ++++ .../beast_basics/threads/beast_Semaphore.cpp | 130 +++ .../beast_basics/threads/beast_Semaphore.h | 91 ++ .../beast_basics/threads/beast_SerialFor.h | 84 ++ .../threads/beast_SharedObject.cpp | 49 + .../beast_basics/threads/beast_SharedObject.h | 323 +++++++ .../beast_basics/threads/beast_SpinDelay.h | 57 ++ .../threads/beast_ThreadGroup.cpp | 118 +++ .../beast_basics/threads/beast_ThreadGroup.h | 246 +++++ .../threads/beast_ThreadWithCallQueue.cpp | 158 +++ .../threads/beast_ThreadWithCallQueue.h | 157 +++ .../beast/modules/beast_core/beast_core.h | 6 +- .../beast_core/containers/beast_Array.h | 2 +- .../beast_core/containers/beast_OwnedArray.h | 6 +- .../containers/beast_ReferenceCountedArray.h | 2 +- .../beast_core/containers/beast_SortedSet.h | 2 +- .../beast_core/containers/beast_Variant.cpp | 4 +- .../modules/beast_core/files/beast_File.cpp | 6 +- .../beast_core/files/beast_TemporaryFile.cpp | 4 +- .../modules/beast_core/json/beast_JSON.cpp | 2 +- .../beast_core/maths/beast_BigInteger.cpp | 6 +- .../beast_core/maths/beast_Expression.cpp | 4 +- .../modules/beast_core/memory/beast_Atomic.h | 16 +- .../memory/beast_LeakedObjectDetector.h | 4 +- .../beast_core/native/beast_android_Files.cpp | 2 +- .../native/beast_android_JNIHelpers.h | 2 +- .../native/beast_android_SystemStats.cpp | 4 +- .../beast_core/native/beast_linux_Files.cpp | 4 +- .../beast_core/native/beast_linux_Network.cpp | 2 +- .../beast_core/native/beast_linux_Threads.cpp | 2 +- .../beast_core/native/beast_mac_Files.mm | 2 +- .../beast_core/native/beast_mac_Network.mm | 2 +- .../native/beast_mac_SystemStats.mm | 2 +- .../beast_core/native/beast_mac_Threads.mm | 4 +- .../native/beast_posix_SharedCode.h | 6 +- .../native/beast_win32_ComSmartPtr.h | 2 +- .../beast_core/native/beast_win32_Files.cpp | 2 +- .../native/beast_win32_SystemStats.cpp | 6 +- .../beast_core/native/beast_win32_Threads.cpp | 8 +- .../beast_core/network/beast_Socket.cpp | 2 +- .../beast_core/streams/beast_InputStream.cpp | 2 +- .../beast_core/system/beast_PlatformDefs.h | 12 +- .../beast_core/system/beast_SystemStats.cpp | 2 +- .../modules/beast_core/text/beast_String.cpp | 6 +- .../beast_core/text/beast_StringArray.cpp | 2 +- .../threads/beast_ReadWriteLock.cpp | 2 +- .../beast_core/threads/beast_Thread.cpp | 2 +- .../beast_core/unit_tests/beast_UnitTest.cpp | 2 +- .../beast_core/xml/beast_XmlElement.cpp | 2 +- .../zip/beast_GZIPCompressorOutputStream.cpp | 2 +- .../containers/ripple_KeyCache.h | 1 - 122 files changed, 15337 insertions(+), 77 deletions(-) create mode 100644 Subtrees/beast/modules/beast_basics/beast_basics.cpp create mode 100644 Subtrees/beast/modules/beast_basics/beast_basics.h create mode 100644 Subtrees/beast/modules/beast_basics/containers/beast_List.h create mode 100644 Subtrees/beast/modules/beast_basics/containers/beast_LockFreeQueue.h create mode 100644 Subtrees/beast/modules/beast_basics/containers/beast_LockFreeStack.h create mode 100644 Subtrees/beast/modules/beast_basics/containers/beast_SharedTable.h create mode 100644 Subtrees/beast/modules/beast_basics/containers/beast_SortedLookupTable.h create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.cpp create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.h create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.cpp create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.h create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.cpp create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.h create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.cpp create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.h create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.cpp create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.h create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_SafeBool.h create mode 100644 Subtrees/beast/modules/beast_basics/diagnostic/beast_Throw.h create mode 100644 Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.cpp create mode 100644 Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.h create mode 100644 Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.cpp create mode 100644 Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.h create mode 100644 Subtrees/beast/modules/beast_basics/functor/beast_Bind.h create mode 100644 Subtrees/beast/modules/beast_basics/functor/beast_Function.h create mode 100644 Subtrees/beast/modules/beast_basics/math/beast_Interval.h create mode 100644 Subtrees/beast/modules/beast_basics/math/beast_Math.h create mode 100644 Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.cpp create mode 100644 Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_AllocatedBy.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_AtomicCounter.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_AtomicFlag.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_AtomicPointer.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_AtomicState.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_CacheLine.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStore.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.cpp create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.cpp create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_GlobalFifoFreeStore.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.cpp create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_MemoryAlignment.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.cpp create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_RefCountedSingleton.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_StaticObject.h create mode 100644 Subtrees/beast/modules/beast_basics/memory/beast_Uncopyable.h create mode 100644 Subtrees/beast/modules/beast_basics/native/beast_posix_FPUFlags.cpp create mode 100644 Subtrees/beast/modules/beast_basics/native/beast_posix_Threads.cpp create mode 100644 Subtrees/beast/modules/beast_basics/native/beast_win32_FPUFlags.cpp create mode 100644 Subtrees/beast/modules/beast_basics/native/beast_win32_Threads.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentState.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_GlobalThreadGroup.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_Listeners.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_Listeners.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_SerialFor.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_SpinDelay.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.h create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.cpp create mode 100644 Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.h diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj index 5ecfa00779..d0ec639079 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj @@ -41,6 +41,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -160,6 +211,115 @@ + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + + + true + true + true diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters index 1867cf7991..49586ac255 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -89,6 +89,33 @@ {31038502-9139-4c19-bd67-8f90f08a70ca} + + {e3a8f3eb-7f0f-4b81-b978-0dd0823f583b} + + + {3e9389c0-c8f0-4657-ab11-cbbea889d3be} + + + {ba11b980-76dd-49a4-b2c7-878e9f08f8ce} + + + {b8caa85d-f224-4e3a-966f-a19b65023869} + + + {bb0bef46-51a6-4c26-8354-4df753c3bace} + + + {1d53386e-0732-4213-b45d-026ff3d14042} + + + {9e850052-6ab7-4a65-911d-adfde81ceb5f} + + + {811c5374-8959-4df9-aba9-a7e27b85046e} + + + {f58dddf7-fe43-49a2-8e57-91feba586119} + @@ -440,6 +467,159 @@ beast_core\zip\zlib + + beast_basics + + + beast_basics\containers + + + beast_basics\containers + + + beast_basics\containers + + + beast_basics\containers + + + beast_basics\containers + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\events + + + beast_basics\events + + + beast_basics\functor + + + beast_basics\functor + + + beast_basics\math + + + beast_basics\math + + + beast_basics\math + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + @@ -691,5 +871,89 @@ beast_core\zip\zlib + + beast_basics + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\diagnostic + + + beast_basics\events + + + beast_basics\events + + + beast_basics\math + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\memory + + + beast_basics\native + + + beast_basics\native + + + beast_basics\native + + + beast_basics\native + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + + + beast_basics\threads + \ No newline at end of file diff --git a/Subtrees/beast/ReadMe.md b/Subtrees/beast/ReadMe.md index 5acd2f38c2..57c2293e6b 100644 --- a/Subtrees/beast/ReadMe.md +++ b/Subtrees/beast/ReadMe.md @@ -9,6 +9,6 @@ The hope is that this will replace the use of boost and other cumbersome jalopie ## JUCE -Beast is based on the juce_core module which is provided under the ISC +Beast is based on the beast_core module which is provided under the ISC license. More information about JUCE is available at http://www.juce.com diff --git a/Subtrees/beast/modules/beast_basics/beast_basics.cpp b/Subtrees/beast/modules/beast_basics/beast_basics.cpp new file mode 100644 index 0000000000..4a62756512 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/beast_basics.cpp @@ -0,0 +1,89 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +/** Add this to get the @ref beast_basics module. + + @file beast_basics.cpp + @ingroup beast_basics +*/ + +#include "BeastConfig.h" + +#include "beast_basics.h" + +#if BEAST_MSVC && _DEBUG +#include +#endif + +#if BEAST_MSVC +#pragma warning (push) +#pragma warning (disable: 4100) // unreferenced formal parmaeter +#pragma warning (disable: 4355) // 'this' used in base member +#endif + +namespace beast +{ + +#include "diagnostic/beast_CatchAny.cpp" +#include "diagnostic/beast_Debug.cpp" +#include "diagnostic/beast_Error.cpp" +#include "diagnostic/beast_FPUFlags.cpp" +#include "diagnostic/beast_LeakChecked.cpp" + +#include "events/beast_OncePerSecond.cpp" +#include "events/beast_PerformedAtExit.cpp" + +#include "math/beast_MurmurHash.cpp" + +#include "threads/beast_InterruptibleThread.cpp" +#include "threads/beast_Semaphore.cpp" + +#if BEAST_WINDOWS +#include "native/beast_win32_FPUFlags.cpp" +#include "native/beast_win32_Threads.cpp" + +#else +#include "native/beast_posix_FPUFlags.cpp" +#include "native/beast_posix_Threads.cpp" + +#endif + +#if BEAST_USE_BOOST +#include "memory/beast_FifoFreeStoreWithTLS.cpp" +#else +#include "memory/beast_FifoFreeStoreWithoutTLS.cpp" +#endif +#include "memory/beast_GlobalPagedFreeStore.cpp" +#include "memory/beast_PagedFreeStore.cpp" + +#include "threads/beast_CallQueue.cpp" +#include "threads/beast_ConcurrentObject.cpp" +#include "threads/beast_Listeners.cpp" +#include "threads/beast_ManualCallQueue.cpp" +#include "threads/beast_ParallelFor.cpp" +#include "threads/beast_ReadWriteMutex.cpp" +#include "threads/beast_SharedObject.cpp" +#include "threads/beast_ThreadGroup.cpp" +#include "threads/beast_ThreadWithCallQueue.cpp" + +} + +#if BEAST_MSVC +#pragma warning (pop) +#endif diff --git a/Subtrees/beast/modules/beast_basics/beast_basics.h b/Subtrees/beast/modules/beast_basics/beast_basics.h new file mode 100644 index 0000000000..cc661b7273 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/beast_basics.h @@ -0,0 +1,497 @@ +/*============================================================================*/ +/* + Beast: https://github.com/vinniefalco/Beast + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + Beast is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +/** Include this to get the @ref beast_basics module. + + @file beast_basics.h + @ingroup beast_basics +*/ + +#ifndef BEAST_BASICS_BEASTHEADER +#define BEAST_BASICS_BEASTHEADER + +//============================================================================== +/** + @mainpage Beast: A multipurpose library using parts of JUCE. + + ### Version 1.1 + + Copyright (C) 2008 by Vinnie Falco \ ([e-mail][0]) + + Beast is a source code collection of individual modules containing + functionality for a variety of applications, with an emphasis on building + concurrent systems. Beast requires [JUCE][3] (Jules' Utility Class + Extensions), available from [Raw Material Software][4]. JUCE is available + under both the [GNU General Public License][5] and a [commercial license][6]. + Other than JUCE, Beast has no external dependencies. + + Beast is hosted on Github at [https://github.com/vinniefalco/Beast][1] + + The online documentation is at [http://vinniefalco.github.com/Beast][2] + + ## Platforms + + All platforms supported by JUCE are also supported by Beast. Currently these + platforms include: + + - **Windows**: Applications and VST/RTAS/NPAPI/ActiveX plugins can be built + using MS Visual Studio. The results are all fully compatible with Windows + XP, Vista or Windows 7. + + - **Mac OS X**: Applications and VST/AudioUnit/RTAS/NPAPI plugins with Xcode. + + - **GNU/Linux**: Applications and plugins can be built for any kernel 2.6 or + later. + + - **iOS**: Native iPhone and iPad apps. + + - **Android**: Supported. + + ## Prerequisites + + This documentation assumes that the reader has a working knowledge of JUCE. + Some modules built on external libraries assume that the reader understands + the operation of those external libraries. Certain modules assume that the + reader understands additional domain-specific information. Modules with + additional prerequisites are marked in the documentation. + + ## External Modules + + Some modules bring in functionality provided by external libraries. For + example, the @ref beast_bzip2 module provides the compression and decompression + algorithms in [bZip2][7]. Usage of these external library modules is optional. + They come with complete source code, as well as options for using either + system or user provided variants of the external libraries: it is not + necessary to download additional source code packages to use these modules. + + External code incorporated into Beast is covered by separate licenses. See + the licensing information and notes in the corresponding source files for + copyright information and terms of use. + + ## Integration + + Beast requires recent versions of JUCE. It won't work with versions 1.53 or + earlier. To use the library it is necessary to first download JUCE to a + location where your development environment can find it. Or, you can use your + existing installation of JUCE. + + This library uses the same modularized organizational structure as JUCE. To + use a module, first add a path to the list of includes searched by your + development environment or project, which points to the Beast directory. Then, + add the single corresponding .c or .cpp file to your existing project which + already uses JUCE. For example, to use the @ref beast_core module, add the file + beast_core.cpp to your project. Some modules depend on other modules. + + To use a module, include the appropriate header from within your source code. + For example, to access classes in the @ref beast_concurrent module, use this: + + @code + + #include "modules/beast_concurrent/beast_concurrent.h" + + @endcode + + Then add the corresponding file beast_concurrent.cpp to your build. + + ## AppConfig + + Some Beast features can be controlled at compilation time through + preprocessor directives. The available choices of compilation options are + described in AppConfig.h, located in the AppConfigTemplate directory. Copy + the provided settings into your existing AppConfig.h (a file used by JUCE + convention). + + ## License + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + Beast is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + + Some files contain portions of these external projects, licensed separately: + + - [bZip2][7] is Copyright (C) 1996-2010 Julian R Seward. All rights + reserved. See the corresponding file LICENSE for licensing terms. + + - Portions of the software are Copyright (C) 1996-2001, 2006 by [The FreeType + Project][8]. All rights reserved. [FreeType][8] is distributed + under both the [GNU General Public License][5], or the + [FreeType License][9]. + + - Portions of this software are Copyright (C) 1994-2012 [Lua.org][10], PUC-Rio. + Lua is distributed under the terms of the [MIT License][11]. + + - [Luabridge][12] is Copyright (C) 2012 by Vinnie Falco and Copyrighted (C) + 2007 by Nathan Reed. [Luabridge][12] is distributed under the terms of the + [MIT License][11]. + + - [Soci][13] is Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton, and + various others noted in the corresponding source files. Soci is distributed + under the [Boost Software License, Version 1.0][14]. + + - [SQLite][15], placed in the public domain. + + - [TagLib][16] is distributed under both the [GNU Lesser General Public License, + Version 2.1][17] and the [Mozilla Public License][18]. + + [0]: mailto:vinnie.falco@gmail.com "Vinnie Falco (Email)" + [1]: https://github.com/vinniefalco/Beast "Beast Project" + [2]: http://vinniefalco.github.com/Beast/ "Beast Documentation" + [3]: http://rawmaterialsoftware.com/juce.php "JUCE" + [4]: http://rawmaterialsoftware.com/ "Raw Material Software" + [5]: http://www.gnu.org/licenses/gpl-2.0.html "GNU General Public License, version 2" + [6]: http://rawmaterialsoftware.com/jucelicense.php "JUCE Licenses" + [7]: http://www.bzip.org/ "bZip2: Home" + [8]: http://freetype.org/ "The FreeType Project" + [9]: http://www.freetype.org/FTL.TXT "The FreeType Project License" + [10]: http://www.lua.org/ "The Programming Language Lua" + [11]: http://www.opensource.org/licenses/mit-license.html "The MIT License" + [12]: https://github.com/vinniefalco/LuaBridge + [13]: http://soci.sourceforge.net/ "SOCI" + [14]: http://www.boost.org/LICENSE_1_0.txt "Boost Software License, Version 1.0" + [15]: http://sqlite.org/ "SQLite Home Page" + [16]: http://developer.kde.org/~wheeler/taglib.html "TagLib" + [17]: http://www.gnu.org/licenses/lgpl-2.1.html "Gnu Lesser General Public License, version 2.1" + [18]: http://www.mozilla.org/MPL/1.1/ "Mozilla Public License" + + @copyright Copyright (C) 2008 by Vinnie Falco \ ([e-mail][0]) + @copyright Provided under the [MIT License][11] +*/ + +/*============================================================================*/ +/** + @internal + + Implementation classes. + + Thase classes are used internally. + + @defgroup internal internal +*/ + +/*============================================================================*/ +/** + External modules. + + These modules bring in functionality from third party or system libraries. + + @defgroup external external +*/ + +/*============================================================================*/ +/** + Core classes. + + This module provides core required functionality, and classes useful for + general development. All other modules require this module. + + @todo Discuss the treatment of exceptions versus Error objects in the library. + + @todo Discuss the additions to AppConfig.h + + @defgroup beast_core beast_core +*/ + +/* See the Juce notes regarding AppConfig.h + + This file must always be included before any Juce headers. + + There are some Beast specific build options that may be placed + into this file. See the AppConfig.h provided with Beast. +*/ + +/* BeastConfig.h must be included before this file */ + +/* Use sensible default configurations if they forgot + to append the necessary macros into their AppConfig.h. +*/ +#ifndef BEAST_USE_BOOST +#define BEAST_USE_BOOST 0 +#endif + +#ifndef BEAST_USE_BZIP2 +#define BEAST_USE_BZIP2 0 +#endif + +#ifndef BEAST_USE_FREETYPE +#define BEAST_USE_FREETYPE 0 +#endif + +#ifndef BEAST_USE_NATIVE_FREETYPE +#define BEAST_USE_NATIVE_FREETYPE 1 +#endif + +#ifndef BEAST_USE_NATIVE_SQLITE +#define BEAST_USE_NATIVE_SQLITE 1 +#endif + +#ifndef BEAST_USE_LEAKCHECKED +#define BEAST_USE_LEAKCHECKED BEAST_CHECK_MEMORY_LEAKS +#endif + +/* Get this early so we can use it. */ +#include "../beast_core/system/beast_TargetPlatform.h" + +// Handy macro that lets pragma warnings be clicked in the output window +// Usage: #pragma message(BEAST_LOC_"Advertise here!") +#define BEAST_STR2_(x) #x +#define BEAST_STR1_(x) BEAST_STR2_(x) +#define BEAST_LOC_ __FILE__ "("BEAST_STR1_(__LINE__)") : WARNING: " + +#if BEAST_USE_BOOST +#include +#endif + +#if BEAST_MSVC +# include +# include + +#elif BEAST_IOS +# if BEAST_USE_BOOST +# include +# include +# else +# include // detect std::lib +# if _LIBCPP_VERSION // libc++ +# include +# else // libstdc++ (GNU) +# include +# endif +# endif + +#elif BEAST_MAC +# include // detect std::lib +# if _LIBCPP_VERSION // libc++ +# include +# else // libstdc++ (GNU) +# include +# endif + +#elif BEAST_LINUX +# include + +#else +# error Unnkown platform! + +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _CRTDBG_MAP_ALLOC +#error "MSVC C Runtime Debug Macros not supported" +#endif + +// If the MSVC debug heap headers were included, disable +// the macros during the juce include since they conflict. +#ifdef _CRTDBG_MAP_ALLOC +#include +#include +#include + +#pragma push_macro("calloc") +#pragma push_macro("free") +#pragma push_macro("malloc") +#pragma push_macro("realloc") +#pragma push_macro("_recalloc") +#pragma push_macro("_aligned_free") +#pragma push_macro("_aligned_malloc") +#pragma push_macro("_aligned_offset_malloc") +#pragma push_macro("_aligned_realloc") +#pragma push_macro("_aligned_recalloc") +#pragma push_macro("_aligned_offset_realloc") +#pragma push_macro("_aligned_offset_recalloc") +#pragma push_macro("_aligned_msize") + +#undef calloc +#undef free +#undef malloc +#undef realloc +#undef _recalloc +#undef _aligned_free +#undef _aligned_malloc +#undef _aligned_offset_malloc +#undef _aligned_realloc +#undef _aligned_recalloc +#undef _aligned_offset_realloc +#undef _aligned_offset_recalloc +#undef _aligned_msize +#endif + +#include "../beast_core/beast_core.h" + +#ifdef _CRTDBG_MAP_ALLOC +#pragma pop_macro("_aligned_msize") +#pragma pop_macro("_aligned_offset_recalloc") +#pragma pop_macro("_aligned_offset_realloc") +#pragma pop_macro("_aligned_recalloc") +#pragma pop_macro("_aligned_realloc") +#pragma pop_macro("_aligned_offset_malloc") +#pragma pop_macro("_aligned_malloc") +#pragma pop_macro("_aligned_free") +#pragma pop_macro("_recalloc") +#pragma pop_macro("realloc") +#pragma pop_macro("malloc") +#pragma pop_macro("free") +#pragma pop_macro("calloc") +#endif + +/** The Beast namespace. + + This namespace contains all Beast symbols. +*/ +namespace beast +{ + +// This group must come first since other files need it +#include "memory/beast_Uncopyable.h" +#include "diagnostic/beast_CatchAny.h" +#include "diagnostic/beast_Debug.h" +#include "diagnostic/beast_Error.h" +#include "diagnostic/beast_FPUFlags.h" +#include "diagnostic/beast_LeakChecked.h" +#include "diagnostic/beast_SafeBool.h" +#include "diagnostic/beast_Throw.h" + +#include "containers/beast_List.h" +#include "containers/beast_LockFreeStack.h" +#include "containers/beast_LockFreeQueue.h" +#include "containers/beast_SharedTable.h" +#include "containers/beast_SortedLookupTable.h" + +#include "events/beast_OncePerSecond.h" +#include "events/beast_PerformedAtExit.h" + +#include "functor/beast_Bind.h" +#include "functor/beast_Function.h" + +#include "math/beast_Interval.h" +#include "math/beast_Math.h" +#include "math/beast_MurmurHash.h" + +#include "memory/beast_MemoryAlignment.h" +#include "memory/beast_StaticObject.h" +#include "memory/beast_AtomicCounter.h" +#include "memory/beast_AtomicFlag.h" +#include "memory/beast_AtomicPointer.h" +#include "memory/beast_AtomicState.h" +#include "memory/beast_AllocatedBy.h" +#include "memory/beast_RefCountedSingleton.h" +#include "memory/beast_FifoFreeStore.h" +#if BEAST_USE_BOOST +#include "memory/beast_FifoFreeStoreWithTLS.h" +#else +#include "memory/beast_FifoFreeStoreWithoutTLS.h" +#endif +#include "memory/beast_GlobalFifoFreeStore.h" +#include "memory/beast_GlobalPagedFreeStore.h" +#include "memory/beast_PagedFreeStore.h" + +#if BEAST_MSVC +#pragma warning (push) +#pragma warning (disable: 4100) // unreferenced formal parmaeter +#pragma warning (disable: 4355) // 'this' used in base member +#endif +#include "memory/beast_CacheLine.h" +#if BEAST_MSVC +#pragma warning (pop) +#endif + +#include "threads/beast_Semaphore.h" +#include "threads/beast_SerialFor.h" +#include "threads/beast_SpinDelay.h" +#include "threads/beast_InterruptibleThread.h" +#include "threads/beast_ReadWriteMutex.h" +#include "threads/beast_ThreadGroup.h" +#include "threads/beast_CallQueue.h" +#include "threads/beast_ConcurrentObject.h" +#include "threads/beast_ConcurrentState.h" +#include "threads/beast_GlobalThreadGroup.h" +#include "threads/beast_Listeners.h" +#include "threads/beast_ManualCallQueue.h" +#include "threads/beast_ParallelFor.h" +#include "threads/beast_ThreadWithCallQueue.h" +#include "threads/beast_SharedObject.h" + +} + +#endif + diff --git a/Subtrees/beast/modules/beast_basics/containers/beast_List.h b/Subtrees/beast/modules/beast_basics/containers/beast_List.h new file mode 100644 index 0000000000..5ea32c865e --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/containers/beast_List.h @@ -0,0 +1,809 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_LIST_BEASTHEADER +#define BEAST_LIST_BEASTHEADER + +struct ListDefaultTag; + +/*============================================================================*/ +/** + Intrusive Containers + + # Introduction + + Intrusive containers are special containers that offer better performance + and exception safety guarantees than non-intrusive containers (like the + STL containers). They are useful building blocks for high performance + concurrent systems or other purposes where allocations are restricted + (such as the AudioIODeviceCallback object), because intrusive list + operations do not allocate or free memory. + + While intrusive containers were and are widely used in C, they became more + and more forgotten in C++ due to the presence of the standard containers + which don't support intrusive techniques. VFLib not only reintroduces this + technique to C++ for lists, it also encapsulates the implementation in a + mostly compliant STL interface. Hence anyone familiar with standard + containers can easily use them. + + # Interface + + The interface for intrusive elements in this library is unified for all + containers. Unlike STL containers, objects placed into intrusive containers + are not copied. Instead, a pointer to the object is stored. All + responsibility for object lifetime is the responsibility of the caller; + the intrusive container just keeps track of what is in it. + + Summary of intrusive container differences: + + - Holds pointers to existing objects instead of copies. + + - Does not allocate or free any objects. + + - Requires a element's class declaration to be modified. + + - Methods never throw exceptions when called with valid arguments. + + # Usage + + Like STL containers, intrusive containers are all template based, where the + template argument specifies the type of object that the container will hold. + These declarations specify a doubly linked list where each element points + to a user defined class: + + @code + + class Object; // Forward declaration + + List list; // Doubly-linked list of Object + + @endcode + + Because intrusive containers allocate no memory, allowing objects to be + placed inside requires a modification to their class declaration. Each + intrusive container declares a nested class `Node` which elements must be + derived from, using the Curiously Recurring Template Pattern (CRTP). We + will continue to fully declare the Object type from the previous example + to support emplacement into an intrusive container: + + @code + + class Object : public List ::Node // Required for List + { + public: + void performAction (); + }; + + @endcode + + Usage of a typedef eliminates redundant specification of the template + arguments but requires a forward declaration. The following code is + equivalent. + + @code + + class Object; // Forward declaration + + // Specify template parameters just once + typedef List ListType; + + class Object : public ListType::Node + { + void performAction (); + }; + + ListType::Node list; + + @endcode + + With these declarations we may proceed to create our objects, add them to + the list, and perform operations: + + @code + + // Create a few objects and put them in the list + for (i = 0; i < 5; ++i) + list.push_back (*new Object); + + // Call a method on each list + for (ListType::iterator iter = list.begin(); iter != list.end (); ++iter) + iter->performAction (); + + @endcode + + Unlike regular STL containers, an object derived from an intrusive container + node cannot exist in more than one instance of that list at a time. This is + because the bookkeeping information for maintaining the list is kept in + the object rather than the list. + + To support objects existing in multiple containers, templates variations + are instantiated by distinguishing them with an empty structure, called a + tag. The object is derived from multiple instances of Node, where each + instance specifies a unique tag. The tag is passed as the second template + argument. When the second argument is unspecified, the default tag is used. + + This declaration example shows the usage of tags to allow an object to exist + simultaneously in two separate lists: + + @code + + struct GlobalListTag { }; // list of all objects + struct ActiveListTag { }; // subset of all objects that are active + + class Object : public List + , public List + { + public: + Object () : m_isActive (false) + { + // Add ourselves to the global list + s_globalList.push_front (*this); + } + + ~Object () + { + deactivate (); + } + + void becomeActive () + { + // Add ourselves to the active list + if (!m_isActive) + { + s_activeList.push_front (*this); + m_isActive = true; + } + } + + void deactivate () + { + if (m_isActive) + { + // Doesn't delete the object + s_activeList.erase (s_activeList.iterator_to (this)); + + m_isActive = false; + } + } + + private: + bool m_isActive; + + static List s_globalList; + static List s_activeList; + } + + @endcode + + @defgroup intrusive intrusive + @ingroup beast_core +*/ + +/*============================================================================*/ +/** + Intrusive doubly linked list. + + This intrusive List is a container similar in operation to std::list in the + Standard Template Library (STL). Like all @ref intrusive containers, List + requires you to first derive your class from List<>::Node: + + @code + + struct Object : List ::Node + { + Object (int value) : m_value (value) + { + } + + int m_value; + }; + + @endcode + + Now we define the list, and add a couple of items. + + @code + + List list; + + list.push_back (* (new Object (1))); + list.push_back (* (new Object (2))); + + @endcode + + For compatibility with the standard containers, push_back() expects a + reference to the object. Unlike the standard container, however, push_back() + places the actual object in the list and not a copy-constructed duplicate. + + Iterating over the list follows the same idiom as the STL: + + @code + + for (List ::iterator iter = list.begin(); iter != list.end; ++iter) + std::cout << iter->m_value; + + @endcode + + You can even use BOOST_FOREACH, or range based for loops: + + @code + + BOOST_FOREACH (Object& object, list) // boost only + std::cout << object.m_value; + + for (Object& object : list) // C++11 only + std::cout << object.m_value; + + @endcode + + Because List is mostly STL compliant, it can be passed into STL algorithms: + e.g. `std::for_each()` or `std::find_first_of()`. + + In general, objects placed into a List should be dynamically allocated + although this cannot be enforced at compile time. Since the caller provides + the storage for the object, the caller is also responsible for deleting the + object. An object still exists after being removed from a List, until the + caller deletes it. This means an element can be moved from one List to + another with practically no overhead. + + Unlike the standard containers, an object may only exist in one list at a + time, unless special preparations are made. The Tag template parameter is + used to distinguish between different list types for the same object, + allowing the object to exist in more than one list simultaneously. + + For example, consider an actor system where a global list of actors is + maintained, so that they can each be periodically receive processing + time. We wish to also maintain a list of the subset of actors that require + a domain-dependent update. To achieve this, we declare two tags, the + associated list types, and the list element thusly: + + @code + + struct Actor; // Forward declaration required + + struct ProcessTag { }; + struct UpdateTag { }; + + typedef List ProcessList; + typedef List UpdateList; + + // Derive from both node types so we can be in each list at once. + // + struct Actor : ProcessList::Node, UpdateList::Node + { + bool process (); // returns true if we need an update + void update (); + }; + + @endcode + + @tparam Element The base type of element which the list will store + pointers to. + + @tparam Tag An optional unique type name used to distinguish lists and nodes, + when the object can exist in multiple lists simultaneously. + + @ingroup beast_core intrusive +*/ +template +class List : Uncopyable +{ +public: + typedef int size_type; + + typedef Element value_type; + typedef Element& reference; + typedef Element const& const_reference; + typedef Element* pointer; + typedef Element const* const_pointer; + + class Node : Uncopyable + { + public: + Node () { } + + private: + friend class List; + Node* m_next; + Node* m_prev; + }; + +private: + template + class iterator_base : public std::iterator < + std::bidirectional_iterator_tag, int > + { + public: + typedef ElemType value_type; + typedef ElemType* pointer; + typedef ElemType& reference; + + iterator_base (NodeType* node = nullptr) : m_node (node) + { + } + + template + iterator_base (iterator_base const& other) + : m_node (other.m_node) + { + } + + template + iterator_base& operator= (iterator_base const& other) + { + m_node = other.m_node; + return *this; + } + + template + bool operator == (iterator_base const& other) const + { + return m_node == other.m_node; + } + + template + bool operator != (iterator_base const& other) const + { + return ! this->operator== (other); + } + + reference operator* () const + { + return dereference (); + } + + pointer operator-> () const + { + return &dereference (); + } + + iterator_base& operator++ () + { + increment (); + return *this; + } + + iterator_base operator++ (int) + { + iterator_base result (*this); + increment (); + return result; + } + + iterator_base& operator-- () + { + decrement (); + return *this; + } + + iterator_base operator-- (int) + { + iterator_base result (*this); + decrement (); + return result; + } + + private: + friend class List; + + NodeType* get_node () + { + return m_node; + } + + NodeType const* get_node () const + { + return m_node; + } + + reference dereference () const + { + return *static_cast (m_node); + } + + bool equal (NodeType* const* node) const + { + return m_node == node; + } + + void increment () + { + bassert (m_node->m_next); + m_node = m_node->m_next; + } + + void decrement () + { + bassert (m_node->m_prev && m_node->m_prev->m_prev != 0); + m_node = m_node->m_prev; + } + + private: + NodeType* m_node; + }; + +public: + /** A read/write List iterator. */ + typedef iterator_base iterator; + + /** A read-only List iterator. */ + typedef iterator_base const_iterator; + +public: + /** Create an empty list. */ + List () : m_size (0) + { + m_head.m_prev = nullptr; // identifies the head + m_tail.m_next = nullptr; // identifies the tail + clear (); + } + + /** Returns the number of elements in the list + + @return The number of elements in the list. + */ + size_type size () const + { + return m_size; + } + + /** Obtain a reference to the first element. + + @invariant The list may not be empty. + + @return A reference to the first element. + */ + reference front () + { + if (empty ()) + Throw (Error ().fail (__FILE__, __LINE__, Error::noMoreData)); + + return element_from (m_head.m_next); + } + + /** Obtain a const reference to the first element. + + @invariant The list may not be empty. + + @return A const reference to the first element. + */ + const_reference front () const + { + if (empty ()) + Throw (Error ().fail (__FILE__, __LINE__, Error::noMoreData)); + + return element_from (m_head.m_next); + } + + /** Obtain a reference to the last element. + + @invariant The list may not be empty. + + @return A reference to the last element. + */ + reference back () + { + if (empty ()) + Throw (Error ().fail (__FILE__, __LINE__, Error::noMoreData)); + + return element_from (m_tail.m_prev); + } + + /** Obtain a const reference to the last element. + + @invariant The list may not be empty. + + @return A const reference to the last element. + */ + const_reference back () const + { + if (empty ()) + Throw (Error ().fail (__FILE__, __LINE__, Error::noMoreData)); + + return element_from (m_tail.m_prev); + } + + /** Obtain an iterator to the beginning of the list. + + @return An iterator pointing to the beginning of the list. + */ + iterator begin () + { + return iterator (m_head.m_next); + } + + /** Obtain a const iterator to the beginning of the list. + + @return A const iterator pointing to the beginning of the list. + */ + const_iterator begin () const + { + return const_iterator (m_head.m_next); + } + + /** Obtain a const iterator to the beginning of the list. + + @return A const iterator pointing to the beginning of the list. + */ + const_iterator cbegin () const + { + return const_iterator (m_head.m_next); + } + + /** Obtain a iterator to the end of the list. + + @return An iterator pointing to the end of the list. + */ + iterator end () + { + return iterator (&m_tail); + } + + /** Obtain a const iterator to the end of the list. + + @return A constiterator pointing to the end of the list. + */ + const_iterator end () const + { + return const_iterator (&m_tail); + } + + /** Obtain a const iterator to the end of the list. + + @return A constiterator pointing to the end of the list. + */ + const_iterator cend () const + { + return const_iterator (&m_tail); + } + + /** Determine if the list is empty. + + @return `true` if the list is empty. + */ + bool empty () const + { + return m_head.m_next == &m_tail; + } + + /** Clear the list. + + @note This does not free the elements. + */ + void clear () + { + m_head.m_next = &m_tail; + m_tail.m_prev = &m_head; + m_size = 0; + } + + /** Insert an element. + + @invariant The element must not already be in the list. + + @param pos The location to insert after. + + @param elem The element to insert. + + @return An iterator pointing to the newly inserted element. + */ + iterator insert (iterator pos, Element& elem) + { + Node* node = node_from (elem); + node->m_next = pos.get_node (); + node->m_prev = node->m_next->m_prev; + node->m_next->m_prev = node; + node->m_prev->m_next = node; + ++m_size; + return iterator (node); + } + + /** Insert another list into this one. + + The other list is cleared. + + @param pos The location to insert after. + + @param other The list to insert. + */ + + void insert (iterator pos, List& other) + { + if (!other.empty ()) + { + Node* before = pos.get_node (); + other.m_head.m_next->m_prev = before->m_prev; + before->m_prev->m_next = other.m_head.m_next; + other.m_tail.m_prev->m_next = before; + before->m_prev = other.m_tail.m_prev; + m_size += other.m_size; + other.clear (); + } + } + + /** Remove an element. + + @invariant The element must exist in the list. + + @param pos An iterator pointing to the element to remove. + + @return An iterator pointing to the next element after the one removed. + */ + iterator erase (iterator pos) + { + Node* node = pos.get_node (); + ++pos; + node->m_next->m_prev = node->m_prev; + node->m_prev->m_next = node->m_next; + --m_size; + return pos; + } + + /** Insert an element at the beginning of the list. + + @invariant The element must not exist in the list. + + @param elem The element to insert. + */ + void push_front (Element& elem) + { + insert (begin (), elem); + } + + /** Remove the element at the beginning of the list. + + @invariant The list must not be empty. + */ + void pop_front () + { + if (empty ()) + Throw (Error ().fail (__FILE__, __LINE__, Error::noMoreData)); + + erase (begin ()); + } + + /** Append an element at the end of the list. + + @invariant The element must not exist in the list. + + @param elem The element to append. + */ + void push_back (Element& elem) + { + insert (end (), elem); + } + + /** Remove the element at the end of the list. + + @invariant The list must not be empty. + */ + void pop_back () + { + if (empty ()) + Throw (Error ().fail (__FILE__, __LINE__, Error::noMoreData)); + + erase (--end ()); + } + + /** Swap contents with another list. + */ + void swap (List& other) + { + List temp; + temp.append (other); + other.append (*this); + append (temp); + } + + /** Insert another list at the beginning of this list. + + The other list is cleared. + + @param list The other list to insert. + */ + void prepend (List& list) + { + insert (begin (), list); + } + + /** Append another list at the end of this list. + + The other list is cleared. + + @param list the other list to append. + */ + void append (List& list) + { + insert (end (), list); + } + + /** Obtain an iterator from an element. + + @invariant The element must exist in the list. + + @param elem The element to obtain an iterator for. + + @return An iterator to the element. + */ + iterator iterator_to (Element& elem) const + { + return iterator (static_cast (&elem)); + } + + /** Obtain a const iterator from an element. + + @invariant The element must exist in the list. + + @param elem The element to obtain an iterator for. + + @return A const iterator to the element. + */ + const_iterator const_iterator_to (Element const& elem) const + { + return const_iterator (static_cast (&elem)); + } + +private: + inline reference element_from (Node* node) + { + return * (static_cast (node)); + } + + inline const_reference element_from (Node const* node) const + { + return * (static_cast (node)); + } + + inline Node* node_from (Element& elem) + { + return static_cast (&elem); + } + + inline Node const* node_from (Element const& elem) const + { + return static_cast (&elem); + } + +private: + size_type m_size; + Node m_head; + Node m_tail; +}; + +/** + Default tag for List. + + @ingroup beast_core intrusive +*/ +struct ListDefaultTag { }; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/containers/beast_LockFreeQueue.h b/Subtrees/beast/modules/beast_basics/containers/beast_LockFreeQueue.h new file mode 100644 index 0000000000..75be589e35 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/containers/beast_LockFreeQueue.h @@ -0,0 +1,239 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_LOCKFREEQUEUE_BEASTHEADER +#define BEAST_LOCKFREEQUEUE_BEASTHEADER + +#include "../memory/beast_CacheLine.h" +#include "../memory/beast_AtomicPointer.h" +#include "../threads/beast_SpinDelay.h" + +struct LockFreeQueueDefaultTag; + +/*============================================================================*/ +/** + Multiple Producer, Single Consumer (MPSC) intrusive FIFO. + + This container uses the same intrusive interface as List. It is wait-free + for producers and lock-free for consumers. The caller is responsible for + preventing the ABA problem (http://en.wikipedia.org/wiki/ABA_problem) + + Invariants: + + - Any thread may call push_back() at any time (Multiple Producer). + + - Only one thread may call try_pop_front() at a time (Single Consumer) + + - The queue is signaled if there are one or more elements. + + @param Tag A type name used to distinguish lists and nodes, for + putting objects in multiple lists. If this parameter is + omitted, the default tag is used. + + @ingroup beast_core intrusive +*/ +template +class LockFreeQueue +{ +public: + class Node : Uncopyable + { + public: + Node () { } + explicit Node (Node* next) : m_next (next) { } + + AtomicPointer m_next; + }; + +public: + /** Create an empty list. + */ + LockFreeQueue () + : m_head (&m_null) + , m_tail (&m_null) + , m_null (nullptr) + { + } + + /** Determine if the list is empty. + + This is not thread safe, the caller must synchronize. + + @return true if the list is empty. + */ + bool empty () const + { + return (m_head.get () == m_tail); + } + + /** Put an element into the list. + + This operation is wait-free. + + @param node The element to enqueue. + + @return true if the list was previously empty. + */ + bool push_back (Node* node) + { + node->m_next.set (0); + + Node* prev = m_head.exchange (node); + + // (*) If a try_pop_front() happens at this point, it might not see the + // element we are pushing. This only happens when the list is empty, + // and furthermore it is detectable. + + prev->m_next.set (node); + + return prev == &m_null; + } + + /** Retrieve an element from the list. + + This operation is lock-free. + + @return The element, or nullptr if the list was empty. + */ + Element* pop_front () + { + Element* elem; + + // Avoid the SpinDelay ctor if possible + if (!try_pop_front (&elem)) + { + SpinDelay delay; + + do + { + delay.pause (); + } + while (!try_pop_front (&elem)); + } + + return elem; + } + + /** Attempt to retrieve an element. + + This attempts to pop an element from the front of the list. The return + value indicates if the operation was successful. An operation is + successful if there is no contention for the list. On a successful + operation, an element is returned if the list was non empty, else nullptr + is returned. On failure, the returned element is undefined. + + This operation is wait-free. + + @param[out] pElem The element that was retrieved, or nullptr if the + list was empty. + + @return true if the list was uncontended. + */ + bool try_pop_front (Element** pElem) + { + Node* tail = m_tail; + Node* next = tail->m_next.get (); + + if (tail == &m_null) + { + if (next == 0) + { + // (*) If a push_back() happens at this point, + // we might not see the element. + + if (m_head.get () == tail) + { + *pElem = nullptr; + return true; // success, but queue empty + } + else + { + return false; // failure: a push_back() caused contention + } + } + + m_tail = next; + tail = next; + next = next->m_next.get (); + } + + if (next) + { + m_tail = next; + *pElem = static_cast (tail); + return true; + } + + Node* head = m_head.get (); + + if (tail == head) + { + push_back (&m_null); + next = tail->m_next.get (); + + if (next) + { + m_tail = next; + *pElem = static_cast (tail); + return true; + } + } + + // (*) If a push_back() happens at this point, + // we might not see the element. + + if (head == m_tail) + { + *pElem = nullptr; + return true; // success, but queue empty + } + else + { + return false; // failure: a push_back() caused contention + } + } + +private: + // Elements are pushed on to the head and popped from the tail. + AtomicPointer m_head; + Node* m_tail; + Node m_null; +}; + +/*============================================================================*/ +/** Default tag for LockFreeQueue + + @ingroup beast_core intrusive +*/ +struct LockFreeQueueDefaultTag { }; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/containers/beast_LockFreeStack.h b/Subtrees/beast/modules/beast_basics/containers/beast_LockFreeStack.h new file mode 100644 index 0000000000..61016480bd --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/containers/beast_LockFreeStack.h @@ -0,0 +1,179 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_LOCKFREESTACK_BEASTHEADER +#define BEAST_LOCKFREESTACK_BEASTHEADER + +#include "../memory/beast_AtomicPointer.h" + +struct LockFreeStackDefaultTag; + +/*============================================================================*/ +/** + Multiple Producer, Multiple Consumer (MPMC) intrusive stack. + + This stack is implemented using the same intrusive interface as List. All + operations are lock-free. + + The caller is responsible for preventing the "ABA" problem + (http://en.wikipedia.org/wiki/ABA_problem) + + @param Tag A type name used to distinguish lists and nodes, for + putting objects in multiple lists. If this parameter is + omitted, the default tag is used. + + @ingroup beast_core intrusive +*/ +template +class LockFreeStack : Uncopyable +{ +public: + class Node : Uncopyable + { + public: + Node () + { + } + + explicit Node (Node* next) : m_next (next) + { + } + + private: + friend class LockFreeStack; + + AtomicPointer m_next; + }; + +public: + LockFreeStack () : m_head (0) + { + } + + /** Create a LockFreeStack from another stack. + + The contents of the other stack are atomically acquired. + The other stack is cleared. + + @param other The other stack to acquire. + */ + explicit LockFreeStack (LockFreeStack& other) + { + Node* head; + + do + { + head = other.m_head.get (); + } + while (!other.m_head.compareAndSet (0, head)); + + m_head = head; + } + + /** Push a node onto the stack. + + The caller is responsible for preventing the ABA problem. This operation + is lock-free. + + @param node The node to push. + + @return True if the stack was previously empty. If multiple threads + are attempting to push, only one will receive true. + */ + bool push_front (Node* node) + { + bool first; + Node* head; + + do + { + head = m_head.get (); + first = head == 0; + node->m_next = head; + } + while (!m_head.compareAndSet (node, head)); + + return first; + } + + /** Pop an element off the stack. + + The caller is responsible for preventing the ABA problem. This operation + is lock-free. + + @return The element that was popped, or nullptr if the stack was empty. + */ + Element* pop_front () + { + Node* node; + Node* head; + + do + { + node = m_head.get (); + + if (node == 0) + break; + + head = node->m_next.get (); + } + while (!m_head.compareAndSet (head, node)); + + return node ? static_cast (node) : nullptr; + } + + /** Swap the contents of this stack with another stack. + + This call is not thread safe or atomic. The caller is responsible for + synchronizing access. + + @param other The other stack to swap contents with. + */ + void swap (LockFreeStack& other) + { + Node* temp = other.m_head.get (); + other.m_head.set (m_head.get ()); + m_head.set (temp); + } + +private: + AtomicPointer m_head; +}; + +/*============================================================================*/ +/** Default tag for LockFreeStack + + @ingroup beast_core intrusive +*/ +struct LockFreeStackDefaultTag { }; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/containers/beast_SharedTable.h b/Subtrees/beast/modules/beast_basics/containers/beast_SharedTable.h new file mode 100644 index 0000000000..9acbc0acd4 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/containers/beast_SharedTable.h @@ -0,0 +1,226 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_SHAREDTABLE_BEASTHEADER +#define BEAST_SHAREDTABLE_BEASTHEADER + +/** Handle to a reference counted fixed size table. + + @note Currently, ElementType must be an aggregate of POD. + + @tparam ElementType The type of element. + + @ingroup beast_gui +*/ +template +class SharedTable +{ +public: + typedef ElementType Entry; + + static SharedTable const null; + + /** Creates a null table. + */ + SharedTable () + { + } + + /** Creates a table with the specified number of entries. + + The entries are uninitialized. + + @param numEntries The number of entries in the table. + + @todo Initialize the data if ElementType is not POD. + */ + explicit SharedTable (int numEntries) + : m_data (new Data (numEntries)) + { + } + + /** Creates a shared reference to another table. + */ + SharedTable (SharedTable const& other) + : m_data (other.m_data) + { + } + + /** Makes this table refer to another table. + */ + SharedTable& operator= (SharedTable const& other) + { + m_data = other.m_data; + return *this; + } + +#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS + SharedTable (SharedTable&& other) noexcept +: + m_data (static_cast < typename Data::Ptr&& > (other.m_data)) + { + } + + SharedTable& operator= (SharedTable && other) noexcept + { + m_data = static_cast < typename Data::Ptr && > (other.m_data); + return *this; + } +#endif + + /** Destructor. + */ + ~SharedTable () + { + } + + /** Returns true if the two tables share the same set of entries. + */ + bool operator== (SharedTable const& other) const noexcept + { + return m_data == other.m_data; + } + + /** Returns true if the two tables do not share the same set of entries. + */ + bool operator!= (SharedTable const& other) const noexcept + { + return m_data != other.m_data; + } + + /** Returns true if the table is not null. + */ + inline bool isValid () const noexcept + { + return m_data != nullptr; + } + + /** Returns true if the table is null. + */ + inline bool isNull () const noexcept + { + return m_data == nullptr; + } + + /** Returns the number of tables referring to the same shared entries. + */ + int getReferenceCount () const noexcept + { + return m_data == nullptr ? 0 : m_data->getReferenceCount (); + } + + /** Create a physical duplicate of the table. + */ + SharedTable createCopy () const + { + return SharedTable (m_data != nullptr ? m_data->clone () : nullptr); + } + + /** Makes sure no other tables share the same entries as this table. + */ + void duplicateIfShared () + { + if (m_data != nullptr && m_data->getReferenceCount () > 1) + m_data = m_data->clone (); + } + + /** Return the number of entries in this table. + */ + inline int getNumEntries () const noexcept + { + return m_data->getNumEntries (); + } + + /** Retrieve a table entry. + + @param index The index of the entry, from 0 to getNumEntries (). + */ + inline ElementType& operator [] (int index) const noexcept + { + return m_data->getReference (index); + } + +private: + class Data : public ReferenceCountedObject + { + public: + typedef ReferenceCountedObjectPtr Ptr; + + explicit Data (int numEntries) + : m_numEntries (numEntries) + , m_table (numEntries) + { + } + + inline Data* clone () const + { + Data* data = new Data (m_numEntries); + + memcpy ( + data->m_table.getData (), + m_table.getData (), + m_numEntries * sizeof (ElementType)); + + return data; + } + + inline int getNumEntries () const + { + return m_numEntries; + } + + inline ElementType& getReference (int index) const + { + bassert (index >= 0 && index < m_numEntries); + return m_table [index]; + } + + private: + int const m_numEntries; + HeapBlock const m_table; + }; + + explicit SharedTable (Data* data) + : m_data (data) + { + } + + ReferenceCountedObjectPtr m_data; +}; + +template +SharedTable const SharedTable ::null; + +#endif + +//------------------------------------------------------------------------------ + diff --git a/Subtrees/beast/modules/beast_basics/containers/beast_SortedLookupTable.h b/Subtrees/beast/modules/beast_basics/containers/beast_SortedLookupTable.h new file mode 100644 index 0000000000..86a92e6262 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/containers/beast_SortedLookupTable.h @@ -0,0 +1,169 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_SORTEDLOOKUPTABLE_BEASTHEADER +#define BEAST_SORTEDLOOKUPTABLE_BEASTHEADER + +//============================================================================== +/** + Sorted map for fast lookups. + + This container is optimized for a data set with fixed elements. + + SchemaType obeys this concept: + + @code + + struct SchemaType + { + typename KeyType; + typename ValueType; + + // Retrieve the key for a specified value. + KeyType getKey (Value const& value); + }; + + @endcode + + To use the table, reserve space with reserveSpaceForValues() if the number + of elements is known ahead of time. Then, call insert() for all the your + elements. Call prepareForLookups() once then call lookupValueByKey () +*/ +template +class SortedLookupTable +{ +private: + typedef typename SchemaType::KeyType KeyType; + typedef typename SchemaType::ValueType ValueType; + + typedef std::vector values_t; + + values_t m_values; + +private: + struct SortCompare + { + bool operator () (ValueType const& lhs, ValueType const& rhs) const + { + return SchemaType ().getKey (lhs) < SchemaType ().getKey (rhs); + } + }; + + struct FindCompare + { + bool operator () (ValueType const& lhs, ValueType const& rhs) + { + return SchemaType ().getKey (lhs) < SchemaType ().getKey (rhs); + } + + bool operator () (KeyType const& key, ValueType const& rhs) + { + return key < SchemaType ().getKey (rhs); + } + + bool operator () (ValueType const& lhs, KeyType const& key) + { + return SchemaType ().getKey (lhs) < key; + } + }; + +public: + typedef typename values_t::size_type size_type; + + /** Reserve space for values. + + Although not necessary, this can help with memory usage if the + number of values is known ahead of time. + + @param numberOfValues The amount of space to reserve. + */ + void reserveSpaceForValues (size_type numberOfValues) + { + m_values.reserve (numberOfValues); + } + + /** Insert a value into the index. + + @invariant The value must not already exist in the index. + + @param valueToInsert The value to insert. + */ + void insert (ValueType const& valueToInsert) + { + m_values.push_back (valueToInsert); + } + + /** Prepare the index for lookups. + + This must be called at least once after calling insert() + and before calling find(). + */ + void prepareForLookups () + { + std::sort (m_values.begin (), m_values.end (), SortCompare ()); + } + + /** Find the value for a key. + + Quickly locates a value matching the key, or returns false + indicating no value was found. + + @invariant You must call prepareForLookups() once, after all + insertions, before calling this function. + + @param key The key to locate. + @param pFoundValue Pointer to store the value if a matching + key was found. + @return `true` if the value was found. + */ + bool lookupValueByKey (KeyType const& key, ValueType* pFoundValue) + { + bool found; + + std::pair result = + std::equal_range (m_values.begin (), m_values.end (), key, FindCompare ()); + + if (result.first != result.second) + { + *pFoundValue = *result.first; + found = true; + } + else + { + found = false; + } + + return found; + } +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.cpp b/Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.cpp new file mode 100644 index 0000000000..91ce6f2ebb --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.cpp @@ -0,0 +1,289 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#if 0 +#include + +//------------------------------------------------------------------------------ +// +// Windows structured exception handling +// +#if BEAST_MSVC + +#include + +namespace vf +{ + +namespace +{ + +// +// While this object is in scope, any Windows SEH +// exceptions will be caught and re-thrown as an Error object. +// +class ScopedPlatformExceptionCatcher : Uncopyable +{ +public: + ScopedPlatformExceptionCatcher () + { + //s_mutex.enter (); + + if (++s_count == 1) + s_sehPrev = ::SetUnhandledExceptionFilter (sehFilter); + + //s_mutex.exit (); + } + + ~ScopedPlatformExceptionCatcher () + { + //s_mutex.enter (); + + if (--s_count == 0) + SetUnhandledExceptionFilter (s_sehPrev); + + //s_mutex.exit (); + } + + static LONG WINAPI sehFilter (_EXCEPTION_POINTERS* ei) + { + EXCEPTION_RECORD* er = ei->ExceptionRecord; + + if (er->ExceptionCode == EXCEPTION_BREAKPOINT || + er->ExceptionCode == EXCEPTION_SINGLE_STEP) + { + // pass through + } + else + { + String s; + + switch (er->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + s = TRANS ("an access violation occurred"); + break; + + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + s = TRANS ("array bounds were exceeded"); + break; + + case EXCEPTION_DATATYPE_MISALIGNMENT: + s = TRANS ("memory access was unaligned"); + break; + + case EXCEPTION_FLT_DENORMAL_OPERAND: + s = TRANS ("a floating point operation produced a denormal"); + break; + + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + s = TRANS ("a floating point divide by zero was attempted"); + break; + + case EXCEPTION_FLT_INEXACT_RESULT: + s = TRANS ("the floating point operation was unrepresentable"); + break; + + case EXCEPTION_FLT_INVALID_OPERATION: + s = TRANS ("the floating point operation was invalid"); + break; + + case EXCEPTION_FLT_OVERFLOW: + s = TRANS ("the floating point operation overflowed"); + break; + + case EXCEPTION_FLT_STACK_CHECK: + s = TRANS ("a stack check resulted from a floating point operation"); + break; + + case EXCEPTION_FLT_UNDERFLOW: + s = TRANS ("the floating point operation underflowed"); + break; + + case EXCEPTION_ILLEGAL_INSTRUCTION: + s = TRANS ("an invalid instruction was received"); + break; + + case EXCEPTION_IN_PAGE_ERROR: + s = TRANS ("a virtual paging error occurred"); + break; + + case EXCEPTION_INT_DIVIDE_BY_ZERO: + s = TRANS ("an integer divide by zero was attempted"); + break; + + case EXCEPTION_INT_OVERFLOW: + s = TRANS ("an integer operation overflowed"); + break; + + case EXCEPTION_INVALID_DISPOSITION: + s = TRANS ("the exception handler returned an invalid disposition"); + break; + + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + s = TRANS ("a non-continuable exception occurred"); + break; + + case EXCEPTION_PRIV_INSTRUCTION: + s = TRANS ("a privileged instruction was attempted"); + break; + + case EXCEPTION_STACK_OVERFLOW: + s = TRANS ("the stack overflowed"); + break; + + default: + s = TRANS ("an unknown system exception of code "); + s << String ((unsigned int)er->ExceptionCode); + s << " " << TRANS ("occurred"); + break; + } + + Throw (Error ().fail (__FILE__, __LINE__, s, Error::platform)); + } + + return s_sehPrev (ei); + } + +private: + static int s_count; + static CriticalSection s_mutex; + static LPTOP_LEVEL_EXCEPTION_FILTER s_sehPrev; +}; + +CriticalSection ScopedPlatformExceptionCatcher::s_mutex; +int ScopedPlatformExceptionCatcher::s_count = 0; +LPTOP_LEVEL_EXCEPTION_FILTER ScopedPlatformExceptionCatcher::s_sehPrev = 0; + +} + +} + +//------------------------------------------------------------------------------ + +#else + +// TODO: POSIX SIGNAL HANDLER + +#pragma message(BEAST_LOC_"Missing class ScopedPlatformExceptionCatcher") + +namespace vf +{ + +namespace +{ + +class ScopedPlatformExceptionCatcher +{ +public: + // Missing +}; + +} + +END_BEAST_NAMESPACE + +#endif + +#endif + +//------------------------------------------------------------------------------ + +bool CatchAny (Function f, bool returnFromException) +{ + bool caughtException = true; // assume the worst + +#if 0 + try + { + //ScopedPlatformExceptionCatcher platformExceptionCatcher; + + f (); + + caughtException = false; + } + catch (Error& e) + { + if (!returnFromException) + { + JUCEApplication* app = JUCEApplication::getInstance (); + + if (app) + { + app->unhandledException ( + &e, + e.getSourceFilename (), + e.getLineNumber ()); + } + else + { + std::cout << e.what (); + std::unexpected (); + } + } + } + catch (std::exception& e) + { + if (!returnFromException) + { + JUCEApplication* app = JUCEApplication::getInstance (); + + if (app) + { + app->unhandledException (&e, __FILE__, __LINE__); + } + else + { + std::cout << e.what (); + std::unexpected (); + } + } + } + catch (...) + { + if (!returnFromException) + { + JUCEApplication* app = JUCEApplication::getInstance (); + + if (app) + { + app->unhandledException (0, __FILE__, __LINE__); + } + else + { + std::unexpected (); + } + } + } +#endif + return caughtException; +} diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.h b/Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.h new file mode 100644 index 0000000000..04484dbef0 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_CatchAny.h @@ -0,0 +1,69 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_CATCHANY_BEASTHEADER +#define BEAST_CATCHANY_BEASTHEADER + +#include "../functor/beast_Function.h" + +/** + Exception catcher. + + Executes the function and catches any exception. + In addition to C++ exceptions, this will also catch + any platform-specific exceptions. For example, SEH + (Structured Exception Handling) on Windows, or POSIX + signals if they are available. + + If returnFromException is false then a framework + specific unhandled exception handler will be called. + Otherwise, this function will return true if it + catches something or else false. + + The return value approach is useful for detecting + when outside code fails (for example, a VST plugin), + and disabling its future use for example. + + @todo Remove dependence on the JUCEApplication object and remove beast_gui_basics.h from beast_core.cpp + + @param f The function to call. + + @param returnFromException `false` if exceptions should terminate the app. + + @return `true` if an exception was caught. + + @ingroup beast_core +*/ +extern bool CatchAny (Function f, + bool returnFromException = false); + +#endif diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.cpp b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.cpp new file mode 100644 index 0000000000..23de169839 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.cpp @@ -0,0 +1,268 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +namespace Debug +{ + +//------------------------------------------------------------------------------ + +bool isDebuggerAttached () +{ + return beast_isRunningUnderDebugger (); +} + +//------------------------------------------------------------------------------ + +#if BEAST_DEBUG && defined (beast_breakDebugger) +void breakPoint () +{ + if (isDebuggerAttached ()) + beast_breakDebugger; +} + +#else +void breakPoint () +{ + bassertfalse +} + +#endif + +//---------------------------------------------------------------------------- + +#if BEAST_MSVC && defined (_DEBUG) + +void setHeapAlwaysCheck (bool bAlwaysCheck) +{ + int flags = _CrtSetDbgFlag (_CRTDBG_REPORT_FLAG); + + if (bAlwaysCheck) flags |= _CRTDBG_CHECK_ALWAYS_DF; // on + else flags &= ~_CRTDBG_CHECK_ALWAYS_DF; // off + + _CrtSetDbgFlag (flags); +} + +void setHeapDelayedFree (bool bDelayedFree) +{ + int flags = _CrtSetDbgFlag (_CRTDBG_REPORT_FLAG); + + if (bDelayedFree) flags |= _CRTDBG_DELAY_FREE_MEM_DF; // on + else flags &= ~_CRTDBG_DELAY_FREE_MEM_DF; // off + + _CrtSetDbgFlag (flags); +} + +void setHeapReportLeaks (bool bReportLeaks) +{ + int flags = _CrtSetDbgFlag (_CRTDBG_REPORT_FLAG); + + if (bReportLeaks) flags |= _CRTDBG_LEAK_CHECK_DF; // on + else flags &= ~_CRTDBG_LEAK_CHECK_DF; // off + + _CrtSetDbgFlag (flags); +} + +void checkHeap () +{ + _CrtCheckMemory (); +} + +#else + +void setHeapAlwaysCheck (bool) +{ +} + +void setHeapDelayedFree (bool) +{ +} + +void setHeapReportLeaks (bool) +{ +} + +void checkHeap () +{ +} + +#endif + +//------------------------------------------------------------------------------ + +const String getFileNameFromPath (const char* sourceFileName) +{ + return File::createFileWithoutCheckingPath (sourceFileName).getFileName (); +} + +// Returns a String with double quotes escaped +static const String withEscapedQuotes (String const& string) +{ + String escaped; + + int i0 = 0; + int i; + + do + { + i = string.indexOfChar (i0, '"'); + + if (i == -1) + { + escaped << string.substring (i0, string.length ()); + } + else + { + escaped << string.substring (i0, i) << "\\\""; + i0 = i + 1; + } + } + while (i != -1); + + return escaped; +} + +// Converts escaped quotes back into regular quotes +static const String withUnescapedQuotes (String const& string) +{ + String unescaped; + + int i0 = 0; + int i; + + do + { + i = string.indexOfChar (i0, '\\'); + + if (i == -1) + { + unescaped << string.substring (i0, string.length ()); + } + else + { + // peek + if (string.length () > i && string[i + 1] == '\"') + { + unescaped << string.substring (i0, i) << '"'; + i0 = i + 2; + } + else + { + unescaped << string.substring (i0, i + 1); + i0 = i + 1; + } + } + } + while (i != -1); + + return unescaped; +} + +// Converts a String that may contain newlines, into a +// command line where each line is delimited with quotes. +// Any quotes in the actual string will be escaped via \". +String stringToCommandLine (String const& string) +{ + String commandLine; + + int i0 = 0; + int i; + + for (i = 0; i < string.length (); i++) + { + beast_wchar c = string[i]; + + if (c == '\n') + { + if (i0 != 0) + commandLine << ' '; + + commandLine << '"' << withEscapedQuotes (string.substring (i0, i)) << '"'; + i0 = i + 1; + } + } + + if (i0 < i) + { + if (i0 != 0) + commandLine << ' '; + + commandLine << '"' << withEscapedQuotes (string.substring (i0, i)) << '"'; + } + + return commandLine; +} + +// Converts a command line consisting of multiple quoted strings +// back into a single string with newlines delimiting each quoted +// string. Escaped quotes \" are turned into real quotes. +String commandLineToString (const String& commandLine) +{ + String string; + + bool quoting = false; + int i0 = 0; + int i; + + for (i = 0; i < commandLine.length (); i++) + { + beast_wchar c = commandLine[i]; + + if (c == '\\') + { + // peek + if (commandLine.length () > i && commandLine[i + 1] == '\"') + { + i++; + } + } + else if (c == '"') + { + if (!quoting) + { + i0 = i + 1; + quoting = true; + } + else + { + if (!string.isEmpty ()) + string << '\n'; + + string << withUnescapedQuotes (commandLine.substring (i0, i)); + quoting = false; + } + } + } + + return string; +} + +} diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.h b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.h new file mode 100644 index 0000000000..834109f382 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.h @@ -0,0 +1,69 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_DEBUG_BEASTHEADER +#define BEAST_DEBUG_BEASTHEADER + +// Auxiliary outines for debugging + +namespace Debug +{ + +// Returns true if a debugger is attached, for any build. +extern bool isDebuggerAttached (); + +// Breaks to the debugger if a debugger is attached. +extern void breakPoint (); + +// VF: IS THIS REALLY THE RIGHT PLACE FOR THESE?? + +// Return only the filename portion of sourceFileName +// This hides the programmer's directory structure from end-users. +const String getFileNameFromPath (const char* sourceFileName); + +// Convert a String that may contain double quotes and newlines +// into a String with double quotes escaped as \" and each +// line as a separate quoted command line argument. +String stringToCommandLine (const String& s); + +// Convert a quoted and escaped command line back into a String +// that can contain newlines and double quotes. +String commandLineToString (const String& commandLine); + +extern void setHeapAlwaysCheck (bool bAlwaysCheck); +extern void setHeapDelayedFree (bool bDelayedFree); +extern void setHeapReportLeaks (bool bReportLeaks); +extern void checkHeap (); + +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.cpp b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.cpp new file mode 100644 index 0000000000..26604f2af9 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.cpp @@ -0,0 +1,256 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +Error::Error () + : m_code (success) + , m_lineNumber (0) + , m_needsToBeChecked (true) + , m_szWhat (0) +{ +} + +Error::Error (const Error& other) + : m_code (other.m_code) + , m_reasonText (other.m_reasonText) + , m_sourceFileName (other.m_sourceFileName) + , m_lineNumber (other.m_lineNumber) + , m_needsToBeChecked (true) + , m_szWhat (0) +{ + other.m_needsToBeChecked = false; +} + +Error::~Error () noexcept +{ + /* If this goes off it means an error object was created but never tested */ + bassert (!m_needsToBeChecked); +} + +Error& Error::operator= (const Error& other) +{ + m_code = other.m_code; + m_reasonText = other.m_reasonText; + m_sourceFileName = other.m_sourceFileName; + m_lineNumber = other.m_lineNumber; + m_needsToBeChecked = true; + m_what = String::empty; + m_szWhat = 0; + + other.m_needsToBeChecked = false; + + return *this; +} + +Error::Code Error::code () const +{ + m_needsToBeChecked = false; + return m_code; +} + +bool Error::failed () const +{ + return code () != success; +} + +bool Error::asBoolean () const +{ + return code () != success; +} + +const String Error::getReasonText () const +{ + return m_reasonText; +} + +const String Error::getSourceFilename () const +{ + return m_sourceFileName; +} + +int Error::getLineNumber () const +{ + return m_lineNumber; +} + +Error& Error::fail (const char* sourceFileName, + int lineNumber, + const String reasonText, + Code errorCode) +{ + bassert (m_code == success); + bassert (errorCode != success); + + m_code = errorCode; + m_reasonText = reasonText; + m_sourceFileName = Debug::getFileNameFromPath (sourceFileName); + m_lineNumber = lineNumber; + m_needsToBeChecked = true; + + return *this; +} + +Error& Error::fail (const char* sourceFileName, + int lineNumber, + Code errorCode) +{ + return fail (sourceFileName, + lineNumber, + getReasonTextForCode (errorCode), + errorCode); +} + +void Error::reset () +{ + m_code = success; + m_reasonText = String::empty; + m_sourceFileName = String::empty; + m_lineNumber = 0; + m_needsToBeChecked = true; + m_what = String::empty; + m_szWhat = 0; +} + +void Error::willBeReported () const +{ + m_needsToBeChecked = false; +} + +const char* Error::what () const noexcept +{ + if (!m_szWhat) + { + // The application could not be initialized because sqlite was denied access permission + // The application unexpectedly quit because the exception 'sqlite was denied access permission at file ' was thrown + m_what << + m_reasonText << " " << + TRANS ("at file") << " '" << + m_sourceFileName << "' " << + TRANS ("line") << " " << + String (m_lineNumber) << " " << + TRANS ("with code") << " = " << + String (m_code); + + m_szWhat = (const char*)m_what.toUTF8 (); + } + + return m_szWhat; +} + +const String Error::getReasonTextForCode (Code code) +{ + String s; + + switch (code) + { + case success: + s = TRANS ("the operation was successful"); + break; + + case general: + s = TRANS ("a general error occurred"); + break; + + case canceled: + s = TRANS ("the operation was canceled"); + break; + + case exception: + s = TRANS ("an exception was thrown"); + break; + + case unexpected: + s = TRANS ("an unexpected result was encountered"); + break; + + case platform: + s = TRANS ("a system exception was signaled"); + break; + + case noMemory: + s = TRANS ("there was not enough memory"); + break; + + case noMoreData: + s = TRANS ("the end of data was reached"); + break; + + case invalidData: + s = TRANS ("the data is corrupt or invalid"); + break; + + case bufferSpace: + s = TRANS ("the buffer is too small"); + break; + + case badParameter: + s = TRANS ("one or more parameters were invalid"); + break; + + case assertFailed: + s = TRANS ("an assertion failed"); + break; + + case fileInUse: + s = TRANS ("the file is in use"); + break; + + case fileExists: + s = TRANS ("the file exists"); + break; + + case fileNoPerm: + s = TRANS ("permission was denied"); + break; + + case fileIOError: + s = TRANS ("an I/O or device error occurred"); + break; + + case fileNoSpace: + s = TRANS ("there is no space left on the device"); + break; + + case fileNotFound: + s = TRANS ("the file was not found"); + break; + + case fileNameInvalid: + s = TRANS ("the file name was illegal or malformed"); + break; + + default: + s = TRANS ("an unknown error code was received"); + break; + } + + return s; +} diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.h b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.h new file mode 100644 index 0000000000..0a769c75fa --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.h @@ -0,0 +1,139 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_ERROR_BEASTHEADER +#define BEAST_ERROR_BEASTHEADER + +#include "beast_SafeBool.h" + +/** + A concise error report. + + This lightweight but flexible class records lets you record the file and + line where a recoverable error occurred, along with some optional human + readable text. + + A recoverable error can be passed along and turned into a non recoverable + error by throwing the object: it's derivation from std::exception is + fully compliant with the C++ exception interface. + + @ingroup beast_core +*/ +class Error + : public std::exception + , public SafeBool +{ +public: + /** Numeric code. + + This enumeration is useful when the caller needs to take different + actions depending on the failure. For example, trying again later if + a file is locked. + */ + enum Code + { + success, //!< "the operation was successful" + + general, //!< "a general error occurred" + + canceled, //!< "the operation was canceled" + exception, //!< "an exception was thrown" + unexpected, //!< "an unexpected result was encountered" + platform, //!< "a system exception was signaled" + + noMemory, //!< "there was not enough memory" + noMoreData, //!< "the end of data was reached" + invalidData, //!< "the data is corrupt or invalid" + bufferSpace, //!< "the buffer is too small" + badParameter, //!< "one or more parameters were invalid" + assertFailed, //!< "an assertion failed" + + fileInUse, //!< "the file is in use" + fileExists, //!< "the file exists" + fileNoPerm, //!< "permission was denied" (file attributes conflict) + fileIOError, //!< "an I/O or device error occurred" + fileNoSpace, //!< "there is no space left on the device" + fileNotFound, //!< "the file was not found" + fileNameInvalid //!< "the file name was illegal or malformed" + }; + + Error (); + Error (const Error& other); + Error& operator= (const Error& other); + + virtual ~Error () noexcept; + + Code code () const; + bool failed () const; + + bool asBoolean () const; + + const String getReasonText () const; + const String getSourceFilename () const; + int getLineNumber () const; + + Error& fail (const char* sourceFileName, + int lineNumber, + const String reasonText, + Code errorCode = general); + + Error& fail (const char* sourceFileName, + int lineNumber, + Code errorCode = general); + + // A function that is capable of recovering from an error (for + // example, by performing a different action) can reset the + // object so it can be passed up. + void reset (); + + // Call this when reporting the error to clear the "checked" flag + void willBeReported () const; + + // for std::exception. This lets you throw an Error that should + // terminate the application. The what() message will be less + // descriptive so ideally you should catch the Error object instead. + const char* what () const noexcept; + + static const String getReasonTextForCode (Code code); + +private: + Code m_code; + String m_reasonText; + String m_sourceFileName; + int m_lineNumber; + mutable bool m_needsToBeChecked; + + mutable String m_what; // created on demand + mutable const char* m_szWhat; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.cpp b/Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.cpp new file mode 100644 index 0000000000..22287d1933 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.cpp @@ -0,0 +1,53 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +void FPUFlags::clearUnsetFlagsFrom (const FPUFlags& flags) +{ + if (!flags.getMaskNaNs ().is_set ()) m_maskNaNs.clear (); + + if (!flags.getMaskDenormals ().is_set ()) m_maskDenormals.clear (); + + if (!flags.getMaskZeroDivides ().is_set ()) m_maskZeroDivides.clear (); + + if (!flags.getMaskOverflows ().is_set ()) m_maskOverflows.clear (); + + if (!flags.getMaskUnderflows ().is_set ()) m_maskUnderflows.clear (); + + //if (!flags.getMaskInexacts().is_set ()) m_maskInexacts.clear (); + if (!flags.getFlushDenormals ().is_set ()) m_flushDenormals.clear (); + + if (!flags.getInfinitySigned ().is_set ()) m_infinitySigned.clear (); + + if (!flags.getRounding ().is_set ()) m_rounding.clear (); + + if (!flags.getPrecision ().is_set ()) m_precision.clear (); +} diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.h b/Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.h new file mode 100644 index 0000000000..60d3dc1653 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.h @@ -0,0 +1,348 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_FPUFLAGS_BEASTHEADER +#define BEAST_FPUFLAGS_BEASTHEADER + +/*============================================================================*/ +/** + A set of IEEE FPU flags. + + Description. + + @ingroup beast_core +*/ +class FPUFlags +{ +public: + /** An individual FPU flag */ + struct Flag + { + Flag () : m_set (false) { } + Flag (Flag const& flag) : m_set (flag.m_set), m_value (flag.m_value) { } + Flag& operator= (Flag const& flag) + { + m_set = flag.m_set; + m_value = flag.m_value; + return *this; + } + bool is_set () const + { + return m_set; + } + bool value () const + { + assert (m_set); + return m_value; + } + void set_value (bool value) + { + m_set = true; + m_value = value; + } + void clear () + { + m_set = false; + } + + private: + bool m_set : 1; + bool m_value : 1; + }; + + /** A multi-valued FPU setting */ + template + struct Enum + { + Enum () : m_set (false) { } + Enum (Enum const& value) : m_set (value.m_set), m_value (value.m_value) { } + Enum& operator= (Enum const& value) + { + m_set = value.m_set; + m_value = value.m_value; + return *this; + } + bool is_set () const + { + return m_set; + } + Constants value () const + { + return m_value; + } + void set_value (Constants value) + { + m_set = true; + m_value = value; + } + void clear () + { + m_set = false; + } + + private: + bool m_set : 1; + Constants m_value; + }; + +public: + // + // Exception masks + // + + void setMaskNaNs (bool mask = true) + { + m_maskNaNs.set_value (mask); + } + void setMaskDenormals (bool mask = true) + { + m_maskDenormals.set_value (mask); + } + void setMaskZeroDivides (bool mask = true) + { + m_maskZeroDivides.set_value (mask); + } + void setMaskOverflows (bool mask = true) + { + m_maskOverflows.set_value (mask); + } + void setMaskUnderflows (bool mask = true) + { + m_maskUnderflows.set_value (mask); + } + //void setMaskInexacts (bool mask = true) { m_maskInexacts.set_value (mask); } + + void setUnmaskAllExceptions (bool unmask = true) + { + setMaskNaNs (!unmask); + setMaskDenormals (!unmask); + setMaskZeroDivides (!unmask); + setMaskOverflows (!unmask); + setMaskUnderflows (!unmask); + //setMaskInexacts (!unmask); + } + + // + // Denormal control + // + + void setFlushDenormals (bool flush = true) + { + m_flushDenormals.set_value (flush); + } + + // + // Infinity control + // + + void setInfinitySigned (bool is_signed = true) + { + m_infinitySigned.set_value (is_signed); + } + + // + // Rounding control + // + + enum Rounding + { + roundChop, + roundUp, + roundDown, + roundNear + }; + + void setRounding (Rounding rounding) + { + m_rounding.set_value (rounding); + } + + // + // Precision control + // + + enum Precision + { + bits24, + bits53, + bits64 + }; + + void setPrecision (Precision precision) + { + m_precision.set_value (precision); + } + + // + // Retrieval + // + + const Flag getMaskNaNs () const + { + return m_maskNaNs; + } + const Flag getMaskDenormals () const + { + return m_maskDenormals; + } + const Flag getMaskZeroDivides () const + { + return m_maskZeroDivides; + } + const Flag getMaskOverflows () const + { + return m_maskOverflows; + } + const Flag getMaskUnderflows () const + { + return m_maskUnderflows; + } + //const Flag getMaskInexacts () const { return m_maskInexacts; } + const Flag getFlushDenormals () const + { + return m_flushDenormals; + } + const Flag getInfinitySigned () const + { + return m_infinitySigned; + } + const Enum getRounding () const + { + return m_rounding; + } + const Enum getPrecision () const + { + return m_precision; + } + + Flag& getMaskNaNs () + { + return m_maskNaNs; + } + Flag& getMaskDenormals () + { + return m_maskDenormals; + } + Flag& getMaskZeroDivides () + { + return m_maskZeroDivides; + } + Flag& getMaskOverflows () + { + return m_maskOverflows; + } + Flag& getMaskUnderflows () + { + return m_maskUnderflows; + } + //Flag& getMaskInexacts () { return m_maskInexacts; } + Flag& getFlushDenormals () + { + return m_flushDenormals; + } + Flag& getInfinitySigned () + { + return m_infinitySigned; + } + Enum & getRounding () + { + return m_rounding; + } + Enum & getPrecision () + { + return m_precision; + } + + // Clears our flags if they are not set in another object + void clearUnsetFlagsFrom (FPUFlags const& flags); + + // Retrieve the current flags fron the FPU + static FPUFlags getCurrent (); + + // Change the current FPU flags based on what is set in flags + static void setCurrent (FPUFlags const& flags); + +private: + Flag m_maskNaNs; + Flag m_maskDenormals; + Flag m_maskZeroDivides; + Flag m_maskOverflows; + Flag m_maskUnderflows; + //Flag m_maskInexacts; + Flag m_flushDenormals; + Flag m_infinitySigned; + Enum m_rounding; + Enum m_precision; +}; + +//------------------------------------------------------------------------------ + +/*============================================================================*/ +/** + IEEE FPU flag modifications with scoped lifetime. + + An instance of the class saves the FPU flags and updates + + FPUFlags flags; + flags.setUnmaskAllExceptions (); + + { + ScopedFPUFlags fpu (flags); + + // Perform floating point calculations + } + + // FPU flags are back to what they were now + + @ingroup beast_core +*/ +class ScopedFPUFlags +{ +public: + ScopedFPUFlags (FPUFlags const& flagsToSet) + { + m_savedFlags = FPUFlags::getCurrent (); + m_savedFlags.clearUnsetFlagsFrom (flagsToSet); + FPUFlags::setCurrent (flagsToSet); + } + + ~ScopedFPUFlags () + { + FPUFlags::setCurrent (m_savedFlags); + } + +private: + FPUFlags m_savedFlags; +}; + +#endif + diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.cpp b/Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.cpp new file mode 100644 index 0000000000..1be3982279 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.cpp @@ -0,0 +1,104 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#if BEAST_USE_LEAKCHECKED + +/*============================================================================*/ +// Type-independent portion of Counter +class LeakCheckedBase::CounterBase::Singleton +{ +public: + void push_back (CounterBase* counter) + { + m_list.push_front (counter); + } + + void detectAllLeaks () + { + for (;;) + { + CounterBase* counter = m_list.pop_front (); + + if (!counter) + break; + + counter->detectLeaks (); + } + } + + static Singleton& getInstance () + { + static Singleton instance; + + return instance; + } + +private: + LockFreeStack m_list; +}; + +//------------------------------------------------------------------------------ + +LeakCheckedBase::CounterBase::CounterBase () +{ + Singleton::getInstance ().push_back (this); +} + +void LeakCheckedBase::CounterBase::detectAllLeaks () +{ + Singleton::getInstance ().detectAllLeaks (); +} + +void LeakCheckedBase::CounterBase::detectLeaks () +{ + // If there's a runtime error from this line, it means there's + // an order of destruction problem between different translation units! + // + this->checkPureVirtual (); + + int const count = m_count.get (); + + if (count > 0) + { + bassertfalse; + DBG ("[LEAK] " << count << " of " << getClassName ()); + } +} + +//------------------------------------------------------------------------------ + +void LeakCheckedBase::detectAllLeaks () +{ + CounterBase::detectAllLeaks (); +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.h b/Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.h new file mode 100644 index 0000000000..c518e0bdca --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_LeakChecked.h @@ -0,0 +1,184 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_LEAKCHECKED_BEASTHEADER +#define BEAST_LEAKCHECKED_BEASTHEADER + +#include "beast_Error.h" +#include "beast_Throw.h" +#include "../memory/beast_StaticObject.h" +#include "../containers/beast_LockFreeStack.h" + +// +// Derived classes are automatically leak-checked on exit +// + +#if BEAST_USE_LEAKCHECKED + +class LeakCheckedBase +{ +public: + static void detectAllLeaks (); + +protected: + class CounterBase : public LockFreeStack ::Node + { + public: + CounterBase (); + + virtual ~CounterBase () { } + + inline int increment () + { + return ++m_count; + } + + inline int decrement () + { + return --m_count; + } + + virtual char const* getClassName () const = 0; + + static void detectAllLeaks (); + + private: + void detectLeaks (); + + virtual void checkPureVirtual () const = 0; + + protected: + class Singleton; + + Atomic m_count; + }; +}; + +//------------------------------------------------------------------------------ + +/** Detects leaks at program exit. + + To use this, derive your class from this template using CRTP (curiously + recurring template pattern). +*/ +template +class LeakChecked : private LeakCheckedBase +{ +protected: + LeakChecked () noexcept + { + if (getLeakCheckedCounter ().increment () == 0) + { + DBG ("[LOGIC] " << getLeakCheckedName ()); + Throw (Error ().fail (__FILE__, __LINE__)); + } + } + + LeakChecked (const LeakChecked&) noexcept + { + if (getLeakCheckedCounter ().increment () == 0) + { + DBG ("[LOGIC] " << getLeakCheckedName ()); + Throw (Error ().fail (__FILE__, __LINE__)); + } + } + + ~LeakChecked () + { + if (getLeakCheckedCounter ().decrement () < 0) + { + DBG ("[LOGIC] " << getLeakCheckedName ()); + Throw (Error ().fail (__FILE__, __LINE__)); + } + } + +private: + class Counter : public CounterBase + { + public: + Counter () noexcept + { + } + + char const* getClassName () const + { + return getLeakCheckedName (); + } + + void checkPureVirtual () const { } + }; + +private: + /* Due to a bug in Visual Studio 10 and earlier, the string returned by + typeid().name() will appear to leak on exit. Therefore, we should + only call this function when there's an actual leak, or else there + will be spurious leak notices at exit. + */ + static const char* getLeakCheckedName () + { + return typeid (Object).name (); + } + + static Counter& getLeakCheckedCounter () noexcept + { + static Counter* volatile s_instance; + static Static::Initializer s_initializer; + + if (s_initializer.begin ()) + { + static char s_storage [sizeof (Counter)]; + s_instance = new (s_storage) Counter; + s_initializer.end (); + } + + return *s_instance; + } +}; + +#else + +class LeakCheckedBase +{ +private: + friend class PerformedAtExit; + + static void detectAllLeaks () { } +}; + +template +struct LeakChecked : LeakCheckedBase +{ +}; + +#endif + +#endif diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_SafeBool.h b/Subtrees/beast/modules/beast_basics/diagnostic/beast_SafeBool.h new file mode 100644 index 0000000000..421b9f7cb9 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_SafeBool.h @@ -0,0 +1,104 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_SAFEBOOL_BEASTHEADER +#define BEAST_SAFEBOOL_BEASTHEADER + +/** + Safe evaluation of class as `bool`. + + This allows a class to be safely evaluated as a bool without the usual harmful + side effects of the straightforward operator conversion approach. To use it, + derive your class from SafeBool and implement `asBoolean()` as: + + @code + + bool asBoolean () const; + + @endcode + + Ideas from http://www.artima.com/cppsource/safebool.html + + @class SafeBool + + @ingroup beast_core +*/ + +class SafeBoolBase +{ +private: + void disallowed () const { } + +public: + void allowed () const { } + +protected: + typedef void (SafeBoolBase::*boolean_t) () const; + + SafeBoolBase () { } + SafeBoolBase (SafeBoolBase const&) { } + SafeBoolBase& operator= (SafeBoolBase const&) + { + return *this; + } + ~SafeBoolBase () { } +}; + +template +class SafeBool : public SafeBoolBase +{ +public: + operator boolean_t () const + { + return (static_cast (this))->asBoolean () + ? &SafeBoolBase::allowed : 0; + } + +protected: + ~SafeBool () { } +}; + +template +void operator== (SafeBool const& lhs, SafeBool const& rhs) +{ + lhs.disallowed (); +} + +template +void operator!= (SafeBool const& lhs, SafeBool const& rhs) +{ + lhs.disallowed (); +} + +#endif + + diff --git a/Subtrees/beast/modules/beast_basics/diagnostic/beast_Throw.h b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Throw.h new file mode 100644 index 0000000000..f93e111522 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/diagnostic/beast_Throw.h @@ -0,0 +1,51 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_THROW_BEASTHEADER +#define BEAST_THROW_BEASTHEADER + +#include "beast_Debug.h" + +// +// Throw an exception, with the opportunity to get a +// breakpoint with the call stack before the throw. +// + +template +inline void Throw (Exception const& e) +{ + Debug::breakPoint (); + + throw e; +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.cpp b/Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.cpp new file mode 100644 index 0000000000..77aec8d92b --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.cpp @@ -0,0 +1,124 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +class OncePerSecond::TimerSingleton + : public RefCountedSingleton + , private InterruptibleThread::EntryPoint +{ +private: + TimerSingleton () + : RefCountedSingleton ( + SingletonLifetime::persistAfterCreation) + , m_thread ("Once Per Second") + { + m_thread.start (this); + } + + ~TimerSingleton () + { + m_thread.join (); + + bassert (m_list.empty ()); + } + + void threadRun () + { + for (;;) + { + const bool interrupted = m_thread.wait (1000); + + if (interrupted) + break; + + notify (); + } + } + + void notify () + { + CriticalSection::ScopedLockType lock (m_mutex); + + for (List ::iterator iter = m_list.begin (); iter != m_list.end ();) + { + OncePerSecond* object = iter->object; + ++iter; + object->doOncePerSecond (); + } + } + +public: + void insert (Elem* elem) + { + CriticalSection::ScopedLockType lock (m_mutex); + + m_list.push_back (*elem); + } + + void remove (Elem* elem) + { + CriticalSection::ScopedLockType lock (m_mutex); + + m_list.erase (m_list.iterator_to (*elem)); + } + + static TimerSingleton* createInstance () + { + return new TimerSingleton; + } + +private: + InterruptibleThread m_thread; + CriticalSection m_mutex; + List m_list; +}; + +//------------------------------------------------------------------------------ + +OncePerSecond::OncePerSecond () +{ + m_elem.instance = TimerSingleton::getInstance (); + m_elem.object = this; +} + +OncePerSecond::~OncePerSecond () +{ +} + +void OncePerSecond::startOncePerSecond () +{ + m_elem.instance->insert (&m_elem); +} + +void OncePerSecond::endOncePerSecond () +{ + m_elem.instance->remove (&m_elem); +} diff --git a/Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.h b/Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.h new file mode 100644 index 0000000000..08da0bfe1b --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/events/beast_OncePerSecond.h @@ -0,0 +1,77 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_ONCEPERSECOND_BEASTHEADER +#define BEAST_ONCEPERSECOND_BEASTHEADER + +#include "../containers/beast_List.h" + +/*============================================================================*/ +/** + Provides a once per second notification. + + Derive your class from OncePerSecond and override doOncePerSecond(). Then, + call startOncePerSecond() to begin receiving the notifications. No clean-up + or other actions are required. + + @ingroup beast_core +*/ +class OncePerSecond : Uncopyable +{ +public: + OncePerSecond (); + virtual ~OncePerSecond (); + + /** Begin receiving notifications. */ + void startOncePerSecond (); + + /** Stop receiving notifications. */ + void endOncePerSecond (); + +protected: + /** Called once per second. */ + virtual void doOncePerSecond () = 0; + +private: + class TimerSingleton; + typedef ReferenceCountedObjectPtr TimerPtr; + + struct Elem : List ::Node + { + TimerPtr instance; + OncePerSecond* object; + }; + + Elem m_elem; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.cpp b/Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.cpp new file mode 100644 index 0000000000..8dca197db6 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.cpp @@ -0,0 +1,79 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +class PerformedAtExit::Performer +{ +public: + typedef Static::Storage , PerformedAtExit> StackType; + +private: + ~Performer () + { + PerformedAtExit* object = s_list->pop_front (); + + while (object != nullptr) + { + object->performAtExit (); + + object = s_list->pop_front (); + } + + LeakCheckedBase::detectAllLeaks (); + } + +public: + static void push_front (PerformedAtExit* object) + { + s_list->push_front (object); + } + +private: + friend class PerformedAtExit; + + static StackType s_list; + + static Performer s_performer; +}; + +PerformedAtExit::Performer PerformedAtExit::Performer::s_performer; +PerformedAtExit::Performer::StackType PerformedAtExit::Performer::s_list; + +PerformedAtExit::PerformedAtExit () +{ +#if BEAST_IOS + // TODO: PerformedAtExit::Performer::push_front crashes on iOS if s_storage is not accessed before used + char* hack = PerformedAtExit::Performer::s_list.s_storage; +#endif + + Performer::push_front (this); +} + diff --git a/Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.h b/Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.h new file mode 100644 index 0000000000..4ad6020bae --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/events/beast_PerformedAtExit.h @@ -0,0 +1,63 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_PERFORMEDATEXIT_BEASTHEADER +#define BEAST_PERFORMEDATEXIT_BEASTHEADER + +#include "../containers/beast_LockFreeStack.h" + +/*============================================================================*/ +/** + Perform an action at program exit + + To use, derive your class from PerformedAtExit, and override `performAtExit()`. + The call will be made during the destruction of objects with static storage + duration, before LeakChecked performs its diagnostics. + + @ingroup beast_core +*/ +class PerformedAtExit : public LockFreeStack ::Node +{ +protected: + PerformedAtExit (); + virtual ~PerformedAtExit () { } + +protected: + /** Called at program exit. + */ + virtual void performAtExit () = 0; + +private: + class Performer; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/functor/beast_Bind.h b/Subtrees/beast/modules/beast_basics/functor/beast_Bind.h new file mode 100644 index 0000000000..39c70d6566 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/functor/beast_Bind.h @@ -0,0 +1,109 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_BIND_BEASTHEADER +#define BEAST_BIND_BEASTHEADER + +/* Brings functional support into our namespace, based on environment. +*/ +#if BEAST_MSVC +// Visual Studio has these in std. +using std::ref; +using std::bind; +using std::function; +using std::placeholders::_1; +using std::placeholders::_2; + +#elif BEAST_IOS +#if BEAST_USE_BOOST +/* If boost is activated, use it. This works + around a bug with the iOS implementation of bind. +*/ +using boost::ref +using boost::bind; +using boost::function; +using ::_1; +using ::_2; +#else +#if _LIBCPP_VERSION // libc++ +using std::ref; +using std::bind; +using std::function; +using std::placeholders::_1; +using std::placeholders::_2; +#else // libstdc++ (GNU) +using std::tr1::ref; +using std::tr1::bind; +using std::tr1::function; +using std::tr1::placeholders::_1; +using std::tr1::placeholders::_2; +#endif +#endif + +#elif BEAST_MAC +#if _LIBCPP_VERSION // libc++ +using std::ref; +using std::bind; +using std::function; +using std::placeholders::_1; +using std::placeholders::_2; +#else // libstdc++ (GNU) +using std::tr1::ref; +using std::tr1::bind; +using std::tr1::function; +using std::tr1::placeholders::_1; +using std::tr1::placeholders::_2; +#endif + +#elif BEAST_LINUX +using std::tr1::bind; +using std::tr1::placeholders::_1; +using std::tr1::placeholders::_2; + +#else +#error Unknown platform in beast_Bind.h + +#endif + +/** Max number of arguments to bind, total. +*/ +#if BEAST_MSVC +# ifdef _VARIADIC_MAX +# define VFLIB_VARIADIC_MAX _VARIADIC_MAX +# else +# define VFLIB_VARIADIC_MAX 9 +# endif +#else +# define VFLIB_VARIADIC_MAX 9 +#endif + +#endif diff --git a/Subtrees/beast/modules/beast_basics/functor/beast_Function.h b/Subtrees/beast/modules/beast_basics/functor/beast_Function.h new file mode 100644 index 0000000000..a86ba7d9ea --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/functor/beast_Function.h @@ -0,0 +1,279 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_FUNCTION_BEASTHEADER +#define BEAST_FUNCTION_BEASTHEADER + +// +// Strong replacement for boost::function: +// +// #1 Bounded memory requirement, avoids the free store. +// +// #2 Always refers to a functor (i.e. is never invalid) +// +// #3 Default value (None) is a function that +// returns a default object (the result type +// constructed with a default constructor). +// + +template +class Function; + +// +// nullary function +// + +template +class Function +{ +public: + typedef R result_type; + typedef Function self_type; + + struct None + { + typedef R result_type; + result_type operator () () const + { + return result_type (); + } + }; + + Function () + { + constructCopyOf (None ()); + } + + Function (Function const& f) + { + f.getCall ().constructCopyInto (m_storage); + } + + template + Function (Functor const& f) + { + constructCopyOf (f); + } + + ~Function () + { + getCall ().~Call (); + } + + Function& operator= (Function const& f) + { + getCall ().~Call (); + f.getCall ().constructCopyInto (m_storage); + return *this; + } + + template + Function& operator= (Functor const& f) + { + getCall ().~Call (); + constructCopyOf (f); + return *this; + } + + result_type operator () () + { + return getCall ().operator () (); + } + +private: + template + void constructCopyOf (Functor const& f) + { + // If this generates a compile error it means that + // the functor is too large for the static buffer. + // Increase the storage template parameter until + // the error message goes away. This might cause + // changes throughout the application with other + // template classes that depend on the size. + static_bassert (sizeof (StoredCall ) <= Bytes); + new (m_storage) StoredCall (f); + } + +private: + struct Call + { + virtual ~Call () {} + virtual void constructCopyInto (void* p) const = 0; + virtual result_type operator () () = 0; + }; + + template + struct StoredCall : Call + { + explicit StoredCall (Functor const& f) : m_f (f) { } + StoredCall (const StoredCall& c) : m_f (c.m_f) { } + void constructCopyInto (void* p) const + { + new (p) StoredCall (m_f); + } + result_type operator () () + { + return m_f (); + } + private: + Functor m_f; + }; + + Call& getCall () + { + return *reinterpret_cast (&m_storage[0]); + } + + Call const& getCall () const + { + return *reinterpret_cast (&m_storage[0]); + } + + char m_storage [Bytes]; // should be enough +}; + +//------------------------------------------------------------------------------ + +// +// unary function +// + +template +class Function +{ +public: + typedef R result_type; + typedef Function self_type; + + struct None + { + typedef R result_type; + result_type operator () (T1) const + { + return result_type (); + } + }; + + Function () + { + constructCopyOf (None ()); + } + + Function (const Function& f) + { + f.getCall ().constructCopyInto (m_storage); + } + + template + Function (Functor const& f) + { + constructCopyOf (f); + } + + ~Function () + { + getCall ().~Call (); + } + + Function& operator= (const Function& f) + { + getCall ().~Call (); + f.getCall ().constructCopyInto (m_storage); + return *this; + } + + template + Function& operator= (Functor const& f) + { + getCall ().~Call (); + constructCopyOf (f); + return *this; + } + + result_type operator () (T1 t1) + { + return getCall ().operator () (t1); + } + +private: + template + void constructCopyOf (Functor const& f) + { + // If this generates a compile error it means that + // the functor is too large for the static buffer. + // Increase the storage template parameter until + // the error message goes away. This might cause + // changes throughout the application with other + // template classes that depend on the size. + static_bassert (sizeof (StoredCall ) <= Bytes); + new (m_storage) StoredCall (f); + } + +private: + struct Call + { + virtual ~Call () {} + virtual void constructCopyInto (void* p) const = 0; + virtual result_type operator () (T1 t1) = 0; + }; + + template + struct StoredCall : Call + { + explicit StoredCall (Functor const& f) : m_f (f) { } + StoredCall (const StoredCall& c) : m_f (c.m_f) { } + void constructCopyInto (void* p) const + { + new (p) StoredCall (m_f); + } + result_type operator () (T1 t1) + { + return m_f (t1); + } + private: + Functor m_f; + }; + + Call& getCall () + { + return *reinterpret_cast (&m_storage[0]); + } + + Call const& getCall () const + { + return *reinterpret_cast (&m_storage[0]); + } + + char m_storage [Bytes]; // should be enough +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/math/beast_Interval.h b/Subtrees/beast/modules/beast_basics/math/beast_Interval.h new file mode 100644 index 0000000000..668c940d06 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/math/beast_Interval.h @@ -0,0 +1,400 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_INTERVAL_BEASTHEADER +#define BEAST_INTERVAL_BEASTHEADER + +/** A half-open interval. + + This represents the half-open interval [begin, end) over the scalar + type of template parameter `Ty`. It may also be considered as the + specification of a subset of a 1-dimensional Euclidean space. + + @tparam Ty A scalar numerical type. +*/ +template +class Interval +{ +public: + typedef Ty value_type; + + /** The empty interval. + */ + static const Interval none; + + /** Create an uninitialized interval. + */ + Interval () + { + } + + /** Create an interval with the specified values. + */ + Interval (Ty begin, Ty end) + : m_begin (begin) + , m_end (end) + { + } + + /** Create an interval from another interval. + */ + Interval (Interval const& other) + : m_begin (other.m_begin) + , m_end (other.m_end) + { + } + + /** Assign from another interval. + + @param other The interval to assign from. + + @return A reference to this interval. + */ + Interval& operator= (const Interval& other) + { + m_begin = other.m_begin; + m_end = other.m_end; + return *this; + } + + /** Compare an interval for equality. + + Empty intervals are always equal to other empty intervals. + + @param rhs The other interval to compare. + + @return `true` if this interval is equal to the specified interval. + */ + bool operator== (Interval const& rhs) const + { + return (empty () && rhs.empty ()) || + (m_begin == rhs.m_begin && m_end == rhs.m_end); + } + + /** Compare an interval for inequality. + + @param rhs The other interval to compare. + + @return `true` if this interval is not equal to the specified interval. + */ + bool operator!= (Interval const& rhs) const + { + return !this->operator== (rhs); + } + + /** Get the starting value of the interval. + + @return The starting point of the interval. + */ + Ty begin () const + { + return m_begin; + } + + /** Get the ending value of the interval. + + @return The ending point of the interval. + */ + Ty end () const + { + return m_end; + } + + /** Get the Lebesque measure. + + @return The Lebesque measure. + */ + Ty length () const + { + return empty () ? Ty () : (end () - begin ()); + } + + //Ty count () const { return length (); } // sugar + //Ty distance () const { return length (); } // sugar + + /** Determine if the interval is empty. + + @return `true` if the interval is empty. + */ + bool empty () const + { + return m_begin >= m_end; + } + + /** Determine if the interval is non-empty. + + @return `true` if the interval is not empty. + */ + bool notEmpty () const + { + return m_begin < m_end; + } + + /** Set the starting point of the interval. + + @param v The starting point. + */ + void setBegin (Ty v) + { + m_begin = v; + } + + /** Set the ending point of the interval. + + @param v The ending point. + */ + void setEnd (Ty v) + { + m_end = v; + } + + /** Set the ending point relative to the starting point. + + @param v The length of the resulting interval. + */ + void setLength (Ty v) + { + m_end = m_begin + v; + } + + /** Determine if a value is contained in the interval. + + @param v The value to check. + + @return `true` if this interval contains `v`. + */ + bool contains (Ty v) const + { + return notEmpty () && v >= m_begin && v < m_end; + } + + /** Determine if this interval intersects another interval. + + @param other The other interval. + + @return `true` if the intervals intersect. + */ + template + bool intersects (Interval const& other) const + { + return notEmpty () && other.notEmpty () && + end () > other.begin () && begin () < other.end (); + } + + /** Determine if this interval adjoins another interval. + + An interval is adjoint to another interval if and only if the union of the + intervals is a single non-empty half-open subset. + + @param other The other interval. + + @return `true` if the intervals are adjoint. + */ + template + bool adjoins (Interval const& other) const + { + return (empty () != other.empty ()) || + (notEmpty () && end () >= other.begin () + && begin () <= other.end ()); + } + + /** Determine if this interval is disjoint from another interval. + + @param other The other interval. + + @return `true` if the intervals are disjoint. + */ + bool disjoint (Interval const& other) const + { + return !intersects (other); + } + + /** Determine if this interval is a superset of another interval. + + An interval A is a superset of interval B if B is empty or if A fully + contains B. + + @param other The other interval. + + @return `true` if this is a superset of `other`. + */ + template + bool superset_of (Interval const& other) const + { + return other.empty () || + (notEmpty () && begin () <= other.begin () + && end () >= other.end ()); + } + + /** Determine if this interval is a proper superset of another interval. + + An interval A is a proper superset of interval B if A is a superset of + B and A is not equal to B. + + @param other The other interval. + + @return `true` if this interval is a proper superset of `other`. + */ + template + bool proper_superset_of (Interval const& other) const + { + return this->superset_of (other) && this->operator != (other); + } + + /** Determine if this interval is a subset of another interval. + + @param other The other interval. + + @return `true` if this interval is a subset of `other`. + */ + template + bool subset_of (Interval const& other) const + { + return other.superset_of (*this); + } + + /** Determine if this interval is a proper subset of another interval. + + @param other The other interval. + + @return `true` if this interval is a proper subset of `other`. + */ + template + bool proper_subset_of (Interval const& other) const + { + return other.proper_superset_of (*this); + } + + /** Return the intersection of this interval with another interval. + + @param other The other interval. + + @return The intersection of the intervals. + */ + template + Interval intersection (Interval const& other) const + { + return Interval (std::max (begin (), other.begin ()), + std::min (end (), other.end ())); + } + + /** Determine the smallest interval that contains both intervals. + + @param other The other interval. + + @return The simple union of the intervals. + */ + template + Interval simple_union (Interval const& other) const + { + return Interval ( + std::min (other.normalized ().begin (), normalized ().begin ()), + std::max (other.normalized ().end (), normalized ().end ())); + } + + /** Calculate the single-interval union. + + The result is empty if the union cannot be represented as a + single half-open interval. + + @param other The other interval. + + @return The simple union of the intervals. + */ + template + Interval single_union (Interval const& other) const + { + if (empty ()) + return other; + + else if (other.empty ()) + return *this; + + else if (end () < other.begin () || begin () > other.end ()) + return none; + + else + return Interval (std::min (begin (), other.begin ()), + std::max (end (), other.end ())); + } + + /** Determine if the interval is correctly ordered. + + @return `true` if the interval is correctly ordered. + */ + bool normal () const + { + return end () >= begin (); + } + + /** Return a normalized interval. + + @return The normalized interval. + */ + Interval normalized () const + { + if (normal ()) + return *this; + else + return Interval (end (), begin ()); + } + + /** Clamp a value to the interval. + + @param v The value to clamp. + + @return The clamped result. + */ + template + Ty clamp (Tv v) const + { + // These conditionals are carefully ordered so + // that if m_begin == m_end, value is assigned m_begin. + if (v > end ()) + v = end () - (std::numeric_limits ::is_integer ? 1 : + std::numeric_limits ::epsilon ()); + + if (v < begin ()) + v = begin (); + + return v; + } + +private: + Ty m_begin; + Ty m_end; +}; + +template +const Interval Interval::none = Interval (Ty (), Ty ()); + +#endif diff --git a/Subtrees/beast/modules/beast_basics/math/beast_Math.h b/Subtrees/beast/modules/beast_basics/math/beast_Math.h new file mode 100644 index 0000000000..db3d6261af --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/math/beast_Math.h @@ -0,0 +1,97 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_MATH_BEASTHEADER +#define BEAST_MATH_BEASTHEADER + +// +// Miscellaneous mathematical calculations +// + +// Calculate the bin for a value given the bin size. +// This correctly handles negative numbers. For example +// if value == -1 then calc_bin returns -1. +template +inline Ty calc_bin (Ty value, int size) +{ + if (value >= 0) + return value / size; + else + return (value - size + 1) / size; +} + +// Given a number and a bin size, this returns the first +// corresponding value of the bin associated with the given number. +// It correctly handles negative numbers. For example, +// if value == -1 then calc_bin always returns -size +template +inline Ty calc_bin_start (Ty value, int size) +{ + return calc_bin (value, size) * size; +} + +template +inline T pi () noexcept +{ + return 3.14159265358979; +} + +template +inline T twoPi () noexcept +{ + return 6.28318530717958; +} + +template +inline T oneOverTwoPi () noexcept +{ + return 0.1591549430918955; +} + +template +inline T degreesToRadians (U degrees) +{ + return T (degrees * 0.0174532925199433); +} + +template +inline T radiansToDegrees (U radians) +{ + T deg = T (radians * U (57.29577951308238)); + + if (deg < 0) + deg += 360; + + return deg; +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.cpp b/Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.cpp new file mode 100644 index 0000000000..4676f1c55c --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.cpp @@ -0,0 +1,506 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +// http://code.google.com/p/smhasher/ + +//#include "modules/beast_core/system/beast_TargetPlatform.h" + +namespace Murmur +{ + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if BEAST_MSVC + +#define FORCE_INLINE __forceinline + +#define ROTL32(x,y) _rotl(x,y) +#define ROTL64(x,y) _rotl64(x,y) + +#define BIG_CONSTANT(x) (x) + +// Other compilers + +#else + +#define FORCE_INLINE __attribute__((always_inline)) + +static inline uint32_t rotl32 ( uint32_t x, int8_t r ) +{ + return (x << r) | (x >> (32 - r)); +} + +static inline uint64_t rotl64 ( uint64_t x, int8_t r ) +{ + return (x << r) | (x >> (64 - r)); +} + +#define ROTL32(x,y) rotl32(x,y) +#define ROTL64(x,y) rotl64(x,y) + +#define BIG_CONSTANT(x) (x##LLU) + +#endif + +//----------------------------------------------------------------------------- +// Block read - if your platform needs to do endian-swapping or can only +// handle aligned reads, do the conversion here + +static FORCE_INLINE uint32_t getblock ( const uint32_t* p, int i ) +{ + return p[i]; +} + +static FORCE_INLINE uint64_t getblock ( const uint64_t* p, int i ) +{ + return p[i]; +} + +//----------------------------------------------------------------------------- +// Finalization mix - force all bits of a hash block to avalanche + +static FORCE_INLINE uint32_t fmix ( uint32_t h ) +{ + h ^= h >> 16; + h *= 0x85ebca6b; + h ^= h >> 13; + h *= 0xc2b2ae35; + h ^= h >> 16; + + return h; +} + +//---------- + +static FORCE_INLINE uint64_t fmix ( uint64_t k ) +{ + k ^= k >> 33; + k *= BIG_CONSTANT (0xff51afd7ed558ccd); + k ^= k >> 33; + k *= BIG_CONSTANT (0xc4ceb9fe1a85ec53); + k ^= k >> 33; + + return k; +} + +//----------------------------------------------------------------------------- + +void MurmurHash3_x86_32 ( const void* key, int len, + uint32_t seed, void* out ) +{ + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 4; + + uint32_t h1 = seed; + + uint32_t c1 = 0xcc9e2d51; + uint32_t c2 = 0x1b873593; + + //---------- + // body + + const uint32_t* blocks = (const uint32_t*) (data + nblocks * 4); + + for (int i = -nblocks; i; i++) + { + uint32_t k1 = getblock (blocks, i); + + k1 *= c1; + k1 = ROTL32 (k1, 15); + k1 *= c2; + + h1 ^= k1; + h1 = ROTL32 (h1, 13); + h1 = h1 * 5 + 0xe6546b64; + } + + //---------- + // tail + + const uint8_t* tail = (const uint8_t*) (data + nblocks * 4); + + uint32_t k1 = 0; + + switch (len & 3) + { + case 3: + k1 ^= tail[2] << 16; + + case 2: + k1 ^= tail[1] << 8; + + case 1: + k1 ^= tail[0]; + k1 *= c1; + k1 = ROTL32 (k1, 15); + k1 *= c2; + h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + + h1 = fmix (h1); + + * (uint32_t*)out = h1; +} + +//----------------------------------------------------------------------------- + +void MurmurHash3_x86_128 ( const void* key, const int len, + uint32_t seed, void* out ) +{ + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 16; + + uint32_t h1 = seed; + uint32_t h2 = seed; + uint32_t h3 = seed; + uint32_t h4 = seed; + + uint32_t c1 = 0x239b961b; + uint32_t c2 = 0xab0e9789; + uint32_t c3 = 0x38b34ae5; + uint32_t c4 = 0xa1e38b93; + + //---------- + // body + + const uint32_t* blocks = (const uint32_t*) (data + nblocks * 16); + + for (int i = -nblocks; i; i++) + { + uint32_t k1 = getblock (blocks, i * 4 + 0); + uint32_t k2 = getblock (blocks, i * 4 + 1); + uint32_t k3 = getblock (blocks, i * 4 + 2); + uint32_t k4 = getblock (blocks, i * 4 + 3); + + k1 *= c1; + k1 = ROTL32 (k1, 15); + k1 *= c2; + h1 ^= k1; + + h1 = ROTL32 (h1, 19); + h1 += h2; + h1 = h1 * 5 + 0x561ccd1b; + + k2 *= c2; + k2 = ROTL32 (k2, 16); + k2 *= c3; + h2 ^= k2; + + h2 = ROTL32 (h2, 17); + h2 += h3; + h2 = h2 * 5 + 0x0bcaa747; + + k3 *= c3; + k3 = ROTL32 (k3, 17); + k3 *= c4; + h3 ^= k3; + + h3 = ROTL32 (h3, 15); + h3 += h4; + h3 = h3 * 5 + 0x96cd1c35; + + k4 *= c4; + k4 = ROTL32 (k4, 18); + k4 *= c1; + h4 ^= k4; + + h4 = ROTL32 (h4, 13); + h4 += h1; + h4 = h4 * 5 + 0x32ac3b17; + } + + //---------- + // tail + + const uint8_t* tail = (const uint8_t*) (data + nblocks * 16); + + uint32_t k1 = 0; + uint32_t k2 = 0; + uint32_t k3 = 0; + uint32_t k4 = 0; + + switch (len & 15) + { + case 15: + k4 ^= tail[14] << 16; + + case 14: + k4 ^= tail[13] << 8; + + case 13: + k4 ^= tail[12] << 0; + k4 *= c4; + k4 = ROTL32 (k4, 18); + k4 *= c1; + h4 ^= k4; + + case 12: + k3 ^= tail[11] << 24; + + case 11: + k3 ^= tail[10] << 16; + + case 10: + k3 ^= tail[ 9] << 8; + + case 9: + k3 ^= tail[ 8] << 0; + k3 *= c3; + k3 = ROTL32 (k3, 17); + k3 *= c4; + h3 ^= k3; + + case 8: + k2 ^= tail[ 7] << 24; + + case 7: + k2 ^= tail[ 6] << 16; + + case 6: + k2 ^= tail[ 5] << 8; + + case 5: + k2 ^= tail[ 4] << 0; + k2 *= c2; + k2 = ROTL32 (k2, 16); + k2 *= c3; + h2 ^= k2; + + case 4: + k1 ^= tail[ 3] << 24; + + case 3: + k1 ^= tail[ 2] << 16; + + case 2: + k1 ^= tail[ 1] << 8; + + case 1: + k1 ^= tail[ 0] << 0; + k1 *= c1; + k1 = ROTL32 (k1, 15); + k1 *= c2; + h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + + h2 ^= len; + + h3 ^= len; + + h4 ^= len; + + h1 += h2; + + h1 += h3; + + h1 += h4; + + h2 += h1; + + h3 += h1; + + h4 += h1; + + h1 = fmix (h1); + + h2 = fmix (h2); + + h3 = fmix (h3); + + h4 = fmix (h4); + + h1 += h2; + + h1 += h3; + + h1 += h4; + + h2 += h1; + + h3 += h1; + + h4 += h1; + + ((uint32_t*)out)[0] = h1; + + ((uint32_t*)out)[1] = h2; + + ((uint32_t*)out)[2] = h3; + + ((uint32_t*)out)[3] = h4; +} + +//----------------------------------------------------------------------------- + +void MurmurHash3_x64_128 ( const void* key, const int len, + const uint32_t seed, void* out ) +{ + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 16; + + uint64_t h1 = seed; + uint64_t h2 = seed; + + uint64_t c1 = BIG_CONSTANT (0x87c37b91114253d5); + uint64_t c2 = BIG_CONSTANT (0x4cf5ad432745937f); + + //---------- + // body + + const uint64_t* blocks = (const uint64_t*) (data); + + for (int i = 0; i < nblocks; i++) + { + uint64_t k1 = getblock (blocks, i * 2 + 0); + uint64_t k2 = getblock (blocks, i * 2 + 1); + + k1 *= c1; + k1 = ROTL64 (k1, 31); + k1 *= c2; + h1 ^= k1; + + h1 = ROTL64 (h1, 27); + h1 += h2; + h1 = h1 * 5 + 0x52dce729; + + k2 *= c2; + k2 = ROTL64 (k2, 33); + k2 *= c1; + h2 ^= k2; + + h2 = ROTL64 (h2, 31); + h2 += h1; + h2 = h2 * 5 + 0x38495ab5; + } + + //---------- + // tail + + const uint8_t* tail = (const uint8_t*) (data + nblocks * 16); + + uint64_t k1 = 0; + uint64_t k2 = 0; + + switch (len & 15) + { + case 15: + k2 ^= uint64_t (tail[14]) << 48; + + case 14: + k2 ^= uint64_t (tail[13]) << 40; + + case 13: + k2 ^= uint64_t (tail[12]) << 32; + + case 12: + k2 ^= uint64_t (tail[11]) << 24; + + case 11: + k2 ^= uint64_t (tail[10]) << 16; + + case 10: + k2 ^= uint64_t (tail[ 9]) << 8; + + case 9: + k2 ^= uint64_t (tail[ 8]) << 0; + k2 *= c2; + k2 = ROTL64 (k2, 33); + k2 *= c1; + h2 ^= k2; + + case 8: + k1 ^= uint64_t (tail[ 7]) << 56; + + case 7: + k1 ^= uint64_t (tail[ 6]) << 48; + + case 6: + k1 ^= uint64_t (tail[ 5]) << 40; + + case 5: + k1 ^= uint64_t (tail[ 4]) << 32; + + case 4: + k1 ^= uint64_t (tail[ 3]) << 24; + + case 3: + k1 ^= uint64_t (tail[ 2]) << 16; + + case 2: + k1 ^= uint64_t (tail[ 1]) << 8; + + case 1: + k1 ^= uint64_t (tail[ 0]) << 0; + k1 *= c1; + k1 = ROTL64 (k1, 31); + k1 *= c2; + h1 ^= k1; + }; + + //---------- + // finalization + + h1 ^= len; + + h2 ^= len; + + h1 += h2; + + h2 += h1; + + h1 = fmix (h1); + + h2 = fmix (h2); + + h1 += h2; + + h2 += h1; + + ((uint64_t*)out)[0] = h1; + + ((uint64_t*)out)[1] = h2; +} + +} diff --git a/Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.h b/Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.h new file mode 100644 index 0000000000..9f61433df3 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.h @@ -0,0 +1,79 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_MURMURHASH_BEASTHEADER +#define BEAST_MURMURHASH_BEASTHEADER + +// Original source code links in .cpp file + +// This file depends on some Juce declarations and defines + +namespace Murmur +{ + +extern void MurmurHash3_x86_32 (const void* key, int len, uint32 seed, void* out); +extern void MurmurHash3_x86_128 (const void* key, int len, uint32 seed, void* out); +extern void MurmurHash3_x64_128 (const void* key, int len, uint32 seed, void* out); + +// Uses Juce to choose an appropriate routine + +// This handy template deduces which size hash is desired +template +inline void Hash (const void* key, int len, uint32 seed, HashType* out) +{ + switch (8 * sizeof (HashType)) + { + case 32: + MurmurHash3_x86_32 (key, len, seed, out); + break; + +#if BEAST_64BIT + + case 128: + MurmurHash3_x64_128 (key, len, seed, out); + break; +#else + + case 128: + MurmurHash3_x86_128 (key, len, seed, out); + break; +#endif + + default: + Throw (std::runtime_error ("invalid key size in MurmurHash")); + break; + }; +} + +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_AllocatedBy.h b/Subtrees/beast/modules/beast_basics/memory/beast_AllocatedBy.h new file mode 100644 index 0000000000..b76af12a99 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_AllocatedBy.h @@ -0,0 +1,76 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_ALLOCATEDBY_BEASTHEADER +#define BEAST_ALLOCATEDBY_BEASTHEADER + +/*============================================================================*/ +/** + Customized allocation for heap objects. + + Derived classes will use the specified allocator for new and delete. + + @param AllocatorType The type of allocator to use. + + @ingroup beast_concurrent +*/ +template +class AllocatedBy +{ +public: + static inline void* operator new (size_t bytes, AllocatorType& allocator) noexcept + { + return allocator.allocate (bytes); + } + + static inline void* operator new (size_t bytes, AllocatorType* allocator) noexcept + { + return allocator->allocate (bytes); + } + + static inline void operator delete (void* p, AllocatorType&) noexcept + { + AllocatorType::deallocate (p); + } + + static inline void operator delete (void* p, AllocatorType*) noexcept + { + AllocatorType::deallocate (p); + } + + static inline void operator delete (void* p) noexcept + { + AllocatorType::deallocate (p); + } +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_AtomicCounter.h b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicCounter.h new file mode 100644 index 0000000000..41271ee846 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicCounter.h @@ -0,0 +1,96 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_ATOMICCOUNTER_BEASTHEADER +#define BEAST_ATOMICCOUNTER_BEASTHEADER + +/*============================================================================*/ +/** + A thread safe usage counter. + + This provides a simplified interface to an atomic integer suitable for + measuring reference or usage counts. The counter is signaled when the + count is non zero. + + @ingroup beast_core +*/ +class AtomicCounter +{ +public: + /** Create a new counter. + + @param initialValue An optional starting usage count (default is 0). + */ + AtomicCounter (int initialValue = 0) noexcept +: + m_value (initialValue) + { + } + + /** Increment the usage count. + + @return `true` if the counter became signaled. + */ + inline bool addref () noexcept + { + return (++m_value) == 1; + } + + /** Decrements the usage count. + + @return `true` if the counter became non-signaled. + */ + inline bool release () noexcept + { + // Unfortunately, AllocatorWithoutTLS breaks this assert + //bassert (isSignaled ()); + + return (--m_value) == 0; + } + + /** Determine if the counter is signaled. + + Note that another thread can cause the counter to become reset after + this function returns true. + + @return `true` if the counter was signaled. + */ + inline bool isSignaled () const noexcept + { + return m_value.get () > 0; + } + +private: + Atomic m_value; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_AtomicFlag.h b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicFlag.h new file mode 100644 index 0000000000..51d34b326e --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicFlag.h @@ -0,0 +1,115 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_ATOMICFLAG_BEASTHEADER +#define BEAST_ATOMICFLAG_BEASTHEADER + +/*============================================================================*/ +/** + A thread safe flag. + + This provides a simplified interface to an atomic integer suitable for + representing a flag. The flag is signaled when on, else it is considered + reset. + + @ingroup beast_core +*/ +class AtomicFlag +{ +public: + /** Create an AtomicFlag in the reset state. */ + AtomicFlag () noexcept +: + m_value (0) + { + } + + /** Signal the flag. + + If two or more threads simultaneously attempt to signal the flag, + only one will receive a true return value. + + @return true if the flag was previously reset. + */ + inline bool trySignal () noexcept + { + return m_value.compareAndSetBool (1, 0); + } + + /** Signal the flag. + + The flag must be in the reset state. Only one thread may + call this at a time. + */ + inline void signal () noexcept + { +#if BEAST_DEBUG + const bool success = m_value.compareAndSetBool (1, 0); + bassert (success); +#else + m_value.set (1); +#endif + } + + /** Reset the flag. + + The flag must be in the signaled state. Only one thread may + call this at a time. Usually it is the thread that was successful + in a previous call to trySignal(). + */ + inline void reset () noexcept + { +#if BEAST_DEBUG + const bool success = m_value.compareAndSetBool (0, 1); + bassert (success); +#else + m_value.set (0); +#endif + } + + /** Check if the AtomicFlag is signaled + + The signaled status may change immediately after this call + returns. The caller must synchronize. + + @return true if the flag was signaled. + */ + inline bool isSignaled () const noexcept + { + return m_value.get () == 1; + } + +private: + Atomic m_value; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_AtomicPointer.h b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicPointer.h new file mode 100644 index 0000000000..18900e401f --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicPointer.h @@ -0,0 +1,146 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_ATOMICPOINTER_BEASTHEADER +#define BEAST_ATOMICPOINTER_BEASTHEADER + +/*============================================================================*/ +/** + A thread safe pointer. + + This provides a simplified interface to an atomic pointer suitable + for building containers or composite classes. Operator overloads + allow access to the underlying pointer using natural C++ syntax. + + @ingroup beast_core +*/ +template +class AtomicPointer +{ +public: + /** Create a pointer. + + @param initialValue An optional starting value (default is null). + */ + explicit AtomicPointer (P* const initialValue = nullptr) noexcept +: + m_value (initialValue) + { + } + + /** Retrieve the pointer value */ + inline P* get () const noexcept + { + return m_value.get (); + } + + /** Obtain a pointer to P through type conversion. + + The caller must synchronize access to P. + + @return A pointer to P. + */ + inline operator P* () const noexcept + { + return get (); + } + + /** Dereference operator + + The caller must synchronize access to P. + + @return A reference to P. + */ + inline P& operator* () const noexcept + { + return &get (); + } + + /** Member selection + + The caller must synchronize access to P. + + @return A pointer to P. + */ + inline P* operator-> () const noexcept + { + return get (); + } + + inline void set (P* p) + { + m_value.set (p); + } + + /** Atomically assign a new pointer + + @param newValue The new value to assign. + */ + inline void operator= (P* newValue) noexcept + { + set (newValue); + } + + /** Atomically assign a new pointer and return the old value. + + @param newValue The new value to assign. + + @return The previous value. + */ + inline P* exchange (P* newValue) + { + return m_value.exchange (newValue); + } + + /** Conditionally perform an atomic assignment. + + The current value is compared with oldValue and atomically + set to newValue if the comparison is equal. + + The caller is responsible for handling the ABA problem. + + @param newValue The new value to assign. + + @param oldValue The matching old value. + + @return true if the assignment was performed. + */ + inline bool compareAndSet (P* newValue, P* oldValue) + { + return m_value.compareAndSetBool (newValue, oldValue); + } + +private: + Atomic m_value; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_AtomicState.h b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicState.h new file mode 100644 index 0000000000..3699f0d1da --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_AtomicState.h @@ -0,0 +1,114 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_ATOMICSTATE_BEASTHEADER +#define BEAST_ATOMICSTATE_BEASTHEADER + +/*============================================================================*/ +/** + A thread safe state variable. + + This provides a simplified interface to an integer used to control atomic + state transitions. A state is distinguished by a single integer value. + + @ingroup beast_core +*/ +class AtomicState +{ +public: + /** Create a new state with an optional starting value. + + @param initialState The initial state. + */ + + + explicit AtomicState (const int initialState = 0) noexcept +: + m_value (initialState) + { + } + + /** Retrieve the current state. + + This converts the object to an integer reflecting the current state. + + Note that other threads may change the value immediately after this + function returns. The caller is responsible for synchronizing. + + @return The state at the time of the call. + */ + inline operator int () const + { + return m_value.get (); + } + + /** Attempt a state transition. + + The current state is compared to `from`, and if the comparison is + successful the state becomes `to`. The entire operation is atomic. + + @param from The current state, for comparison. + + @param to The desired new state. + + @return true if the state transition succeeded. + */ + inline bool tryChangeState (const int from, const int to) noexcept + { + return m_value.compareAndSetBool (to, from); + } + + /** Perform a state transition. + + This attempts to change the state and generates a diagnostic on + failure. This routine can be used instead of tryChangeState() + when program logic requires that the state change must succeed. + + @param from The required current state. + + @param to The new state. + */ + inline void changeState (const int from, const int to) noexcept + { +#if BEAST_DEBUG + const bool success = tryChangeState (from, to); + bassert (success); +#else + tryChangeState (from, to); +#endif + } + +private: + Atomic m_value; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_CacheLine.h b/Subtrees/beast/modules/beast_basics/memory/beast_CacheLine.h new file mode 100644 index 0000000000..096af2175f --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_CacheLine.h @@ -0,0 +1,491 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_CACHELINE_BEASTHEADER +#define BEAST_CACHELINE_BEASTHEADER + +#include "beast_MemoryAlignment.h" + +// Allows turning off of all padding, +// e.g. for memory-constrained systems or testing. +// +#define GLOBAL_PADDING_ENABLED 0 + +namespace CacheLine +{ + +#if GLOBAL_PADDING_ENABLED + +// Pads an object so that it starts on a cache line boundary. +// +template +class Aligned +{ +public: + ~Aligned () + { + ptr ()->~T (); + } + + Aligned () + { + new (ptr ()) T; + } + + template + explicit Aligned (const T1& t1) + { + new (ptr ()) T (t1); + } + + template + Aligned (const T1& t1, const T2& t2) + { + new (ptr ()) T (t1, t2); + } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3) + { + new (ptr ()) T (t1, t2, t3); + } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { + new (ptr ()) T (t1, t2, t3, t4); + } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5) + { + new (ptr ()) T (t1, t2, t3, t4, t5); + } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6) + { + new (ptr ()) T (t1, t2, t3, t4, t5, t6); + } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7 > + Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + { + new (ptr ()) T (t1, t2, t3, t4, t5, t6, t7); + } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8 > + Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + { + new (ptr ()) T (t1, t2, t3, t4, t5, t6, t7, t8); + } + + void operator= (T const& other) + { + *ptr () = other; + } + + inline T& operator* () noexcept { return *ptr (); } + inline T* operator-> () noexcept { return ptr (); } + inline operator T& () noexcept { return *ptr (); } + inline operator T* () noexcept { return ptr (); } + + inline const T& operator* () const noexcept + { + return *ptr (); + } + inline const T* operator-> () const noexcept + { + return ptr (); + } + inline operator const T& () const noexcept + { + return *ptr (); + } + inline operator const T* () const noexcept + { + return ptr (); + } + +private: + inline T* ptr () noexcept + { + return (T*) ((uintptr_t (m_storage) + Memory::cacheLineAlignMask) + & ~Memory::cacheLineAlignMask); + /* + return reinterpret_cast (Memory::pointerAdjustedForAlignment ( + m_storage, Memory::cacheLineBytes)); + */ + } + + char m_storage [ (sizeof (T) + Memory::cacheLineAlignMask) + & ~Memory::cacheLineAlignMask]; +}; + +// Holds an object padded it to completely fill a CPU cache line. +// The caller must ensure that this object starts at the beginning +// of a cache line. +// +template +class Padded +{ +public: + Padded () + { } + + template + explicit Padded (const T1& t1) + : m_t (t1) { } + + template + Padded (const T1& t1, const T2& t2) + : m_t (t1, t2) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3) + : m_t (t1, t2, t3) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4) + : m_t (t1, t2, t3, t4) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5) + : m_t (t1, t2, t3, t4, t5) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6) + : m_t (t1, t2, t3, t4, t5, t6) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7 > + Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + : m_t (t1, t2, t3, t4, t5, t6, t7) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8 > + Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + : m_t (t1, t2, t3, t4, t5, t6, t7, t8) { } + + void operator= (const T& other) + { + m_t = other; + } + + T& operator* () noexcept { return m_t; } + T* operator-> () noexcept { return &m_t; } + operator T& () noexcept { return m_t; } + operator T* () noexcept { return &m_t; } + + const T& operator* () const noexcept + { + return m_t; + } + const T* operator-> () const noexcept + { + return &m_t; + } + operator const T& () const noexcept + { + return m_t; + } + operator const T* () const noexcept + { + return &m_t; + } + +private: + T m_t; + char pad [Memory::cacheLineAlignBytes - sizeof (T)]; +}; + +#else + +template +class Aligned +{ +public: + Aligned () + { } + + template + explicit Aligned (const T1& t1) + : m_t (t1) { } + + template + Aligned (const T1& t1, const T2& t2) + : m_t (t1, t2) { } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3) + : m_t (t1, t2, t3) { } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4) + : m_t (t1, t2, t3, t4) { } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5) + : m_t (t1, t2, t3, t4, t5) { } + + template + Aligned (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6) + : m_t (t1, t2, t3, t4, t5, t6) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7 > + Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + : m_t (t1, t2, t3, t4, t5, t6, t7) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8 > + Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + : m_t (t1, t2, t3, t4, t5, t6, t7, t8) { } + + void operator= (const T& other) + { + m_t = other; + } + + T& operator* () noexcept { return m_t; } + T* operator-> () noexcept { return &m_t; } + operator T& () noexcept { return m_t; } + operator T* () noexcept { return &m_t; } + + const T& operator* () const noexcept + { + return m_t; + } + const T* operator-> () const noexcept + { + return &m_t; + } + operator const T& () const noexcept + { + return m_t; + } + operator const T* () const noexcept + { + return &m_t; + } + +private: + T m_t; +}; + +template +class Padded +{ +public: + Padded () + { } + + template + explicit Padded (const T1& t1) + : m_t (t1) { } + + template + Padded (const T1& t1, const T2& t2) + : m_t (t1, t2) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3) + : m_t (t1, t2, t3) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4) + : m_t (t1, t2, t3, t4) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5) + : m_t (t1, t2, t3, t4, t5) { } + + template + Padded (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6) + : m_t (t1, t2, t3, t4, t5, t6) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7 > + Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + : m_t (t1, t2, t3, t4, t5, t6, t7) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8 > + Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + : m_t (t1, t2, t3, t4, t5, t6, t7, t8) { } + + void operator= (const T& other) + { + m_t = other; + } + + T& operator* () noexcept { return m_t; } + T* operator-> () noexcept { return &m_t; } + operator T& () noexcept { return m_t; } + operator T* () noexcept { return &m_t; } + + const T& operator* () const noexcept + { + return m_t; + } + const T* operator-> () const noexcept + { + return &m_t; + } + operator const T& () const noexcept + { + return m_t; + } + operator const T* () const noexcept + { + return &m_t; + } + +private: + T m_t; +}; + +#endif + +// +// Used to remove padding without changing code +// + +template +class Unpadded +{ +public: + Unpadded () + { } + + template + explicit Unpadded (const T1& t1) + : m_t (t1) { } + + template + Unpadded (const T1& t1, const T2& t2) + : m_t (t1, t2) { } + + template + Unpadded (const T1& t1, const T2& t2, const T3& t3) + : m_t (t1, t2, t3) { } + + template + Unpadded (const T1& t1, const T2& t2, const T3& t3, const T4& t4) + : m_t (t1, t2, t3, t4) { } + + template + Unpadded (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5) + : m_t (t1, t2, t3, t4, t5) { } + + template + Unpadded (const T1& t1, const T2& t2, const T3& t3, + const T4& t4, const T5& t5, const T6& t6) + : m_t (t1, t2, t3, t4, t5, t6) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7 > + Unpadded (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7) + : m_t (t1, t2, t3, t4, t5, t6, t7) { } + + template < class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8 > + Unpadded (const T1& t1, const T2& t2, const T3& t3, const T4& t4, + const T5& t5, const T6& t6, const T7& t7, const T8& t8) + : m_t (t1, t2, t3, t4, t5, t6, t7, t8) { } + + void operator= (const T& other) + { + m_t = other; + } + + T& operator* () + { + return m_t; + } + T* operator-> () + { + return &m_t; + } + operator T& () + { + return m_t; + } + operator T* () + { + return &m_t; + } + + const T& operator* () const + { + return m_t; + } + const T* operator-> () const + { + return &m_t; + } + operator const T& () const + { + return m_t; + } + operator const T* () const + { + return &m_t; + } + +private: + T m_t; +}; + +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStore.h b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStore.h new file mode 100644 index 0000000000..4698f5a62c --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStore.h @@ -0,0 +1,54 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_FIFOFREESTORE_BEASTHEADER +#define BEAST_FIFOFREESTORE_BEASTHEADER + +#if BEAST_USE_BOOST +#include "beast_FifoFreeStoreWithTLS.h" + +#else +#include "beast_FifoFreeStoreWithoutTLS.h" + +#endif + +/** Selected free store based on compilation settings. + + @ingroup beast_concurrent +*/ +#if BEAST_USE_BOOST +typedef FifoFreeStoreWithTLS FifoFreeStoreType; +#else +typedef FifoFreeStoreWithoutTLS FifoFreeStoreType; +#endif + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.cpp b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.cpp new file mode 100644 index 0000000000..73c7508711 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.cpp @@ -0,0 +1,207 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +// Implementation notes +// +// - A Page is a large allocation from a global PageAllocator. +// +// - Each thread maintains an 'active' page from which it makes allocations. +// +// - When the active page is full, a new one takes it's place. +// +// - Page memory is deallocated when it is not active and no longer referenced. +// +// - Each instance of FifoFreeStoreWithTLS maintains its own set of per-thread active pages, +// but uses a global PageAllocator. This reduces memory consumption without +// affecting performance. +// + +// This precedes every allocation +// +struct FifoFreeStoreWithTLS::Header +{ + FifoFreeStoreWithTLS::Page* page; +}; + +//------------------------------------------------------------------------------ + +class FifoFreeStoreWithTLS::Page : LeakChecked , Uncopyable +{ +public: + explicit Page (const size_t bytes) : m_refs (1) + { + m_end = reinterpret_cast (this) + bytes; + m_free = reinterpret_cast ( + Memory::pointerAdjustedForAlignment (this + 1)); + } + + ~Page () + { + bassert (! m_refs.isSignaled ()); + } + + inline bool release () + { + bassert (! m_refs.isSignaled ()); + + return m_refs.release (); + } + + void* allocate (size_t bytes) + { + bassert (bytes > 0); + + char* p = Memory::pointerAdjustedForAlignment (m_free); + char* free = p + bytes; + + if (free <= m_end) + { + m_free = free; + + m_refs.addref (); + } + else + { + p = 0; + } + + return p; + } + +private: + AtomicCounter m_refs; // reference count + char* m_free; // next free byte + char* m_end; // last free byte + 1 +}; + +//------------------------------------------------------------------------------ + +class FifoFreeStoreWithTLS::PerThreadData : LeakChecked , Uncopyable +{ +public: + explicit PerThreadData (FifoFreeStoreWithTLS* allocator) + : m_allocator (*allocator) + , m_active (m_allocator.newPage ()) + { + } + + ~PerThreadData () + { + if (m_active->release ()) + m_allocator.deletePage (m_active); + } + + inline void* allocate (const size_t bytes) + { + const size_t headerBytes = Memory::sizeAdjustedForAlignment (sizeof (Header)); + const size_t bytesNeeded = headerBytes + bytes; + + if (bytesNeeded > m_allocator.m_pages->getPageBytes ()) + Throw (Error ().fail (__FILE__, __LINE__, TRANS ("the memory request was too large"))); + + Header* header; + + header = reinterpret_cast (m_active->allocate (bytesNeeded)); + + if (!header) + { + if (m_active->release ()) + deletePage (m_active); + + m_active = m_allocator.newPage (); + + header = reinterpret_cast (m_active->allocate (bytesNeeded)); + } + + header->page = m_active; + + return reinterpret_cast (header) + headerBytes; + } + +private: + FifoFreeStoreWithTLS& m_allocator; + Page* m_active; +}; + +//------------------------------------------------------------------------------ + +inline FifoFreeStoreWithTLS::Page* FifoFreeStoreWithTLS::newPage () +{ + return new (m_pages->allocate ()) Page (m_pages->getPageBytes ()); +} + +inline void FifoFreeStoreWithTLS::deletePage (Page* page) +{ + // Safe, because each thread maintains its own active page. + page->~Page (); + PagedFreeStoreType::deallocate (page); +} + +FifoFreeStoreWithTLS::FifoFreeStoreWithTLS () + : m_pages (PagedFreeStoreType::getInstance ()) +{ + //bassert (m_pages->getPageBytes () >= sizeof (Page) + Memory::allocAlignBytes); +} + +FifoFreeStoreWithTLS::~FifoFreeStoreWithTLS () +{ + // Clean up this thread's data before we release + // the reference to the global page allocator. + m_tsp.reset (0); +} + +//------------------------------------------------------------------------------ + +void* FifoFreeStoreWithTLS::allocate (const size_t bytes) +{ + PerThreadData* data = m_tsp.get (); + + if (!data) + { + data = new PerThreadData (this); + m_tsp.reset (data); + } + + return data->allocate (bytes); +} + +//------------------------------------------------------------------------------ + +void FifoFreeStoreWithTLS::deallocate (void* p) +{ + const size_t headerBytes = Memory::sizeAdjustedForAlignment (sizeof (Header)); + Header* const header = reinterpret_cast (reinterpret_cast (p) - headerBytes); + Page* const page = header->page; + + if (page->release ()) + deletePage (page); +} diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.h b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.h new file mode 100644 index 0000000000..6ca750d1f0 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithTLS.h @@ -0,0 +1,80 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_FIFOFREESTOREWITHTLS_BEASTHEADER +#define BEAST_FIFOFREESTOREWITHTLS_BEASTHEADER + +#include "beast_GlobalPagedFreeStore.h" + +/*============================================================================*/ +/** + Lock-free and mostly wait-free FIFO memory allocator. + + This allocator is suitable for use with CallQueue and Listeners. It is + expected that over time, deallocations will occur in roughly the same order + as allocations. + + @note This implementation uses Thread Local Storage to further improve + performance. However, it requires boost style thread_specific_ptr. + + @invariant allocate() and deallocate() are fully concurrent. + + @invariant The ABA problem is handled automatically. + + @ingroup beast_concurrent +*/ +class FifoFreeStoreWithTLS +{ +public: + FifoFreeStoreWithTLS (); + ~FifoFreeStoreWithTLS (); + + void* allocate (const size_t bytes); + static void deallocate (void* const p); + +private: + typedef GlobalPagedFreeStore PagedFreeStoreType; + struct Header; + + class Page; + + inline Page* newPage (); + static inline void deletePage (Page* page); + +private: + class PerThreadData; + boost::thread_specific_ptr m_tsp; + + PagedFreeStoreType::Ptr m_pages; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.cpp b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.cpp new file mode 100644 index 0000000000..756d112778 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.cpp @@ -0,0 +1,254 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +// This precedes every allocation +struct FifoFreeStoreWithoutTLS::Header +{ + union + { + FifoFreeStoreWithoutTLS::Block* block; // backpointer to the page + + char pad [Memory::allocAlignBytes]; + }; +}; + +//------------------------------------------------------------------------------ + +class FifoFreeStoreWithoutTLS::Block : Uncopyable +{ +public: + explicit Block (const size_t bytes) : m_refs (1) + { + m_end = reinterpret_cast (this) + bytes; + m_free = reinterpret_cast ( + Memory::pointerAdjustedForAlignment (this + 1)); + } + + ~Block () + { + bassert (!m_refs.isSignaled ()); + } + + inline void addref () + { + m_refs.addref (); + } + + inline bool release () + { + return m_refs.release (); + } + + enum Result + { + success, // successful allocation + ignore, // disregard the block + consumed // block is consumed (1 thread sees this) + }; + + Result allocate (size_t bytes, void* pBlock) + { + bassert (bytes > 0); + + Result result; + + for (;;) + { + char* base = m_free.get (); + + if (base) + { + char* p = Memory::pointerAdjustedForAlignment (base); + char* free = p + bytes; + + if (free <= m_end) + { + // Try to commit the allocation + if (m_free.compareAndSet (free, base)) + { + * (reinterpret_cast (pBlock)) = p; + result = success; + break; + } + else + { + // Someone changed m_free, retry. + } + } + else + { + // Mark the block consumed. + if (m_free.compareAndSet (0, base)) + { + // Only one caller sees this, the rest get 'ignore' + result = consumed; + break; + } + else + { + // Happens with another concurrent allocate(), retry. + } + } + } + else + { + // Block is consumed, ignore it. + result = ignore; + break; + } + } + + return result; + } + +private: + AtomicCounter m_refs; // reference count + AtomicPointer m_free; // next free byte or 0 if inactive. + char* m_end; // last free byte + 1 +}; + +//------------------------------------------------------------------------------ + +inline FifoFreeStoreWithoutTLS::Block* FifoFreeStoreWithoutTLS::newBlock () +{ + return new (m_pages->allocate ()) Block (m_pages->getPageBytes ()); +} + +inline void FifoFreeStoreWithoutTLS::deleteBlock (Block* b) +{ + // It is critical that we do not call the destructor, + // because due to the lock-free implementation, a Block + // can be accessed for a short time after it is deleted. + /* b->~Block (); */ // DO NOT CALL!!! + + PagedFreeStoreType::deallocate (b); +} + +FifoFreeStoreWithoutTLS::FifoFreeStoreWithoutTLS () + : m_pages (GlobalPagedFreeStore::getInstance ()) +{ + if (m_pages->getPageBytes () < sizeof (Block) + 256) + Throw (Error ().fail (__FILE__, __LINE__, TRANS ("the block size is too small"))); + + m_active = newBlock (); +} + +FifoFreeStoreWithoutTLS::~FifoFreeStoreWithoutTLS () +{ + deleteBlock (m_active); +} + +//------------------------------------------------------------------------------ + +void* FifoFreeStoreWithoutTLS::allocate (const size_t bytes) +{ + const size_t actual = sizeof (Header) + bytes; + + if (actual > m_pages->getPageBytes ()) + Throw (Error ().fail (__FILE__, __LINE__, TRANS ("the memory request was too large"))); + + Header* h; + + for (;;) + { + // Get an active block. + Block* b = m_active; + + while (!b) + { + Thread::yield (); + b = m_active; + } + + // (*) It is possible for the block to get a final release here + // In this case it will have been put in the garbage, and + // m_active will not match. + + // Acquire a reference. + b->addref (); + + // Is it still active? + if (m_active == b) + { + // Yes so try to allocate from it. + const Block::Result result = b->allocate (actual, &h); + + if (result == Block::success) + { + // Keep the reference and return the allocation. + h->block = b; + break; + } + else if (result == Block::consumed) + { + // Remove block from active. + m_active = 0; + + // Take away the reference we added + b->release (); + + // Take away the original active reference. + if (b->release ()) + deleteBlock (b); + + // Install a fresh empty active block. + m_active = newBlock (); + } + else + { + if (b->release ()) + deleteBlock (b); + } + + // Try again. + } + else + { + // Block became inactive, so release our reference. + b->release (); + + // (*) It is possible for this to be a duplicate final release. + } + } + + return h + 1; +} + +//------------------------------------------------------------------------------ + +void FifoFreeStoreWithoutTLS::deallocate (void* p) +{ + Block* const b = (reinterpret_cast (p) - 1)->block; + + if (b->release ()) + deleteBlock (b); +} diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.h b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.h new file mode 100644 index 0000000000..3acdb61e69 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_FifoFreeStoreWithoutTLS.h @@ -0,0 +1,80 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_FIFOFREESTOREWITHOUTTLS_BEASTHEADER +#define BEAST_FIFOFREESTOREWITHOUTTLS_BEASTHEADER + +#include "beast_GlobalPagedFreeStore.h" + +/*============================================================================*/ +/** + Lock-free FIFO memory allocator. + + This allocator is suitable for use with CallQueue and Listeners. It is + expected that over time, deallocations will occur in roughly the same order + as allocations. + + @note This version of the fifo free store uses less memory and doesn't require + thread specific storage. However, it runs slower. The performance + differences are negligible for desktop class applications. + + @invariant allocate() and deallocate() are fully concurrent. + + @invariant The ABA problem is handled automatically. + + @ingroup beast_concurrent +*/ +class FifoFreeStoreWithoutTLS +{ +public: + explicit FifoFreeStoreWithoutTLS (); + ~FifoFreeStoreWithoutTLS (); + + void* allocate (const size_t bytes); + static void deallocate (void* const p); + +private: + typedef GlobalPagedFreeStore PagedFreeStoreType; + + struct Header; + + class Block; + + inline Block* newBlock (); + static inline void deleteBlock (Block* b); + +private: + Block* volatile m_active; + PagedFreeStoreType::Ptr m_pages; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_GlobalFifoFreeStore.h b/Subtrees/beast/modules/beast_basics/memory/beast_GlobalFifoFreeStore.h new file mode 100644 index 0000000000..a352a4c766 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_GlobalFifoFreeStore.h @@ -0,0 +1,78 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_GLOBALFIFOFREESTORE_BEASTHEADER +#define BEAST_GLOBALFIFOFREESTORE_BEASTHEADER + +#include "beast_FifoFreeStore.h" + +/*============================================================================*/ +/** + A @ref FifoFreeStoreType singleton. + + @ingroup beast_concurrent +*/ +template +class GlobalFifoFreeStore : public RefCountedSingleton > +{ +public: + inline void* allocate (size_t bytes) + { + return m_allocator.allocate (bytes); + } + + static inline void deallocate (void* const p) + { + FifoFreeStoreType::deallocate (p); + } + + static GlobalFifoFreeStore* createInstance () + { + return new GlobalFifoFreeStore; + } + +private: + GlobalFifoFreeStore () + : RefCountedSingleton > + (SingletonLifetime::persistAfterCreation) + { + } + + ~GlobalFifoFreeStore () + { + } + +private: + FifoFreeStoreType m_allocator; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.cpp b/Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.cpp new file mode 100644 index 0000000000..212b446701 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.cpp @@ -0,0 +1,55 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +namespace +{ + +// Size of a page +// +static const size_t globalPageBytes = 8 * 1024; + +} + +GlobalPagedFreeStore::GlobalPagedFreeStore () + : RefCountedSingleton (SingletonLifetime::persistAfterCreation) + , m_allocator (globalPageBytes) +{ +} + +GlobalPagedFreeStore::~GlobalPagedFreeStore () +{ +} + +GlobalPagedFreeStore* GlobalPagedFreeStore::createInstance () +{ + return new GlobalPagedFreeStore; +} diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.h b/Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.h new file mode 100644 index 0000000000..2987458878 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_GlobalPagedFreeStore.h @@ -0,0 +1,74 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_GLOBALPAGEDFREESTORE_BEASTHEADER +#define BEAST_GLOBALPAGEDFREESTORE_BEASTHEADER + +#include "beast_PagedFreeStore.h" + +/*============================================================================*/ +/** + A PagedFreeStore singleton. + + @ingroup beast_concurrent +*/ +class GlobalPagedFreeStore + : public RefCountedSingleton + , LeakChecked +{ +private: + GlobalPagedFreeStore (); + ~GlobalPagedFreeStore (); + +public: + inline size_t getPageBytes () + { + return m_allocator.getPageBytes (); + } + + inline void* allocate () + { + return m_allocator.allocate (); + } + + static inline void deallocate (void* const p) + { + PagedFreeStore::deallocate (p); + } + + static GlobalPagedFreeStore* createInstance (); + +private: + PagedFreeStore m_allocator; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_MemoryAlignment.h b/Subtrees/beast/modules/beast_basics/memory/beast_MemoryAlignment.h new file mode 100644 index 0000000000..a8e7865262 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_MemoryAlignment.h @@ -0,0 +1,73 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_MEMORYALIGNMENT_BEASTHEADER +#define BEAST_MEMORYALIGNMENT_BEASTHEADER + +namespace Memory +{ + +// Constants + +const int cacheLineAlignBits = 6; // 64 bytes +const int cacheLineAlignBytes = 1 << cacheLineAlignBits; +const int cacheLineAlignMask = cacheLineAlignBytes - 1; + +const int allocAlignBits = 3; // 8 bytes +const int allocAlignBytes = 1 << allocAlignBits; +const int allocAlignMask = allocAlignBytes - 1; + +// Returns the number of bytes needed to advance p to the correct alignment +template +inline size_t bytesNeededForAlignment (P const* const p) +{ + return (allocAlignBytes - (uintptr_t (p) & allocAlignMask)) + & allocAlignMask; +} + +// Returns the number of bytes to make "bytes" an aligned size +inline size_t sizeAdjustedForAlignment (const size_t bytes) +{ + return (bytes + allocAlignMask) & ~allocAlignMask; +} + +// Returns a pointer with alignment added. +template +inline P* pointerAdjustedForAlignment (P* const p) +{ + return reinterpret_cast (reinterpret_cast (p) + + bytesNeededForAlignment (p)); +} + +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.cpp b/Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.cpp new file mode 100644 index 0000000000..ab1dc7316d --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.cpp @@ -0,0 +1,239 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#define LOG_GC 0 + +namespace +{ + +// This is the upper limit on the amount of physical memory an instance of the +// allocator will allow. Going over this limit means that consumers cannot keep +// up with producers, and application logic should be re-examined. +// +// TODO: ENFORCE THIS GLOBALLY? MEASURE IN KILOBYTES AND FORCE KILOBYTE PAGE SIZES +#define HARD_LIMIT 1 +const size_t hardLimitMegaBytes = 256; + +} + +/* + +Implementation notes + +- There are two pools, the 'hot' pool and the 'cold' pool. + +- When a new page is needed we pop from the 'fresh' stack of the hot pool. + +- When a page is deallocated it is pushed to the 'garbage' stack of the hot pool. + +- Every so often, a garbage collection is performed on a separate thread. + During collection, fresh and garbage are swapped in the cold pool. + Then, the hot and cold pools are atomically swapped. + +*/ +//------------------------------------------------------------------------------ + +struct PagedFreeStore::Page : Pages::Node, LeakChecked +{ + explicit Page (PagedFreeStore* const allocator) + : m_allocator (*allocator) + { + } + + PagedFreeStore& getAllocator () const + { + return m_allocator; + } + +private: + PagedFreeStore& m_allocator; +}; + +inline void* PagedFreeStore::fromPage (Page* const p) +{ + return reinterpret_cast (p) + + Memory::sizeAdjustedForAlignment (sizeof (Page)); +} + +inline PagedFreeStore::Page* PagedFreeStore::toPage (void* const p) +{ + return reinterpret_cast ( + (reinterpret_cast (p) - + Memory::sizeAdjustedForAlignment (sizeof (Page)))); +} + +//------------------------------------------------------------------------------ + +PagedFreeStore::PagedFreeStore (const size_t pageBytes) + : m_pageBytes (pageBytes) + , m_pageBytesAvailable (pageBytes - Memory::sizeAdjustedForAlignment (sizeof (Page))) + , m_newPagesLeft (int ((hardLimitMegaBytes * 1024 * 1024) / m_pageBytes)) +#if LOG_GC + , m_swaps (0) +#endif +{ + m_hot = m_pool1; + m_cold = m_pool2; + + startOncePerSecond (); +} + +PagedFreeStore::~PagedFreeStore () +{ + endOncePerSecond (); + +#if LOG_GC + bassert (!m_used.isSignaled ()); +#endif + + dispose (m_pool1); + dispose (m_pool2); + +#if LOG_GC + bassert (!m_total.isSignaled ()); +#endif +} + +//------------------------------------------------------------------------------ + +void* PagedFreeStore::allocate () +{ + Page* page = m_hot->fresh->pop_front (); + + if (!page) + { +#if HARD_LIMIT + const bool exhausted = m_newPagesLeft.release (); + + if (exhausted) + Throw (Error ().fail (__FILE__, __LINE__, + TRANS ("the limit of memory allocations was reached"))); + +#endif + + void* storage = ::malloc (m_pageBytes); + + if (!storage) + Throw (Error ().fail (__FILE__, __LINE__, + TRANS ("a memory allocation failed"))); + + page = new (storage) Page (this); + +#if LOG_GC + m_total.addref (); +#endif + } + +#if LOG_GC + m_used.addref (); +#endif + + return fromPage (page); +} + +void PagedFreeStore::deallocate (void* const p) +{ + Page* const page = toPage (p); + PagedFreeStore& allocator = page->getAllocator (); + + allocator.m_hot->garbage->push_front (page); + +#if LOG_GC + allocator.m_used.release (); +#endif +} + +// +// Perform garbage collection. +// +void PagedFreeStore::doOncePerSecond () +{ + // Physically free one page. + // This will reduce the working set over time after a spike. + { + Page* page = m_cold->garbage->pop_front (); + + if (page) + { + page->~Page (); + ::free (page); + m_newPagesLeft.addref (); +#ifdef LOG_GC + m_total.release (); +#endif + } + } + + m_cold->fresh->swap (m_cold->garbage); + + // Swap atomically with respect to m_hot + Pool* temp = m_hot; + m_hot = m_cold; // atomic + m_cold = temp; + +#if LOG_GC + String s; + s << "swap " << String (++m_swaps); + s << " (" << String (m_used.get ()) << "/" + << String (m_total.get ()) << " of " + << String (m_newPagesLeft.get ()) << ")"; + Logger::outputDebugString (s); +#endif +} + +void PagedFreeStore::dispose (Pages& pages) +{ + for (;;) + { + Page* const page = pages.pop_front (); + + if (page) + { + page->~Page (); + ::free (page); + +#if LOG_GC + m_total.release (); +#endif + } + else + { + break; + } + } +} + +void PagedFreeStore::dispose (Pool& pool) +{ + dispose (pool.fresh); + dispose (pool.garbage); +} diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.h b/Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.h new file mode 100644 index 0000000000..81409172e0 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_PagedFreeStore.h @@ -0,0 +1,106 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_PAGEDFREESTORE_BEASTHEADER +#define BEAST_PAGEDFREESTORE_BEASTHEADER + +/*============================================================================*/ +/** + Lock-free memory allocator for fixed size pages. + + The ABA problem (http://en.wikipedia.org/wiki/ABA_problem) is avoided by + treating freed pages as garbage, and performing a collection every second. + + @ingroup beast_concurrent +*/ +class PagedFreeStore : private OncePerSecond +{ +public: + explicit PagedFreeStore (const size_t pageBytes); + ~PagedFreeStore (); + + // The available bytes per page is a little bit less + // than requested in the constructor, due to overhead. + // + inline size_t getPageBytes () const + { + return m_pageBytesAvailable; + } + + inline void* allocate (const size_t bytes) + { + if (bytes > m_pageBytes) + Throw (Error ().fail (__FILE__, __LINE__, "the size is too large")); + + return allocate (); + } + + void* allocate (); + static void deallocate (void* const p); + +private: + void* newPage (); + void doOncePerSecond (); + +private: + struct Page; + typedef LockFreeStack Pages; + + struct Pool + { + CacheLine::Padded fresh; + CacheLine::Padded garbage; + }; + + static inline void* fromPage (Page* const p); + static inline Page* toPage (void* const p); + + void dispose (Pages& pages); + void dispose (Pool& pool); + +private: + const size_t m_pageBytes; + const size_t m_pageBytesAvailable; + CacheLine::Aligned m_pool1; // pair of pools + CacheLine::Aligned m_pool2; + Pool* volatile m_cold; // pool which is cooling down + Pool* volatile m_hot; // pool we are currently using + AtomicCounter m_newPagesLeft; // limit of system allocations + +#if 1 + int m_swaps; + AtomicCounter m_total; + AtomicCounter m_used; +#endif +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_RefCountedSingleton.h b/Subtrees/beast/modules/beast_basics/memory/beast_RefCountedSingleton.h new file mode 100644 index 0000000000..0ad1ce7ce8 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_RefCountedSingleton.h @@ -0,0 +1,212 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_REFERENCECOUNTEDSINGLETON_BEASTHEADER +#define BEAST_REFERENCECOUNTEDSINGLETON_BEASTHEADER + +#include "../events/beast_PerformedAtExit.h" +#include "../memory/beast_StaticObject.h" + +/** + Thread-safe singleton which comes into existence on first use. Use this + instead of creating objects with static storage duration. These singletons + are automatically reference counted, so if you hold a pointer to it in every + object that depends on it, the order of destruction of objects is assured + to be correct. + + class Object must provide the function `Object* Object::createInstance()` + + @class RefCountedSingleton + @ingroup beast_core +*/ +/** @{ */ +class SingletonLifetime +{ + // "base classes dependent on a template parameter + // aren't part of lookup." - ville +public: + /** + Construction options for RefCountedSingleton + + @ingroup beast_core + */ + enum Lifetime + { + /** Singleton is created on first use and destroyed when + the last reference is removed. + */ + createOnDemand, + + /** Like createOnDemand, but after the Singleton is destroyed an + exception will be thrown if an attempt is made to create it again. + */ + createOnDemandOnce, + + /** The singleton is created on first use and persists until program exit. + */ + persistAfterCreation + }; +}; + +template +class RefCountedSingleton + : public SingletonLifetime + , private PerformedAtExit +{ +protected: + typedef SpinLock LockType; + + /** Create the singleton. + + @param lifetime The lifetime management option. + */ + explicit RefCountedSingleton (Lifetime const lifetime) + : m_lifetime (lifetime) + { + bassert (s_instance == nullptr); + + if (m_lifetime == persistAfterCreation) + { + incReferenceCount (); + } + else if (m_lifetime == createOnDemandOnce && *s_created) + { + Throw (Error ().fail (__FILE__, __LINE__)); + } + + *s_created = true; + } + + virtual ~RefCountedSingleton () + { + bassert (s_instance == nullptr); + } + +public: + typedef ReferenceCountedObjectPtr Ptr; + + /** Retrieve a reference to the singleton. + */ + static Ptr getInstance () + { + Ptr instance; + + instance = s_instance; + + if (instance == nullptr) + { + LockType::ScopedLockType lock (*s_mutex); + + instance = s_instance; + + if (instance == nullptr) + { + s_instance = Object::createInstance (); + + instance = s_instance; + } + } + + return instance; + } + + inline void incReferenceCount () noexcept + { + m_refs.addref (); + } + + inline void decReferenceCount () noexcept + { + if (m_refs.release ()) + destroySingleton (); + } + + // Caller must synchronize. + inline bool isBeingReferenced () const + { + return m_refs.isSignaled (); + } + +private: + void performAtExit () + { + if (m_lifetime == SingletonLifetime::persistAfterCreation) + decReferenceCount (); + } + + void destroySingleton () + { + bool destroy; + + { + LockType::ScopedLockType lock (*s_mutex); + + if (isBeingReferenced ()) + { + destroy = false; + } + else + { + destroy = true; + s_instance = 0; + } + } + + if (destroy) + { + delete this; + } + } + +private: + Lifetime const m_lifetime; + AtomicCounter m_refs; + +private: + static Object* s_instance; + static Static::Storage > s_mutex; + static Static::Storage > s_created; +}; +/** @{ */ + +template +Object* RefCountedSingleton ::s_instance; + +template +Static::Storage ::LockType, RefCountedSingleton > +RefCountedSingleton ::s_mutex; + +template +Static::Storage > +RefCountedSingleton ::s_created; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_StaticObject.h b/Subtrees/beast/modules/beast_basics/memory/beast_StaticObject.h new file mode 100644 index 0000000000..88bb00c2a4 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_StaticObject.h @@ -0,0 +1,200 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_STATICOBJECT_BEASTHEADER +#define BEAST_STATICOBJECT_BEASTHEADER + +#include "../threads/beast_SpinDelay.h" + +// +// A full suite of thread-safe objects designed for static storage duration. +// +// Wraps an object with a thread-safe initialization preamble so that it can +// properly exist with static storage duration. +// +// Implementation notes: +// +// This is accomplished by omitting the constructor and relying on the C++ +// specification that plain data types with static storage duration are filled +// with zeroes before any other initialization code executes. +// +// Spec: N2914=09-0104 +// +// [3.6.2] Initialization of non-local objects +// +// Objects with static storage duration (3.7.1) or thread storage +// duration (3.7.2) shall be zero-initialized (8.5) before any +// other initialization takes place. +// +// Requirements: +// +// Object must be constructible without parameters. +// The StaticObject must be declared with static storage duration or +// the behavior is undefined. +// +// Usage example: +// +// Object* getInstance () +// { +// static StaticObject instance; +// return instance->getObject (); +// } +// + +namespace Static +{ + +//------------------------------------------------------------------------------ + +// Holds an object with static storage duration. +// The owner determines if and when the object is constructed and destroyed. +// Caller is responsible for synchronization. +// +template +class Storage +{ +public: + static inline void construct () + { + new (getObjectPtr ()) ObjectType; + } + + static inline void destroy () + { + getObjectPtr ()->~ObjectType (); + } + + static inline ObjectType* getObjectPtr () + { + return reinterpret_cast (s_storage); + } + + static inline ObjectType& getObject () + { + return *getObjectPtr (); + } + + inline ObjectType* operator-> () const + { + return getObjectPtr (); + } + + inline ObjectType& operator* () const + { + return getObject (); + } + + inline operator ObjectType* () const + { + return getObjectPtr (); + } + + // TODO: Crashes on iOS if not accessed before usage + static char s_storage [sizeof (ObjectType)]; + +private: +}; + +template +char Storage ::s_storage [sizeof (ObjectType)]; + +//------------------------------------------------------------------------------ + +// Provides a thread safe flag for indicating if and when +// initialization is required for an object with static storage duration. +// +class Initializer +{ +public: + /* + bool inited () const + { + return m_state.get () == stateInitialized; + } + */ + + // If the condition is not initialized, the first caller will + // receive true, while concurrent callers get blocked until + // initialization completes. + // + bool begin () + { + bool shouldInitialize; + + if (m_state.get () == stateUninitialized) + { + if (m_state.compareAndSetBool (stateInitializing, stateUninitialized)) + { + shouldInitialize = true; + } + else + { + SpinDelay delay; + + do + { + delay.pause (); + } + while (m_state.get () != stateInitialized); + + shouldInitialize = false; + } + } + else + { + shouldInitialize = false; + } + + return shouldInitialize; + } + + // Called to signal that the initialization is complete + // + void end () + { + m_state.set (stateInitialized); + } + +private: + enum + { + stateUninitialized = 0, // must be zero + stateInitializing, + stateInitialized + }; + + Atomic m_state; +}; + +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/memory/beast_Uncopyable.h b/Subtrees/beast/modules/beast_basics/memory/beast_Uncopyable.h new file mode 100644 index 0000000000..9e975dd202 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/memory/beast_Uncopyable.h @@ -0,0 +1,51 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_UNCOPYABLE_BEASTHEADER +#define BEAST_UNCOPYABLE_BEASTHEADER + +// Prevents warnings about missing copy +// constructors and assignment operators. + +// Ideas based on boost +class Uncopyable +{ +protected: + inline Uncopyable () { } + inline ~Uncopyable () { } + +private: + Uncopyable (Uncopyable const&); + Uncopyable const& operator= (Uncopyable const&); +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/native/beast_posix_FPUFlags.cpp b/Subtrees/beast/modules/beast_basics/native/beast_posix_FPUFlags.cpp new file mode 100644 index 0000000000..34890c3f35 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/native/beast_posix_FPUFlags.cpp @@ -0,0 +1,13 @@ +// Copyright (C) 2008 by Vinnie Falco, this file is part of VFLib. +// See the file LICENSE.txt for licensing information. + +#pragma message(BEAST_LOC_"Missing platform-specific implementation") + +FPUFlags FPUFlags::getCurrent () +{ + return FPUFlags (); +} + +void FPUFlags::setCurrent (const FPUFlags& flags) +{ +} diff --git a/Subtrees/beast/modules/beast_basics/native/beast_posix_Threads.cpp b/Subtrees/beast/modules/beast_basics/native/beast_posix_Threads.cpp new file mode 100644 index 0000000000..e9c0324a34 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/native/beast_posix_Threads.cpp @@ -0,0 +1,31 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ diff --git a/Subtrees/beast/modules/beast_basics/native/beast_win32_FPUFlags.cpp b/Subtrees/beast/modules/beast_basics/native/beast_win32_FPUFlags.cpp new file mode 100644 index 0000000000..d0c76a5c7b --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/native/beast_win32_FPUFlags.cpp @@ -0,0 +1,189 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +FPUFlags FPUFlags::getCurrent () +{ + unsigned int currentControl; + const unsigned int newControl = 0; + const unsigned int mask = 0; + + errno_t result = _controlfp_s (¤tControl, newControl, mask); + + if (result != 0) + Throw (std::runtime_error ("error in _controlfp_s")); + + FPUFlags flags; + + flags.setMaskNaNs ((currentControl & _EM_INVALID) == _EM_INVALID); + flags.setMaskDenormals ((currentControl & _EM_DENORMAL) == _EM_DENORMAL); + flags.setMaskZeroDivides ((currentControl & _EM_ZERODIVIDE) == _EM_ZERODIVIDE); + flags.setMaskOverflows ((currentControl & _EM_OVERFLOW) == _EM_OVERFLOW); + flags.setMaskUnderflows ((currentControl & _EM_UNDERFLOW) == _EM_UNDERFLOW); + //flags.setMaskInexacts ((currentControl & _EM_INEXACT) == _EM_INEXACT); + flags.setFlushDenormals ((currentControl & _DN_FLUSH) == _DN_FLUSH); + flags.setInfinitySigned ((currentControl & _IC_AFFINE) == _IC_AFFINE); + + Rounding rounding = roundDown; + + switch (currentControl & _MCW_RC) + { + case _RC_CHOP: + rounding = roundChop; + break; + + case _RC_UP: + rounding = roundUp; + break; + + case _RC_DOWN: + rounding = roundDown; + break; + + case _RC_NEAR: + rounding = roundNear; + break; + + default: + Throw (std::runtime_error ("unknown rounding in _controlfp_s")); + }; + + flags.setRounding (rounding); + + Precision precision = bits64; + + switch (currentControl & _MCW_PC ) + { + case _PC_64: + precision = bits64; + break; + + case _PC_53: + precision = bits53; + break; + + case _PC_24: + precision = bits24; + break; + + default: + Throw (std::runtime_error ("unknown precision in _controlfp_s")); + }; + + flags.setPrecision (precision); + + return flags; +} + +static void setControl (const FPUFlags::Flag& flag, + unsigned int& newControl, + unsigned int& mask, + unsigned int constant) +{ + if (flag.is_set ()) + { + mask |= constant; + + if (flag.value ()) + newControl |= constant; + } +} + +void FPUFlags::setCurrent (const FPUFlags& flags) +{ + unsigned int newControl = 0; + unsigned int mask = 0; + + setControl (flags.getMaskNaNs (), newControl, mask, _EM_INVALID); + setControl (flags.getMaskDenormals (), newControl, mask, _EM_DENORMAL); + setControl (flags.getMaskZeroDivides (), newControl, mask, _EM_ZERODIVIDE); + setControl (flags.getMaskOverflows (), newControl, mask, _EM_OVERFLOW); + setControl (flags.getMaskUnderflows (), newControl, mask, _EM_UNDERFLOW); + //setControl (flags.getMaskInexacts(), newControl, mask, _EM_INEXACT); + setControl (flags.getFlushDenormals (), newControl, mask, _DN_FLUSH); + setControl (flags.getInfinitySigned (), newControl, mask, _IC_AFFINE); + + if (flags.getRounding ().is_set ()) + { + Rounding rounding = flags.getRounding ().value (); + + switch (rounding) + { + case roundChop: + mask |= _MCW_RC; + newControl |= _RC_CHOP; + break; + + case roundUp: + mask |= _MCW_RC; + newControl |= _RC_UP; + break; + + case roundDown: + mask |= _MCW_RC; + newControl |= _RC_DOWN; + break; + + case roundNear: + mask |= _MCW_RC; + newControl |= _RC_NEAR; + break; + } + } + + if (flags.getPrecision ().is_set ()) + { + switch (flags.getPrecision ().value ()) + { + case bits64: + mask |= _MCW_PC; + newControl |= _PC_64; + break; + + case bits53: + mask |= _MCW_PC; + newControl |= _PC_53; + break; + + case bits24: + mask |= _MCW_PC; + newControl |= _PC_24; + break; + } + } + + unsigned int currentControl; + + errno_t result = _controlfp_s (¤tControl, newControl, mask); + + if (result != 0) + Throw (std::runtime_error ("error in _controlfp_s")); +} diff --git a/Subtrees/beast/modules/beast_basics/native/beast_win32_Threads.cpp b/Subtrees/beast/modules/beast_basics/native/beast_win32_Threads.cpp new file mode 100644 index 0000000000..e9c0324a34 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/native/beast_win32_Threads.cpp @@ -0,0 +1,31 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.cpp new file mode 100644 index 0000000000..e8afdd9f5c --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.cpp @@ -0,0 +1,166 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +CallQueue::CallQueue (String name) + : m_name (name) +{ +} + +CallQueue::~CallQueue () +{ + // Someone forget to close the queue. + bassert (m_closed.isSignaled ()); + + // Can't destroy queue with unprocessed calls. + bassert (m_queue.empty ()); +} + +bool CallQueue::isAssociatedWithCurrentThread () const +{ + return Thread::getCurrentThreadId () == m_id; +} + +// Adds a call to the queue of execution. +void CallQueue::queuep (Work* c) +{ + // If this goes off it means calls are being made after the + // queue is closed, and probably there is no one around to + // process it. + bassert (!m_closed.isSignaled ()); + + if (m_queue.push_back (c)) + signal (); +} + +// Append the Work to the queue. If this call is made from the same +// thread as the last thread that called synchronize(), then the call +// will execute synchronously. +// +void CallQueue::callp (Work* c) +{ + queuep (c); + + // If we are called on the process thread and we are not + // recursed into doSynchronize, then process the queue. This + // makes calls from the process thread synchronous. + // + // NOTE: The value of isBeingSynchronized is invalid/volatile unless + // this thread is the last process thread. + // + // NOTE: There is a small window of opportunity where we + // might get an undesired synchronization if new thread + // calls synchronize() concurrently. + // + if (isAssociatedWithCurrentThread () && + m_isBeingSynchronized.trySignal ()) + { + doSynchronize (); + + m_isBeingSynchronized.reset (); + } +} + +bool CallQueue::synchronize () +{ + bool did_something; + + // Detect recursion into doSynchronize(), and + // break ties for concurrent calls atomically. + // + if (m_isBeingSynchronized.trySignal ()) + { + // Remember this thread. + m_id = Thread::getCurrentThreadId (); + + did_something = doSynchronize (); + + m_isBeingSynchronized.reset (); + } + else + { + did_something = false; + } + + return did_something; +} + +// Can still have pending calls, just can't put new ones in. +void CallQueue::close () +{ + m_closed.signal (); + + synchronize (); +} + +// Process everything in the queue. The list of pending calls is +// acquired atomically. New calls may enter the queue while we are +// processing. +// +// Returns true if any functors were called. +// +bool CallQueue::doSynchronize () +{ + bool did_something; + + // Reset since we are emptying the queue. Since we loop + // until the queue is empty, it is possible for us to exit + // this function with an empty queue and signaled state. + // + reset (); + + Work* call = m_queue.pop_front (); + + if (call) + { + did_something = true; + + // This method of processing one at a time has the desired + // side effect of synchronizing nested calls to us from a functor. + // + for (;;) + { + call->operator () (); + delete call; + + call = m_queue.pop_front (); + + if (call == 0) + break; + } + } + else + { + did_something = false; + } + + return did_something; +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.h b/Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.h new file mode 100644 index 0000000000..817f85a01b --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.h @@ -0,0 +1,555 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_CALLQUEUE_BEASTHEADER +#define BEAST_CALLQUEUE_BEASTHEADER + +/*============================================================================*/ +/** + A FIFO for calling functors asynchronously. + + This object is an alternative to traditional locking techniques used to + implement concurrent systems. Instead of acquiring a mutex to change shared + data, a functor is queued for later execution (usually on another thread). The + execution of the functor applies the transformation to the shared state that + was formerly performed within a lock (i.e. CriticalSection). + + For read operations on shared data, instead of acquiring a mutex and + accessing the data directly, copies are made (one for each thread), and the + thread accesses its copy without acquiring a lock. One thread owns the master + copy of the shared state. Requests for changing shared state are made by other + threads by posting functors to the master thread's CallQueue. The master + thread notifies other threads of changes by posting functors to their + respective associated CallQueue, using the Listeners interface. + + The purpose of the functor is to encapsulate one mutation of shared state to + guarantee progress towards a consensus of the concurrent data among + participating threads. Functors should execute quickly, ideally in constant + time. Dynamically allocated objects of class type passed as functor parameters + should, in general, be reference counted. The ConcurrentObject class is ideal + for meeting this requirement, and has the additional benefit that the workload + of deletion is performed on a separate, provided thread. This queue is not a + replacement for a thread pool or job queue type system. + + A CallQueue is considered signaled when one or more functors are present. + Functors are executed during a call to synchronize(). The operation of + executing functors via the call to synchronize() is called synchronizing + the queue. It can more generally be thought of as synchronizing multiple + copies of shared data between threads. + + Although there is some extra work required to set up and maintain this + system, the benefits are significant. Since shared data is only synchronized + at well defined times, the programmer can reason and make strong statements + about the correctness of the concurrent system. For example, if an + AudioIODeviceCallback synchronizes the CallQueue only at the beginning of its + execution, it is guaranteed that shared data will remain the same throughout + the remainder of the function. + + Because shared data is accessed for reading without a lock, upper bounds + on the run time performance can easily be calculated and assured. Compare + this with the use of a mutex - the run time performance experiences a + combinatorial explosion of possibilities depending on the complex interaction + of multiple threads. + + Since a CallQueue is almost always used to invoke parameterized member + functions of objects, the call() function comes in a variety of convenient + forms to make usage easy: + + @code + + void func1 (int); + + struct Object + { + void func2 (void); + void func3 (String name); + + static void func4 (); + }; + + CallQueue fifo ("Example"); + + void example () + { + fifo.call (func1, 42); // same as: func1 (42) + + Object* object = new Object; + + fifo.call (&Object::func2, object); // same as: object->func2 () + + fifo.call (&Object::func3, // same as: object->funcf ("Label") + object, + "Label"); + + fifo.call (&Object::func4); // even static members can be called. + + fifo.callf (bind (&Object::func2, // same as: object->func2 () + object)); + } + + @endcode + + @invariant Functors can be added from any thread at any time, to any queue + which is not closed. + + @invariant When synchronize() is called, functors are called and deleted. + + @invariant The thread from which synchronize() is called is considered the + thread associated with the CallQueue. + + @invariant Functors queued by the same thread always execute in the same + order they were queued. + + @invariant Functors are guaranteed to execute. It is an error if the + CallQueue is deleted while there are functors in it. + + Normally, you will not use CallQueue directly, but one of its subclasses + instead. The CallQueue is one of a handful of objects that work together to + implement this system of concurrent data access. + + For performance considerations, this implementation is wait-free for + producers and mostly wait-free for consumers. It also uses a lock-free + and wait-free (in the fast path) custom memory allocator. + + @see GuiCallQueue, ManualCallQueue, MessageThread, ThreadWithCallQueue + + @ingroup beast_concurrent +*/ +class CallQueue +{ +public: + //============================================================================ + + /** Type of allocator to use. + + @internal + */ + typedef FifoFreeStoreType AllocatorType; + + /** Abstract nullary functor in a @ref CallQueue. + + Custom implementations may derive from this object for efficiency instead + of using the automatic binding functions. + */ + class Work : public LockFreeQueue ::Node, + public AllocatedBy + { + public: + virtual ~Work () { } + + /** Calls the functor. + + This executes during the queue's call to synchronize(). + */ + virtual void operator () () = 0; + }; + + //============================================================================ + + /** Create the CallQueue. + + The queue starts out open and empty. + + @param name A string to identify the queue during debugging. + */ + explicit CallQueue (String name); + + /** Destroy the CallQueue. + + @invariant Destroying a queue that contains functors results in undefined + behavior. + + @note It is customary to call close() on the CallQueue early in the + shutdown process to catch functors going into the queue late. + */ + virtual ~CallQueue (); + + //============================================================================ + + /** Add a functor and possibly synchronize. + + Use this when you want to perform the bind yourself. + + @param f The functor to add, typically the return value of a call + to bind(). + + @see call + */ + template + void callf (Functor f) + { + callp (new (m_allocator) CallType (f)); + } + + /** Add a function call and possibly synchronize. + + Parameters are evaluated immediately and added to the queue as a packaged + functor. If the current thread of execution is the same as the thread + associated with the CallQueue, synchronize() is called automatically. This + behavior can be avoided by using queue() instead. + + @param f The function to call followed by up to eight parameters, + evaluated immediately. The parameter list must match the function + signature. For class member functions, the first argument must be a + pointer to the class object. + + @see queue + + @todo Provide an example of when synchronize() is needed in call(). + */ + /** @{ */ +#if VFLIB_VARIADIC_MAX >= 1 + template + void call (Fn f) + { + callf (bind (f)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void call (Fn f, T1 t1) + { + callf (bind (f, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void call (Fn f, T1 t1, T2 t2) + { + callf (bind (f, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void call (Fn f, T1 t1, T2 t2, T3 t3) + { + callf (bind (f, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4) + { + callf (bind (f, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + callf (bind (f, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + callf (bind (f, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + callf (bind (f, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void call (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + callf (bind (f, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ + + /** Add a functor without synchronizing. + + Use this when you want to perform the bind yourself. + + @param f The functor to add, typically the return value of a call + to bind(). + + @see queue + */ + template + void queuef (Functor f) + { + queuep (new (m_allocator) CallType (f)); + } + + /** Add a function call without synchronizing. + + Parameters are evaluated immediately, then the resulting functor is added + to the queue. This is used to postpone the call to synchronize() when + there would be adverse side effects to executing the function immediately. + In this example, we use queue() instead of call() to avoid a deadlock: + + @code + + struct SharedState; // contains data shared between threads + + ConcurrentState sharedState; + + void stateChanged () + { + ConcurrentState ::ReadAccess state (sharedState); + + // (read state) + } + + CallQueue fifo; + + void changeState () + { + ConcurrentState ::WriteAccess state (sharedState); + + // (read and write state) + + fifo.call (&stateChanged); // BUG: DEADLOCK because of the implicit synchronize(). + + fifo.queue (&stateChanged); // Okay, synchronize() will be called later, + // after the write lock is released. + } + + @endcode + + @param f The function to call followed by up to eight parameters, + evaluated immediately. The parameter list must match the + function signature. For non-static class member functions, + the first argument must be a pointer an instance of the class. + + @see call + */ + /** @{ */ +#if VFLIB_VARIADIC_MAX >= 1 + template + void queue (Fn f) + { + queuef (bind (f)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void queue (Fn f, T1 t1) + { + queuef (bind (f, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void queue (Fn f, T1 t1, T2 t2) + { + queuef (bind (f, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void queue (Fn f, T1 t1, T2 t2, T3 t3) + { + queuef (bind (f, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4) + { + queuef (bind (f, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + queuef (bind (f, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + queuef (bind (f, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + queuef (bind (f, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void queue (Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + queuef (bind (f, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ + +protected: + //============================================================================ + /** Synchronize the queue. + + A synchronize operation calls all functors in the queue. If a functor + causes additional functors to be added, they are eventually executed + before synchronize() returns. Derived class call this when the queue is + signaled, and optionally at any other time. Calling this function from + more than one thread simultaneously is undefined. + + @return true if any functors were executed. + */ + bool synchronize (); + + /** Close the queue. + + Functors may not be added after this routine is called. This is used for + diagnostics, to track down spurious calls during application shutdown + or exit. Derived classes may call this if the appropriate time is known. + + The queue is synchronized after it is closed. + */ + void close (); + + /** Called when the queue becomes signaled. + + A queue is signaled on the transition from empty to non-empty. Derived + classes implement this function to perform a notification so that + synchronize() will be called. For example, by triggering a WaitableEvent. + + @note Due to the implementation the queue can remain signaled for one + extra cycle. This does not happen under load and is not an issue + in practice. + */ + virtual void signal () = 0; + + /** Called when the queue is reset. + + A queue is reset when it was previously signaled and then becomes empty + as a result of a call to synchronize. + */ + virtual void reset () = 0; + +public: + //============================================================================ + + /** Add a raw call. + + @internal + + Custom implementations use this to control the allocation. + + @param c The call to add. The memory must come from the allocator. + */ + void callp (Work* c); + + /** Queue a raw call. + + Custom implementations use this to control the allocation. + + @param c The call to add. The memory must come from the allocator. + */ + void queuep (Work* c); + + /** Retrieve the allocator. + + @return The allocator to use when allocating a raw Work object. + */ + inline AllocatorType& getAllocator () + { + return m_allocator; + } + + /** See if the caller is on the association thread. + + @return `true` if the calling thread of execution is associated with the + queue. + */ + bool isAssociatedWithCurrentThread () const; + + /** See if the queue is being synchronized. + + This is used for diagnostics. + + @note This must be called from the associated thread or else the return + value is undefined. + + @return `true` if the call stack contains synchronize() for this queue. + */ + bool isBeingSynchronized () const + { + return m_isBeingSynchronized.isSignaled (); + } + +private: + template + class CallType : public Work + { + public: + explicit CallType (Functor f) : m_f (f) { } + void operator () () + { + m_f (); + } + + private: + Functor m_f; + }; + + bool doSynchronize (); + +private: + String const m_name; + Thread::ThreadID m_id; + LockFreeQueue m_queue; + AtomicFlag m_closed; + AtomicFlag m_isBeingSynchronized; + AllocatorType m_allocator; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.cpp new file mode 100644 index 0000000000..51cd2a7cbd --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.cpp @@ -0,0 +1,89 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +class ConcurrentObject::Deleter : private ThreadWithCallQueue::EntryPoints +{ +private: + Deleter () : m_thread ("AsyncDeleter") + { + m_thread.start (this); + } + + ~Deleter () + { + m_thread.stop (true); + } + + void performAtExit () + { + //delete this; + } + + static void doDelete (ConcurrentObject* sharedObject) + { + delete sharedObject; + } + +public: + void destroy (ConcurrentObject* sharedObject) + { + if (m_thread.isAssociatedWithCurrentThread ()) + delete sharedObject; + else + m_thread.call (&Deleter::doDelete, sharedObject); + } + + static Deleter& getInstance () + { + static Deleter instance; + + return instance; + } + +private: + ThreadWithCallQueue m_thread; +}; + +//------------------------------------------------------------------------------ + +ConcurrentObject::ConcurrentObject () +{ +} + +ConcurrentObject::~ConcurrentObject () +{ +} + +void ConcurrentObject::destroyConcurrentObject () +{ + Deleter::getInstance ().destroy (this); +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.h b/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.h new file mode 100644 index 0000000000..0a6404a9f4 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentObject.h @@ -0,0 +1,92 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_CONCURRENTOBJECT_BEASTHEADER +#define BEAST_CONCURRENTOBJECT_BEASTHEADER + +/*============================================================================*/ +/** + A reference counted object with overridable destroy behavior. + + This is a reference counted object compatible with + ReferenceCountedObjectPtr. When the last reference is removed, the + object is queued for deletion on a separate, provided thread. On + program exit the thread will clean itself up - no other action is + required. + + This class is useful for offloading the deletion work of "deep" objects + shared by multiple threads: objects containing complex members, or a + hierarchy of allocated structures. For example, a ValueTree. The problem + of performing heavyweight memory or cleanup operations from either an + AudioIODeviceCallback or the message thread is avoided. + + The deletion behavior can be overriden by providing a replacement + for destroyConcurrentObject(). + + @ingroup beast_concurrent +*/ +class ConcurrentObject : Uncopyable +{ +public: + inline void incReferenceCount () noexcept + { + m_refs.addref (); + } + + inline void decReferenceCount () noexcept + { + if (m_refs.release ()) + destroyConcurrentObject (); + } + +protected: + ConcurrentObject (); + + virtual ~ConcurrentObject (); + + /** Delete the object. + + This function is called when the reference count drops to zero. The + default implementation performs the delete on a separate, provided thread + that cleans up after itself on exit. + */ + virtual void destroyConcurrentObject (); + +protected: + class Deleter; + +private: + AtomicCounter m_refs; +}; + +#endif + diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentState.h b/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentState.h new file mode 100644 index 0000000000..5d3d36b060 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ConcurrentState.h @@ -0,0 +1,311 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_CONCURRENTSTATE_BEASTHEADER +#define BEAST_CONCURRENTSTATE_BEASTHEADER + +/*============================================================================*/ +/** + Structured access to a shared state. + + This template wraps an object containing members representing state + information shared between multiple threads of execution, where any thread + may need to read or write as needed. Synchronized access to the concurrent + state is enforced at compile time through strongly typed accessor classes. + This interface design facilitates source code pattern matching to find all + areas where a concurrent state is accessed. + + There are three types of access: + + - ReadAccess + + Allows read access to the underlying object as `const`. ReadAccess may be + granted to one or more threads simultaneously. If one or more threads have + ReadAccess, requests to obtain WriteAccess are blocked. + + - WriteAccess + + Allows exclusive read/write access the underlying object. A WriteAccess + request blocks until all existing ReadAccess and WriteAccess requests are + released. While a WriteAccess exists, requests for ReadAccess will block. + + - UnlockedAccess + + Allows read access to the underlying object without using the lock. This + can be helpful when designing concurrent structures through composition. + It also makes it easier to search for places in code which use unlocked + access. + + This code example demonstrates various forms of access to a ConcurrentState: + + @code + + struct SharedData + { + int value1; + String value2; + }; + + typedef ConcurrentState SharedState; + + SharedState sharedState; + + void readExample () + { + SharedState::ReadAccess state (sharedState); + + print (state->value1); // read access + print (state->value2); // read access + + state->value1 = 42; // write disallowed: compile error + } + + void writeExample () + { + SharedState::WriteAccess state (sharedState); + + state->value2 = "Label"; // write access + } + + @endcode + + Forwarding constructors with up to eight parameters are provided. This lets + you write constructors into the underlying data object. For example: + + @code + + struct SharedData + { + explicit SharedData (int numSlots) + { + m_array.reserve (numSlots); + } + + std::vector m_array; + }; + + // Construct SharedData with one parameter + ConcurrentState sharedState (16); + + @endcode + + @param Object The type of object to encapsulate. + + @warning Recursive calls are not supported. It is generally not possible for + a thread of execution to acquire write access while it already has + read access. Such an attempt will result in undefined behavior. Calling into + unknown code while holding a lock can cause deadlock. See + @ref CallQueue::queue(). + + @ingroup beast_concurrent +*/ +template +class ConcurrentState : Uncopyable +{ +public: + class ReadAccess; + class WriteAccess; + class UnlockedAccess; + + /** Create a concurrent state. + + Up to 8 parameters can be specified in the constructor. These parameters + are forwarded to the corresponding constructor in Object. If no + constructor in Object matches the parameter list, a compile error is + generated. + */ + /** @{ */ + ConcurrentState () { } + + template + explicit ConcurrentState (T1 t1) + : m_obj (t1) { } + + template + ConcurrentState (T1 t1, T2 t2) + : m_obj (t1, t2) { } + + template + ConcurrentState (T1 t1, T2 t2, T3 t3) + : m_obj (t1, t2, t3) { } + + template + ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4) + : m_obj (t1, t2, t3, t4) { } + + template + ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + : m_obj (t1, t2, t3, t4, t5) { } + + template + ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + : m_obj (t1, t2, t3, t4, t5, t6) { } + + template + ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) : m_obj (t1, t2, t3, t4, t5, t6, t7) { } + + template + ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + : m_obj (t1, t2, t3, t4, t5, t6, t7, t8) { } + /** @} */ + +private: + typedef ReadWriteMutex ReadWriteMutexType; + + Object m_obj; + ReadWriteMutexType m_mutex; +}; + +//------------------------------------------------------------------------------ + +/** Unlocked access to a ConcurrentState. + + Use sparingly. +*/ +template +class ConcurrentState ::UnlockedAccess : Uncopyable +{ +public: + explicit UnlockedAccess (ConcurrentState const& state) + : m_state (state) + { + } + + Object const& getObject () const + { + return m_state.m_obj; + } + Object const& operator* () const + { + return getObject (); + } + Object const* operator-> () const + { + return &getObject (); + } + +private: + ConcurrentState const& m_state; +}; + +//------------------------------------------------------------------------------ + +/** Read only access to a ConcurrentState */ +template +class ConcurrentState ::ReadAccess : Uncopyable +{ +public: + /** Create a ReadAccess from the specified ConcurrentState */ + explicit ReadAccess (ConcurrentState const volatile& state) + : m_state (const_cast (state)) + , m_lock (m_state.m_mutex) + { + } + + /** Obtain a read only reference to Object */ + Object const& getObject () const + { + return m_state.m_obj; + } + + /** Obtain a read only reference to Object */ + Object const& operator* () const + { + return getObject (); + } + + /** Obtain a read only smart pointer to Object */ + Object const* operator-> () const + { + return &getObject (); + } + +private: + ConcurrentState const& m_state; + ReadWriteMutexType::ScopedReadLockType m_lock; +}; + +//------------------------------------------------------------------------------ + +/** Read/write access to a ConcurrentState */ +template +class ConcurrentState ::WriteAccess : Uncopyable +{ +public: + explicit WriteAccess (ConcurrentState& state) + : m_state (state) + , m_lock (m_state.m_mutex) + { + } + + /** Obtain a read only reference to Object */ + Object const* getObject () const + { + return m_state.m_obj; + } + + /** Obtain a read only reference to Object */ + Object const& operator* () const + { + return getObject (); + } + + /** Obtain a read only smart pointer to Object */ + Object const* operator-> () const + { + return &getObject (); + } + + /** Obtain a read/write pointer to Object */ + Object& getObject () + { + return m_state.m_obj; + } + + /** Obtain a read/write reference to Object */ + Object& operator* () + { + return getObject (); + } + + /** Obtain a read/write smart pointer to Object */ + Object* operator-> () + { + return &getObject (); + } + +private: + ConcurrentState& m_state; + ReadWriteMutexType::ScopedWriteLockType m_lock; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_GlobalThreadGroup.h b/Subtrees/beast/modules/beast_basics/threads/beast_GlobalThreadGroup.h new file mode 100644 index 0000000000..28463500e1 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_GlobalThreadGroup.h @@ -0,0 +1,62 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_GLOBALTHREADGROUP_BEASTHEADER +#define BEAST_GLOBALTHREADGROUP_BEASTHEADER + +/*============================================================================*/ +/** + A ThreadGroup singleton. + + @see ThreadGroup + + @ingroup beast_concurrent +*/ +class GlobalThreadGroup : public ThreadGroup, + public RefCountedSingleton +{ +private: + friend class RefCountedSingleton ; + + GlobalThreadGroup () + : RefCountedSingleton ( + SingletonLifetime::persistAfterCreation) + { + } + + static GlobalThreadGroup* createInstance () + { + return new GlobalThreadGroup; + } +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.cpp new file mode 100644 index 0000000000..e52a819d44 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.cpp @@ -0,0 +1,238 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +InterruptibleThread::ThreadHelper::ThreadHelper (String name, + InterruptibleThread* owner) + : Thread (name) + , m_owner (owner) +{ +} + +InterruptibleThread* InterruptibleThread::ThreadHelper::getOwner () const +{ + return m_owner; +} + +void InterruptibleThread::ThreadHelper::run () +{ + m_owner->run (); +} + +//------------------------------------------------------------------------------ + +InterruptibleThread::InterruptibleThread (String name) + : m_thread (name, this) + , m_entryPoint (nullptr) + , m_state (stateRun) +{ +} + +InterruptibleThread::~InterruptibleThread () +{ + m_runEvent.signal (); + + join (); +} + +void InterruptibleThread::start (EntryPoint* const entryPoint) +{ + m_entryPoint = entryPoint; + + m_thread.startThread (); + + // Prevent data race with member variables + // + m_runEvent.signal (); +} + +void InterruptibleThread::join () +{ + m_thread.stopThread (-1); +} + +bool InterruptibleThread::wait (int milliSeconds) +{ + // Can only be called from the corresponding thread of execution. + // + bassert (isTheCurrentThread ()); + + bool interrupted = false; + + for (;;) + { + bassert (m_state != stateWait); + + // See if we are interrupted + // + if (m_state.tryChangeState (stateInterrupt, stateRun)) + { + // We were interrupted, state is changed to Run. Caller must run now. + // + interrupted = true; + break; + } + else if (m_state.tryChangeState (stateRun, stateWait) || + m_state.tryChangeState (stateReturn, stateWait)) + { + // Transitioned to wait. Caller must wait now. + // + interrupted = false; + break; + } + } + + if (!interrupted) + { + interrupted = m_thread.wait (milliSeconds); + + if (!interrupted) + { + if (m_state.tryChangeState (stateWait, stateRun)) + { + interrupted = false; + } + else + { + bassert (m_state == stateInterrupt); + + interrupted = true; + } + } + } + + return interrupted; +} + +void InterruptibleThread::interrupt () +{ + for (;;) + { + int const state = m_state; + + if (state == stateInterrupt || + state == stateReturn || + m_state.tryChangeState (stateRun, stateInterrupt)) + { + // Thread will see this at next interruption point. + // + break; + } + else if (m_state.tryChangeState (stateWait, stateRun)) + { + m_thread.notify (); + break; + } + } +} + +bool InterruptibleThread::interruptionPoint () +{ + // Can only be called from the thread of execution. + // + bassert (isTheCurrentThread ()); + + if (m_state == stateWait) + { + // It is impossible for this function to be called while in the wait state. + // + Throw (Error ().fail (__FILE__, __LINE__)); + } + else if (m_state == stateReturn) + { + // If this goes off it means the thread called the + // interruption a second time after already getting interrupted. + // + Throw (Error ().fail (__FILE__, __LINE__)); + } + + bool const interrupted = m_state.tryChangeState (stateInterrupt, stateRun); + + return interrupted; +} + +InterruptibleThread::id InterruptibleThread::getId () const +{ + return m_threadId; +} + +bool InterruptibleThread::isTheCurrentThread () const +{ + return m_thread.getCurrentThreadId () == m_threadId; +} + +void InterruptibleThread::setPriority (int priority) +{ + m_thread.setPriority (priority); +} + +InterruptibleThread* InterruptibleThread::getCurrentThread () +{ + InterruptibleThread* result = nullptr; + + Thread* const thread = Thread::getCurrentThread (); + + if (thread != nullptr) + { + ThreadHelper* const helper = dynamic_cast (thread); + + bassert (helper != nullptr); + + result = helper->getOwner (); + } + + return result; +} + +void InterruptibleThread::run () +{ + m_threadId = m_thread.getThreadId (); + + m_runEvent.wait (); + + //CatchAny (m_function); + m_entryPoint->threadRun (); +} + +//------------------------------------------------------------------------------ + +bool CurrentInterruptibleThread::interruptionPoint () +{ + bool interrupted = false; + + InterruptibleThread* const interruptibleThread (InterruptibleThread::getCurrentThread ()); + + bassert (interruptibleThread != nullptr); + + interrupted = interruptibleThread->interruptionPoint (); + + return interrupted; +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.h b/Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.h new file mode 100644 index 0000000000..4b3c6747fd --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_InterruptibleThread.h @@ -0,0 +1,201 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_INTERRUPTIBLETHREAD_BEASTHEADER +#define BEAST_INTERRUPTIBLETHREAD_BEASTHEADER + +#include "../diagnostic/beast_SafeBool.h" +#include "../functor/beast_Function.h" + +//============================================================================== +/** + A thread with soft interruption support. + + The thread must periodically call interruptionPoint(), which returns `true` + the first time an interruption has occurred since the last call to + interruptionPoint(). + + To create a thread, derive your class from InterruptibleThread::EntryPoint + and implement the threadRun() function. Then, call run() with your object. + + @ingroup beast_core +*/ +class InterruptibleThread +{ +public: + /** InterruptibleThread entry point. + */ + class EntryPoint + { + public: + virtual ~EntryPoint () { } + + virtual void threadRun () = 0; + }; + +public: + typedef Thread::ThreadID id; + + /** Construct an interruptible thread. + + The name is used for debugger diagnostics. + + @param name The name of the thread. + */ + explicit InterruptibleThread (String name); + + /** Destroy the interruptible thread. + + This will signal an interrupt and wait until the thread exits. + */ + ~InterruptibleThread (); + + /** Start the thread. + */ + void start (EntryPoint* const entryPoint); + + /** Wait for the thread to exit. + */ + void join (); + + /** Wait for interrupt or timeout. + + This call blocks until the thread is interrupted, or until the timeout + expires if milliSeconds is non-negative. + + May only be called by the thread of execution. + + @param milliSeconds The amount of time to wait. Negative values mean + no timeout. + + @return `true` if the interrupt occurred, or `false` if the + timeout expired. + */ + bool wait (int milliSeconds = -1); + + /** Interrupt the thread of execution. + + This can be called from any thread. + */ + void interrupt (); + + /** Determine if an interruption is requested. + + After the function returns `true`, the interrupt status is cleared. + Subsequent calls will return `false` until another interrupt is requested. + + May only be called by the thread of execution. + + @see CurrentInterruptibleThread::interruptionPoint + + @return `true` if an interrupt was requested. + */ + bool interruptionPoint (); + + /** Get the ID of the associated thread. + + @return The ID of the thread. + */ + id getId () const; + + /** Determine if this is the thread of execution. + + @note The return value is undefined if the thread is not running. + + @return `true` if the caller is this thread of execution. + */ + bool isTheCurrentThread () const; + + /** Adjust the thread priority. + + @note This only affects some platforms. + + @param priority A number from 0..10 + */ + void setPriority (int priority); + + /** Get the InterruptibleThread for the thread of execution. + + This will return `nullptr` when called from the message thread, or from + a thread of execution that is not an InterruptibleThread. + */ + static InterruptibleThread* getCurrentThread (); + +private: + class ThreadHelper : public Thread + { + public: + ThreadHelper (String name, InterruptibleThread* owner); + + InterruptibleThread* getOwner () const; + + void run (); + + private: + InterruptibleThread* const m_owner; + }; + + void run (); + + ThreadHelper m_thread; + EntryPoint* m_entryPoint; + Function m_function; + WaitableEvent m_runEvent; + id m_threadId; + + enum + { + stateRun, + stateInterrupt, + stateReturn, + stateWait + }; + + AtomicState m_state; +}; + +//------------------------------------------------------------------------------ + +/** Global operations on the current InterruptibleThread. + + Calling members of the class from a thread of execution which is not an + InterruptibleThread results in undefined behavior. +*/ +class CurrentInterruptibleThread +{ +public: + /** Call the current thread's interrupt point function. + */ + static bool interruptionPoint (); +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_Listeners.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_Listeners.cpp new file mode 100644 index 0000000000..686ce07ae2 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_Listeners.cpp @@ -0,0 +1,778 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +// CallQueue item to process a Call for a particular listener. +// This is used to avoid bind overhead. +// +class ListenersBase::CallWork : public CallQueue::Work +{ +public: + inline CallWork (ListenersBase::Call* const c, void* const listener) + : m_call (c), m_listener (listener) + { + } + + void operator () () + { + m_call->operator () (m_listener); + } + +private: + ListenersBase::Call::Ptr m_call; + void* const m_listener; +}; + +//------------------------------------------------------------------------------ + +// CallQueue item to process a Call for a group. +// This is used to avoid bind overhead. +// +class ListenersBase::GroupWork : public CallQueue::Work +{ +public: + inline GroupWork (Group* group, + ListenersBase::Call* c, + const timestamp_t timestamp) + : m_group (group) + , m_call (c) + , m_timestamp (timestamp) + { + } + + void operator () () + { + m_group->do_call (m_call, m_timestamp); + } + +private: + Group::Ptr m_group; + ListenersBase::Call::Ptr m_call; + const timestamp_t m_timestamp; +}; + +//------------------------------------------------------------------------------ + +// CallQueue item to process a call for a particular listener. +// This is used to avoid bind overhead. +// +class ListenersBase::GroupWork1 : public CallQueue::Work +{ +public: + inline GroupWork1 (Group* group, + ListenersBase::Call* c, + const timestamp_t timestamp, + void* const listener) + : m_group (group) + , m_call (c) + , m_timestamp (timestamp) + , m_listener (listener) + { + } + + void operator () () + { + m_group->do_call1 (m_call, m_timestamp, m_listener); + } + +private: + Group::Ptr m_group; + ListenersBase::Call::Ptr m_call; + const timestamp_t m_timestamp; + void* const m_listener; +}; + +//------------------------------------------------------------------------------ + +// A Proxy maintains a list of Entry. +// Each Entry holds a group and the current Call (which can be updated). +// +struct ListenersBase::Proxy::Entry : Entries::Node, + ReferenceCountedObject, + AllocatedBy +{ + typedef ReferenceCountedObjectPtr Ptr; + + explicit Entry (Group* g) + : group (g) + { + } + + ~Entry () + { + bassert (call.get () == 0); + } + + Group::Ptr group; + AtomicPointer call; +}; + +//------------------------------------------------------------------------------ + +// A Group maintains a list of Entry. +// +struct ListenersBase::Group::Entry : List ::Node, + AllocatedBy +{ + Entry (void* const l, const timestamp_t t) + : listener (l) + , timestamp (t) + { + } + + void* const listener; + const timestamp_t timestamp; +}; + +//------------------------------------------------------------------------------ +// +// Group +// +//------------------------------------------------------------------------------ + +// - A list of listeners associated with the same CallQueue. +// +// - The list is only iterated on the CallQueue's thread. +// +// - It is safe to add or remove listeners from the group +// at any time. +// + +ListenersBase::Group::Group (CallQueue& callQueue) + : m_fifo (callQueue) + , m_listener (0) +{ +} + +ListenersBase::Group::~Group () +{ + // If this goes off it means a Listener forgot to remove itself. + bassert (m_list.empty ()); + + // shouldn't be deleting group during a call + bassert (m_listener == 0); +} + +// Add the listener with the given timestamp. +// The listener will only get calls with higher timestamps. +// The caller must prevent duplicates. +// +void ListenersBase::Group::add (void* listener, + const timestamp_t timestamp, + AllocatorType& allocator) +{ + ReadWriteMutex::ScopedWriteLockType lock (m_mutex); + + bassert (!contains (listener)); + + // Should never be able to get here while in call() + bassert (m_listener == 0); + + // Add the listener and remember the time stamp so we don't + // send it calls that were queued earlier than the add(). + m_list.push_back (*new (allocator) Entry (listener, timestamp)); +} + +// Removes the listener from the group if it exists. +// Returns true if the listener was removed. +// +bool ListenersBase::Group::remove (void* listener) +{ + bool found = false; + + ReadWriteMutex::ScopedWriteLockType lock (m_mutex); + + // Should never be able to get here while in call() + bassert (m_listener == 0); + + for (List ::iterator iter = m_list.begin (); iter != m_list.end (); ++iter) + { + Entry* entry = & (*iter); + + if (entry->listener == listener) + { + m_list.erase (m_list.iterator_to (*entry)); + delete entry; + found = true; + break; + } + } + + return found; +} + +// Used for assertions. +// The caller must synchronize. +// +bool ListenersBase::Group::contains (void* const listener) /*const*/ +{ + for (List ::iterator iter = m_list.begin (); iter != m_list.end (); iter++) + if (iter->listener == listener) + return true; + + return false; +} + +void ListenersBase::Group::call (Call* const c, const timestamp_t timestamp) +{ + bassert (!empty ()); + m_fifo.callp (new (m_fifo.getAllocator ()) GroupWork (this, c, timestamp)); +} + +void ListenersBase::Group::queue (Call* const c, const timestamp_t timestamp) +{ + bassert (!empty ()); + m_fifo.queuep (new (m_fifo.getAllocator ()) GroupWork (this, c, timestamp)); +} + +void ListenersBase::Group::call1 (Call* const c, + const timestamp_t timestamp, + void* const listener) +{ + m_fifo.callp (new (m_fifo.getAllocator ()) GroupWork1 ( + this, c, timestamp, listener)); +} + +void ListenersBase::Group::queue1 (Call* const c, + const timestamp_t timestamp, + void* const listener) +{ + m_fifo.queuep (new (m_fifo.getAllocator ()) GroupWork1 ( + this, c, timestamp, listener)); +} + +// Queues a reference to the Call on the thread queue of each listener +// that is currently in our list. The thread queue must be in the +// stack's call chain, either directly from CallQueue::synchronize(), +// or from Proxy::do_call() called from CallQueue::synchronize(). +// +void ListenersBase::Group::do_call (Call* const c, const timestamp_t timestamp) +{ + if (!empty ()) + { + ReadWriteMutex::ScopedReadLockType lock (m_mutex); + + // Recursion not allowed. + bassert (m_listener == 0); + + // The body of the loop MUST NOT cause listeners to get called. + // Therefore, we don't have to worry about listeners removing + // themselves while iterating the list. + // + for (List ::iterator iter = m_list.begin (); iter != m_list.end ();) + { + Entry* entry = & (*iter++); + + // Since it is possible for a listener to be added after a + // Call gets queued but before it executes, this prevents listeners + // from seeing Calls created before they were added. + // + if (timestamp > entry->timestamp) + { + m_listener = entry->listener; + + // The thread queue's synchronize() function MUST be in our call + // stack to guarantee that these calls will not execute immediately. + // They will be handled by the tail recusion unrolling in the + // thread queue. + bassert (m_fifo.isBeingSynchronized ()); + + m_fifo.callp (new (m_fifo.getAllocator ()) CallWork (c, m_listener)); + + m_listener = 0; + } + } + } + else + { + // last listener was removed before we got here, + // and the parent listener list may have been deleted. + } +} + +void ListenersBase::Group::do_call1 (Call* const c, const timestamp_t timestamp, + void* const listener) +{ + if (!empty ()) + { + ReadWriteMutex::ScopedReadLockType lock (m_mutex); + + // Recursion not allowed. + bassert (m_listener == 0); + + for (List ::iterator iter = m_list.begin (); iter != m_list.end ();) + { + Entry* entry = & (*iter++); + + if (entry->listener == listener) + { + if (timestamp > entry->timestamp) + { + m_listener = entry->listener; + + bassert (m_fifo.isBeingSynchronized ()); + + m_fifo.callp (new (m_fifo.getAllocator ()) CallWork (c, m_listener)); + + m_listener = 0; + } + } + } + } + else + { + // Listener was removed + } +} + +//------------------------------------------------------------------------------ +// +// Proxy +// +//------------------------------------------------------------------------------ + +// CallQueue item for processing a an Entry for a Proxy. +// This is used to avoid bind overhead. +// +class ListenersBase::Proxy::Work : public CallQueue::Work +{ +public: + inline Work (Proxy* proxy, + Entry* const entry, + const timestamp_t timestamp) + : m_proxy (proxy) + , m_entry (entry) + , m_timestamp (timestamp) + { + } + + void operator () () + { + ListenersBase::Call* c = m_entry->call.exchange (0); + + Group* group = m_entry->group; + + if (!group->empty ()) + group->do_call (c, m_timestamp); + + c->decReferenceCount (); + } + +private: + Proxy* const m_proxy; + Entry::Ptr m_entry; + const timestamp_t m_timestamp; +}; + +// Holds a Call, and gets put in the CallQueue in place of the Call. +// The Call may be replaced if it hasn't been processed yet. +// A Proxy exists for the lifetime of the Listeners. +// +ListenersBase::Proxy::Proxy (void const* const member, const size_t bytes) + : m_bytes (bytes) +{ + if (bytes > maxMemberBytes) + Throw (Error ().fail (__FILE__, __LINE__, "the Proxy member is too large")); + + memcpy (m_member, member, bytes); +} + +ListenersBase::Proxy::~Proxy () +{ + // If the proxy is getting destroyed it means: + // - the listeners object is getting destroyed + // - all listeners must have removed themselves + // - all thread queues have been fully processed + // Therefore, our entries should be gone. + + // NO it is possible for an empty Group, for which + // the parent listeners object has been destroyed, + // to still exist in a thread queue!!! + + // But all listeners should have removed themselves + // so our list of groups should still be empty. + bassert (m_entries.empty ()); +} + +// Adds the group to the Proxy. +// Caller must have the proxies mutex. +// Caller is responsible for preventing duplicates. +// +void ListenersBase::Proxy::add (Group* group, AllocatorType& allocator) +{ + Entry* entry (new (allocator) Entry (group)); + + // Manual addref and put raw pointer in list + entry->incReferenceCount (); + m_entries.push_back (*entry); +} + +// Removes the group from the Proxy. +// Caller must have the proxies mutex. +// Caller is responsible for making sure the group exists. +void ListenersBase::Proxy::remove (Group* group) +{ + for (Entries::iterator iter = m_entries.begin (); iter != m_entries.end ();) + { + Entry* entry = & (*iter++); + + if (entry->group == group) + { + // remove from list and manual release + m_entries.erase (m_entries.iterator_to (*entry)); + entry->decReferenceCount (); + + // Entry might still be in the empty group's thread queue + break; + } + } +} + +// For each group, updates the call. +// Queues each group that isn't already queued. +// Caller must acquire the group read lock. +// +void ListenersBase::Proxy::update (Call* const c, const timestamp_t timestamp) +{ + // why would we even want to be called? + bassert (!m_entries.empty ()); + + // With the read lock, this list can't change on us unless someone + // adds a listener to a new thread queue in response to a call. + for (Entries::iterator iter = m_entries.begin (); iter != m_entries.end ();) + { + Entry* entry = & (*iter++); + + // Manually add a reference since we use a raw pointer + c->incReferenceCount (); + + // Atomically exchange the new call for the old one + Call* old = entry->call.exchange (c); + + // If no old call then they need to be queued + if (!old) + { + CallQueue& callQueue = entry->group->getCallQueue (); + callQueue.callp (new (callQueue.getAllocator ()) Work (this, entry, timestamp)); + } + else + { + old->decReferenceCount (); + } + } +} + +bool ListenersBase::Proxy::match (void const* const member, const size_t bytes) const +{ + return m_bytes == bytes && memcmp (member, m_member, bytes) == 0; +} + +//------------------------------------------------------------------------------ +// +// ListenersBase +// +//------------------------------------------------------------------------------ + +ListenersBase::ListenersBase () + : m_timestamp (0) + , m_allocator (AllocatorType::getInstance ()) + , m_callAllocator (CallAllocatorType::getInstance ()) +{ +} + +ListenersBase::~ListenersBase () +{ + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group* group = & (*iter++); + + // If this goes off it means a Listener forgot to remove. + bassert (group->empty ()); + + group->decReferenceCount (); + } + + // Proxies are never deleted until here. + for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();) + delete & (*iter++); +} + +void ListenersBase::add_void (void* const listener, CallQueue& callQueue) +{ + ReadWriteMutex::ScopedWriteLockType lock (m_groups_mutex); + +#if BEAST_DEBUG + + // Make sure the listener has not already been added + // SHOULD USE const_iterator! + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group* group = & (*iter++); + + // We can be in do_call() on another thread now, but it + // doesn't modify the list, and we have the write lock. + bassert (!group->contains (listener)); + } + +#endif + + // See if we already have a Group for this thread queue. + Group::Ptr group; + + // SHOULD USE const_iterator + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group::Ptr cur = & (*iter++); + + if (&cur->getCallQueue () == &callQueue) + { + group = cur; + break; + } + } + + if (!group) + { + group = new (m_allocator) Group (callQueue); + + // Add it to the list, and give it a manual ref + // since the list currently uses raw pointers. + group->incReferenceCount (); + m_groups.push_back (*group); + + // Tell existing proxies to add the group + ReadWriteMutex::ScopedReadLockType lock (m_proxies_mutex); + + for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();) + (iter++)->add (group, *m_allocator); + } + + // Add the listener to the group with the current timestamp + group->add (listener, m_timestamp, *m_allocator); + + // Increment the timestamp within the mutex so + // future calls will be newer than this listener. + ++m_timestamp; +} + +void ListenersBase::remove_void (void* const listener) +{ + ReadWriteMutex::ScopedWriteLockType lock (m_groups_mutex); + + // Make sure the listener exists +#if BEAST_DEBUG + { + bool exists = false; + + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group* group = & (*iter++); + + // this should never happen while we hold the mutex + bassert (!group->empty ()); + + if (group->contains (listener)) + { + bassert (!exists); // added twice? + + exists = true; + // keep going to make sure there are no empty groups + } + } + + bassert (exists); + } +#endif + + // Find the group and remove + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group::Ptr group = & (*iter++); + + // If the listener is in there, take it out. + if (group->remove (listener)) + { + // Are we the last listener? + if (group->empty ()) + { + // Tell proxies to remove the group + { + ReadWriteMutex::ScopedWriteLockType lock (m_proxies_mutex); + + for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();) + { + Proxy* proxy = & (*iter++); + proxy->remove (group); + } + } + + // Remove it from the list and manually release + // the reference since the list uses raw pointers. + m_groups.erase (m_groups.iterator_to (*group.getObject ())); + group->decReferenceCount (); + + // It is still possible for the group to exist at this + // point in a thread queue but it will get processed, + // do nothing, and release its own final reference. + } + + break; + } + } +} + +void ListenersBase::callp (Call::Ptr cp) +{ + Call* c = cp; + + ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex); + + // can't be const iterator because queue() might cause called functors + // to modify the list. + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + (iter++)->call (c, m_timestamp); +} + +void ListenersBase::queuep (Call::Ptr cp) +{ + Call* c = cp; + + ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex); + + // can't be const iterator because queue() might cause called functors + // to modify the list. + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + (iter++)->queue (c, m_timestamp); +} + +void ListenersBase::call1p_void (void* const listener, Call* c) +{ + ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex); + + // can't be const iterator because queue() might cause called functors + // to modify the list. + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group* group = & (*iter++); + + if (group->contains (listener)) + { + group->call1 (c, m_timestamp, listener); + break; + } + } +} + +void ListenersBase::queue1p_void (void* const listener, Call* c) +{ + ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex); + + // can't be const iterator because queue() might cause called functors + // to modify the list. + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group* group = & (*iter++); + + if (group->contains (listener)) + { + group->queue1 (c, m_timestamp, listener); + break; + } + } +} + +// Search for an existing Proxy that matches the pointer to +// member and replace it's Call, or create a new Proxy for it. +// +void ListenersBase::updatep (void const* const member, + const size_t bytes, Call::Ptr cp) +{ + Call* c = cp; + + ReadWriteMutex::ScopedReadLockType lock (m_groups_mutex); + + if (!m_groups.empty ()) + { + Proxy* proxy; + + { + ReadWriteMutex::ScopedReadLockType lock (m_proxies_mutex); + + // See if there's already a proxy + proxy = find_proxy (member, bytes); + } + + // Possibly create one + if (!proxy) + { + ReadWriteMutex::ScopedWriteLockType lock (m_proxies_mutex); + + // Have to search for it again in case someone else added it + proxy = find_proxy (member, bytes); + + if (!proxy) + { + // Create a new empty proxy + proxy = new (m_allocator) Proxy (member, bytes); + + // Add all current groups to the Proxy. + // We need the group read lock for this (caller provided). + for (Groups::iterator iter = m_groups.begin (); iter != m_groups.end ();) + { + Group* group = & (*iter++); + proxy->add (group, *m_allocator); + } + + // Add it to the list. + m_proxies.push_front (*proxy); + } + } + + // Requires the group read lock + proxy->update (c, m_timestamp); + } +} + +// Searches for a proxy that matches the pointer to member. +// Caller synchronizes. +// +ListenersBase::Proxy* ListenersBase::find_proxy (const void* member, size_t bytes) +{ + for (Proxies::iterator iter = m_proxies.begin (); iter != m_proxies.end ();) + { + Proxy* proxy = & (*iter++); + + if (proxy->match (member, bytes)) + return proxy; + } + + return 0; +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_Listeners.h b/Subtrees/beast/modules/beast_basics/threads/beast_Listeners.h new file mode 100644 index 0000000000..17160c628f --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_Listeners.h @@ -0,0 +1,900 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_LISTENERS_BEASTHEADER +#define BEAST_LISTENERS_BEASTHEADER + +/*============================================================================*/ +/** + A group of concurrent Listeners. + + A Listener is an object of class type which inherits from a defined + interface, and registers on a provided instance of Listeners to receive + asynchronous notifications of changes to concurrent states. Another way of + defining Listeners, is that it is similar to a Juce ListenerList but with + the provision that the Listener registers with the CallQueue upon which the + notification should be made. + + Listeners makes extensive use of CallQueue for providing the notifications, + and provides a higher level facility for implementing the concurrent + synchronization strategy outlined in CallQueue. Therefore, the same notes + which apply to functors in CallQueue also apply to Listener member + invocations. Their execution time should be brief, limited in scope to + updating the recipient's view of a shared state, and use reference counting + for parameters of class type. + + To use this system, first declare your Listener interface: + + @code + + struct Listener + { + // Sent on every output block + virtual void onOutputLevelChanged (const float outputLevel) { } + }; + + @endcode + + Now set up the place where you want to send the notifications. In this + example, we will set up the AudioIODeviceCallback to notify anyone who is + interested about changes in the current audio output level. We will use + this to implement a VU meter: + + @code + + Listeners listeners; + + // (Process audio data) + + // Calculate output level + float outputLevel = calcOutputLevel (); + + // Notify listeners + listeners.call (&Listener::onOutputLevelChanged, outputLevel); + + @endcode + + To receive notifications, derive from Listener and then add yourself to the + Listeners object using the desired CallQueue. + + @code + + // We want notifications on the message thread + GuiCallQueue fifo; + + struct VUMeter : public Listener, public Component + { + VUMeter () : m_outputLevel (0) + { + listeners.add (this, fifo); + } + + ~VUMeter () + { + listeners.remove (this); + } + + void onOutputLevelChanged (float outputLevel) + { + // Update our copy of the output level shared state. + m_outputLevel = outputLevel; + + // Now trigger a redraw of the control. + repaint (); + } + + float m_outputLevel; + }; + + @endcode + + In this example, the VUMeter constructs with the output level set to zero, + and must wait for a notification before it shows up to date data. For a + simple VU meter, this is likely not a problem. But if the shared state + contains complex information, such as dynamically allocated objects with + rich data, then we need a more solid system. + + We will add some classes to create a complete robust example of the use of + Listeners to synchronize shared state: + + @code + + // Handles audio device output. + class AudioDeviceOutput : public AudioIODeviceCallback + { + public: + struct Listener + { + // Sent on every output block. + virtual void onOutputLevelChanged (float outputLevel) { } + }; + + AudioDeviceOutput () : AudioDeviceOutput ("Audio CallQueue") + { + } + + ~AudioDeviceOutput () + { + m_fifo.close (); + } + + void addListener (Listener* listener, CallQueue& callQueue) + { + // Acquire read access to the shared state. + ConcurrentState ::ReadAccess state (m_state); + + // Add the listener. + m_listeners.add (listener, callQueue); + + // Queue an update for the listener to receive the initial state. + m_listeners.queue1 (listener, + &Listener::onOutputLevelChanged, + state->outputLevel); + } + + void removeListener (Listener* listener) + { + m_listeners.remove (listener); + } + + protected: + void audioDeviceIOCallback (const float** inputChannelData, + int numInputChannels, + float** outputChannelData, + int numOutputChannels, + int numSamples) + { + // Synchronize our call queue. Not needed for this example but + // included here as a best-practice for audio device I/O callbacks. + m_fifo.synchronize (); + + // (Process audio data) + + // Calculate output level. + float newOutputLevel = calcOutputLevel (); + + // Update shared state. + { + ConcurrentState ::WriteAccess state (m_state); + + m_state->outputLevel = newOutputLevel; + } + + // Notify listeners. + listeners.call (&Listener::onOutputLevelChanged, newOutputLevel); + } + + private: + struct State + { + State () : outputLevel (0) { } + + float outputLevel; + }; + + ConcurrentState m_state; + + ManualCallQueue m_fifo; + }; + + @endcode + + Although the rigor demonstrated in the example above is not strictly + required when the shared state consists only of a single float, it + becomes necessary when there are dynamically allocated objects with complex + interactions in the shared state. + + @see CallQueue + + @class Listeners + @ingroup beast_concurrent +*/ +class ListenersBase +{ +public: + struct ListenersStructureTag { }; + + typedef GlobalFifoFreeStore AllocatorType; + + typedef GlobalFifoFreeStore CallAllocatorType; + + class Call : public ReferenceCountedObject, + public AllocatedBy + { + public: + typedef ReferenceCountedObjectPtr Ptr; + virtual void operator () (void* const listener) = 0; + }; + +private: + typedef unsigned long timestamp_t; + + class Group; + typedef List Groups; + + class Proxy; + typedef List Proxies; + + class CallWork; + class GroupWork; + class GroupWork1; + + // Maintains a list of listeners registered on the same CallQueue + // + class Group : public Groups::Node, + public ReferenceCountedObject, + public AllocatedBy + { + public: + typedef ReferenceCountedObjectPtr Ptr; + + explicit Group (CallQueue& callQueue); + ~Group (); + void add (void* listener, const timestamp_t timestamp, + AllocatorType& allocator); + bool remove (void* listener); + bool contains (void* const listener); + void call (Call* const c, const timestamp_t timestamp); + void queue (Call* const c, const timestamp_t timestamp); + void call1 (Call* const c, const timestamp_t timestamp, + void* const listener); + void queue1 (Call* const c, const timestamp_t timestamp, + void* const listener); + void do_call (Call* const c, const timestamp_t timestamp); + void do_call1 (Call* const c, const timestamp_t timestamp, + void* const listener); + + bool empty () const + { + return m_list.empty (); + } + CallQueue& getCallQueue () const + { + return m_fifo; + } + + private: + struct Entry; + + CallQueue& m_fifo; + List m_list; + void* m_listener; + CacheLine::Aligned m_mutex; + }; + + // A Proxy is keyed to a unique pointer-to-member of a + // ListenerClass and is used to consolidate multiple unprocessed + // Calls into a single call to prevent excess messaging. It is up + // to the user of the class to decide when this behavior is appropriate. + // + class Proxy : public Proxies::Node, + public AllocatedBy + { + public: + enum + { + maxMemberBytes = 16 + }; + + Proxy (void const* const member, const size_t bytes); + ~Proxy (); + + void add (Group* group, AllocatorType& allocator); + void remove (Group* group); + void update (Call* const c, const timestamp_t timestamp); + + bool match (void const* const member, const size_t bytes) const; + + private: + class Work; + struct Entry; + typedef List Entries; + char m_member [maxMemberBytes]; + const size_t m_bytes; + Entries m_entries; + }; + +protected: + ListenersBase (); + ~ListenersBase (); + + inline CallAllocatorType& getCallAllocator () + { + return *m_callAllocator; + } + + void add_void (void* const listener, CallQueue& callQueue); + void remove_void (void* const listener); + + void callp (Call::Ptr c); + void queuep (Call::Ptr c); + void call1p_void (void* const listener, Call* c); + void queue1p_void (void* const listener, Call* c); + void updatep (void const* const member, + const size_t bytes, Call::Ptr cp); + +private: + Proxy* find_proxy (const void* member, size_t bytes); + +private: + Groups m_groups; + Proxies m_proxies; + timestamp_t m_timestamp; + CacheLine::Aligned m_groups_mutex; + CacheLine::Aligned m_proxies_mutex; + AllocatorType::Ptr m_allocator; + CallAllocatorType::Ptr m_callAllocator; +}; + +/*============================================================================*/ + +template +class Listeners : public ListenersBase +{ +private: + template + class CallType : public Call + { + public: + CallType (Functor f) : m_f (f) + { + } + + void operator () (void* const listener) + { + ListenerClass* object = static_cast (listener); + m_f.operator () (object); + } + + private: + Functor m_f; + }; + + template + inline void callf (Functor f) + { + callp (new (getCallAllocator ()) CallType (f)); + } + + template + inline void queuef (Functor f) + { + queuep (new (getCallAllocator ()) CallType (f)); + } + + inline void call1p (ListenerClass* const listener, Call::Ptr c) + { + call1p_void (listener, c); + } + + inline void queue1p (ListenerClass* const listener, Call::Ptr c) + { + queue1p_void (listener, c); + } + + template + inline void call1f (ListenerClass* const listener, Functor f) + { + call1p (listener, new (getCallAllocator ()) CallType (f)); + } + + template + inline void queue1f (ListenerClass* const listener, Functor f) + { + queue1p (listener, new (getCallAllocator ()) CallType (f)); + } + + template + inline void updatef (Member member, Functor f) + { + updatep (reinterpret_cast (&member), sizeof (Member), + new (getCallAllocator ()) CallType (f)); + } + +public: + /** Add a listener. + + The specified listener is associated with the specified CallQueue and + added to the list. + + Invariants: + + - All other members of Listeners are blocked during add(). + + - The listener is guaranteed to receive every subsequent call. + + - The listener must not already exist in the list. + + - Safe to call from any thread. + + @param listener The listener to add. + + @param callQueue The CallQueue to associate with the listener. + */ + void add (ListenerClass* const listener, CallQueue& callQueue) + { + add_void (listener, callQueue); + } + + /** Remove a listener. + + The specified listener, which must have been previously added, is removed + from the list. A listener always needs to remove itself before the + associated CallQueue is closed. + + Invariants: + + - All other members of Listeners are blocked during remove(). + + - The listener is guaranteed not to receive calls after remove() returns. + + - Safe to call from any thread. + + @param listener The listener to remove. + */ + void remove (ListenerClass* const listener) + { + remove_void (listener); + } + + /** Call a member function on every added listener, on its associated + CallQueue. + + A listener's CallQueue will be synchronized if this function is called + from it's associated thread. + + Invariants: + + - A listener that later removes itself afterwards may not get called. + + - Calls from the same thread always execute in order. + + - A listener can remove itself even if it has a pending call. + + @param mf The member function to call. This may be followed by up to 8 + arguments. + */ + /** @{ */ +#if VFLIB_VARIADIC_MAX >= 1 + template + inline void call (Mf mf) + { + callf (vf::bind (mf, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void call (Mf mf, T1 t1) + { + callf (vf::bind (mf, vf::_1, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void call (Mf mf, T1 t1, T2 t2) + { + callf (vf::bind (mf, vf::_1, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void call (Mf mf, T1 t1, T2 t2, T3 t3) + { + callf (vf::bind (mf, vf::_1, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4) + { + callf (vf::bind (mf, vf::_1, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + callf (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + callf (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + callf (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void call (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + callf (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ + + /** Queue a member function on every added listener, without synchronizing. + + Operates like call(), but no CallQueue synchronization takes place. This + can be necessary when the call to queue() is made inside a held lock. + + @param mf The member function to call. This may be followed by up to 8 + arguments. + */ + /** @{ */ +#if VFLIB_VARIADIC_MAX >= 1 + template + inline void queue (Mf mf) + { + queuef (vf::bind (mf, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void queue (Mf mf, T1 t1) + { + queuef (vf::bind (mf, vf::_1, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void queue (Mf mf, T1 t1, T2 t2) + { + queuef (vf::bind (mf, vf::_1, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void queue (Mf mf, T1 t1, T2 t2, T3 t3) + { + queuef (vf::bind (mf, vf::_1, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4) + { + queuef (vf::bind (mf, vf::_1, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + queuef (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + queuef (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + queuef (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void queue (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + queuef (vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ + + /** Call a member function on every added listener, replacing pending + calls to the same member. + + This operates like call(), except that if there are pending unprocessed + calls to the same member function,they will be replaced, with the previous + parameters destroyed normally. This functionality is useful for + high frequency notifications of non critical data, where the recipient + may not catch up often enough. For example, the output level of the + AudioIODeviceCallback in the example is a candidate for the use of + update(). + + @param mf The member function to call. This may be followed by up to 8 + arguments. + */ + /** @{ */ +#if VFLIB_VARIADIC_MAX >= 1 + template + inline void update (Mf mf) + { + updatef (mf, vf::bind (mf, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void update (Mf mf, T1 t1) + { + updatef (mf, vf::bind (mf, vf::_1, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void update (Mf mf, T1 t1, T2 t2) + { + updatef (mf, vf::bind (mf, vf::_1, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void update (Mf mf, T1 t1, T2 t2, T3 t3) + { + updatef (mf, vf::bind (mf, vf::_1, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4) + { + updatef (mf, vf::bind (mf, vf::_1, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + updatef (mf, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + updatef (mf, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + updatef (mf, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void update (Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + updatef (mf, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ + + /** Call a member function on a specific listener. + + Like call(), except that one listener is targeted only. This is useful when + builing complex behaviors during the addition of a listener, such as + providing an initial state. + + @param listener The listener to call. + + @param mf The member function to call. This may be followed by up + to 8 arguments. + */ + /** @{ */ +#if VFLIB_VARIADIC_MAX >= 1 + template + inline void call1 (ListenerClass* const listener, Mf mf) + { + call1f (listener, vf::bind (mf, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1) + { + call1f (listener, vf::bind (mf, vf::_1, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2) + { + call1f (listener, vf::bind (mf, vf::_1, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3) + { + call1f (listener, vf::bind (mf, vf::_1, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4) + { + call1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + call1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + call1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + call1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void call1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + call1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ + + /** Queue a member function on a specific listener. + + Like call1(), except that no CallQueue synchronization takes place. + + @param listener The listener to call. + + @param mf The member function to call. This may be followed by up + to 8 arguments. + */ + /** @{ */ +#if VFLIB_VARIADIC_MAX >= 1 + template + inline void queue1 (ListenerClass* const listener, Mf mf) + { + queue1f (listener, vf::bind (mf, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1) + { + queue1f (listener, vf::bind (mf, vf::_1, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2) + { + queue1f (listener, vf::bind (mf, vf::_1, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3) + { + queue1f (listener, vf::bind (mf, vf::_1, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4) + { + queue1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + queue1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + queue1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + queue1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void queue1 (ListenerClass* const listener, Mf mf, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + queue1f (listener, vf::bind (mf, vf::_1, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ +}; +/** @} */ + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.cpp new file mode 100644 index 0000000000..cd03818be3 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.cpp @@ -0,0 +1,54 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +ManualCallQueue::ManualCallQueue (String name) + : CallQueue (name) +{ +} + +void ManualCallQueue::close () +{ + CallQueue::close (); +} + +bool ManualCallQueue::synchronize () +{ + return CallQueue::synchronize (); +} + +void ManualCallQueue::signal () +{ +} + +void ManualCallQueue::reset () +{ +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.h b/Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.h new file mode 100644 index 0000000000..67cc0940ab --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ManualCallQueue.h @@ -0,0 +1,108 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef VF_MANUALCALLQUEUE_VFHEADER +#define VF_MANUALCALLQUEUE_VFHEADER + +/*============================================================================*/ +/** + A CallQueue that requires periodic manual synchronization. + + To use this, declare an instance and then place calls into it as usual. + Every so often, you must call synchronize() from the thread you want to + associate with the queue. Typically this is done within an + AudioIODeviceCallback: + + @code + + class AudioIODeviceCallbackWithCallQueue + : public AudioIODeviceCallback + , public CallQueue + { + public: + AudioIODeviceCallbackWithCallQueue () : m_fifo ("Audio CallQueue") + { + } + + void audioDeviceIOCallback (const float** inputChannelData, + int numInputChannels, + float** outputChannelData, + int numOutputChannels, + int numSamples) + { + CallQueue::synchronize (); + + // do audio i/o + } + + void signal () { } // No action required + void reset () { } // No action required + }; + + @endcode + + The close() function is provided for diagnostics. Call it as early as + possible based on the exit or shutdown logic of your application. If calls + are put into the queue after it is closed, it will generate an exception so + you can track it down. + + @see CallQueue + + @ingroup vf_concurrent +*/ +class ManualCallQueue : public CallQueue +{ +public: + /** Create a ManualCallQueue. + + @param name A string used to help identify the associated + thread for debugging. + */ + explicit ManualCallQueue (String name); + + /** Close the queue. If calls are placed into a closed queue, an exception + is thrown. + */ + void close (); + + /** Synchronize the queue by calling all pending functors. + + @return `true` if any functors were called. + */ + bool synchronize (); + +private: + void signal (); + void reset (); +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.cpp new file mode 100644 index 0000000000..241ccb5496 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.cpp @@ -0,0 +1,76 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +ParallelFor::ParallelFor (ThreadGroup& pool) + : m_pool (pool) + , m_finishedEvent (false) // auto-reset +{ +} + +int ParallelFor::getNumberOfThreads () const +{ + return m_pool.getNumberOfThreads (); +} + +void ParallelFor::doLoop (int numberOfIterations, Iteration& iteration) +{ + if (numberOfIterations > 1) + { + int const numberOfThreads = m_pool.getNumberOfThreads (); + + // The largest number of pool threads we need is one less than the number + // of iterations, because we also run the loop body on the caller's thread. + // + int const maxThreads = numberOfIterations - 1; + + // Calculate the number of parallel instances as the smaller of the number + // of threads available (including the caller's) and the number of iterations. + // + int const numberOfParallelInstances = std::min ( + numberOfThreads + 1, numberOfIterations); + + LoopState* loopState (new (m_pool.getAllocator ()) LoopState ( + iteration, m_finishedEvent, numberOfIterations, numberOfParallelInstances)); + + m_pool.call (maxThreads, &LoopState::forLoopBody, loopState); + + // Also use the caller's thread to run the loop body. + loopState->forLoopBody (); + + m_finishedEvent.wait (); + } + else if (numberOfIterations == 1) + { + // Just one iteration, so do it. + iteration (0); + } +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.h b/Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.h new file mode 100644 index 0000000000..2b370f37fe --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.h @@ -0,0 +1,504 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_PARALLELFOR_BEASTHEADER +#define BEAST_PARALLELFOR_BEASTHEADER + +/*============================================================================*/ +/** + Parallel for loop. + + This uses a ThreadGroup to iterate through a for loop in parallel. The + following two pieces of code perform identical operations: + + @code + + extern void function (int loopIndex); + + // Serial computation + // + for (int i = 0; i < numberOfIterations; ++i) + function (i); + + // Parallel computation + // + ParallelFor().loop (numberOfIterations, &function); + + @endcode + + `function` is a caller provided functor. Convenience functions are provided + for automatic binding to member or non member functions with up to 8 + arguments (not including the loop index). + + @note The last argument to function () is always the loop index. + + @see ThreadGroup + + @ingroup beast_concurrent +*/ +class ParallelFor : Uncopyable +{ +public: + /** Create a parallel for loop. + + It is best to keep this object around instead of creating and destroying + it every time you need to run a loop. + + @param pool The ThreadGroup to use. If this is omitted then a singleton + ThreadGroup is used which contains one thread per CPU. + */ + explicit ParallelFor (ThreadGroup& pool = *GlobalThreadGroup::getInstance ()); + + /** Determine the number of threads in the group. + + @return The number of threads in the group. + */ + int getNumberOfThreads () const; + + template + void operator () (int numberOfIterations, T1 t1) + { + } + + /** Execute parallel for loop. + + Functor is called once for each value in the range + [0, numberOfIterations), using the ThreadGroup. + + @param numberOfIterations The number of times to loop. + + @param f The functor to call for each loop index. + */ + /** @{ */ + template + void loopf (int numberOfIterations, Functor const& f) + { + IterationType iteration (f); + + doLoop (numberOfIterations, iteration); + } + +#if VFLIB_VARIADIC_MAX >= 1 + template + void loop (int n, Fn f) + { + loopf (n, vf::bind (f, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void loop (int n, Fn f, T1 t1) + { + loopf (n, vf::bind (f, t1, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void loop (int n, Fn f, T1 t1, T2 t2) + { + loopf (n, vf::bind (f, t1, t2, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void loop (int n, Fn f, T1 t1, T2 t2, T3 t3) + { + loopf (n, vf::bind (f, t1, t2, t3, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4) + { + loopf (n, vf::bind (f, t1, t2, t3, t4, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + loopf (n, vf::bind (f, t1, t2, t3, t4, t5, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + loopf (n, vf::bind (f, t1, t2, t3, t4, t5, t6, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + loopf (n, vf::bind (f, t1, t2, t3, t4, t5, t6, t7, vf::_1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void loop (int n, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + loopf (n, vf::bind (f, t1, t2, t3, t4, t5, t6, t7, t8, vf::_1)); + } +#endif + /** @} */ + +private: + class Iteration + { + public: + virtual ~Iteration () { } + virtual void operator () (int loopIndex) = 0; + }; + + template + class IterationType : public Iteration, Uncopyable + { + public: + explicit IterationType (Functor const& f) : m_f (f) + { + } + + void operator () (int loopIndex) + { + m_f (loopIndex); + } + + private: + Functor m_f; + }; + +private: + class LoopState + : public AllocatedBy + , Uncopyable + { + private: + Iteration& m_iteration; + WaitableEvent& m_finishedEvent; + int const m_numberOfIterations; + Atomic m_loopIndex; + Atomic m_iterationsRemaining; + Atomic m_numberOfParallelInstances; + + public: + LoopState (Iteration& iteration, + WaitableEvent& finishedEvent, + int numberOfIterations, + int numberOfParallelInstances) + : m_iteration (iteration) + , m_finishedEvent (finishedEvent) + , m_numberOfIterations (numberOfIterations) + , m_loopIndex (-1) + , m_iterationsRemaining (numberOfIterations) + , m_numberOfParallelInstances (numberOfParallelInstances) + { + } + + ~LoopState () + { + } + + void forLoopBody () + { + for (;;) + { + // Request a loop index to process. + int const loopIndex = ++m_loopIndex; + + // Is it in range? + if (loopIndex < m_numberOfIterations) + { + // Yes, so process it. + m_iteration (loopIndex); + + // Was this the last work item to complete? + if (--m_iterationsRemaining == 0) + { + // Yes, signal. + m_finishedEvent.signal (); + break; + } + } + else + { + // Out of range, all work is complete or assigned. + break; + } + } + + release (); + } + + void release () + { + if (--m_numberOfParallelInstances == 0) + delete this; + } + }; + +private: + void doLoop (int numberOfIterations, Iteration& iteration); + +private: + ThreadGroup& m_pool; + WaitableEvent m_finishedEvent; + Atomic m_currentIndex; + Atomic m_numberOfInstances; + int m_numberOfIterations; +}; + +//------------------------------------------------------------------------------ + +class ParallelFor2 : Uncopyable +{ +public: + /** Create a parallel for loop. + + It is best to keep this object around instead of creating and destroying + it every time you need to run a loop. + + @param pool The ThreadGroup to use. If this is omitted then a singleton + ThreadGroup is used which contains one thread per CPU. + */ + explicit ParallelFor2 (ThreadGroup& pool = *GlobalThreadGroup::getInstance ()) + : m_pool (pool) + , m_finishedEvent (false) // auto-reset + { + } + + /** Determine the number of threads in the group. + + @return The number of threads in the group. + */ + int getNumberOfThreads () const + { + return m_pool.getNumberOfThreads (); + } + + + template + void operator () (int numberOfIterations, T1 t1, T2 t2, T3 t3, T4 t4) + { + Factory4 f (t1, t2, t3, t4); + doLoop (numberOfIterations, f); + } + +private: + typedef ThreadGroup::AllocatorType AllocatorType; + + //--- + + struct Iterator : public AllocatedBy + { + virtual ~Iterator () { } + virtual void operator () (int loopIndex) = 0; + }; + + //--- + + template + struct IteratorType : public Iterator, Uncopyable + { + explicit IteratorType (Functor f) : m_f (f) + { + } + + void operator () (int loopIndex) + { + m_f (loopIndex); + } + + private: + Functor m_f; + }; + + //--- + + struct Factory + { + virtual ~Factory () { } + virtual Iterator* operator () (AllocatorType& allocator) = 0; + }; + + template + struct Factory4 : Factory + { + Factory4 (T1 t1, T2 t2, T3 t3, T4 t4) + : m_t1 (t1), m_t2 (t2), m_t3 (t3), m_t4 (t4) { } + + Iterator* operator () (AllocatorType& allocator) + { + return new (allocator) IteratorType (m_t1, m_t2, m_t3, m_t4); + } + + private: + T1 m_t1; + T2 m_t2; + T3 m_t3; + T4 m_t4; + }; + +private: + class LoopState + : public AllocatedBy + , Uncopyable + { + private: + Factory& m_factory; + WaitableEvent& m_finishedEvent; + int const m_numberOfIterations; + Atomic m_loopIndex; + Atomic m_iterationsRemaining; + Atomic m_numberOfParallelInstances; + AllocatorType& m_allocator; + + public: + LoopState (Factory& factory, + WaitableEvent& finishedEvent, + int numberOfIterations, + int numberOfParallelInstances, + AllocatorType& allocator) + : m_factory (factory) + , m_finishedEvent (finishedEvent) + , m_numberOfIterations (numberOfIterations) + , m_loopIndex (-1) + , m_iterationsRemaining (numberOfIterations) + , m_numberOfParallelInstances (numberOfParallelInstances) + , m_allocator (allocator) + { + } + + ~LoopState () + { + } + + void forLoopBody () + { + Iterator* iterator = m_factory (m_allocator); + + for (;;) + { + // Request a loop index to process. + int const loopIndex = ++m_loopIndex; + + // Is it in range? + if (loopIndex < m_numberOfIterations) + { + // Yes, so process it. + (*iterator) (loopIndex); + + // Was this the last work item to complete? + if (--m_iterationsRemaining == 0) + { + // Yes, signal. + m_finishedEvent.signal (); + break; + } + } + else + { + // Out of range, all work is complete or assigned. + break; + } + } + + release (); + + delete iterator; + } + + void release () + { + if (--m_numberOfParallelInstances == 0) + delete this; + } + }; + +private: + void doLoop (int numberOfIterations, Factory& factory) + { + if (numberOfIterations > 1) + { + int const numberOfThreads = m_pool.getNumberOfThreads (); + + // The largest number of pool threads we need is one less than the number + // of iterations, because we also run the loop body on the caller's thread. + // + int const maxThreads = numberOfIterations - 1; + + // Calculate the number of parallel instances as the smaller of the number + // of threads available (including the caller's) and the number of iterations. + // + int const numberOfParallelInstances = std::min ( + numberOfThreads + 1, numberOfIterations); + + LoopState* loopState (new (m_pool.getAllocator ()) LoopState ( + factory, + m_finishedEvent, + numberOfIterations, + numberOfParallelInstances, + m_pool.getAllocator ())); + + m_pool.call (maxThreads, &LoopState::forLoopBody, loopState); + + // Also use the caller's thread to run the loop body. + loopState->forLoopBody (); + + m_finishedEvent.wait (); + } + else if (numberOfIterations == 1) + { + // Just one iteration, so do it. + Iterator* iter = factory (m_pool.getAllocator ()); + (*iter) (0); + delete iter; + } + } + +private: + ThreadGroup& m_pool; + WaitableEvent m_finishedEvent; + Atomic m_currentIndex; + Atomic m_numberOfInstances; + int m_numberOfIterations; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.cpp new file mode 100644 index 0000000000..ecf78f57f2 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.cpp @@ -0,0 +1,111 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +ReadWriteMutex::ReadWriteMutex () noexcept +{ +} + +ReadWriteMutex::~ReadWriteMutex () noexcept +{ +} + +void ReadWriteMutex::enterRead () const noexcept +{ + for (;;) + { + // attempt the lock optimistically + // THIS IS NOT CACHE-FRIENDLY! + m_readers->addref (); + + // is there a writer? + // THIS IS NOT CACHE-FRIENDLY! + if (m_writes->isSignaled ()) + { + // a writer exists, give up the read lock + m_readers->release (); + + // block until the writer is done + { + CriticalSection::ScopedLockType lock (m_mutex); + } + + // now try the loop again + } + else + { + break; + } + } +} + +void ReadWriteMutex::exitRead () const noexcept +{ + m_readers->release (); +} + +void ReadWriteMutex::enterWrite () const noexcept +{ + // Optimistically acquire the write lock. + m_writes->addref (); + + // Go for the mutex. + // Another writer might block us here. + m_mutex.enter (); + + // Only one competing writer will get here, + // but we don't know who, so we have to drain + // readers no matter what. New readers will be + // blocked by the mutex. + // + if (m_readers->isSignaled ()) + { + SpinDelay delay; + + do + { + delay.pause (); + } + while (m_readers->isSignaled ()); + } +} + +void ReadWriteMutex::exitWrite () const noexcept +{ + // Releasing the mutex first and then decrementing the + // writer count allows another waiting writer to atomically + // acquire the lock, thus starving readers. This fulfills + // the write-preferencing requirement. + + m_mutex.exit (); + + m_writes->release (); +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.h b/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.h new file mode 100644 index 0000000000..9488b67940 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ReadWriteMutex.h @@ -0,0 +1,159 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_READWRITEMUTEX_BEASTHEADER +#define BEAST_READWRITEMUTEX_BEASTHEADER + +/*============================================================================*/ +/** + Multiple consumer, single producer (MCSP) synchronization. + + This is an optimized lock for the multiple reader, single writer + scenario. It provides only a subset of features of the more general + traditional read/write lock. Specifically, these rules apply: + + - A caller cannot hold a read lock while acquiring a write lock. + + - Write locks are only recursive with respect to write locks. + + - Read locks are only recursive with respect to read locks. + + - A write lock cannot be downgraded. + + - Writes are preferenced over reads. + + For real-time applications, these restrictions are often not an issue. + + The implementation is wait-free in the fast path: acquiring read access + for a lock without contention - just one interlocked increment! + + @class ReadWriteMutex + @ingroup beast_concurrent +*/ + +/*============================================================================*/ +/** + Scoped read lock for ReadWriteMutex. + + @ingroup beast_concurrent +*/ +template +struct GenericScopedReadLock : Uncopyable +{ + inline explicit GenericScopedReadLock (LockType const& lock) noexcept +: + m_lock (lock) + { + m_lock.enterRead (); + } + + inline ~GenericScopedReadLock () noexcept + { + m_lock.exitRead (); + } + +private: + LockType const& m_lock; +}; + +/*============================================================================*/ +/** + Scoped write lock for ReadWriteMutex. + + @ingroup beast_concurrent +*/ +template +struct GenericScopedWriteLock : Uncopyable +{ + inline explicit GenericScopedWriteLock (LockType const& lock) noexcept +: + m_lock (lock) + { + m_lock.enterWrite (); + } + + inline ~GenericScopedWriteLock () noexcept + { + m_lock.exitWrite (); + } + +private: + LockType const& m_lock; +}; + +class ReadWriteMutex +{ +public: + /** Provides the type of scoped read lock to use with a ReadWriteMutex. */ + typedef GenericScopedReadLock ScopedReadLockType; + + /** Provides the type of scoped write lock to use with a ReadWriteMutex. */ + typedef GenericScopedWriteLock ScopedWriteLockType; + + /** Create a ReadWriteMutex */ + ReadWriteMutex () noexcept; + + /** Destroy a ReadWriteMutex + + If the object is destroyed while a lock is held, the result is + undefined behavior. + */ + ~ReadWriteMutex () noexcept; + + /** Acquire a read lock. + + This is recursive with respect to other read locks. Calling this while + holding a write lock is undefined. + */ + void enterRead () const noexcept; + + /** Release a previously acquired read lock */ + void exitRead () const noexcept; + + /** Acquire a write lock. + + This is recursive with respect to other write locks. Calling this while + holding a read lock is undefined. + */ + void enterWrite () const noexcept; + + /** Release a previously acquired write lock */ + void exitWrite () const noexcept; + +private: + CriticalSection m_mutex; + + mutable CacheLine::Padded m_writes; + mutable CacheLine::Padded m_readers; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.cpp new file mode 100644 index 0000000000..4339569f01 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.cpp @@ -0,0 +1,130 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +Semaphore::WaitingThread::WaitingThread () + : m_event (false) // auto-reset +{ +} + +void Semaphore::WaitingThread::wait () +{ + m_event.wait (); +} + +void Semaphore::WaitingThread::signal () +{ + m_event.signal (); +} + +//============================================================================== + +Semaphore::Semaphore (int initialCount) + : m_counter (initialCount) +{ +} + +Semaphore::~Semaphore () +{ + // Can't delete the semaphore while threads are waiting on it!! + bassert (m_waitingThreads.pop_front () == nullptr); + + for (;;) + { + WaitingThread* waitingThread = m_deleteList.pop_front (); + + if (waitingThread != nullptr) + delete waitingThread; + else + break; + } +} + +void Semaphore::signal (int amount) +{ + bassert (amount > 0); + + while (amount--) + { + // Make counter and list operations atomic. + LockType::ScopedLockType lock (m_mutex); + + if (++m_counter <= 0) + { + WaitingThread* waitingThread = m_waitingThreads.pop_front (); + + bassert (waitingThread != nullptr); + + waitingThread->signal (); + } + } +} + +void Semaphore::wait () +{ + // Always prepare the WaitingThread object first, either + // from the delete list or through a new allocation. + // + WaitingThread* waitingThread = m_deleteList.pop_front (); + + if (waitingThread == nullptr) + waitingThread = new WaitingThread; + + { + // Make counter and list operations atomic. + LockType::ScopedLockType lock (m_mutex); + + if (--m_counter >= 0) + { + // Acquired the resource so put waitingThread back. + m_deleteList.push_front (waitingThread); + + waitingThread = nullptr; + } + else + { + // Out of resources, go on to the waiting list. + m_waitingThreads.push_front (waitingThread); + } + } + + // Do we need to wait? + if (waitingThread != nullptr) + { + // Yes so do it. + waitingThread->wait (); + + // If the wait is satisfied, then we've been taken off the + // waiting list so put waitingThread back in the delete list. + // + m_deleteList.push_front (waitingThread); + } +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.h b/Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.h new file mode 100644 index 0000000000..b1928013df --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.h @@ -0,0 +1,91 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_SEMAPHORE_BEASTHEADER +#define BEAST_SEMAPHORE_BEASTHEADER + +/*============================================================================*/ +/** + A semaphore. + + This provides a traditional semaphore synchronization primitive. There is no + upper limit on the number of signals. + + @note There is no tryWait() or timeout facility for acquiring a resource. + + @ingroup beast_core +*/ +class Semaphore +{ +public: + /** Create a semaphore with the specified number of resources. + + @param initialCount The starting number of resources. + */ + explicit Semaphore (int initialCount); + + ~Semaphore (); + + /** Increase the number of available resources. + + @param amount The number of new resources available. + */ + void signal (int amount = 1); + + /** Wait for a resource. + */ + void wait (); + +private: + class WaitingThread + : public LockFreeStack ::Node + , LeakChecked + { + public: + WaitingThread (); + + void wait (); + void signal (); + + private: + WaitableEvent m_event; + }; + + typedef SpinLock LockType; + + LockType m_mutex; + Atomic m_counter; + LockFreeStack m_waitingThreads; + LockFreeStack m_deleteList; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_SerialFor.h b/Subtrees/beast/modules/beast_basics/threads/beast_SerialFor.h new file mode 100644 index 0000000000..b305866213 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_SerialFor.h @@ -0,0 +1,84 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_SERIALFOR_BEASTHEADER +#define BEAST_SERIALFOR_BEASTHEADER + +/*============================================================================*/ + +/** Serial for loop. + + Iterates a for loop sequentially. This is a drop in replacement for + ParallelFor. + + @see ParallelFor + + @ingroup beast_core +*/ +class SerialFor : Uncopyable +{ +public: + /** Create a serial for loop. + */ + inline SerialFor () + { + } + + /** Determine the number of threads used to process loops. + + @return Always 1. + */ + inline int getNumberOfThreads () const + { + return 1; + } + + template + inline void operator () (int numberOfIterations) + { + F f; + + for (int i = 0; i < numberOfIterations; ++i) + f (i); + } + + template + inline void operator () (int numberOfIterations, T1 t1) + { + F f (t1); + + for (int i = 0; i < numberOfIterations; ++i) + f (i); + } +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.cpp new file mode 100644 index 0000000000..7762f1aa82 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.cpp @@ -0,0 +1,49 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +SharedObject::ThreadedScope::ThreadedScope (char const* name) + : m_thread (name) +{ + m_thread.start (this); +} + +void SharedObject::ThreadedScope::destroySharedObject (SharedObject* const object) +{ + deleteAsync (object); +} + +//------------------------------------------------------------------------------ + +void SharedObject::destroySharedObject () +{ + delete this; +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.h b/Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.h new file mode 100644 index 0000000000..791f5bdb53 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.h @@ -0,0 +1,323 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_SHAREDOBJECT_BEASTHEADER +#define BEAST_SHAREDOBJECT_BEASTHEADER + +//============================================================================== +/** + A reference counted object with overridable destroy behavior. + + This is a reference counted object compatible with SharedObjectPtr or + ReferenceCountedObjectPtr. When the last reference is removed, an + overridable virtual function is called to destroy the object. The default + behavior simply calls operator delete. Overrides can perform more complex + dispose actions, typically to destroy the object on a separate thread. + + @ingroup beast_concurrent +*/ +class SharedObject : Uncopyable +{ +public: + /** Abstract SharedObject scope. + + The scope is invoked to destroy the object. + */ + class Scope + { + public: + virtual ~Scope () { } + + virtual void destroySharedObject (SharedObject* const object) = 0; + }; + +public: + /** Separate thread for a SharedObject scope. + + This Scope deletes the shared object on a separate provided thread. + */ + class ThreadedScope + : public Scope + , private ThreadWithCallQueue::EntryPoints + { + public: + /** Create a ThreadedScope. + + @param name The name of the provided thread, for diagnostics. + */ + explicit ThreadedScope (char const* name); + + void destroySharedObject (SharedObject* const object); + + /** Delete a dynamic object asynchronously. + + This convenient template will delete a dynamically allocated + object on the provided thread. + */ + template + void deleteAsync (Object* const object) + { + // If an object being deleted recursively triggers async deletes, + // it is possible that the call queue has already been closed. + // We detect this condition by checking the associated thread and + // doing the delete directly. + // + if (m_thread.isAssociatedWithCurrentThread ()) + delete object; + else + m_thread.callf (Delete (object)); + } + + private: + // Simple functor to delete an object. + // + template + struct Delete + { + Delete (Object* const object) : m_object (object) + { + } + + void operator () () + { + delete m_object; + } + + private: + Delete& operator= (Delete const&); + + Object* const m_object; + }; + + private: + ThreadWithCallQueue m_thread; + }; + +protected: + /** Construct a SharedObject. + + The constructor is protected to require subclassing. + */ + SharedObject () { } + + virtual ~SharedObject () { } + + /** Delete the object. + + The default behavior calls operator delete. + */ + virtual void destroySharedObject (); + +public: + /** Increment the reference count. + + It should not be necessary to call this function directly. Use one of + the RAII containers that manages the reference count to hold the + object instead. + */ + inline void incReferenceCount () noexcept + { + m_refs.addref (); + } + + /** Decrement the reference count. + + It should not be necessary to call this function directly. Use one of + the RAII containers that manages the reference count to hold the + object instead. + */ + inline void decReferenceCount () noexcept + { + if (m_refs.release ()) + destroySharedObject (); + } + +private: + AtomicCounter m_refs; +}; + +//------------------------------------------------------------------------------ + +/** RAII container for SharedObject. + + This container is used to hold a pointer to a SharedObject and manage the + reference counts for you. +*/ +template +class SharedObjectPtr +{ +public: + typedef Object ReferencedType; + + inline SharedObjectPtr () noexcept +: + m_object (nullptr) + { + } + + inline SharedObjectPtr (Object* const refCountedObject) noexcept +: + m_object (refCountedObject) + { + if (refCountedObject != nullptr) + refCountedObject->incReferenceCount (); + } + + inline SharedObjectPtr (const SharedObjectPtr& other) noexcept +: + m_object (other.m_object) + { + if (m_object != nullptr) + m_object->incReferenceCount (); + } + +#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS + inline SharedObjectPtr (SharedObjectPtr&& other) noexcept +: + m_object (other.m_object) + { + other.m_object = nullptr; + } +#endif + + template + inline SharedObjectPtr (const SharedObjectPtr & other) noexcept +: + m_object (static_cast (other.get ())) + { + if (m_object != nullptr) + m_object->incReferenceCount (); + } + + SharedObjectPtr& operator= (const SharedObjectPtr& other) + { + return operator= (other.m_object); + } + + template + SharedObjectPtr& operator= (const SharedObjectPtr & other) + { + return operator= (static_cast (other.get ())); + } + +#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS + SharedObjectPtr& operator= (SharedObjectPtr && other) + { + std::swap (m_object, other.m_object); + return *this; + } +#endif + + SharedObjectPtr& operator= (Object* const newObject) + { + if (m_object != newObject) + { + if (newObject != nullptr) + newObject->incReferenceCount (); + + Object* const oldObject = m_object; + m_object = newObject; + + if (oldObject != nullptr) + oldObject->decReferenceCount (); + } + + return *this; + } + + inline ~SharedObjectPtr () + { + if (m_object != nullptr) + m_object->decReferenceCount (); + } + + inline operator Object* () const noexcept + { + return m_object; + } + + inline Object* operator-> () const noexcept + { + return m_object; + } + + inline Object* get () const noexcept + { + return m_object; + } + + inline Object* getObject () const noexcept + { + return m_object; + } + +private: + Object* m_object; +}; + +template +bool operator== (const SharedObjectPtr & object1, Object* const object2) noexcept +{ + return object1.get () == object2; +} + +template +bool operator== (const SharedObjectPtr & object1, const SharedObjectPtr & object2) noexcept +{ + return object1.get () == object2.get (); +} + +template +bool operator== (Object* object1, SharedObjectPtr & object2) noexcept +{ + return object1 == object2.get (); +} + +template +bool operator!= (const SharedObjectPtr & object1, const Object* object2) noexcept +{ + return object1.get () != object2; +} + +template +bool operator!= (const SharedObjectPtr & object1, SharedObjectPtr & object2) noexcept +{ + return object1.get () != object2.get (); +} + +template +bool operator!= (Object* object1, SharedObjectPtr & object2) noexcept +{ + return object1 != object2.get (); +} + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_SpinDelay.h b/Subtrees/beast/modules/beast_basics/threads/beast_SpinDelay.h new file mode 100644 index 0000000000..872048d17c --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_SpinDelay.h @@ -0,0 +1,57 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_SPINDELAY_BEASTHEADER +#define BEAST_SPINDELAY_BEASTHEADER + +// +// Synchronization element +// + +class SpinDelay +{ +public: + SpinDelay () : m_count (0) + { + } + + inline void pause () + { + if (++m_count > 20) + Thread::yield (); + } + +private: + int m_count; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.cpp new file mode 100644 index 0000000000..32cd6a99dd --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.cpp @@ -0,0 +1,118 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +void ThreadGroup::QuitType::operator () (Worker* worker) +{ + worker->setShouldExit (); +} + +//============================================================================== + +ThreadGroup::Worker::Worker (String name, ThreadGroup& group) + : Thread (name) + , m_group (group) + , m_shouldExit (false) +{ + startThread (); +} + +ThreadGroup::Worker::~Worker () +{ + // Make sure the thread is stopped. + stopThread (-1); +} + +void ThreadGroup::Worker::setShouldExit () +{ + m_shouldExit = true; +} + +void ThreadGroup::Worker::run () +{ + do + { + m_group.m_semaphore.wait (); + + Work* work = m_group.m_queue.pop_front (); + + bassert (work != nullptr); + + work->operator () (this); + + delete work; + } + while (!m_shouldExit); +} + +//============================================================================== + +ThreadGroup::ThreadGroup (int numberOfThreads) + : m_numberOfThreads (numberOfThreads) + , m_semaphore (0) +{ + for (int i = 0; i++ < numberOfThreads; ) + { + String s; + s << "ThreadGroup (" << i << ")"; + + m_threads.push_front (new Worker (s, *this)); + } +} + +ThreadGroup::~ThreadGroup () +{ + // Put one quit item in the queue for each worker to stop. + for (int i = 0; i < m_numberOfThreads; ++i) + { + m_queue.push_front (new (getAllocator ()) QuitType); + + m_semaphore.signal (); + } + + for (;;) + { + Worker* worker = m_threads.pop_front (); + + if (worker != nullptr) + delete worker; + else + break; + } + + // There must not be pending work! + bassert (m_queue.pop_front () == nullptr); +} + +int ThreadGroup::getNumberOfThreads () const +{ + return m_numberOfThreads; +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.h b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.h new file mode 100644 index 0000000000..96539b4442 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.h @@ -0,0 +1,246 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_THREADGROUP_BEASTHEADER +#define BEAST_THREADGROUP_BEASTHEADER + +/*============================================================================*/ +/** + @ingroup beast_concurrent + + @brief A group of threads for parallelizing tasks. + + @see ParallelFor +*/ +class ThreadGroup +{ +public: + typedef FifoFreeStoreType AllocatorType; + + /** Creates the specified number of threads. + + @param numberOfThreads The number of threads in the group. This must be + greater than zero. If this parameter is omitted, + one thread is created per available CPU. + */ + explicit ThreadGroup (int numberOfThreads = SystemStats::getNumCpus ()); + + ~ThreadGroup (); + + /** Allocator access. + */ + inline AllocatorType& getAllocator () + { + return m_allocator; + } + + /** Determine the number of threads in the group. + + @return The number of threads in the group. + */ + int getNumberOfThreads () const; + + /** Calls a functor on multiple threads. + + The specified functor is executed on some or all available threads at once. + A call is always guaranteed to execute. + + @param maxThreads The maximum number of threads to use, or -1 for all. + + @param f The functor to call for each thread. + */ + /** @{ */ + template + void callf (int maxThreads, Functor f) + { + bassert (maxThreads > 0 || maxThreads == -1); + + int numberOfThreads = getNumberOfThreads (); + + if (maxThreads != -1 && maxThreads < numberOfThreads) + numberOfThreads = maxThreads; + + while (numberOfThreads--) + { + m_queue.push_front (new (getAllocator ()) WorkType (f)); + m_semaphore.signal (); + } + } + +#if VFLIB_VARIADIC_MAX >= 1 + template + void call (int maxThreads, Fn f) + { + callf (maxThreads, bind (f)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 2 + template + void call (int maxThreads, Fn f, T1 t1) + { + callf (maxThreads, bind (f, t1)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 3 + template + void call (int maxThreads, Fn f, T1 t1, T2 t2) + { + callf (maxThreads, bind (f, t1, t2)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 4 + template + void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3) + { + callf (maxThreads, bind (f, t1, t2, t3)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 5 + template + void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4) + { + callf (maxThreads, bind (f, t1, t2, t3, t4)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 6 + template + void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) + { + callf (maxThreads, bind (f, t1, t2, t3, t4, t5)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 7 + template + void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) + { + callf (maxThreads, bind (f, t1, t2, t3, t4, t5, t6)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 8 + template + void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) + { + callf (maxThreads, bind (f, t1, t2, t3, t4, t5, t6, t7)); + } +#endif + +#if VFLIB_VARIADIC_MAX >= 9 + template + void call (int maxThreads, Fn f, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) + { + callf (maxThreads, bind (f, t1, t2, t3, t4, t5, t6, t7, t8)); + } +#endif + /** @} */ + +private: + void stopThreads (int numberOfThreadsToStop); + + //============================================================================ +private: + /** A thread in the group. + */ + class Worker + : public LockFreeStack ::Node + , public Thread + , LeakChecked + { + public: + Worker (String name, ThreadGroup& group); + ~Worker (); + + void setShouldExit (); + + private: + void run (); + + private: + ThreadGroup& m_group; + bool m_shouldExit; + }; + + //============================================================================ +private: + /** Abstract work item. + */ + class Work : public LockFreeStack ::Node + , public AllocatedBy + { + public: + virtual ~Work () { } + + /* The worker is passed in so we can make it quit later. + */ + virtual void operator () (Worker* worker) = 0; + }; + + template + class WorkType : public Work, LeakChecked > + { + public: + explicit WorkType (Functor const& f) : m_f (f) { } + ~WorkType () { } + void operator () (Worker*) + { + m_f (); + } + + private: + Functor m_f; + }; + + /** Used to make a Worker stop + */ + class QuitType + : public Work + , LeakChecked + { + public: + void operator () (Worker* worker); + }; + +private: + int const m_numberOfThreads; + Semaphore m_semaphore; + AllocatorType m_allocator; + LockFreeStack m_queue; + LockFreeStack m_threads; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.cpp b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.cpp new file mode 100644 index 0000000000..83dda61a86 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.cpp @@ -0,0 +1,158 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +ThreadWithCallQueue::ThreadWithCallQueue (String name) + : CallQueue (name) + , m_thread (name) + , m_entryPoints (nullptr) + , m_calledStart (false) + , m_calledStop (false) + , m_shouldStop (false) +{ +} + +ThreadWithCallQueue::~ThreadWithCallQueue () +{ + stop (true); +} + +void ThreadWithCallQueue::start (EntryPoints* const entryPoints) +{ + { + // This is mostly for diagnostics + // TODO: Atomic flag for this whole thing + CriticalSection::ScopedLockType lock (m_mutex); + + // start() MUST be called. + bassert (!m_calledStart); + m_calledStart = true; + } + + m_entryPoints = entryPoints; + + m_thread.start (this); +} + +void ThreadWithCallQueue::stop (bool const wait) +{ + // can't call stop(true) from within a thread function + bassert (!wait || !m_thread.isTheCurrentThread ()); + + { + CriticalSection::ScopedLockType lock (m_mutex); + + // start() MUST be called. + bassert (m_calledStart); + + // TODO: Atomic for this + if (!m_calledStop) + { + m_calledStop = true; + + { + CriticalSection::ScopedUnlockType unlock (m_mutex); // getting fancy + + call (&ThreadWithCallQueue::doStop, this); + + // in theory something could slip in here + + close (); + } + } + } + + if (wait) + m_thread.join (); +} + +// Should be called periodically by the idle function. +// There are three possible results: +// +// #1 Returns false. The idle function may continue or return. +// #2 Returns true. The idle function should return as soon as possible. +// #3 Throws a Thread::Interruption exception. +// +// If interruptionPoint returns true or throws, it must +// not be called again before the thread has the opportunity to reset. +// +bool ThreadWithCallQueue::interruptionPoint () +{ + return m_thread.interruptionPoint (); +} + +// Interrupts the idle function by queueing a call that does nothing. +void ThreadWithCallQueue::interrupt () +{ + call (&ThreadWithCallQueue::doNothing); +} + +void ThreadWithCallQueue::doNothing () +{ + // Intentionally empty +} + +void ThreadWithCallQueue::signal () +{ + m_thread.interrupt (); +} + +void ThreadWithCallQueue::reset () +{ +} + +void ThreadWithCallQueue::doStop () +{ + m_shouldStop = true; +} + +void ThreadWithCallQueue::threadRun () +{ + m_entryPoints->threadInit (); + + for (;;) + { + CallQueue::synchronize (); + + if (m_shouldStop) + break; + + bool interrupted = m_entryPoints->threadIdle (); + + if (!interrupted) + interrupted = interruptionPoint (); + + if (!interrupted) + m_thread.wait (); + } + + m_entryPoints->threadExit (); +} diff --git a/Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.h b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.h new file mode 100644 index 0000000000..f8da542610 --- /dev/null +++ b/Subtrees/beast/modules/beast_basics/threads/beast_ThreadWithCallQueue.h @@ -0,0 +1,157 @@ +/*============================================================================*/ +/* + VFLib: https://github.com/vinniefalco/VFLib + + Copyright (C) 2008 by Vinnie Falco + + This library contains portions of other open source products covered by + separate licenses. Please see the corresponding source files for specific + terms. + + VFLib is provided under the terms of The MIT License (MIT): + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ +/*============================================================================*/ + +#ifndef BEAST_THREADWITHCALLQUEUE_BEASTHEADER +#define BEAST_THREADWITHCALLQUEUE_BEASTHEADER + +/*============================================================================*/ +/** + An InterruptibleThread with a CallQueue. + + This combines an InterruptibleThread with a CallQueue, allowing functors to + be queued for asynchronous execution on the thread. + + The thread runs an optional user-defined idle function, which must regularly + check for an interruption using the InterruptibleThread interface. When an + interruption is signaled, the idle function returns and the CallQueue is + synchronized. Then, the idle function is resumed. + + When the ThreadWithCallQueue first starts up, an optional user-defined + initialization function is executed on the thread. When the thread exits, + a user-defined exit function may be executed on the thread. + + @see CallQueue + + @ingroup beast_concurrent +*/ +class ThreadWithCallQueue + : public CallQueue + , private InterruptibleThread::EntryPoint +{ +public: + /** Entry points for a ThreadWithCallQueue. + */ + class EntryPoints + { + public: + virtual ~EntryPoints () { } + + virtual void threadInit () { } + + virtual void threadExit () { } + + virtual bool threadIdle () + { + bool interrupted = false; + + return interrupted; + } + }; + + /** Create a thread. + + @param name The name of the InterruptibleThread and CallQueue, used + for diagnostics when debugging. + */ + explicit ThreadWithCallQueue (String name); + + /** Destroy a ThreadWithCallQueue. + + If the thread is still running it is stopped. The destructor blocks + until the thread exits cleanly. + */ + ~ThreadWithCallQueue (); + + /** Start the thread. + */ + void start (EntryPoints* const entryPoints); + + /* Stop the thread. + + Stops the thread and optionally wait until it exits. It is safe to call + this function at any time and as many times as desired. + + After a call to stop () the CallQueue is closed, and attempts to queue new + functors will throw a runtime exception. Existing functors will still + execute. + + Any listeners registered on the CallQueue need to be removed + before stop is called + + @invariant The caller is not on the associated thread. + + @param wait `true` if the function should wait until the thread exits + before returning. + */ + + void stop (bool const wait); + + /** + Determine if the thread needs interruption. + + Should be called periodically by the idle function. If interruptionPoint + returns true or throws, it must not be called again until the idle function + returns and is re-entered. + + @invariant No previous calls to interruptionPoint() made after the idle + function entry point returned `true`. + + @return `false` if the idle function may continue, or `true` if the + idle function must return as soon as possible. + */ + bool interruptionPoint (); + + /* Interrupts the idle function. + */ + void interrupt (); + +private: + static void doNothing (); + + void signal (); + + void reset (); + + void doStop (); + + void threadRun (); + +private: + InterruptibleThread m_thread; + EntryPoints* m_entryPoints; + bool m_calledStart; + bool m_calledStop; + bool m_shouldStop; + CriticalSection m_mutex; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_core/beast_core.h b/Subtrees/beast/modules/beast_core/beast_core.h index 8c829e9548..a37730cd61 100644 --- a/Subtrees/beast/modules/beast_core/beast_core.h +++ b/Subtrees/beast/modules/beast_core/beast_core.h @@ -53,14 +53,14 @@ //============================================================================= /** Config: BEAST_LOG_ASSERTIONS - If this flag is enabled, the the bassert and jassertfalse macros will always use Logger::writeToLog() + If this flag is enabled, the the bassert and bassertfalse macros will always use Logger::writeToLog() to write a message when an assertion happens. Enabling it will also leave this turned on in release builds. When it's disabled, - however, the bassert and jassertfalse macros will not be compiled in a + however, the bassert and bassertfalse macros will not be compiled in a release build. - @see bassert, jassertfalse, Logger + @see bassert, bassertfalse, Logger */ #ifndef BEAST_LOG_ASSERTIONS #if BEAST_ANDROID diff --git a/Subtrees/beast/modules/beast_core/containers/beast_Array.h b/Subtrees/beast/modules/beast_core/containers/beast_Array.h index 35c6ac42d0..1cec6d7fdd 100644 --- a/Subtrees/beast/modules/beast_core/containers/beast_Array.h +++ b/Subtrees/beast/modules/beast_core/containers/beast_Array.h @@ -594,7 +594,7 @@ public: if (startIndex < 0) { - jassertfalse; + bassertfalse; startIndex = 0; } diff --git a/Subtrees/beast/modules/beast_core/containers/beast_OwnedArray.h b/Subtrees/beast/modules/beast_core/containers/beast_OwnedArray.h index 4740f8caea..e4a13429ff 100644 --- a/Subtrees/beast/modules/beast_core/containers/beast_OwnedArray.h +++ b/Subtrees/beast/modules/beast_core/containers/beast_OwnedArray.h @@ -394,7 +394,7 @@ public: } else { - jassertfalse; // you're trying to set an object at a negative index, which doesn't have + bassertfalse; // you're trying to set an object at a negative index, which doesn't have // any effect - but since the object is not being added, it may be leaking.. } } @@ -418,7 +418,7 @@ public: if (startIndex < 0) { - jassertfalse; + bassertfalse; startIndex = 0; } @@ -458,7 +458,7 @@ public: if (startIndex < 0) { - jassertfalse; + bassertfalse; startIndex = 0; } diff --git a/Subtrees/beast/modules/beast_core/containers/beast_ReferenceCountedArray.h b/Subtrees/beast/modules/beast_core/containers/beast_ReferenceCountedArray.h index dd4add79ba..9010b78fa8 100644 --- a/Subtrees/beast/modules/beast_core/containers/beast_ReferenceCountedArray.h +++ b/Subtrees/beast/modules/beast_core/containers/beast_ReferenceCountedArray.h @@ -413,7 +413,7 @@ public: if (startIndex < 0) { - jassertfalse; + bassertfalse; startIndex = 0; } diff --git a/Subtrees/beast/modules/beast_core/containers/beast_SortedSet.h b/Subtrees/beast/modules/beast_core/containers/beast_SortedSet.h index ee6e106fc6..93b2725a1c 100644 --- a/Subtrees/beast/modules/beast_core/containers/beast_SortedSet.h +++ b/Subtrees/beast/modules/beast_core/containers/beast_SortedSet.h @@ -346,7 +346,7 @@ public: { if (startIndex < 0) { - jassertfalse; + bassertfalse; startIndex = 0; } diff --git a/Subtrees/beast/modules/beast_core/containers/beast_Variant.cpp b/Subtrees/beast/modules/beast_core/containers/beast_Variant.cpp index 8dd827bec1..4b18140fa6 100644 --- a/Subtrees/beast/modules/beast_core/containers/beast_Variant.cpp +++ b/Subtrees/beast/modules/beast_core/containers/beast_Variant.cpp @@ -253,7 +253,7 @@ public: void writeToStream (const ValueUnion&, OutputStream& output) const { - jassertfalse; // Can't write an object to a stream! + bassertfalse; // Can't write an object to a stream! output.writeCompressedInt (0); } }; @@ -340,7 +340,7 @@ public: void writeToStream (const ValueUnion&, OutputStream& output) const { - jassertfalse; // Can't write a method to a stream! + bassertfalse; // Can't write a method to a stream! output.writeCompressedInt (0); } }; diff --git a/Subtrees/beast/modules/beast_core/files/beast_File.cpp b/Subtrees/beast/modules/beast_core/files/beast_File.cpp index a4235f438c..ffa83d7260 100644 --- a/Subtrees/beast/modules/beast_core/files/beast_File.cpp +++ b/Subtrees/beast/modules/beast_core/files/beast_File.cpp @@ -87,7 +87,7 @@ String File::parseAbsolutePath (const String& p) "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute path if that's what was supplied, or would evaluate a partial path relative to the CWD. */ - jassertfalse; + bassertfalse; path = File::getCurrentWorkingDirectory().getFullPathName().substring (0, 2) + path; } @@ -101,7 +101,7 @@ String File::parseAbsolutePath (const String& p) "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute path if that's what was supplied, or would evaluate a partial path relative to the CWD. */ - jassertfalse; + bassertfalse; return File::getCurrentWorkingDirectory().getChildFile (path).getFullPathName(); } @@ -144,7 +144,7 @@ String File::parseAbsolutePath (const String& p) "File::getCurrentWorkingDirectory().getChildFile (myUnknownPath)" would return an absolute path if that's what was supplied, or would evaluate a partial path relative to the CWD. */ - jassertfalse; + bassertfalse; #if BEAST_LOG_ASSERTIONS Logger::writeToLog ("Illegal absolute path: " + path); diff --git a/Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.cpp b/Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.cpp index d38100875d..561d2c16cf 100644 --- a/Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.cpp +++ b/Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.cpp @@ -65,7 +65,7 @@ TemporaryFile::~TemporaryFile() call TemporaryFile::deleteTemporaryFile() to detect those error cases and handle them appropriately. */ - jassertfalse; + bassertfalse; } } @@ -91,7 +91,7 @@ bool TemporaryFile::overwriteTargetFileWithTemporary() const { // There's no temporary file to use. If your write failed, you should // probably check, and not bother calling this method. - jassertfalse; + bassertfalse; } return false; diff --git a/Subtrees/beast/modules/beast_core/json/beast_JSON.cpp b/Subtrees/beast/modules/beast_core/json/beast_JSON.cpp index a3f7548fe5..268deb8cb5 100644 --- a/Subtrees/beast/modules/beast_core/json/beast_JSON.cpp +++ b/Subtrees/beast/modules/beast_core/json/beast_JSON.cpp @@ -344,7 +344,7 @@ public: if (DynamicObject* const object = v.getDynamicObject()) writeObject (out, *object, indentLevel, allOnOneLine); else - jassertfalse; // Only DynamicObjects can be converted to JSON! + bassertfalse; // Only DynamicObjects can be converted to JSON! } else { diff --git a/Subtrees/beast/modules/beast_core/maths/beast_BigInteger.cpp b/Subtrees/beast/modules/beast_core/maths/beast_BigInteger.cpp index 711c4ee8fd..6da6863b91 100644 --- a/Subtrees/beast/modules/beast_core/maths/beast_BigInteger.cpp +++ b/Subtrees/beast/modules/beast_core/maths/beast_BigInteger.cpp @@ -175,7 +175,7 @@ uint32 BigInteger::getBitRangeAsInt (const int startBit, int numBits) const noex { if (numBits > 32) { - jassertfalse; // use getBitRange() if you need more than 32 bits.. + bassertfalse; // use getBitRange() if you need more than 32 bits.. numBits = 32; } @@ -200,7 +200,7 @@ void BigInteger::setBitRangeAsInt (const int startBit, int numBits, uint32 value { if (numBits > 32) { - jassertfalse; + bassertfalse; numBits = 32; } @@ -939,7 +939,7 @@ String BigInteger::toString (const int base, const int minimumNumCharacters) con } else { - jassertfalse; // can't do the specified base! + bassertfalse; // can't do the specified base! return String::empty; } diff --git a/Subtrees/beast/modules/beast_core/maths/beast_Expression.cpp b/Subtrees/beast/modules/beast_core/maths/beast_Expression.cpp index 13c0640633..d0b1c29403 100644 --- a/Subtrees/beast/modules/beast_core/maths/beast_Expression.cpp +++ b/Subtrees/beast/modules/beast_core/maths/beast_Expression.cpp @@ -41,13 +41,13 @@ public: virtual ReferenceCountedObjectPtr createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/, double /*overallTarget*/, Term* /*topLevelTerm*/) const { - jassertfalse; + bassertfalse; return ReferenceCountedObjectPtr(); } virtual String getName() const { - jassertfalse; // You shouldn't call this for an expression that's not actually a function! + bassertfalse; // You shouldn't call this for an expression that's not actually a function! return String::empty; } diff --git a/Subtrees/beast/modules/beast_core/memory/beast_Atomic.h b/Subtrees/beast/modules/beast_core/memory/beast_Atomic.h index 43eef53f9a..83d43994b2 100644 --- a/Subtrees/beast/modules/beast_core/memory/beast_Atomic.h +++ b/Subtrees/beast/modules/beast_core/memory/beast_Atomic.h @@ -190,11 +190,11 @@ private: #if BEAST_PPC || BEAST_IOS // None of these atomics are available for PPC or for iOS 3.1 or earlier!! - template static Type OSAtomicAdd64Barrier (Type b, BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return *a += b; } - template static Type OSAtomicIncrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return ++*a; } - template static Type OSAtomicDecrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return --*a; } + template static Type OSAtomicAdd64Barrier (Type b, BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return *a += b; } + template static Type OSAtomicIncrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return ++*a; } + template static Type OSAtomicDecrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return --*a; } template static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, BEAST_MAC_ATOMICS_VOLATILE Type* value) noexcept - { jassertfalse; if (old == *value) { *value = newValue; return true; } return false; } + { bassertfalse; if (old == *value) { *value = newValue; return true; } return false; } #define BEAST_64BIT_ATOMICS_UNAVAILABLE 1 #endif @@ -242,10 +242,10 @@ private: #define beast_InterlockedDecrement64(a) _InterlockedDecrement64(a) #else // None of these atomics are available in a 32-bit Windows build!! - template static Type beast_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a += b; return old; } - template static Type beast_InterlockedExchange64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a = b; return old; } - template static Type beast_InterlockedIncrement64 (volatile Type* a) noexcept { jassertfalse; return ++*a; } - template static Type beast_InterlockedDecrement64 (volatile Type* a) noexcept { jassertfalse; return --*a; } + template static Type beast_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a += b; return old; } + template static Type beast_InterlockedExchange64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a = b; return old; } + template static Type beast_InterlockedIncrement64 (volatile Type* a) noexcept { bassertfalse; return ++*a; } + template static Type beast_InterlockedDecrement64 (volatile Type* a) noexcept { bassertfalse; return --*a; } #define BEAST_64BIT_ATOMICS_UNAVAILABLE 1 #endif #endif diff --git a/Subtrees/beast/modules/beast_core/memory/beast_LeakedObjectDetector.h b/Subtrees/beast/modules/beast_core/memory/beast_LeakedObjectDetector.h index 40ab2a8651..eaa01b15df 100644 --- a/Subtrees/beast/modules/beast_core/memory/beast_LeakedObjectDetector.h +++ b/Subtrees/beast/modules/beast_core/memory/beast_LeakedObjectDetector.h @@ -66,7 +66,7 @@ public: your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays, ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs! */ - jassertfalse; + bassertfalse; } } @@ -90,7 +90,7 @@ private: your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays, ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs! */ - jassertfalse; + bassertfalse; } } diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp index 8b6e18315b..ed53676ac8 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp @@ -123,7 +123,7 @@ File File::getSpecialLocation (const SpecialLocationType type) return beast_getExecutableFile(); default: - jassertfalse; // unknown type? + bassertfalse; // unknown type? break; } diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_JNIHelpers.h b/Subtrees/beast/modules/beast_core/native/beast_android_JNIHelpers.h index ac94be2e07..3681c5c6a4 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_android_JNIHelpers.h +++ b/Subtrees/beast/modules/beast_core/native/beast_android_JNIHelpers.h @@ -336,7 +336,7 @@ private: } } - jassertfalse; // too many threads! + bassertfalse; // too many threads! } }; diff --git a/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp index b79534fee0..1dd9a5bc38 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_android_SystemStats.cpp @@ -106,7 +106,7 @@ JNIEnv* getEnv() noexcept if (! systemInitialised) { DBG ("*** Call to getEnv() when system not initialised"); - jassertfalse; + bassertfalse; exit (0); } #endif @@ -302,6 +302,6 @@ double Time::getMillisecondCounterHiRes() noexcept bool Time::setSystemTimeToThisTime() const { - jassertfalse; + bassertfalse; return false; } diff --git a/Subtrees/beast/modules/beast_core/native/beast_linux_Files.cpp b/Subtrees/beast/modules/beast_core/native/beast_linux_Files.cpp index 32c296dfa0..6487f80fb3 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_linux_Files.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_linux_Files.cpp @@ -94,7 +94,7 @@ bool File::isOnHardDisk() const bool File::isOnRemovableDrive() const { - jassertfalse; // xxx not implemented for linux! + bassertfalse; // xxx not implemented for linux! return false; } @@ -209,7 +209,7 @@ File File::getSpecialLocation (const SpecialLocationType type) return beast_readlink ("/proc/self/exe", beast_getExecutableFile()); default: - jassertfalse; // unknown type? + bassertfalse; // unknown type? break; } diff --git a/Subtrees/beast/modules/beast_core/native/beast_linux_Network.cpp b/Subtrees/beast/modules/beast_core/native/beast_linux_Network.cpp index 0bf0782abb..33b8012e7d 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_linux_Network.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_linux_Network.cpp @@ -55,7 +55,7 @@ bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */, const String& /* bodyText */, const StringArray& /* filesToAttach */) { - jassertfalse; // xxx todo + bassertfalse; // xxx todo return false; } diff --git a/Subtrees/beast/modules/beast_core/native/beast_linux_Threads.cpp b/Subtrees/beast/modules/beast_core/native/beast_linux_Threads.cpp index 13defab94e..5ce0db5553 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_linux_Threads.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_linux_Threads.cpp @@ -41,7 +41,7 @@ void Process::setPriority (const ProcessPriority prior) case NormalPriority: param.sched_priority = 0; break; case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break; case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break; - default: jassertfalse; break; + default: bassertfalse; break; } pthread_setschedparam (pthread_self(), policy, ¶m); diff --git a/Subtrees/beast/modules/beast_core/native/beast_mac_Files.mm b/Subtrees/beast/modules/beast_core/native/beast_mac_Files.mm index ac6a066202..020a06514c 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_mac_Files.mm +++ b/Subtrees/beast/modules/beast_core/native/beast_mac_Files.mm @@ -243,7 +243,7 @@ File File::getSpecialLocation (const SpecialLocationType type) } default: - jassertfalse; // unknown type? + bassertfalse; // unknown type? break; } diff --git a/Subtrees/beast/modules/beast_core/native/beast_mac_Network.mm b/Subtrees/beast/modules/beast_core/native/beast_mac_Network.mm index 8515e79678..732956180b 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_mac_Network.mm +++ b/Subtrees/beast/modules/beast_core/native/beast_mac_Network.mm @@ -55,7 +55,7 @@ bool Process::openEmailWithAttachments (const String& targetEmailAddress, { #if BEAST_IOS //xxx probably need to use MFMailComposeViewController - jassertfalse; + bassertfalse; return false; #else BEAST_AUTORELEASEPOOL diff --git a/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm b/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm index 2bfb6a97e2..4834c5fb56 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm +++ b/Subtrees/beast/modules/beast_core/native/beast_mac_SystemStats.mm @@ -280,7 +280,7 @@ int64 Time::getHighResolutionTicks() noexcept { return (int64) mach_ab bool Time::setSystemTimeToThisTime() const { - jassertfalse; + bassertfalse; return false; } diff --git a/Subtrees/beast/modules/beast_core/native/beast_mac_Threads.mm b/Subtrees/beast/modules/beast_core/native/beast_mac_Threads.mm index 340b3c3c11..17f7a382ba 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_mac_Threads.mm +++ b/Subtrees/beast/modules/beast_core/native/beast_mac_Threads.mm @@ -45,12 +45,12 @@ void Process::makeForegroundProcess() void Process::raisePrivilege() { - jassertfalse; + bassertfalse; } void Process::lowerPrivilege() { - jassertfalse; + bassertfalse; } void Process::terminate() diff --git a/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h b/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h index 9d6182f721..a91ad4ecd0 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h +++ b/Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h @@ -855,7 +855,7 @@ void Thread::killThread() if (threadHandle != 0) { #if BEAST_ANDROID - jassertfalse; // pthread_cancel not available! + bassertfalse; // pthread_cancel not available! #else pthread_cancel ((pthread_t) threadHandle); #endif @@ -938,7 +938,7 @@ void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask) /* affinities aren't supported because either the appropriate header files weren't found, or the SUPPORT_AFFINITIES macro was turned off */ - jassertfalse; + bassertfalse; (void) affinityMask; #endif } @@ -1121,7 +1121,7 @@ struct HighResolutionTimer::Pimpl if (pthread_create (&thread, nullptr, timerThread, this) == 0) setThreadToRealtime (thread, newPeriod); else - jassertfalse; + bassertfalse; } } diff --git a/Subtrees/beast/modules/beast_core/native/beast_win32_ComSmartPtr.h b/Subtrees/beast/modules/beast_core/native/beast_win32_ComSmartPtr.h index ee25d3ff38..88b46dc05f 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_win32_ComSmartPtr.h +++ b/Subtrees/beast/modules/beast_core/native/beast_win32_ComSmartPtr.h @@ -25,7 +25,7 @@ #define BEAST_WIN32_COMSMARTPTR_BEASTHEADER #ifndef _MSC_VER -template struct UUIDGetter { static CLSID get() { jassertfalse; return CLSID(); } }; +template struct UUIDGetter { static CLSID get() { bassertfalse; return CLSID(); } }; #define __uuidof(x) UUIDGetter::get() #endif diff --git a/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp b/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp index c58d226018..56f17582f5 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp @@ -535,7 +535,7 @@ File BEAST_CALLTYPE File::getSpecialLocation (const SpecialLocationType type) return WindowsFileHelpers::getModuleFileName (0); default: - jassertfalse; // unknown type? + bassertfalse; // unknown type? return File::nonexistent; } diff --git a/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp b/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp index 15696bbff6..f6568e1bd9 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_win32_SystemStats.cpp @@ -148,13 +148,13 @@ SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() case 2: return Windows8; default: - jassertfalse; // new version needs to be added here! + bassertfalse; // new version needs to be added here! return Windows8; } } } - jassertfalse; // need to support whatever new version is running! + bassertfalse; // need to support whatever new version is running! return UnknownOS; } @@ -169,7 +169,7 @@ String SystemStats::getOperatingSystemName() case WinVista: name = "Windows Vista"; break; case WinXP: name = "Windows XP"; break; case Win2000: name = "Windows 2000"; break; - default: jassertfalse; break; // !! new type of OS? + default: bassertfalse; break; // !! new type of OS? } return name; diff --git a/Subtrees/beast/modules/beast_core/native/beast_win32_Threads.cpp b/Subtrees/beast/modules/beast_core/native/beast_win32_Threads.cpp index 7b9331bb84..2274bec659 100644 --- a/Subtrees/beast/modules/beast_core/native/beast_win32_Threads.cpp +++ b/Subtrees/beast/modules/beast_core/native/beast_win32_Threads.cpp @@ -35,7 +35,7 @@ long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcep __int64 beast_InterlockedCompareExchange64 (volatile __int64* value, __int64 newValue, __int64 valueToCompare) noexcept { - jassertfalse; // This operation isn't available in old MS compiler versions! + bassertfalse; // This operation isn't available in old MS compiler versions! __int64 oldValue = *value; if (oldValue == valueToCompare) @@ -259,7 +259,7 @@ void beast_repeatLastProcessPriority() case Process::NormalPriority: p = NORMAL_PRIORITY_CLASS; break; case Process::HighPriority: p = HIGH_PRIORITY_CLASS; break; case Process::RealtimePriority: p = REALTIME_PRIORITY_CLASS; break; - default: jassertfalse; return; // bad priority value + default: bassertfalse; return; // bad priority value } SetPriorityClass (GetCurrentProcess(), p); @@ -302,12 +302,12 @@ void Process::setCurrentModuleInstanceHandle (void* const newHandle) noexcept void Process::raisePrivilege() { - jassertfalse; // xxx not implemented + bassertfalse; // xxx not implemented } void Process::lowerPrivilege() { - jassertfalse; // xxx not implemented + bassertfalse; // xxx not implemented } void Process::terminate() diff --git a/Subtrees/beast/modules/beast_core/network/beast_Socket.cpp b/Subtrees/beast/modules/beast_core/network/beast_Socket.cpp index dead36b1b9..30013e06a0 100644 --- a/Subtrees/beast/modules/beast_core/network/beast_Socket.cpp +++ b/Subtrees/beast/modules/beast_core/network/beast_Socket.cpp @@ -333,7 +333,7 @@ bool StreamingSocket::connect (const String& remoteHostName, { if (isListener) { - jassertfalse; // a listener socket can't connect to another one! + bassertfalse; // a listener socket can't connect to another one! return false; } diff --git a/Subtrees/beast/modules/beast_core/streams/beast_InputStream.cpp b/Subtrees/beast/modules/beast_core/streams/beast_InputStream.cpp index ee2adb6a8e..ebefef3171 100644 --- a/Subtrees/beast/modules/beast_core/streams/beast_InputStream.cpp +++ b/Subtrees/beast/modules/beast_core/streams/beast_InputStream.cpp @@ -92,7 +92,7 @@ int InputStream::readCompressedInt() const int numBytes = (sizeByte & 0x7f); if (numBytes > 4) { - jassertfalse; // trying to read corrupt data - this method must only be used + bassertfalse; // trying to read corrupt data - this method must only be used // to read data that was written by OutputStream::writeCompressedInt() return 0; } diff --git a/Subtrees/beast/modules/beast_core/system/beast_PlatformDefs.h b/Subtrees/beast/modules/beast_core/system/beast_PlatformDefs.h index 9c1475ba58..dd3ff1051e 100644 --- a/Subtrees/beast/modules/beast_core/system/beast_PlatformDefs.h +++ b/Subtrees/beast/modules/beast_core/system/beast_PlatformDefs.h @@ -92,7 +92,7 @@ It is only compiled in a debug build, (unless BEAST_LOG_ASSERTIONS is enabled for your build). @see bassert */ - #define jassertfalse { beast_LogCurrentAssertion; if (beast::beast_isRunningUnderDebugger()) beast_breakDebugger; } + #define bassertfalse { beast_LogCurrentAssertion; if (beast::beast_isRunningUnderDebugger()) beast_breakDebugger; } //============================================================================== /** Platform-independent assertion macro. @@ -100,19 +100,19 @@ This macro gets turned into a no-op when you're building with debugging turned off, so be careful that the expression you pass to it doesn't perform any actions that are vital for the correct behaviour of your program! - @see jassertfalse + @see bassertfalse */ - #define bassert(expression) { if (! (expression)) jassertfalse; } + #define bassert(expression) { if (! (expression)) bassertfalse; } #else //============================================================================== // If debugging is disabled, these dummy debug and assertion macros are used.. #define DBG(dbgtext) - #define jassertfalse { beast_LogCurrentAssertion } + #define bassertfalse { beast_LogCurrentAssertion } #if BEAST_LOG_ASSERTIONS - #define bassert(expression) { if (! (expression)) jassertfalse; } + #define bassert(expression) { if (! (expression)) bassertfalse; } #else #define bassert(a) {} #endif @@ -202,7 +202,7 @@ namespace beast #define BEAST_TRY try #define BEAST_CATCH_ALL catch (...) {} - #define BEAST_CATCH_ALL_ASSERT catch (...) { jassertfalse; } + #define BEAST_CATCH_ALL_ASSERT catch (...) { bassertfalse; } #if ! BEAST_MODULE_AVAILABLE_beast_gui_basics #define BEAST_CATCH_EXCEPTION BEAST_CATCH_ALL diff --git a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp index 24f361ecb8..d49d5bdc5b 100644 --- a/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp +++ b/Subtrees/beast/modules/beast_core/system/beast_SystemStats.cpp @@ -69,7 +69,7 @@ String SystemStats::getStackBacktrace() String result; #if BEAST_ANDROID || BEAST_MINGW - jassertfalse; // sorry, not implemented yet! + bassertfalse; // sorry, not implemented yet! #elif BEAST_WINDOWS HANDLE process = GetCurrentProcess(); diff --git a/Subtrees/beast/modules/beast_core/text/beast_String.cpp b/Subtrees/beast/modules/beast_core/text/beast_String.cpp index 87de39ad3f..45a64ed674 100644 --- a/Subtrees/beast/modules/beast_core/text/beast_String.cpp +++ b/Subtrees/beast/modules/beast_core/text/beast_String.cpp @@ -1110,7 +1110,7 @@ String String::replaceSection (int index, int numCharsToReplace, const String& s if (index < 0) { // a negative index to replace from? - jassertfalse; + bassertfalse; index = 0; } @@ -1118,7 +1118,7 @@ String String::replaceSection (int index, int numCharsToReplace, const String& s { // replacing a negative number of characters? numCharsToReplace = 0; - jassertfalse; + bassertfalse; } int i = 0; @@ -1129,7 +1129,7 @@ String String::replaceSection (int index, int numCharsToReplace, const String& s if (insertPoint.isEmpty()) { // replacing beyond the end of the string? - jassertfalse; + bassertfalse; return *this + stringToInsert; } diff --git a/Subtrees/beast/modules/beast_core/text/beast_StringArray.cpp b/Subtrees/beast/modules/beast_core/text/beast_StringArray.cpp index d4770d2bd7..8df29ea4f0 100644 --- a/Subtrees/beast/modules/beast_core/text/beast_StringArray.cpp +++ b/Subtrees/beast/modules/beast_core/text/beast_StringArray.cpp @@ -164,7 +164,7 @@ void StringArray::addArray (const StringArray& otherArray, int startIndex, int n { if (startIndex < 0) { - jassertfalse; + bassertfalse; startIndex = 0; } diff --git a/Subtrees/beast/modules/beast_core/threads/beast_ReadWriteLock.cpp b/Subtrees/beast/modules/beast_core/threads/beast_ReadWriteLock.cpp index 13fcaecefb..fbc784a24d 100644 --- a/Subtrees/beast/modules/beast_core/threads/beast_ReadWriteLock.cpp +++ b/Subtrees/beast/modules/beast_core/threads/beast_ReadWriteLock.cpp @@ -91,7 +91,7 @@ void ReadWriteLock::exitRead() const noexcept } } - jassertfalse; // unlocking a lock that wasn't locked.. + bassertfalse; // unlocking a lock that wasn't locked.. } //============================================================================== diff --git a/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp b/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp index e344a5489d..b891733651 100644 --- a/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp +++ b/Subtrees/beast/modules/beast_core/threads/beast_Thread.cpp @@ -187,7 +187,7 @@ void Thread::stopThread (const int timeOutMilliseconds) { // very bad karma if this point is reached, as there are bound to be // locks and events left in silly states when a thread is killed by force.. - jassertfalse; + bassertfalse; Logger::writeToLog ("!! killing thread by force !!"); killThread(); diff --git a/Subtrees/beast/modules/beast_core/unit_tests/beast_UnitTest.cpp b/Subtrees/beast/modules/beast_core/unit_tests/beast_UnitTest.cpp index 50d2abfa42..49b96ce72e 100644 --- a/Subtrees/beast/modules/beast_core/unit_tests/beast_UnitTest.cpp +++ b/Subtrees/beast/modules/beast_core/unit_tests/beast_UnitTest.cpp @@ -228,5 +228,5 @@ void UnitTestRunner::addFail (const String& failureMessage) resultsUpdated(); - if (assertOnFailure) { jassertfalse; } + if (assertOnFailure) { bassertfalse; } } diff --git a/Subtrees/beast/modules/beast_core/xml/beast_XmlElement.cpp b/Subtrees/beast/modules/beast_core/xml/beast_XmlElement.cpp index 3b51fa78bf..9c992c9c6b 100644 --- a/Subtrees/beast/modules/beast_core/xml/beast_XmlElement.cpp +++ b/Subtrees/beast/modules/beast_core/xml/beast_XmlElement.cpp @@ -773,7 +773,7 @@ void XmlElement::setText (const String& newText) if (isTextElement()) setAttribute (beast_xmltextContentAttributeName, newText); else - jassertfalse; // you can only change the text in a text element, not a normal one. + bassertfalse; // you can only change the text in a text element, not a normal one. } String XmlElement::getAllSubText() const diff --git a/Subtrees/beast/modules/beast_core/zip/beast_GZIPCompressorOutputStream.cpp b/Subtrees/beast/modules/beast_core/zip/beast_GZIPCompressorOutputStream.cpp index 0025d9fdb8..a2467d15f8 100644 --- a/Subtrees/beast/modules/beast_core/zip/beast_GZIPCompressorOutputStream.cpp +++ b/Subtrees/beast/modules/beast_core/zip/beast_GZIPCompressorOutputStream.cpp @@ -154,7 +154,7 @@ int64 GZIPCompressorOutputStream::getPosition() bool GZIPCompressorOutputStream::setPosition (int64 /*newPosition*/) { - jassertfalse; // can't do it! + bassertfalse; // can't do it! return false; } diff --git a/modules/ripple_basics/containers/ripple_KeyCache.h b/modules/ripple_basics/containers/ripple_KeyCache.h index b9eb63cbd3..aff5cf2248 100644 --- a/modules/ripple_basics/containers/ripple_KeyCache.h +++ b/modules/ripple_basics/containers/ripple_KeyCache.h @@ -19,7 +19,6 @@ static int getElapsedSeconds (); @endcode - file vf_db.h @ingroup ripple_basics */ template