Add beast_basics module

This commit is contained in:
Vinnie Falco
2013-06-17 06:42:49 -07:00
parent e3228b77c8
commit f6da5ba9d3
122 changed files with 15337 additions and 77 deletions

View File

@@ -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>

View File

@@ -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>

View File

@@ -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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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
//------------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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;
}

View 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_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

View 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;
}
}

View 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

View 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;
}

View 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

View File

@@ -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 ();
}

View 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

View 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.
*/
/*============================================================================*/
#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

View File

@@ -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

View 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

View 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

View File

@@ -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);
}

View File

@@ -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

View 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.
*/
/*============================================================================*/
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);
}

View File

@@ -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

View 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

View 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

View 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

View 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

View 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;
}
}

View 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

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View 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

View 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_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

View File

@@ -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)
{
}

View File

@@ -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.
*/
/*============================================================================*/

View File

@@ -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 (&currentControl, 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 (&currentControl, newControl, mask);
if (result != 0)
Throw (std::runtime_error ("error in _controlfp_s"));
}

View File

@@ -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.
*/
/*============================================================================*/

View 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;
}

View 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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View 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;
}

View 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

View File

@@ -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 ()
{
}

View File

@@ -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

View File

@@ -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);
}
}

View 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

View File

@@ -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 ();
}

View File

@@ -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

View 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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View 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

View File

@@ -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

View File

@@ -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;
}

View 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

View File

@@ -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 ();
}

View File

@@ -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

View File

@@ -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

View File

@@ -594,7 +594,7 @@ public:
if (startIndex < 0)
{
jassertfalse;
bassertfalse;
startIndex = 0;
}

View File

@@ -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;
}

View File

@@ -413,7 +413,7 @@ public:
if (startIndex < 0)
{
jassertfalse;
bassertfalse;
startIndex = 0;
}

View File

@@ -346,7 +346,7 @@ public:
{
if (startIndex < 0)
{
jassertfalse;
bassertfalse;
startIndex = 0;
}

View File

@@ -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);
}
};

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -123,7 +123,7 @@ File File::getSpecialLocation (const SpecialLocationType type)
return beast_getExecutableFile();
default:
jassertfalse; // unknown type?
bassertfalse; // unknown type?
break;
}

View File

@@ -336,7 +336,7 @@ private:
}
}
jassertfalse; // too many threads!
bassertfalse; // too many threads!
}
};

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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