mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 19:15:54 +00:00
Add beast_basics module
This commit is contained in:
@@ -41,6 +41,57 @@
|
||||
<None Include="..\..\README.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\beast_basics\beast_basics.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_List.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_LockFreeQueue.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_LockFreeStack.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_SharedTable.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_SortedLookupTable.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_CatchAny.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_Debug.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_Error.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_FPUFlags.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_LeakChecked.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_SafeBool.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_Throw.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\events\beast_OncePerSecond.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\events\beast_PerformedAtExit.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\functor\beast_Bind.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\functor\beast_Function.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\math\beast_Interval.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\math\beast_Math.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\math\beast_MurmurHash.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AllocatedBy.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicCounter.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicFlag.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicPointer.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicState.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_CacheLine.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_FifoFreeStore.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithoutTLS.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithTLS.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_GlobalFifoFreeStore.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_GlobalPagedFreeStore.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_MemoryAlignment.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_PagedFreeStore.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_RefCountedSingleton.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_StaticObject.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_Uncopyable.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_CallQueue.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ConcurrentObject.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ConcurrentState.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_GlobalThreadGroup.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_InterruptibleThread.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_Listeners.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_MessageThread.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ParallelFor.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ReadWriteMutex.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_Semaphore.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_SerialFor.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_SharedObject.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_SpinDelay.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ThreadGroup.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ThreadWithCallQueue.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\beast_core.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_AbstractFifo.h" />
|
||||
<ClInclude Include="..\..\modules\beast_core\containers\beast_Array.h" />
|
||||
@@ -160,6 +211,115 @@
|
||||
<ClInclude Include="BeastConfig.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\beast_basics\beast_basics.cpp" />
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_CatchAny.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_Debug.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_Error.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_FPUFlags.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_LeakChecked.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\events\beast_OncePerSecond.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\events\beast_PerformedAtExit.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\math\beast_MurmurHash.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithoutTLS.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithTLS.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_GlobalPagedFreeStore.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_PagedFreeStore.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_posix_FPUFlags.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_posix_Threads.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_win32_FPUFlags.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_win32_Threads.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_CallQueue.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ConcurrentObject.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_InterruptibleThread.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_Listeners.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_MessageThread.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ParallelFor.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ReadWriteMutex.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_Semaphore.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_SharedObject.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ThreadGroup.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ThreadWithCallQueue.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp" />
|
||||
<ClCompile Include="..\..\modules\beast_core\containers\beast_AbstractFifo.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -89,6 +89,33 @@
|
||||
<Filter Include="beast_core\zip\zlib">
|
||||
<UniqueIdentifier>{31038502-9139-4c19-bd67-8f90f08a70ca}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics">
|
||||
<UniqueIdentifier>{e3a8f3eb-7f0f-4b81-b978-0dd0823f583b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\containers">
|
||||
<UniqueIdentifier>{3e9389c0-c8f0-4657-ab11-cbbea889d3be}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\diagnostic">
|
||||
<UniqueIdentifier>{ba11b980-76dd-49a4-b2c7-878e9f08f8ce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\events">
|
||||
<UniqueIdentifier>{b8caa85d-f224-4e3a-966f-a19b65023869}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\functor">
|
||||
<UniqueIdentifier>{bb0bef46-51a6-4c26-8354-4df753c3bace}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\math">
|
||||
<UniqueIdentifier>{1d53386e-0732-4213-b45d-026ff3d14042}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\memory">
|
||||
<UniqueIdentifier>{9e850052-6ab7-4a65-911d-adfde81ceb5f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\native">
|
||||
<UniqueIdentifier>{811c5374-8959-4df9-aba9-a7e27b85046e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="beast_basics\threads">
|
||||
<UniqueIdentifier>{f58dddf7-fe43-49a2-8e57-91feba586119}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
|
||||
@@ -440,6 +467,159 @@
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BeastConfig.h" />
|
||||
<ClInclude Include="..\..\modules\beast_basics\beast_basics.h">
|
||||
<Filter>beast_basics</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_List.h">
|
||||
<Filter>beast_basics\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_LockFreeQueue.h">
|
||||
<Filter>beast_basics\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_LockFreeStack.h">
|
||||
<Filter>beast_basics\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_SharedTable.h">
|
||||
<Filter>beast_basics\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\containers\beast_SortedLookupTable.h">
|
||||
<Filter>beast_basics\containers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_CatchAny.h">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_Debug.h">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_Error.h">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_FPUFlags.h">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_LeakChecked.h">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_SafeBool.h">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\diagnostic\beast_Throw.h">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\events\beast_OncePerSecond.h">
|
||||
<Filter>beast_basics\events</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\events\beast_PerformedAtExit.h">
|
||||
<Filter>beast_basics\events</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\functor\beast_Bind.h">
|
||||
<Filter>beast_basics\functor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\functor\beast_Function.h">
|
||||
<Filter>beast_basics\functor</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\math\beast_Interval.h">
|
||||
<Filter>beast_basics\math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\math\beast_Math.h">
|
||||
<Filter>beast_basics\math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\math\beast_MurmurHash.h">
|
||||
<Filter>beast_basics\math</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AllocatedBy.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicCounter.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicFlag.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicPointer.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_AtomicState.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_CacheLine.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_FifoFreeStore.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithoutTLS.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithTLS.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_GlobalFifoFreeStore.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_GlobalPagedFreeStore.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_MemoryAlignment.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_PagedFreeStore.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_RefCountedSingleton.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_StaticObject.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\memory\beast_Uncopyable.h">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_CallQueue.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ConcurrentObject.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ConcurrentState.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_GlobalThreadGroup.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_InterruptibleThread.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_Listeners.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_MessageThread.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ParallelFor.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ReadWriteMutex.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_Semaphore.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_SerialFor.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_SharedObject.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_SpinDelay.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ThreadGroup.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\modules\beast_basics\threads\beast_ThreadWithCallQueue.h">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
||||
@@ -691,5 +871,89 @@
|
||||
<ClCompile Include="..\..\modules\beast_core\zip\zlib\zutil.c">
|
||||
<Filter>beast_core\zip\zlib</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\beast_basics.cpp">
|
||||
<Filter>beast_basics</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_CatchAny.cpp">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_Debug.cpp">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_Error.cpp">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_FPUFlags.cpp">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\diagnostic\beast_LeakChecked.cpp">
|
||||
<Filter>beast_basics\diagnostic</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\events\beast_OncePerSecond.cpp">
|
||||
<Filter>beast_basics\events</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\events\beast_PerformedAtExit.cpp">
|
||||
<Filter>beast_basics\events</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\math\beast_MurmurHash.cpp">
|
||||
<Filter>beast_basics\math</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithoutTLS.cpp">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_FifoFreeStoreWithTLS.cpp">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_GlobalPagedFreeStore.cpp">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\memory\beast_PagedFreeStore.cpp">
|
||||
<Filter>beast_basics\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_posix_FPUFlags.cpp">
|
||||
<Filter>beast_basics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_posix_Threads.cpp">
|
||||
<Filter>beast_basics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_win32_FPUFlags.cpp">
|
||||
<Filter>beast_basics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\native\beast_win32_Threads.cpp">
|
||||
<Filter>beast_basics\native</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_CallQueue.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ConcurrentObject.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_InterruptibleThread.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_Listeners.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_MessageThread.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ParallelFor.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ReadWriteMutex.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_Semaphore.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_SharedObject.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ThreadGroup.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\modules\beast_basics\threads\beast_ThreadWithCallQueue.cpp">
|
||||
<Filter>beast_basics\threads</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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
|
||||
|
||||
89
Subtrees/beast/modules/beast_basics/beast_basics.cpp
Normal file
89
Subtrees/beast/modules/beast_basics/beast_basics.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <crtdbg.h>
|
||||
#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
|
||||
497
Subtrees/beast/modules/beast_basics/beast_basics.h
Normal file
497
Subtrees/beast/modules/beast_basics/beast_basics.h
Normal file
@@ -0,0 +1,497 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
Beast: https://github.com/vinniefalco/Beast
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 \<vinnie.falco@gmail.com\> ([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 \<vinnie.falco@gmail.com\> ([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 <boost/thread/tss.hpp>
|
||||
#endif
|
||||
|
||||
#if BEAST_MSVC
|
||||
# include <crtdbg.h>
|
||||
# include <functional>
|
||||
|
||||
#elif BEAST_IOS
|
||||
# if BEAST_USE_BOOST
|
||||
# include <boost/bind.hpp>
|
||||
# include <boost/function.hpp>
|
||||
# else
|
||||
# include <ciso646> // detect std::lib
|
||||
# if _LIBCPP_VERSION // libc++
|
||||
# include <functional>
|
||||
# else // libstdc++ (GNU)
|
||||
# include <tr1/functional>
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#elif BEAST_MAC
|
||||
# include <ciso646> // detect std::lib
|
||||
# if _LIBCPP_VERSION // libc++
|
||||
# include <functional>
|
||||
# else // libstdc++ (GNU)
|
||||
# include <tr1/functional>
|
||||
# endif
|
||||
|
||||
#elif BEAST_LINUX
|
||||
# include <tr1/functional>
|
||||
|
||||
#else
|
||||
# error Unnkown platform!
|
||||
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstdarg>
|
||||
#include <cstddef>
|
||||
#include <exception>
|
||||
#include <istream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <new>
|
||||
#include <numeric>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <locale.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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 <crtdbg.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#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
|
||||
|
||||
809
Subtrees/beast/modules/beast_basics/containers/beast_List.h
Normal file
809
Subtrees/beast/modules/beast_basics/containers/beast_List.h
Normal file
@@ -0,0 +1,809 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Object> 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 <Object>::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 <Object> 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 <Object, GlobalListTag>
|
||||
, public List <Object, ActiveListTag>
|
||||
{
|
||||
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 <Object, GlobalListTag> s_globalList;
|
||||
static List <Object, ActiveListTag> 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 <Object>::Node
|
||||
{
|
||||
Object (int value) : m_value (value)
|
||||
{
|
||||
}
|
||||
|
||||
int m_value;
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
Now we define the list, and add a couple of items.
|
||||
|
||||
@code
|
||||
|
||||
List <Object> 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 <Object>::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 <Actor, ProcessTag> ProcessList;
|
||||
typedef List <Actor, UpdateTag> 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 Element, class Tag = ListDefaultTag>
|
||||
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 ElemType, class NodeType>
|
||||
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 <class OtherElemType, class OtherNodeType>
|
||||
iterator_base (iterator_base <OtherElemType, OtherNodeType> const& other)
|
||||
: m_node (other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
template <class OtherElemType, class OtherNodeType>
|
||||
iterator_base& operator= (iterator_base <OtherElemType, OtherNodeType> const& other)
|
||||
{
|
||||
m_node = other.m_node;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class OtherElemType, class OtherNodeType>
|
||||
bool operator == (iterator_base <OtherElemType, OtherNodeType> const& other) const
|
||||
{
|
||||
return m_node == other.m_node;
|
||||
}
|
||||
|
||||
template <class OtherElemType, class OtherNodeType>
|
||||
bool operator != (iterator_base <OtherElemType, OtherNodeType> 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 <ElemType*> (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 <Element, Node> iterator;
|
||||
|
||||
/** A read-only List iterator. */
|
||||
typedef iterator_base <Element const, Node const> 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 <Node*> (&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 <Node const*> (&elem));
|
||||
}
|
||||
|
||||
private:
|
||||
inline reference element_from (Node* node)
|
||||
{
|
||||
return * (static_cast <pointer> (node));
|
||||
}
|
||||
|
||||
inline const_reference element_from (Node const* node) const
|
||||
{
|
||||
return * (static_cast <const_pointer> (node));
|
||||
}
|
||||
|
||||
inline Node* node_from (Element& elem)
|
||||
{
|
||||
return static_cast <Node*> (&elem);
|
||||
}
|
||||
|
||||
inline Node const* node_from (Element const& elem) const
|
||||
{
|
||||
return static_cast <Node const*> (&elem);
|
||||
}
|
||||
|
||||
private:
|
||||
size_type m_size;
|
||||
Node m_head;
|
||||
Node m_tail;
|
||||
};
|
||||
|
||||
/**
|
||||
Default tag for List.
|
||||
|
||||
@ingroup beast_core intrusive
|
||||
*/
|
||||
struct ListDefaultTag { };
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,239 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 Element, class Tag = LockFreeQueueDefaultTag>
|
||||
class LockFreeQueue
|
||||
{
|
||||
public:
|
||||
class Node : Uncopyable
|
||||
{
|
||||
public:
|
||||
Node () { }
|
||||
explicit Node (Node* next) : m_next (next) { }
|
||||
|
||||
AtomicPointer <Node> 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 <Element*> (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 <Element*> (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 <Node> m_head;
|
||||
Node* m_tail;
|
||||
Node m_null;
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
/** Default tag for LockFreeQueue
|
||||
|
||||
@ingroup beast_core intrusive
|
||||
*/
|
||||
struct LockFreeQueueDefaultTag { };
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,179 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 Element, class Tag = LockFreeStackDefaultTag>
|
||||
class LockFreeStack : Uncopyable
|
||||
{
|
||||
public:
|
||||
class Node : Uncopyable
|
||||
{
|
||||
public:
|
||||
Node ()
|
||||
{
|
||||
}
|
||||
|
||||
explicit Node (Node* next) : m_next (next)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
friend class LockFreeStack;
|
||||
|
||||
AtomicPointer <Node> 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 <Element*> (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 <Node> m_head;
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
/** Default tag for LockFreeStack
|
||||
|
||||
@ingroup beast_core intrusive
|
||||
*/
|
||||
struct LockFreeStackDefaultTag { };
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,226 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 ElementType>
|
||||
class SharedTable
|
||||
{
|
||||
public:
|
||||
typedef ElementType Entry;
|
||||
|
||||
static SharedTable <ElementType> 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 <Data> 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 <ElementType> const m_table;
|
||||
};
|
||||
|
||||
explicit SharedTable (Data* data)
|
||||
: m_data (data)
|
||||
{
|
||||
}
|
||||
|
||||
ReferenceCountedObjectPtr <Data> m_data;
|
||||
};
|
||||
|
||||
template <class ElementType>
|
||||
SharedTable <ElementType> const SharedTable <ElementType>::null;
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 SchemaType>
|
||||
class SortedLookupTable
|
||||
{
|
||||
private:
|
||||
typedef typename SchemaType::KeyType KeyType;
|
||||
typedef typename SchemaType::ValueType ValueType;
|
||||
|
||||
typedef std::vector <ValueType> 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 <typename values_t::iterator, typename values_t::iterator> 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
|
||||
@@ -0,0 +1,289 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <iostream>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Windows structured exception handling
|
||||
//
|
||||
#if BEAST_MSVC
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
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 <void (void)> 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;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <void (void)> f,
|
||||
bool returnFromException = false);
|
||||
|
||||
#endif
|
||||
268
Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.cpp
Normal file
268
Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
69
Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.h
Normal file
69
Subtrees/beast/modules/beast_basics/diagnostic/beast_Debug.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
256
Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.cpp
Normal file
256
Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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;
|
||||
}
|
||||
139
Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.h
Normal file
139
Subtrees/beast/modules/beast_basics/diagnostic/beast_Error.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Error>
|
||||
{
|
||||
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
|
||||
@@ -0,0 +1,53 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 ();
|
||||
}
|
||||
348
Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.h
Normal file
348
Subtrees/beast/modules/beast_basics/diagnostic/beast_FPUFlags.h
Normal file
@@ -0,0 +1,348 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename Constants>
|
||||
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 <Rounding> getRounding () const
|
||||
{
|
||||
return m_rounding;
|
||||
}
|
||||
const Enum <Precision> 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 <Rounding>& getRounding ()
|
||||
{
|
||||
return m_rounding;
|
||||
}
|
||||
Enum <Precision>& 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 <Rounding> m_rounding;
|
||||
Enum <Precision> 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
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <CounterBase> 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
|
||||
@@ -0,0 +1,184 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <CounterBase>::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 <int> m_count;
|
||||
};
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Detects leaks at program exit.
|
||||
|
||||
To use this, derive your class from this template using CRTP (curiously
|
||||
recurring template pattern).
|
||||
*/
|
||||
template <class Object>
|
||||
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 <class Object>
|
||||
struct LeakChecked : LeakCheckedBase
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
104
Subtrees/beast/modules/beast_basics/diagnostic/beast_SafeBool.h
Normal file
104
Subtrees/beast/modules/beast_basics/diagnostic/beast_SafeBool.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename T = void>
|
||||
class SafeBool : public SafeBoolBase
|
||||
{
|
||||
public:
|
||||
operator boolean_t () const
|
||||
{
|
||||
return (static_cast <T const*> (this))->asBoolean ()
|
||||
? &SafeBoolBase::allowed : 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
~SafeBool () { }
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
void operator== (SafeBool <T> const& lhs, SafeBool <U> const& rhs)
|
||||
{
|
||||
lhs.disallowed ();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
void operator!= (SafeBool <T> const& lhs, SafeBool <U> const& rhs)
|
||||
{
|
||||
lhs.disallowed ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
51
Subtrees/beast/modules/beast_basics/diagnostic/beast_Throw.h
Normal file
51
Subtrees/beast/modules/beast_basics/diagnostic/beast_Throw.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <class Exception>
|
||||
inline void Throw (Exception const& e)
|
||||
{
|
||||
Debug::breakPoint ();
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,124 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <OncePerSecond::TimerSingleton>
|
||||
, private InterruptibleThread::EntryPoint
|
||||
{
|
||||
private:
|
||||
TimerSingleton ()
|
||||
: RefCountedSingleton <OncePerSecond::TimerSingleton> (
|
||||
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 <Elem>::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 <Elem> 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);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <TimerSingleton> TimerPtr;
|
||||
|
||||
struct Elem : List <Elem>::Node
|
||||
{
|
||||
TimerPtr instance;
|
||||
OncePerSecond* object;
|
||||
};
|
||||
|
||||
Elem m_elem;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <LockFreeStack <PerformedAtExit>, 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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <PerformedAtExit>::Node
|
||||
{
|
||||
protected:
|
||||
PerformedAtExit ();
|
||||
virtual ~PerformedAtExit () { }
|
||||
|
||||
protected:
|
||||
/** Called at program exit.
|
||||
*/
|
||||
virtual void performAtExit () = 0;
|
||||
|
||||
private:
|
||||
class Performer;
|
||||
};
|
||||
|
||||
#endif
|
||||
109
Subtrees/beast/modules/beast_basics/functor/beast_Bind.h
Normal file
109
Subtrees/beast/modules/beast_basics/functor/beast_Bind.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
279
Subtrees/beast/modules/beast_basics/functor/beast_Function.h
Normal file
279
Subtrees/beast/modules/beast_basics/functor/beast_Function.h
Normal file
@@ -0,0 +1,279 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename Signature, int Bytes = 128>
|
||||
class Function;
|
||||
|
||||
//
|
||||
// nullary function
|
||||
//
|
||||
|
||||
template <typename R, int Bytes>
|
||||
class Function <R (void), Bytes>
|
||||
{
|
||||
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 <class Functor>
|
||||
Function (Functor const& f)
|
||||
{
|
||||
constructCopyOf (f);
|
||||
}
|
||||
|
||||
~Function ()
|
||||
{
|
||||
getCall ().~Call ();
|
||||
}
|
||||
|
||||
Function& operator= (Function const& f)
|
||||
{
|
||||
getCall ().~Call ();
|
||||
f.getCall ().constructCopyInto (m_storage);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Functor>
|
||||
Function& operator= (Functor const& f)
|
||||
{
|
||||
getCall ().~Call ();
|
||||
constructCopyOf (f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
result_type operator () ()
|
||||
{
|
||||
return getCall ().operator () ();
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Functor>
|
||||
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 <Functor>) <= Bytes);
|
||||
new (m_storage) StoredCall <Functor> (f);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Call
|
||||
{
|
||||
virtual ~Call () {}
|
||||
virtual void constructCopyInto (void* p) const = 0;
|
||||
virtual result_type operator () () = 0;
|
||||
};
|
||||
|
||||
template <class Functor>
|
||||
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 <Call*> (&m_storage[0]);
|
||||
}
|
||||
|
||||
Call const& getCall () const
|
||||
{
|
||||
return *reinterpret_cast <Call const*> (&m_storage[0]);
|
||||
}
|
||||
|
||||
char m_storage [Bytes]; // should be enough
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// unary function
|
||||
//
|
||||
|
||||
template <typename R, typename T1, int Bytes>
|
||||
class Function <R (T1 t1), Bytes>
|
||||
{
|
||||
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 <class Functor>
|
||||
Function (Functor const& f)
|
||||
{
|
||||
constructCopyOf (f);
|
||||
}
|
||||
|
||||
~Function ()
|
||||
{
|
||||
getCall ().~Call ();
|
||||
}
|
||||
|
||||
Function& operator= (const Function& f)
|
||||
{
|
||||
getCall ().~Call ();
|
||||
f.getCall ().constructCopyInto (m_storage);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Functor>
|
||||
Function& operator= (Functor const& f)
|
||||
{
|
||||
getCall ().~Call ();
|
||||
constructCopyOf (f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
result_type operator () (T1 t1)
|
||||
{
|
||||
return getCall ().operator () (t1);
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Functor>
|
||||
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 <Functor>) <= Bytes);
|
||||
new (m_storage) StoredCall <Functor> (f);
|
||||
}
|
||||
|
||||
private:
|
||||
struct Call
|
||||
{
|
||||
virtual ~Call () {}
|
||||
virtual void constructCopyInto (void* p) const = 0;
|
||||
virtual result_type operator () (T1 t1) = 0;
|
||||
};
|
||||
|
||||
template <class Functor>
|
||||
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 <Call*> (&m_storage[0]);
|
||||
}
|
||||
|
||||
Call const& getCall () const
|
||||
{
|
||||
return *reinterpret_cast <Call const*> (&m_storage[0]);
|
||||
}
|
||||
|
||||
char m_storage [Bytes]; // should be enough
|
||||
};
|
||||
|
||||
#endif
|
||||
400
Subtrees/beast/modules/beast_basics/math/beast_Interval.h
Normal file
400
Subtrees/beast/modules/beast_basics/math/beast_Interval.h
Normal file
@@ -0,0 +1,400 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 Ty>
|
||||
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 <class To>
|
||||
bool intersects (Interval <To> 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 <class To>
|
||||
bool adjoins (Interval <To> 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 <class To>
|
||||
bool superset_of (Interval <To> 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 <class To>
|
||||
bool proper_superset_of (Interval <To> 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 <class To>
|
||||
bool subset_of (Interval <To> 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 <class To>
|
||||
bool proper_subset_of (Interval <To> 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 <class To>
|
||||
Interval intersection (Interval <To> 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 <class To>
|
||||
Interval simple_union (Interval <To> 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 <class To>
|
||||
Interval single_union (Interval <To> 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 <typename Tv>
|
||||
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 <Tv>::is_integer ? 1 :
|
||||
std::numeric_limits <Tv>::epsilon ());
|
||||
|
||||
if (v < begin ())
|
||||
v = begin ();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
private:
|
||||
Ty m_begin;
|
||||
Ty m_end;
|
||||
};
|
||||
|
||||
template <typename Ty>
|
||||
const Interval<Ty> Interval<Ty>::none = Interval<Ty> (Ty (), Ty ());
|
||||
|
||||
#endif
|
||||
97
Subtrees/beast/modules/beast_basics/math/beast_Math.h
Normal file
97
Subtrees/beast/modules/beast_basics/math/beast_Math.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename Ty>
|
||||
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 <typename Ty>
|
||||
inline Ty calc_bin_start (Ty value, int size)
|
||||
{
|
||||
return calc_bin (value, size) * size;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T pi () noexcept
|
||||
{
|
||||
return 3.14159265358979;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T twoPi () noexcept
|
||||
{
|
||||
return 6.28318530717958;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T oneOverTwoPi () noexcept
|
||||
{
|
||||
return 0.1591549430918955;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline T degreesToRadians (U degrees)
|
||||
{
|
||||
return T (degrees * 0.0174532925199433);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
inline T radiansToDegrees (U radians)
|
||||
{
|
||||
T deg = T (radians * U (57.29577951308238));
|
||||
|
||||
if (deg < 0)
|
||||
deg += 360;
|
||||
|
||||
return deg;
|
||||
}
|
||||
|
||||
#endif
|
||||
506
Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.cpp
Normal file
506
Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.cpp
Normal file
@@ -0,0 +1,506 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
79
Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.h
Normal file
79
Subtrees/beast/modules/beast_basics/math/beast_MurmurHash.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename HashType>
|
||||
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
|
||||
@@ -0,0 +1,76 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 AllocatorType>
|
||||
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
|
||||
@@ -0,0 +1,96 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <int> m_value;
|
||||
};
|
||||
|
||||
#endif
|
||||
115
Subtrees/beast/modules/beast_basics/memory/beast_AtomicFlag.h
Normal file
115
Subtrees/beast/modules/beast_basics/memory/beast_AtomicFlag.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <int> m_value;
|
||||
};
|
||||
|
||||
#endif
|
||||
146
Subtrees/beast/modules/beast_basics/memory/beast_AtomicPointer.h
Normal file
146
Subtrees/beast/modules/beast_basics/memory/beast_AtomicPointer.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 P>
|
||||
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 <P*> m_value;
|
||||
};
|
||||
|
||||
#endif
|
||||
114
Subtrees/beast/modules/beast_basics/memory/beast_AtomicState.h
Normal file
114
Subtrees/beast/modules/beast_basics/memory/beast_AtomicState.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <int> m_value;
|
||||
};
|
||||
|
||||
#endif
|
||||
491
Subtrees/beast/modules/beast_basics/memory/beast_CacheLine.h
Normal file
491
Subtrees/beast/modules/beast_basics/memory/beast_CacheLine.h
Normal file
@@ -0,0 +1,491 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename T>
|
||||
class Aligned
|
||||
{
|
||||
public:
|
||||
~Aligned ()
|
||||
{
|
||||
ptr ()->~T ();
|
||||
}
|
||||
|
||||
Aligned ()
|
||||
{
|
||||
new (ptr ()) T;
|
||||
}
|
||||
|
||||
template <class T1>
|
||||
explicit Aligned (const T1& t1)
|
||||
{
|
||||
new (ptr ()) T (t1);
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
Aligned (const T1& t1, const T2& t2)
|
||||
{
|
||||
new (ptr ()) T (t1, t2);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
Aligned (const T1& t1, const T2& t2, const T3& t3)
|
||||
{
|
||||
new (ptr ()) T (t1, t2, t3);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4)
|
||||
{
|
||||
new (ptr ()) T (t1, t2, t3, t4);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <T*> (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 <typename T>
|
||||
class Padded
|
||||
{
|
||||
public:
|
||||
Padded ()
|
||||
{ }
|
||||
|
||||
template <class T1>
|
||||
explicit Padded (const T1& t1)
|
||||
: m_t (t1) { }
|
||||
|
||||
template <class T1, class T2>
|
||||
Padded (const T1& t1, const T2& t2)
|
||||
: m_t (t1, t2) { }
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
Padded (const T1& t1, const T2& t2, const T3& t3)
|
||||
: m_t (t1, t2, t3) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4)
|
||||
: m_t (t1, t2, t3, t4) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5>
|
||||
Padded (const T1& t1, const T2& t2, const T3& t3,
|
||||
const T4& t4, const T5& t5)
|
||||
: m_t (t1, t2, t3, t4, t5) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <typename T>
|
||||
class Aligned
|
||||
{
|
||||
public:
|
||||
Aligned ()
|
||||
{ }
|
||||
|
||||
template <class T1>
|
||||
explicit Aligned (const T1& t1)
|
||||
: m_t (t1) { }
|
||||
|
||||
template <class T1, class T2>
|
||||
Aligned (const T1& t1, const T2& t2)
|
||||
: m_t (t1, t2) { }
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
Aligned (const T1& t1, const T2& t2, const T3& t3)
|
||||
: m_t (t1, t2, t3) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
Aligned (const T1& t1, const T2& t2, const T3& t3, const T4& t4)
|
||||
: m_t (t1, t2, t3, t4) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5>
|
||||
Aligned (const T1& t1, const T2& t2, const T3& t3,
|
||||
const T4& t4, const T5& t5)
|
||||
: m_t (t1, t2, t3, t4, t5) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <typename T>
|
||||
class Padded
|
||||
{
|
||||
public:
|
||||
Padded ()
|
||||
{ }
|
||||
|
||||
template <class T1>
|
||||
explicit Padded (const T1& t1)
|
||||
: m_t (t1) { }
|
||||
|
||||
template <class T1, class T2>
|
||||
Padded (const T1& t1, const T2& t2)
|
||||
: m_t (t1, t2) { }
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
Padded (const T1& t1, const T2& t2, const T3& t3)
|
||||
: m_t (t1, t2, t3) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
Padded (const T1& t1, const T2& t2, const T3& t3, const T4& t4)
|
||||
: m_t (t1, t2, t3, t4) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5>
|
||||
Padded (const T1& t1, const T2& t2, const T3& t3,
|
||||
const T4& t4, const T5& t5)
|
||||
: m_t (t1, t2, t3, t4, t5) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <typename T>
|
||||
class Unpadded
|
||||
{
|
||||
public:
|
||||
Unpadded ()
|
||||
{ }
|
||||
|
||||
template <class T1>
|
||||
explicit Unpadded (const T1& t1)
|
||||
: m_t (t1) { }
|
||||
|
||||
template <class T1, class T2>
|
||||
Unpadded (const T1& t1, const T2& t2)
|
||||
: m_t (t1, t2) { }
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
Unpadded (const T1& t1, const T2& t2, const T3& t3)
|
||||
: m_t (t1, t2, t3) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
Unpadded (const T1& t1, const T2& t2, const T3& t3, const T4& t4)
|
||||
: m_t (t1, t2, t3, t4) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5>
|
||||
Unpadded (const T1& t1, const T2& t2, const T3& t3,
|
||||
const T4& t4, const T5& t5)
|
||||
: m_t (t1, t2, t3, t4, t5) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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
|
||||
@@ -0,0 +1,54 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,207 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Page>, Uncopyable
|
||||
{
|
||||
public:
|
||||
explicit Page (const size_t bytes) : m_refs (1)
|
||||
{
|
||||
m_end = reinterpret_cast <char*> (this) + bytes;
|
||||
m_free = reinterpret_cast <char*> (
|
||||
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 <PerThreadData>, 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 <Header*> (m_active->allocate (bytesNeeded));
|
||||
|
||||
if (!header)
|
||||
{
|
||||
if (m_active->release ())
|
||||
deletePage (m_active);
|
||||
|
||||
m_active = m_allocator.newPage ();
|
||||
|
||||
header = reinterpret_cast <Header*> (m_active->allocate (bytesNeeded));
|
||||
}
|
||||
|
||||
header->page = m_active;
|
||||
|
||||
return reinterpret_cast <char*> (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 <Header*> (reinterpret_cast <char*> (p) - headerBytes);
|
||||
Page* const page = header->page;
|
||||
|
||||
if (page->release ())
|
||||
deletePage (page);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <PerThreadData> m_tsp;
|
||||
|
||||
PagedFreeStoreType::Ptr m_pages;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,254 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <char*> (this) + bytes;
|
||||
m_free = reinterpret_cast <char*> (
|
||||
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 <void**> (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 <char> 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 <Header*> (p) - 1)->block;
|
||||
|
||||
if (b->release ())
|
||||
deleteBlock (b);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,78 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 Tag>
|
||||
class GlobalFifoFreeStore : public RefCountedSingleton <GlobalFifoFreeStore <Tag> >
|
||||
{
|
||||
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 <GlobalFifoFreeStore <Tag> >
|
||||
(SingletonLifetime::persistAfterCreation)
|
||||
{
|
||||
}
|
||||
|
||||
~GlobalFifoFreeStore ()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
FifoFreeStoreType m_allocator;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,55 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <GlobalPagedFreeStore> (SingletonLifetime::persistAfterCreation)
|
||||
, m_allocator (globalPageBytes)
|
||||
{
|
||||
}
|
||||
|
||||
GlobalPagedFreeStore::~GlobalPagedFreeStore ()
|
||||
{
|
||||
}
|
||||
|
||||
GlobalPagedFreeStore* GlobalPagedFreeStore::createInstance ()
|
||||
{
|
||||
return new GlobalPagedFreeStore;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <GlobalPagedFreeStore>
|
||||
, LeakChecked <GlobalPagedFreeStore>
|
||||
{
|
||||
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
|
||||
@@ -0,0 +1,73 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <typename P>
|
||||
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 <typename P>
|
||||
inline P* pointerAdjustedForAlignment (P* const p)
|
||||
{
|
||||
return reinterpret_cast <P*> (reinterpret_cast <char*> (p) +
|
||||
bytesNeededForAlignment (p));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,239 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Page>
|
||||
{
|
||||
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 <char*> (p) +
|
||||
Memory::sizeAdjustedForAlignment (sizeof (Page));
|
||||
}
|
||||
|
||||
inline PagedFreeStore::Page* PagedFreeStore::toPage (void* const p)
|
||||
{
|
||||
return reinterpret_cast <Page*> (
|
||||
(reinterpret_cast <char*> (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);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Page> Pages;
|
||||
|
||||
struct Pool
|
||||
{
|
||||
CacheLine::Padded <Pages> fresh;
|
||||
CacheLine::Padded <Pages> 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 <Pool> m_pool1; // pair of pools
|
||||
CacheLine::Aligned <Pool> 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
|
||||
@@ -0,0 +1,212 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 Object>
|
||||
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 <Object> 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 <LockType, RefCountedSingleton <Object> > s_mutex;
|
||||
static Static::Storage <bool, RefCountedSingleton <Object> > s_created;
|
||||
};
|
||||
/** @{ */
|
||||
|
||||
template <class Object>
|
||||
Object* RefCountedSingleton <Object>::s_instance;
|
||||
|
||||
template <class Object>
|
||||
Static::Storage <typename RefCountedSingleton <Object>::LockType, RefCountedSingleton <Object> >
|
||||
RefCountedSingleton <Object>::s_mutex;
|
||||
|
||||
template <class Object>
|
||||
Static::Storage <bool, RefCountedSingleton <Object> >
|
||||
RefCountedSingleton <Object>::s_created;
|
||||
|
||||
#endif
|
||||
200
Subtrees/beast/modules/beast_basics/memory/beast_StaticObject.h
Normal file
200
Subtrees/beast/modules/beast_basics/memory/beast_StaticObject.h
Normal file
@@ -0,0 +1,200 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Object> 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 ObjectType, class Tag>
|
||||
class Storage
|
||||
{
|
||||
public:
|
||||
static inline void construct ()
|
||||
{
|
||||
new (getObjectPtr ()) ObjectType;
|
||||
}
|
||||
|
||||
static inline void destroy ()
|
||||
{
|
||||
getObjectPtr ()->~ObjectType ();
|
||||
}
|
||||
|
||||
static inline ObjectType* getObjectPtr ()
|
||||
{
|
||||
return reinterpret_cast <ObjectType*> (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 <class ObjectType, class Tag>
|
||||
char Storage <ObjectType, Tag>::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 <int> m_state;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
/*============================================================================*/
|
||||
@@ -0,0 +1,189 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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"));
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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.
|
||||
*/
|
||||
/*============================================================================*/
|
||||
166
Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.cpp
Normal file
166
Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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;
|
||||
}
|
||||
555
Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.h
Normal file
555
Subtrees/beast/modules/beast_basics/threads/beast_CallQueue.h
Normal file
@@ -0,0 +1,555 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Work>::Node,
|
||||
public AllocatedBy <AllocatorType>
|
||||
{
|
||||
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 <class Functor>
|
||||
void callf (Functor f)
|
||||
{
|
||||
callp (new (m_allocator) CallType <Functor> (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 <class Fn>
|
||||
void call (Fn f)
|
||||
{
|
||||
callf (bind (f));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Fn, class T1>
|
||||
void call (Fn f, T1 t1)
|
||||
{
|
||||
callf (bind (f, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Fn, class T1, class T2>
|
||||
void call (Fn f, T1 t1, T2 t2)
|
||||
{
|
||||
callf (bind (f, t1, t2));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 4
|
||||
template <class Fn, class T1, class T2, class T3>
|
||||
void call (Fn f, T1 t1, T2 t2, T3 t3)
|
||||
{
|
||||
callf (bind (f, t1, t2, t3));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 5
|
||||
template <class Fn, class T1, class T2, class T3, class T4>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 <class Functor>
|
||||
void queuef (Functor f)
|
||||
{
|
||||
queuep (new (m_allocator) CallType <Functor> (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> sharedState;
|
||||
|
||||
void stateChanged ()
|
||||
{
|
||||
ConcurrentState <SharedState>::ReadAccess state (sharedState);
|
||||
|
||||
// (read state)
|
||||
}
|
||||
|
||||
CallQueue fifo;
|
||||
|
||||
void changeState ()
|
||||
{
|
||||
ConcurrentState <State>::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 <class Fn>
|
||||
void queue (Fn f)
|
||||
{
|
||||
queuef (bind (f));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Fn, class T1>
|
||||
void queue (Fn f, T1 t1)
|
||||
{
|
||||
queuef (bind (f, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Fn, class T1, class T2>
|
||||
void queue (Fn f, T1 t1, T2 t2)
|
||||
{
|
||||
queuef (bind (f, t1, t2));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 4
|
||||
template <class Fn, class T1, class T2, class T3>
|
||||
void queue (Fn f, T1 t1, T2 t2, T3 t3)
|
||||
{
|
||||
queuef (bind (f, t1, t2, t3));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 5
|
||||
template <class Fn, class T1, class T2, class T3, class T4>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 Functor>
|
||||
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 <Work> m_queue;
|
||||
AtomicFlag m_closed;
|
||||
AtomicFlag m_isBeingSynchronized;
|
||||
AllocatorType m_allocator;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <SharedData> 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 <AudioSampleBuffer*> m_array;
|
||||
};
|
||||
|
||||
// Construct SharedData with one parameter
|
||||
ConcurrentState <SharedData> 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 Object>
|
||||
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 <class T1>
|
||||
explicit ConcurrentState (T1 t1)
|
||||
: m_obj (t1) { }
|
||||
|
||||
template <class T1, class T2>
|
||||
ConcurrentState (T1 t1, T2 t2)
|
||||
: m_obj (t1, t2) { }
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
ConcurrentState (T1 t1, T2 t2, T3 t3)
|
||||
: m_obj (t1, t2, t3) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4)
|
||||
: m_obj (t1, t2, t3, t4) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5>
|
||||
ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
|
||||
: m_obj (t1, t2, t3, t4, t5) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
|
||||
: m_obj (t1, t2, t3, t4, t5, t6) { }
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 Object>
|
||||
class ConcurrentState <Object>::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 Object>
|
||||
class ConcurrentState <Object>::ReadAccess : Uncopyable
|
||||
{
|
||||
public:
|
||||
/** Create a ReadAccess from the specified ConcurrentState */
|
||||
explicit ReadAccess (ConcurrentState const volatile& state)
|
||||
: m_state (const_cast <ConcurrentState const&> (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 Object>
|
||||
class ConcurrentState <Object>::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
|
||||
@@ -0,0 +1,62 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <GlobalThreadGroup>
|
||||
{
|
||||
private:
|
||||
friend class RefCountedSingleton <GlobalThreadGroup>;
|
||||
|
||||
GlobalThreadGroup ()
|
||||
: RefCountedSingleton <GlobalThreadGroup> (
|
||||
SingletonLifetime::persistAfterCreation)
|
||||
{
|
||||
}
|
||||
|
||||
static GlobalThreadGroup* createInstance ()
|
||||
{
|
||||
return new GlobalThreadGroup;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <ThreadHelper*> (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;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <void (void)> 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
|
||||
778
Subtrees/beast/modules/beast_basics/threads/beast_Listeners.cpp
Normal file
778
Subtrees/beast/modules/beast_basics/threads/beast_Listeners.cpp
Normal file
@@ -0,0 +1,778 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <AllocatorType>
|
||||
{
|
||||
typedef ReferenceCountedObjectPtr <Entry> Ptr;
|
||||
|
||||
explicit Entry (Group* g)
|
||||
: group (g)
|
||||
{
|
||||
}
|
||||
|
||||
~Entry ()
|
||||
{
|
||||
bassert (call.get () == 0);
|
||||
}
|
||||
|
||||
Group::Ptr group;
|
||||
AtomicPointer <Call> call;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// A Group maintains a list of Entry.
|
||||
//
|
||||
struct ListenersBase::Group::Entry : List <Entry>::Node,
|
||||
AllocatedBy <AllocatorType>
|
||||
{
|
||||
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 <Entry>::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 <Entry>::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 <Entry>::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 <Entry>::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;
|
||||
}
|
||||
900
Subtrees/beast/modules/beast_basics/threads/beast_Listeners.h
Normal file
900
Subtrees/beast/modules/beast_basics/threads/beast_Listeners.h
Normal file
@@ -0,0 +1,900 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <Listener> 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 <State>::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 <State>::WriteAccess state (m_state);
|
||||
|
||||
m_state->outputLevel = newOutputLevel;
|
||||
}
|
||||
|
||||
// Notify listeners.
|
||||
listeners.call (&Listener::onOutputLevelChanged, newOutputLevel);
|
||||
}
|
||||
|
||||
private:
|
||||
struct State
|
||||
{
|
||||
State () : outputLevel (0) { }
|
||||
|
||||
float outputLevel;
|
||||
};
|
||||
|
||||
ConcurrentState <State> 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 <ListenersStructureTag> AllocatorType;
|
||||
|
||||
typedef GlobalFifoFreeStore <ListenersBase> CallAllocatorType;
|
||||
|
||||
class Call : public ReferenceCountedObject,
|
||||
public AllocatedBy <CallAllocatorType>
|
||||
{
|
||||
public:
|
||||
typedef ReferenceCountedObjectPtr <Call> Ptr;
|
||||
virtual void operator () (void* const listener) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
typedef unsigned long timestamp_t;
|
||||
|
||||
class Group;
|
||||
typedef List <Group> Groups;
|
||||
|
||||
class Proxy;
|
||||
typedef List <Proxy> 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 <AllocatorType>
|
||||
{
|
||||
public:
|
||||
typedef ReferenceCountedObjectPtr <Group> 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 <Entry> m_list;
|
||||
void* m_listener;
|
||||
CacheLine::Aligned <ReadWriteMutex> 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 <AllocatorType>
|
||||
{
|
||||
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 <Entry> 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 <ReadWriteMutex> m_groups_mutex;
|
||||
CacheLine::Aligned <ReadWriteMutex> m_proxies_mutex;
|
||||
AllocatorType::Ptr m_allocator;
|
||||
CallAllocatorType::Ptr m_callAllocator;
|
||||
};
|
||||
|
||||
/*============================================================================*/
|
||||
|
||||
template <class ListenerClass>
|
||||
class Listeners : public ListenersBase
|
||||
{
|
||||
private:
|
||||
template <class Functor>
|
||||
class CallType : public Call
|
||||
{
|
||||
public:
|
||||
CallType (Functor f) : m_f (f)
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (void* const listener)
|
||||
{
|
||||
ListenerClass* object = static_cast <ListenerClass*> (listener);
|
||||
m_f.operator () (object);
|
||||
}
|
||||
|
||||
private:
|
||||
Functor m_f;
|
||||
};
|
||||
|
||||
template <class Functor>
|
||||
inline void callf (Functor f)
|
||||
{
|
||||
callp (new (getCallAllocator ()) CallType <Functor> (f));
|
||||
}
|
||||
|
||||
template <class Functor>
|
||||
inline void queuef (Functor f)
|
||||
{
|
||||
queuep (new (getCallAllocator ()) CallType <Functor> (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 <class Functor>
|
||||
inline void call1f (ListenerClass* const listener, Functor f)
|
||||
{
|
||||
call1p (listener, new (getCallAllocator ()) CallType <Functor> (f));
|
||||
}
|
||||
|
||||
template <class Functor>
|
||||
inline void queue1f (ListenerClass* const listener, Functor f)
|
||||
{
|
||||
queue1p (listener, new (getCallAllocator ()) CallType <Functor> (f));
|
||||
}
|
||||
|
||||
template <class Member, class Functor>
|
||||
inline void updatef (Member member, Functor f)
|
||||
{
|
||||
updatep (reinterpret_cast <void*> (&member), sizeof (Member),
|
||||
new (getCallAllocator ()) CallType <Functor> (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 <class Mf>
|
||||
inline void call (Mf mf)
|
||||
{
|
||||
callf (vf::bind (mf, vf::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Mf, class T1>
|
||||
void call (Mf mf, T1 t1)
|
||||
{
|
||||
callf (vf::bind (mf, vf::_1, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Mf, class T1, class T2>
|
||||
void call (Mf mf, T1 t1, T2 t2)
|
||||
{
|
||||
callf (vf::bind (mf, vf::_1, t1, t2));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 4
|
||||
template <class Mf, class T1, class T2, class T3>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 <class Mf>
|
||||
inline void queue (Mf mf)
|
||||
{
|
||||
queuef (vf::bind (mf, vf::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Mf, class T1>
|
||||
void queue (Mf mf, T1 t1)
|
||||
{
|
||||
queuef (vf::bind (mf, vf::_1, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Mf, class T1, class T2>
|
||||
void queue (Mf mf, T1 t1, T2 t2)
|
||||
{
|
||||
queuef (vf::bind (mf, vf::_1, t1, t2));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 4
|
||||
template <class Mf, class T1, class T2, class T3>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 <class Mf>
|
||||
inline void update (Mf mf)
|
||||
{
|
||||
updatef (mf, vf::bind (mf, vf::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Mf, class T1>
|
||||
void update (Mf mf, T1 t1)
|
||||
{
|
||||
updatef (mf, vf::bind (mf, vf::_1, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Mf, class T1, class T2>
|
||||
void update (Mf mf, T1 t1, T2 t2)
|
||||
{
|
||||
updatef (mf, vf::bind (mf, vf::_1, t1, t2));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 4
|
||||
template <class Mf, class T1, class T2, class T3>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 <class Mf>
|
||||
inline void call1 (ListenerClass* const listener, Mf mf)
|
||||
{
|
||||
call1f (listener, vf::bind (mf, vf::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Mf, class T1>
|
||||
void call1 (ListenerClass* const listener, Mf mf, T1 t1)
|
||||
{
|
||||
call1f (listener, vf::bind (mf, vf::_1, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Mf, class T1, class T2>
|
||||
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 <class Mf, class T1, class T2, class T3>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 <class Mf>
|
||||
inline void queue1 (ListenerClass* const listener, Mf mf)
|
||||
{
|
||||
queue1f (listener, vf::bind (mf, vf::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Mf, class T1>
|
||||
void queue1 (ListenerClass* const listener, Mf mf, T1 t1)
|
||||
{
|
||||
queue1f (listener, vf::bind (mf, vf::_1, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Mf, class T1, class T2>
|
||||
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 <class Mf, class T1, class T2, class T3>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Mf, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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
|
||||
@@ -0,0 +1,54 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 ()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,76 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
504
Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.h
Normal file
504
Subtrees/beast/modules/beast_basics/threads/beast_ParallelFor.h
Normal file
@@ -0,0 +1,504 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <class F, class T1>
|
||||
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 <class Functor>
|
||||
void loopf (int numberOfIterations, Functor const& f)
|
||||
{
|
||||
IterationType <Functor> iteration (f);
|
||||
|
||||
doLoop (numberOfIterations, iteration);
|
||||
}
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 1
|
||||
template <class Fn>
|
||||
void loop (int n, Fn f)
|
||||
{
|
||||
loopf (n, vf::bind (f, vf::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Fn, class T1>
|
||||
void loop (int n, Fn f, T1 t1)
|
||||
{
|
||||
loopf (n, vf::bind (f, t1, vf::_1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Fn, class T1, class T2>
|
||||
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 <class Fn, class T1, class T2, class T3>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 Functor>
|
||||
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 <ThreadGroup::AllocatorType>
|
||||
, Uncopyable
|
||||
{
|
||||
private:
|
||||
Iteration& m_iteration;
|
||||
WaitableEvent& m_finishedEvent;
|
||||
int const m_numberOfIterations;
|
||||
Atomic <int> m_loopIndex;
|
||||
Atomic <int> m_iterationsRemaining;
|
||||
Atomic <int> 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 <int> m_currentIndex;
|
||||
Atomic <int> 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 <class F, class T1, class T2, class T3, class T4>
|
||||
void operator () (int numberOfIterations, T1 t1, T2 t2, T3 t3, T4 t4)
|
||||
{
|
||||
Factory4 <F, T1, T2, T3, T4> f (t1, t2, t3, t4);
|
||||
doLoop (numberOfIterations, f);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef ThreadGroup::AllocatorType AllocatorType;
|
||||
|
||||
//---
|
||||
|
||||
struct Iterator : public AllocatedBy <AllocatorType>
|
||||
{
|
||||
virtual ~Iterator () { }
|
||||
virtual void operator () (int loopIndex) = 0;
|
||||
};
|
||||
|
||||
//---
|
||||
|
||||
template <class Functor>
|
||||
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 <class F, class T1, class T2, class T3, class T4>
|
||||
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 <F> (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 <AllocatorType>
|
||||
, Uncopyable
|
||||
{
|
||||
private:
|
||||
Factory& m_factory;
|
||||
WaitableEvent& m_finishedEvent;
|
||||
int const m_numberOfIterations;
|
||||
Atomic <int> m_loopIndex;
|
||||
Atomic <int> m_iterationsRemaining;
|
||||
Atomic <int> 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 <int> m_currentIndex;
|
||||
Atomic <int> m_numberOfInstances;
|
||||
int m_numberOfIterations;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 ();
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <class LockType>
|
||||
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 <class LockType>
|
||||
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 <ReadWriteMutex> ScopedReadLockType;
|
||||
|
||||
/** Provides the type of scoped write lock to use with a ReadWriteMutex. */
|
||||
typedef GenericScopedWriteLock <ReadWriteMutex> 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 <AtomicCounter> m_writes;
|
||||
mutable CacheLine::Padded <AtomicCounter> m_readers;
|
||||
};
|
||||
|
||||
#endif
|
||||
130
Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.cpp
Normal file
130
Subtrees/beast/modules/beast_basics/threads/beast_Semaphore.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <WaitingThread>::Node
|
||||
, LeakChecked <WaitingThread>
|
||||
{
|
||||
public:
|
||||
WaitingThread ();
|
||||
|
||||
void wait ();
|
||||
void signal ();
|
||||
|
||||
private:
|
||||
WaitableEvent m_event;
|
||||
};
|
||||
|
||||
typedef SpinLock LockType;
|
||||
|
||||
LockType m_mutex;
|
||||
Atomic <int> m_counter;
|
||||
LockFreeStack <WaitingThread> m_waitingThreads;
|
||||
LockFreeStack <WaitingThread> m_deleteList;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,84 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <class F>
|
||||
inline void operator () (int numberOfIterations)
|
||||
{
|
||||
F f;
|
||||
|
||||
for (int i = 0; i < numberOfIterations; ++i)
|
||||
f (i);
|
||||
}
|
||||
|
||||
template <class F, class T1>
|
||||
inline void operator () (int numberOfIterations, T1 t1)
|
||||
{
|
||||
F f (t1);
|
||||
|
||||
for (int i = 0; i < numberOfIterations; ++i)
|
||||
f (i);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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;
|
||||
}
|
||||
323
Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.h
Normal file
323
Subtrees/beast/modules/beast_basics/threads/beast_SharedObject.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <class Object>
|
||||
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> (object));
|
||||
}
|
||||
|
||||
private:
|
||||
// Simple functor to delete an object.
|
||||
//
|
||||
template <class Object>
|
||||
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 Object>
|
||||
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 <class DerivedClass>
|
||||
inline SharedObjectPtr (const SharedObjectPtr <DerivedClass>& other) noexcept
|
||||
:
|
||||
m_object (static_cast <Object*> (other.get ()))
|
||||
{
|
||||
if (m_object != nullptr)
|
||||
m_object->incReferenceCount ();
|
||||
}
|
||||
|
||||
SharedObjectPtr& operator= (const SharedObjectPtr& other)
|
||||
{
|
||||
return operator= (other.m_object);
|
||||
}
|
||||
|
||||
template <class DerivedClass>
|
||||
SharedObjectPtr& operator= (const SharedObjectPtr <DerivedClass>& other)
|
||||
{
|
||||
return operator= (static_cast <Object*> (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 <class Object>
|
||||
bool operator== (const SharedObjectPtr <Object>& object1, Object* const object2) noexcept
|
||||
{
|
||||
return object1.get () == object2;
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
bool operator== (const SharedObjectPtr <Object>& object1, const SharedObjectPtr <Object>& object2) noexcept
|
||||
{
|
||||
return object1.get () == object2.get ();
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
bool operator== (Object* object1, SharedObjectPtr <Object>& object2) noexcept
|
||||
{
|
||||
return object1 == object2.get ();
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
bool operator!= (const SharedObjectPtr <Object>& object1, const Object* object2) noexcept
|
||||
{
|
||||
return object1.get () != object2;
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
bool operator!= (const SharedObjectPtr <Object>& object1, SharedObjectPtr <Object>& object2) noexcept
|
||||
{
|
||||
return object1.get () != object2.get ();
|
||||
}
|
||||
|
||||
template <class Object>
|
||||
bool operator!= (Object* object1, SharedObjectPtr <Object>& object2) noexcept
|
||||
{
|
||||
return object1 != object2.get ();
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
@@ -0,0 +1,118 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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;
|
||||
}
|
||||
246
Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.h
Normal file
246
Subtrees/beast/modules/beast_basics/threads/beast_ThreadGroup.h
Normal file
@@ -0,0 +1,246 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 <class Functor>
|
||||
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 <Functor> (f));
|
||||
m_semaphore.signal ();
|
||||
}
|
||||
}
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 1
|
||||
template <class Fn>
|
||||
void call (int maxThreads, Fn f)
|
||||
{
|
||||
callf (maxThreads, bind (f));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 2
|
||||
template <class Fn, class T1>
|
||||
void call (int maxThreads, Fn f, T1 t1)
|
||||
{
|
||||
callf (maxThreads, bind (f, t1));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 3
|
||||
template <class Fn, class T1, class T2>
|
||||
void call (int maxThreads, Fn f, T1 t1, T2 t2)
|
||||
{
|
||||
callf (maxThreads, bind (f, t1, t2));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if VFLIB_VARIADIC_MAX >= 4
|
||||
template <class Fn, class T1, class T2, class T3>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7>
|
||||
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 <class Fn, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
|
||||
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 <Worker>::Node
|
||||
, public Thread
|
||||
, LeakChecked <Worker>
|
||||
{
|
||||
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 <Work>::Node
|
||||
, public AllocatedBy <AllocatorType>
|
||||
{
|
||||
public:
|
||||
virtual ~Work () { }
|
||||
|
||||
/* The worker is passed in so we can make it quit later.
|
||||
*/
|
||||
virtual void operator () (Worker* worker) = 0;
|
||||
};
|
||||
|
||||
template <class Functor>
|
||||
class WorkType : public Work, LeakChecked <WorkType <Functor> >
|
||||
{
|
||||
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 <QuitType>
|
||||
{
|
||||
public:
|
||||
void operator () (Worker* worker);
|
||||
};
|
||||
|
||||
private:
|
||||
int const m_numberOfThreads;
|
||||
Semaphore m_semaphore;
|
||||
AllocatorType m_allocator;
|
||||
LockFreeStack <Work> m_queue;
|
||||
LockFreeStack <Worker> m_threads;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 ();
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*============================================================================*/
|
||||
/*
|
||||
VFLib: https://github.com/vinniefalco/VFLib
|
||||
|
||||
Copyright (C) 2008 by Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -594,7 +594,7 @@ public:
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
bassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -413,7 +413,7 @@ public:
|
||||
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
bassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -346,7 +346,7 @@ public:
|
||||
{
|
||||
if (startIndex < 0)
|
||||
{
|
||||
jassertfalse;
|
||||
bassertfalse;
|
||||
startIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,13 +41,13 @@ public:
|
||||
virtual ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/,
|
||||
double /*overallTarget*/, Term* /*topLevelTerm*/) const
|
||||
{
|
||||
jassertfalse;
|
||||
bassertfalse;
|
||||
return ReferenceCountedObjectPtr<Term>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <typename Type> static Type OSAtomicAdd64Barrier (Type b, BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return *a += b; }
|
||||
template <typename Type> static Type OSAtomicIncrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type OSAtomicDecrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return --*a; }
|
||||
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return *a += b; }
|
||||
template <typename Type> static Type OSAtomicIncrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return ++*a; }
|
||||
template <typename Type> static Type OSAtomicDecrement64Barrier (BEAST_MAC_ATOMICS_VOLATILE Type* a) noexcept { bassertfalse; return --*a; }
|
||||
template <typename Type> 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 <typename Type> static Type beast_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a += b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedExchange64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a = b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedIncrement64 (volatile Type* a) noexcept { jassertfalse; return ++*a; }
|
||||
template <typename Type> static Type beast_InterlockedDecrement64 (volatile Type* a) noexcept { jassertfalse; return --*a; }
|
||||
template <typename Type> static Type beast_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a += b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedExchange64 (volatile Type* a, Type b) noexcept { bassertfalse; Type old = *a; *a = b; return old; }
|
||||
template <typename Type> static Type beast_InterlockedIncrement64 (volatile Type* a) noexcept { bassertfalse; return ++*a; }
|
||||
template <typename Type> static Type beast_InterlockedDecrement64 (volatile Type* a) noexcept { bassertfalse; return --*a; }
|
||||
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ File File::getSpecialLocation (const SpecialLocationType type)
|
||||
return beast_getExecutableFile();
|
||||
|
||||
default:
|
||||
jassertfalse; // unknown type?
|
||||
bassertfalse; // unknown type?
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -336,7 +336,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
jassertfalse; // too many threads!
|
||||
bassertfalse; // too many threads!
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
|
||||
const String& /* bodyText */,
|
||||
const StringArray& /* filesToAttach */)
|
||||
{
|
||||
jassertfalse; // xxx todo
|
||||
bassertfalse; // xxx todo
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user