mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Add Beast fork from JUCE commit 265fb0e8ebc26e1469d6edcc68d2ca9acefeb508
This commit is contained in:
23
BeastConfig.h
Normal file
23
BeastConfig.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
#ifndef BEAST_BEASTCONFIG_HEADER
|
||||||
|
#define BEAST_BEASTCONFIG_HEADER
|
||||||
|
|
||||||
|
// beast_core flags:
|
||||||
|
|
||||||
|
#ifndef BEAST_FORCE_DEBUG
|
||||||
|
//#define BEAST_FORCE_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_LOG_ASSERTIONS
|
||||||
|
//#define BEAST_LOG_ASSERTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_CHECK_MEMORY_LEAKS
|
||||||
|
//#define BEAST_CHECK_MEMORY_LEAKS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
//#define BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup>
|
<ItemDefinitionGroup>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<PreprocessorDefinitions>USE_LEVELDB;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>USE_LEVELDB;BOOST_TEST_ALTERNATIVE_INIT_API;BOOST_TEST_NO_MAIN;_WIN32_WINNT=0x0600;_SCL_SECURE_NO_WARNINGS;_CRT_SECURE_NO_WARNINGS;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<AdditionalIncludeDirectories>$(RepoDir);$(RepoDir)\src\cpp\leveldb;$(RepoDir)\src\cpp\leveldb\include;$(RepoDir)\src\cpp\protobuf\src;$(RepoDir)\src\cpp\protobuf\vsprojects;$(RepoDir)\build\proto;$(RepoDir)\Subtrees\beast;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>$(RepoDir);$(RepoDir)\src\cpp\leveldb;$(RepoDir)\src\cpp\leveldb\include;$(RepoDir)\src\cpp\protobuf\src;$(RepoDir)\src\cpp\protobuf\vsprojects;$(RepoDir)\build\proto;$(RepoDir)\Subtrees\beast;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
|||||||
@@ -151,6 +151,7 @@ if FreeBSD:
|
|||||||
|
|
||||||
env.Append(
|
env.Append(
|
||||||
LIBS = [
|
LIBS = [
|
||||||
|
'rt', # for clock_nanosleep in beast
|
||||||
'protobuf',
|
'protobuf',
|
||||||
'z'
|
'z'
|
||||||
]
|
]
|
||||||
|
|||||||
24
Subtrees/beast/.gitignore
vendored
24
Subtrees/beast/.gitignore
vendored
@@ -1,3 +1,25 @@
|
|||||||
|
._*
|
||||||
|
*.mode1v3
|
||||||
|
*.pbxuser
|
||||||
|
*.perspectivev3
|
||||||
|
*.user
|
||||||
|
*.ncb
|
||||||
|
*.suo
|
||||||
|
*.obj
|
||||||
|
*.ilk
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.dep
|
||||||
|
*.idb
|
||||||
|
*.manifest
|
||||||
|
*.manifest.res
|
||||||
|
*.o
|
||||||
|
*.d
|
||||||
|
*.sdf
|
||||||
|
xcuserdata
|
||||||
|
contents.xcworkspacedata
|
||||||
|
.DS_Store
|
||||||
|
.svn
|
||||||
|
profile
|
||||||
Builds/VisualStudio2012/Debug
|
Builds/VisualStudio2012/Debug
|
||||||
Builds/VisualStudio2012/Release
|
Builds/VisualStudio2012/Release
|
||||||
Builds/VisualStudio2012/*.user
|
|
||||||
|
|||||||
23
Subtrees/beast/Builds/VisualStudio2012/BeastConfig.h
Normal file
23
Subtrees/beast/Builds/VisualStudio2012/BeastConfig.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
#ifndef BEAST_BEASTCONFIG_HEADER
|
||||||
|
#define BEAST_BEASTCONFIG_HEADER
|
||||||
|
|
||||||
|
// beast_core flags:
|
||||||
|
|
||||||
|
#ifndef BEAST_FORCE_DEBUG
|
||||||
|
//#define BEAST_FORCE_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_LOG_ASSERTIONS
|
||||||
|
//#define BEAST_LOG_ASSERTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_CHECK_MEMORY_LEAKS
|
||||||
|
//#define BEAST_CHECK_MEMORY_LEAKS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
//#define BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -13,14 +13,482 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\..\CodingStyle.md" />
|
<None Include="..\..\CodingStyle.md" />
|
||||||
<None Include="..\..\modules\beast_core\beast_core.mm" />
|
<None Include="..\..\modules\beast_core\beast_core.mm" />
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Files.mm">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Network.mm">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Strings.mm">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_SystemStats.mm">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Threads.mm">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\java\BeastAppActivity.java">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\zip\zlib\README" />
|
||||||
<None Include="..\..\README.md" />
|
<None Include="..\..\README.md" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\modules\beast_core\beast_core.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" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ArrayAllocationBase.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_DynamicObject.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ElementComparator.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_HashMap.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_LinkedListPointer.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_NamedValueSet.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_OwnedArray.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_PropertySet.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ReferenceCountedArray.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ScopedValueSetter.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_SortedSet.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_SparseSet.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_Variant.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_DirectoryIterator.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_File.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileInputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileOutputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileSearchPath.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_MemoryMappedFile.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_TemporaryFile.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\json\beast_JSON.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\logging\beast_FileLogger.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\logging\beast_Logger.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_BigInteger.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_Expression.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_MathsFunctions.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_Random.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_Range.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_Atomic.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_ByteOrder.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_HeapBlock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_LeakedObjectDetector.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_Memory.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_MemoryBlock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_OptionalScopedPointer.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_ReferenceCountedObject.h" />
|
||||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ScopedPointer.h" />
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_ScopedPointer.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_Singleton.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_WeakReference.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\misc\beast_Result.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\misc\beast_Uuid.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\misc\beast_WindowsRegistry.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_android_JNIHelpers.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_BasicNativeHeaders.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_osx_ObjCHelpers.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_posix_SharedCode.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_win32_ComSmartPtr.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_IPAddress.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_MACAddress.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_NamedPipe.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_Socket.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_URL.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_FileInputSource.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputSource.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_OutputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_SubregionStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_PlatformDefs.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_StandardHeader.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_SystemStats.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_TargetPlatform.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharacterFunctions.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_ASCII.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF16.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF32.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF8.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_Identifier.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_LocalisedStrings.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_NewLine.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_String.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_StringArray.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPairArray.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPool.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_TextDiff.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ChildProcess.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_CriticalSection.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_DynamicLibrary.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_InterProcessLock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_Process.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedLock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedReadLock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedWriteLock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_SpinLock.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_Thread.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadLocalValue.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadPool.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_WaitableEvent.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\time\beast_PerformanceCounter.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\time\beast_RelativeTime.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\time\beast_Time.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlDocument.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlElement.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\beast_ZipFile.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\crc32.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\deflate.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffast.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffixed.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inflate.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inftrees.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\trees.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.in.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zlib.h" />
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zutil.h" />
|
||||||
|
<ClInclude Include="BeastConfig.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp" />
|
<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>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_DynamicObject.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_NamedValueSet.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_PropertySet.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_Variant.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_DirectoryIterator.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_File.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_FileInputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_FileOutputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_FileSearchPath.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_TemporaryFile.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\json\beast_JSON.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\logging\beast_FileLogger.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\logging\beast_Logger.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\maths\beast_BigInteger.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\maths\beast_Expression.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\maths\beast_Random.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\memory\beast_MemoryBlock.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\misc\beast_Result.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\misc\beast_Uuid.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Files.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Misc.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Network.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_SystemStats.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Threads.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Files.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Network.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_SystemStats.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Threads.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_posix_NamedPipe.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Files.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Network.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Registry.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_SystemStats.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\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_core\network\beast_IPAddress.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_MACAddress.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_NamedPipe.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_Socket.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_URL.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_FileInputSource.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_InputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_OutputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_SubregionStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\system\beast_SystemStats.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_CharacterFunctions.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_Identifier.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_LocalisedStrings.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_String.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_StringArray.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPairArray.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPool.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_TextDiff.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_ChildProcess.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_Thread.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_ThreadPool.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\time\beast_PerformanceCounter.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\time\beast_RelativeTime.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\time\beast_Time.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlDocument.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlElement.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\beast_ZipFile.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\adler32.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\compress.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\crc32.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\deflate.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\infback.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inffast.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inflate.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inftrees.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\trees.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\uncompr.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\zutil.c">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
<ProjectGuid>{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}</ProjectGuid>
|
<ProjectGuid>{73C5A0F0-7629-4DE7-9194-BE7AC6C19535}</ProjectGuid>
|
||||||
@@ -59,6 +527,7 @@
|
|||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
@@ -74,6 +543,7 @@
|
|||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>$(ProjectDir)</AdditionalIncludeDirectories>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Windows</SubSystem>
|
<SubSystem>Windows</SubSystem>
|
||||||
|
|||||||
@@ -6,26 +6,690 @@
|
|||||||
<None Include="..\..\modules\beast_core\beast_core.mm">
|
<None Include="..\..\modules\beast_core\beast_core.mm">
|
||||||
<Filter>beast_core</Filter>
|
<Filter>beast_core</Filter>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Files.mm">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Network.mm">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Strings.mm">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_SystemStats.mm">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\beast_mac_Threads.mm">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\zip\zlib\README">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</None>
|
||||||
|
<None Include="..\..\modules\beast_core\native\java\BeastAppActivity.java">
|
||||||
|
<Filter>beast_core\native\java</Filter>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="beast_core">
|
<Filter Include="beast_core">
|
||||||
<UniqueIdentifier>{6dafd8d5-2901-4b41-85b7-52f6e86baacc}</UniqueIdentifier>
|
<UniqueIdentifier>{6dafd8d5-2901-4b41-85b7-52f6e86baacc}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="beast_core\containers">
|
||||||
|
<UniqueIdentifier>{7cc041c8-fdf4-4e98-a56a-df516c2a9aa2}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\files">
|
||||||
|
<UniqueIdentifier>{3b7d8d7e-eabc-423c-a631-2ff37bf9b9eb}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\json">
|
||||||
|
<UniqueIdentifier>{abe24d69-c1d1-49e2-98a1-1e7bf760b97a}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\logging">
|
||||||
|
<UniqueIdentifier>{0fa6b76b-305f-473c-9b94-c1028a3af3fc}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\maths">
|
||||||
|
<UniqueIdentifier>{e2339099-bb8e-4437-ae8b-d4f64ef1e3f3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="beast_core\memory">
|
<Filter Include="beast_core\memory">
|
||||||
<UniqueIdentifier>{883f776d-bec2-4e7a-b4e8-726ed3039071}</UniqueIdentifier>
|
<UniqueIdentifier>{a89aa17e-4e01-4c2d-ba7e-196e9e0b67bb}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\misc">
|
||||||
|
<UniqueIdentifier>{64a314e1-0361-428a-a294-0615d8140f58}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\native">
|
||||||
|
<UniqueIdentifier>{1d018a70-71b3-4d70-9280-02efd4f348de}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\network">
|
||||||
|
<UniqueIdentifier>{ad675f57-9303-4712-9ff2-c7f59f959e7b}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\streams">
|
||||||
|
<UniqueIdentifier>{016d839c-4860-4bc3-8f6c-e965f50c2bfa}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\system">
|
||||||
|
<UniqueIdentifier>{7fb77af6-ce16-4f53-823e-906963b42985}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\text">
|
||||||
|
<UniqueIdentifier>{4603580c-5668-4e70-bed8-77f00f03f0ff}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\threads">
|
||||||
|
<UniqueIdentifier>{3409dc7a-92b5-43aa-b678-fde9f82ced55}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\time">
|
||||||
|
<UniqueIdentifier>{d3ea4af5-ae48-4144-a2ef-a212342d72ee}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\unit_tests">
|
||||||
|
<UniqueIdentifier>{0a8a6870-87a4-4f19-bbd3-b277f94bb83e}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\xml">
|
||||||
|
<UniqueIdentifier>{a1a38659-7779-41d6-8a3c-068433c4deaf}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\zip">
|
||||||
|
<UniqueIdentifier>{df5f5a69-5919-4a24-bbce-b3f87e4903cf}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\native\java">
|
||||||
|
<UniqueIdentifier>{b0d206d9-c002-4be1-b503-4ad16aca838a}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="beast_core\zip\zlib">
|
||||||
|
<UniqueIdentifier>{31038502-9139-4c19-bd67-8f90f08a70ca}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\..\modules\beast_core\memory\beast_ScopedPointer.h">
|
|
||||||
<Filter>beast_core\memory</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
|
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
|
||||||
<Filter>beast_core</Filter>
|
<Filter>beast_core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_AbstractFifo.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_Array.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ArrayAllocationBase.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_DynamicObject.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ElementComparator.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_HashMap.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_LinkedListPointer.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_NamedValueSet.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_OwnedArray.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_PropertySet.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ReferenceCountedArray.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_ScopedValueSetter.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_SortedSet.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_SparseSet.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\containers\beast_Variant.h">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_DirectoryIterator.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_File.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileInputStream.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileOutputStream.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_FileSearchPath.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_MemoryMappedFile.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\files\beast_TemporaryFile.h">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\json\beast_JSON.h">
|
||||||
|
<Filter>beast_core\json</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\logging\beast_FileLogger.h">
|
||||||
|
<Filter>beast_core\logging</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\logging\beast_Logger.h">
|
||||||
|
<Filter>beast_core\logging</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_BigInteger.h">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_Expression.h">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_MathsFunctions.h">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_Random.h">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\maths\beast_Range.h">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_Atomic.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_ByteOrder.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_HeapBlock.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_LeakedObjectDetector.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_Memory.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_MemoryBlock.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_OptionalScopedPointer.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_ReferenceCountedObject.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_ScopedPointer.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_Singleton.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\memory\beast_WeakReference.h">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\misc\beast_Result.h">
|
||||||
|
<Filter>beast_core\misc</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\misc\beast_Uuid.h">
|
||||||
|
<Filter>beast_core\misc</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\misc\beast_WindowsRegistry.h">
|
||||||
|
<Filter>beast_core\misc</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_android_JNIHelpers.h">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_BasicNativeHeaders.h">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_osx_ObjCHelpers.h">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_posix_SharedCode.h">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\native\beast_win32_ComSmartPtr.h">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_IPAddress.h">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_MACAddress.h">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_NamedPipe.h">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_Socket.h">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\network\beast_URL.h">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_FileInputSource.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputSource.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_InputStream.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_OutputStream.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\streams\beast_SubregionStream.h">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_PlatformDefs.h">
|
||||||
|
<Filter>beast_core\system</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_StandardHeader.h">
|
||||||
|
<Filter>beast_core\system</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_SystemStats.h">
|
||||||
|
<Filter>beast_core\system</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\system\beast_TargetPlatform.h">
|
||||||
|
<Filter>beast_core\system</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharacterFunctions.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_ASCII.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF8.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF16.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_CharPointer_UTF32.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_Identifier.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_LocalisedStrings.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_NewLine.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_String.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_StringArray.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPairArray.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_StringPool.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\text\beast_TextDiff.h">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ChildProcess.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_CriticalSection.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_DynamicLibrary.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_InterProcessLock.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_Process.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedLock.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedReadLock.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ScopedWriteLock.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_SpinLock.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_Thread.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadLocalValue.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_ThreadPool.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\threads\beast_WaitableEvent.h">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\time\beast_PerformanceCounter.h">
|
||||||
|
<Filter>beast_core\time</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\time\beast_RelativeTime.h">
|
||||||
|
<Filter>beast_core\time</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\time\beast_Time.h">
|
||||||
|
<Filter>beast_core\time</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.h">
|
||||||
|
<Filter>beast_core\unit_tests</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlDocument.h">
|
||||||
|
<Filter>beast_core\xml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\xml\beast_XmlElement.h">
|
||||||
|
<Filter>beast_core\xml</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.h">
|
||||||
|
<Filter>beast_core\zip</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.h">
|
||||||
|
<Filter>beast_core\zip</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\beast_ZipFile.h">
|
||||||
|
<Filter>beast_core\zip</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\crc32.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\deflate.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffast.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inffixed.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inflate.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\inftrees.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\trees.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zconf.in.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zlib.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\modules\beast_core\zip\zlib\zutil.h">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="BeastConfig.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
|
||||||
<Filter>beast_core</Filter>
|
<Filter>beast_core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_AbstractFifo.cpp">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_DynamicObject.cpp">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_NamedValueSet.cpp">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_PropertySet.cpp">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\containers\beast_Variant.cpp">
|
||||||
|
<Filter>beast_core\containers</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_DirectoryIterator.cpp">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_File.cpp">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_FileInputStream.cpp">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_FileOutputStream.cpp">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_FileSearchPath.cpp">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\files\beast_TemporaryFile.cpp">
|
||||||
|
<Filter>beast_core\files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\json\beast_JSON.cpp">
|
||||||
|
<Filter>beast_core\json</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\logging\beast_FileLogger.cpp">
|
||||||
|
<Filter>beast_core\logging</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\logging\beast_Logger.cpp">
|
||||||
|
<Filter>beast_core\logging</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\maths\beast_BigInteger.cpp">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\maths\beast_Expression.cpp">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\maths\beast_Random.cpp">
|
||||||
|
<Filter>beast_core\maths</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\memory\beast_MemoryBlock.cpp">
|
||||||
|
<Filter>beast_core\memory</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\misc\beast_Result.cpp">
|
||||||
|
<Filter>beast_core\misc</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\misc\beast_Uuid.cpp">
|
||||||
|
<Filter>beast_core\misc</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Files.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Misc.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Network.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_SystemStats.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_android_Threads.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Files.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Network.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_SystemStats.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_linux_Threads.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_posix_NamedPipe.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Files.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Network.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Registry.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_SystemStats.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\native\beast_win32_Threads.cpp">
|
||||||
|
<Filter>beast_core\native</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_IPAddress.cpp">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_MACAddress.cpp">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_NamedPipe.cpp">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_Socket.cpp">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\network\beast_URL.cpp">
|
||||||
|
<Filter>beast_core\network</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_BufferedInputStream.cpp">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_FileInputSource.cpp">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_InputStream.cpp">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryInputStream.cpp">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_MemoryOutputStream.cpp">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_OutputStream.cpp">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\streams\beast_SubregionStream.cpp">
|
||||||
|
<Filter>beast_core\streams</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\system\beast_SystemStats.cpp">
|
||||||
|
<Filter>beast_core\system</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_CharacterFunctions.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_Identifier.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_LocalisedStrings.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_String.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_StringArray.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPairArray.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_StringPool.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\text\beast_TextDiff.cpp">
|
||||||
|
<Filter>beast_core\text</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_ChildProcess.cpp">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_HighResolutionTimer.cpp">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_ReadWriteLock.cpp">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_Thread.cpp">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_ThreadPool.cpp">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\threads\beast_TimeSliceThread.cpp">
|
||||||
|
<Filter>beast_core\threads</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\time\beast_PerformanceCounter.cpp">
|
||||||
|
<Filter>beast_core\time</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\time\beast_RelativeTime.cpp">
|
||||||
|
<Filter>beast_core\time</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\time\beast_Time.cpp">
|
||||||
|
<Filter>beast_core\time</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\unit_tests\beast_UnitTest.cpp">
|
||||||
|
<Filter>beast_core\unit_tests</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlDocument.cpp">
|
||||||
|
<Filter>beast_core\xml</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\xml\beast_XmlElement.cpp">
|
||||||
|
<Filter>beast_core\xml</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPCompressorOutputStream.cpp">
|
||||||
|
<Filter>beast_core\zip</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\beast_GZIPDecompressorInputStream.cpp">
|
||||||
|
<Filter>beast_core\zip</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\beast_ZipFile.cpp">
|
||||||
|
<Filter>beast_core\zip</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\adler32.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\compress.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\crc32.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\deflate.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\infback.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inffast.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inflate.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\inftrees.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\trees.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\uncompr.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\modules\beast_core\zip\zlib\zutil.c">
|
||||||
|
<Filter>beast_core\zip\zlib</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -6,3 +6,9 @@ No external dependencies, no complicated build steps.
|
|||||||
Things people need for building peer to peer, concurrent, cryptographic systems.
|
Things people need for building peer to peer, concurrent, cryptographic systems.
|
||||||
|
|
||||||
The hope is that this will replace the use of boost and other cumbersome jalopies.
|
The hope is that this will replace the use of boost and other cumbersome jalopies.
|
||||||
|
|
||||||
|
## JUCE
|
||||||
|
|
||||||
|
Beast is based on the juce_core module which is provided under the ISC
|
||||||
|
license. More information about JUCE is available at
|
||||||
|
http://www.juce.com
|
||||||
|
|||||||
@@ -1,2 +1,213 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#if defined (BEAST_CORE_BEASTHEADER) && ! BEAST_AMALGAMATED_INCLUDE
|
||||||
|
/* When you add this cpp file to your project, you mustn't include it in a file where you've
|
||||||
|
already included any other headers - just put it inside a file on its own, possibly with your config
|
||||||
|
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
|
||||||
|
header files that the compiler may be using.
|
||||||
|
*/
|
||||||
|
#error "Incorrect use of BEAST cpp file"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Your project must contain a BeastConfig.h file with your project-specific settings in it,
|
||||||
|
// and your header search path must make it accessible to the module's files.
|
||||||
|
#include "BeastConfig.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#include "native/beast_BasicNativeHeaders.h"
|
||||||
#include "beast_core.h"
|
#include "beast_core.h"
|
||||||
|
|
||||||
|
#include <locale>
|
||||||
|
#include <cctype>
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
|
||||||
|
#if ! BEAST_ANDROID
|
||||||
|
#include <cwctype>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_WINDOWS
|
||||||
|
#include <ctime>
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
#if ! BEAST_MINGW
|
||||||
|
#include <Dbghelp.h>
|
||||||
|
|
||||||
|
#if ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#pragma comment (lib, "DbgHelp.lib")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_MINGW
|
||||||
|
#include <ws2spi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#if BEAST_LINUX || BEAST_ANDROID
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_LINUX
|
||||||
|
#include <langinfo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#if ! BEAST_ANDROID
|
||||||
|
#include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_MAC || BEAST_IOS
|
||||||
|
#include <xlocale.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_ANDROID
|
||||||
|
#include <android/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace beast
|
||||||
|
{
|
||||||
|
|
||||||
|
#include "containers/beast_AbstractFifo.cpp"
|
||||||
|
#include "containers/beast_DynamicObject.cpp"
|
||||||
|
#include "containers/beast_NamedValueSet.cpp"
|
||||||
|
#include "containers/beast_PropertySet.cpp"
|
||||||
|
#include "containers/beast_Variant.cpp"
|
||||||
|
#include "files/beast_DirectoryIterator.cpp"
|
||||||
|
#include "files/beast_File.cpp"
|
||||||
|
#include "files/beast_FileInputStream.cpp"
|
||||||
|
#include "files/beast_FileOutputStream.cpp"
|
||||||
|
#include "files/beast_FileSearchPath.cpp"
|
||||||
|
#include "files/beast_TemporaryFile.cpp"
|
||||||
|
#include "json/beast_JSON.cpp"
|
||||||
|
#include "logging/beast_FileLogger.cpp"
|
||||||
|
#include "logging/beast_Logger.cpp"
|
||||||
|
#include "maths/beast_BigInteger.cpp"
|
||||||
|
#include "maths/beast_Expression.cpp"
|
||||||
|
#include "maths/beast_Random.cpp"
|
||||||
|
#include "memory/beast_MemoryBlock.cpp"
|
||||||
|
#include "misc/beast_Result.cpp"
|
||||||
|
#include "misc/beast_Uuid.cpp"
|
||||||
|
#include "network/beast_MACAddress.cpp"
|
||||||
|
#include "network/beast_NamedPipe.cpp"
|
||||||
|
#include "network/beast_Socket.cpp"
|
||||||
|
#include "network/beast_URL.cpp"
|
||||||
|
#include "network/beast_IPAddress.cpp"
|
||||||
|
#include "streams/beast_BufferedInputStream.cpp"
|
||||||
|
#include "streams/beast_FileInputSource.cpp"
|
||||||
|
#include "streams/beast_InputStream.cpp"
|
||||||
|
#include "streams/beast_MemoryInputStream.cpp"
|
||||||
|
#include "streams/beast_MemoryOutputStream.cpp"
|
||||||
|
#include "streams/beast_OutputStream.cpp"
|
||||||
|
#include "streams/beast_SubregionStream.cpp"
|
||||||
|
#include "system/beast_SystemStats.cpp"
|
||||||
|
#include "text/beast_CharacterFunctions.cpp"
|
||||||
|
#include "text/beast_Identifier.cpp"
|
||||||
|
#include "text/beast_LocalisedStrings.cpp"
|
||||||
|
#include "text/beast_String.cpp"
|
||||||
|
#include "text/beast_StringArray.cpp"
|
||||||
|
#include "text/beast_StringPairArray.cpp"
|
||||||
|
#include "text/beast_StringPool.cpp"
|
||||||
|
#include "text/beast_TextDiff.cpp"
|
||||||
|
#include "threads/beast_ChildProcess.cpp"
|
||||||
|
#include "threads/beast_ReadWriteLock.cpp"
|
||||||
|
#include "threads/beast_Thread.cpp"
|
||||||
|
#include "threads/beast_ThreadPool.cpp"
|
||||||
|
#include "threads/beast_TimeSliceThread.cpp"
|
||||||
|
#include "time/beast_PerformanceCounter.cpp"
|
||||||
|
#include "time/beast_RelativeTime.cpp"
|
||||||
|
#include "time/beast_Time.cpp"
|
||||||
|
#include "unit_tests/beast_UnitTest.cpp"
|
||||||
|
#include "xml/beast_XmlDocument.cpp"
|
||||||
|
#include "xml/beast_XmlElement.cpp"
|
||||||
|
#include "zip/beast_GZIPDecompressorInputStream.cpp"
|
||||||
|
#include "zip/beast_GZIPCompressorOutputStream.cpp"
|
||||||
|
#include "zip/beast_ZipFile.cpp"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_MAC || BEAST_IOS
|
||||||
|
#include "native/beast_osx_ObjCHelpers.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_ANDROID
|
||||||
|
#include "native/beast_android_JNIHelpers.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ! BEAST_WINDOWS
|
||||||
|
#include "native/beast_posix_SharedCode.h"
|
||||||
|
#include "native/beast_posix_NamedPipe.cpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_MAC || BEAST_IOS
|
||||||
|
#include "native/beast_mac_Files.mm"
|
||||||
|
#include "native/beast_mac_Network.mm"
|
||||||
|
#include "native/beast_mac_Strings.mm"
|
||||||
|
#include "native/beast_mac_SystemStats.mm"
|
||||||
|
#include "native/beast_mac_Threads.mm"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif BEAST_WINDOWS
|
||||||
|
#include "native/beast_win32_ComSmartPtr.h"
|
||||||
|
#include "native/beast_win32_Files.cpp"
|
||||||
|
#include "native/beast_win32_Network.cpp"
|
||||||
|
#include "native/beast_win32_Registry.cpp"
|
||||||
|
#include "native/beast_win32_SystemStats.cpp"
|
||||||
|
#include "native/beast_win32_Threads.cpp"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif BEAST_LINUX
|
||||||
|
#include "native/beast_linux_Files.cpp"
|
||||||
|
#include "native/beast_linux_Network.cpp"
|
||||||
|
#include "native/beast_linux_SystemStats.cpp"
|
||||||
|
#include "native/beast_linux_Threads.cpp"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif BEAST_ANDROID
|
||||||
|
#include "native/beast_android_Files.cpp"
|
||||||
|
#include "native/beast_android_Misc.cpp"
|
||||||
|
#include "native/beast_android_Network.cpp"
|
||||||
|
#include "native/beast_android_SystemStats.cpp"
|
||||||
|
#include "native/beast_android_Threads.cpp"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "threads/beast_HighResolutionTimer.cpp"
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,440 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
#include <algorithm>
|
Portions of this file are from JUCE.
|
||||||
#include <cstdlib>
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_CORE_BEASTHEADER
|
||||||
|
#define BEAST_CORE_BEASTHEADER
|
||||||
|
|
||||||
|
#ifndef BEAST_BEASTCONFIG_HEADER
|
||||||
|
/* If you fail to make sure that all your compile units are building Beast with the same set of
|
||||||
|
option flags, then there's a risk that different compile units will treat the classes as having
|
||||||
|
different memory layouts, leading to very nasty memory corruption errors when they all get
|
||||||
|
linked together. That's why it's best to always include the BeastConfig.h file before any beast headers.
|
||||||
|
*/
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma message ("Have you included your BeastConfig.h file before including the Beast headers?")
|
||||||
|
#else
|
||||||
|
#warning "Have you included your BeastConfig.h file before including the Beast headers?"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#include "system/beast_TargetPlatform.h"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: BEAST_FORCE_DEBUG
|
||||||
|
|
||||||
|
Normally, BEAST_DEBUG is set to 1 or 0 based on compiler and project settings,
|
||||||
|
but if you define this value, you can override this to force it to be true or false.
|
||||||
|
*/
|
||||||
|
#ifndef BEAST_FORCE_DEBUG
|
||||||
|
//#define BEAST_FORCE_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: BEAST_LOG_ASSERTIONS
|
||||||
|
|
||||||
|
If this flag is enabled, the the bassert and jassertfalse 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
|
||||||
|
release build.
|
||||||
|
|
||||||
|
@see bassert, jassertfalse, Logger
|
||||||
|
*/
|
||||||
|
#ifndef BEAST_LOG_ASSERTIONS
|
||||||
|
#if BEAST_ANDROID
|
||||||
|
#define BEAST_LOG_ASSERTIONS 1
|
||||||
|
#else
|
||||||
|
#define BEAST_LOG_ASSERTIONS 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: BEAST_CHECK_MEMORY_LEAKS
|
||||||
|
|
||||||
|
Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
|
||||||
|
class and the BEAST_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
|
||||||
|
*/
|
||||||
|
#if BEAST_DEBUG && ! defined (BEAST_CHECK_MEMORY_LEAKS)
|
||||||
|
#define BEAST_CHECK_MEMORY_LEAKS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
|
||||||
|
In a Visual C++ build, this can be used to stop the required system libs being
|
||||||
|
automatically added to the link stage.
|
||||||
|
*/
|
||||||
|
#ifndef BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#define BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Config: BEAST_INCLUDE_ZLIB_CODE
|
||||||
|
This can be used to disable Beast's embedded 3rd-party zlib code.
|
||||||
|
You might need to tweak this if you're linking to an external zlib library in your app,
|
||||||
|
but for normal apps, this option should be left alone.
|
||||||
|
|
||||||
|
If you disable this, you might also want to set a value for BEAST_ZLIB_INCLUDE_PATH, to
|
||||||
|
specify the path where your zlib headers live.
|
||||||
|
*/
|
||||||
|
#ifndef BEAST_INCLUDE_ZLIB_CODE
|
||||||
|
#define BEAST_INCLUDE_ZLIB_CODE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BEAST_ZLIB_INCLUDE_PATH
|
||||||
|
#define BEAST_ZLIB_INCLUDE_PATH <zlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Config: BEAST_CATCH_UNHANDLED_EXCEPTIONS
|
||||||
|
If enabled, this will add some exception-catching code to forward unhandled exceptions
|
||||||
|
to your BEASTApplication::unhandledException() callback.
|
||||||
|
*/
|
||||||
|
#ifndef BEAST_CATCH_UNHANDLED_EXCEPTIONS
|
||||||
|
//#define BEAST_CATCH_UNHANDLED_EXCEPTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//=============================================================================
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4786) // (long class name warning)
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#pragma warning (disable: 1125)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "system/beast_StandardHeader.h"
|
||||||
|
|
||||||
namespace beast
|
namespace beast
|
||||||
{
|
{
|
||||||
|
|
||||||
#include "memory/beast_ScopedPointer.h"
|
// START_AUTOINCLUDE containers, files, json, logging, maths, memory, misc, network,
|
||||||
|
// streams, system, text, threads, time, unit_tests, xml, zip
|
||||||
|
#ifndef BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||||
|
#include "containers/beast_AbstractFifo.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_ARRAY_BEASTHEADER
|
||||||
|
#include "containers/beast_Array.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||||
|
#include "containers/beast_ArrayAllocationBase.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||||
|
#include "containers/beast_DynamicObject.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||||
|
#include "containers/beast_ElementComparator.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_HASHMAP_BEASTHEADER
|
||||||
|
#include "containers/beast_HashMap.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||||
|
#include "containers/beast_LinkedListPointer.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_NAMEDVALUESET_BEASTHEADER
|
||||||
|
#include "containers/beast_NamedValueSet.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_OWNEDARRAY_BEASTHEADER
|
||||||
|
#include "containers/beast_OwnedArray.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_PROPERTYSET_BEASTHEADER
|
||||||
|
#include "containers/beast_PropertySet.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||||
|
#include "containers/beast_ReferenceCountedArray.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||||
|
#include "containers/beast_ScopedValueSetter.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SORTEDSET_BEASTHEADER
|
||||||
|
#include "containers/beast_SortedSet.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SPARSESET_BEASTHEADER
|
||||||
|
#include "containers/beast_SparseSet.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_VARIANT_BEASTHEADER
|
||||||
|
#include "containers/beast_Variant.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||||
|
#include "files/beast_DirectoryIterator.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_FILE_BEASTHEADER
|
||||||
|
#include "files/beast_File.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||||
|
#include "files/beast_FileInputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||||
|
#include "files/beast_FileOutputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_FILESEARCHPATH_BEASTHEADER
|
||||||
|
#include "files/beast_FileSearchPath.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||||
|
#include "files/beast_MemoryMappedFile.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_TEMPORARYFILE_BEASTHEADER
|
||||||
|
#include "files/beast_TemporaryFile.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_JSON_BEASTHEADER
|
||||||
|
#include "json/beast_JSON.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_FILELOGGER_BEASTHEADER
|
||||||
|
#include "logging/beast_FileLogger.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_LOGGER_BEASTHEADER
|
||||||
|
#include "logging/beast_Logger.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_BIGINTEGER_BEASTHEADER
|
||||||
|
#include "maths/beast_BigInteger.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_EXPRESSION_BEASTHEADER
|
||||||
|
#include "maths/beast_Expression.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||||
|
#include "maths/beast_MathsFunctions.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_RANDOM_BEASTHEADER
|
||||||
|
#include "maths/beast_Random.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_RANGE_BEASTHEADER
|
||||||
|
#include "maths/beast_Range.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_ATOMIC_BEASTHEADER
|
||||||
|
#include "memory/beast_Atomic.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_BYTEORDER_BEASTHEADER
|
||||||
|
#include "memory/beast_ByteOrder.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_HEAPBLOCK_BEASTHEADER
|
||||||
|
#include "memory/beast_HeapBlock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||||
|
#include "memory/beast_LeakedObjectDetector.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_MEMORY_BEASTHEADER
|
||||||
|
#include "memory/beast_Memory.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_MEMORYBLOCK_BEASTHEADER
|
||||||
|
#include "memory/beast_MemoryBlock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||||
|
#include "memory/beast_OptionalScopedPointer.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||||
|
#include "memory/beast_ReferenceCountedObject.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||||
|
#include "memory/beast_ScopedPointer.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SINGLETON_BEASTHEADER
|
||||||
|
#include "memory/beast_Singleton.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_WEAKREFERENCE_BEASTHEADER
|
||||||
|
#include "memory/beast_WeakReference.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_RESULT_BEASTHEADER
|
||||||
|
#include "misc/beast_Result.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_UUID_BEASTHEADER
|
||||||
|
#include "misc/beast_Uuid.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||||
|
#include "misc/beast_WindowsRegistry.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_IPADDRESS_BEASTHEADER
|
||||||
|
#include "network/beast_IPAddress.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_MACADDRESS_BEASTHEADER
|
||||||
|
#include "network/beast_MACAddress.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_NAMEDPIPE_BEASTHEADER
|
||||||
|
#include "network/beast_NamedPipe.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SOCKET_BEASTHEADER
|
||||||
|
#include "network/beast_Socket.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_URL_BEASTHEADER
|
||||||
|
#include "network/beast_URL.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_BUFFEREDINPUTSTREAM_BEASTHEADER
|
||||||
|
#include "streams/beast_BufferedInputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_FILEINPUTSOURCE_BEASTHEADER
|
||||||
|
#include "streams/beast_FileInputSource.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_INPUTSOURCE_BEASTHEADER
|
||||||
|
#include "streams/beast_InputSource.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_INPUTSTREAM_BEASTHEADER
|
||||||
|
#include "streams/beast_InputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_MEMORYINPUTSTREAM_BEASTHEADER
|
||||||
|
#include "streams/beast_MemoryInputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_MEMORYOUTPUTSTREAM_BEASTHEADER
|
||||||
|
#include "streams/beast_MemoryOutputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_OUTPUTSTREAM_BEASTHEADER
|
||||||
|
#include "streams/beast_OutputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SUBREGIONSTREAM_BEASTHEADER
|
||||||
|
#include "streams/beast_SubregionStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_PLATFORMDEFS_BEASTHEADER
|
||||||
|
#include "system/beast_PlatformDefs.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_STANDARDHEADER_BEASTHEADER
|
||||||
|
#include "system/beast_StandardHeader.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SYSTEMSTATS_BEASTHEADER
|
||||||
|
#include "system/beast_SystemStats.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_TARGETPLATFORM_BEASTHEADER
|
||||||
|
#include "system/beast_TargetPlatform.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_CHARACTERFUNCTIONS_BEASTHEADER
|
||||||
|
#include "text/beast_CharacterFunctions.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_CHARPOINTER_ASCII_BEASTHEADER
|
||||||
|
#include "text/beast_CharPointer_ASCII.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_CHARPOINTER_UTF16_BEASTHEADER
|
||||||
|
#include "text/beast_CharPointer_UTF16.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_CHARPOINTER_UTF32_BEASTHEADER
|
||||||
|
#include "text/beast_CharPointer_UTF32.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_CHARPOINTER_UTF8_BEASTHEADER
|
||||||
|
#include "text/beast_CharPointer_UTF8.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_IDENTIFIER_BEASTHEADER
|
||||||
|
#include "text/beast_Identifier.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_LOCALISEDSTRINGS_BEASTHEADER
|
||||||
|
#include "text/beast_LocalisedStrings.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_NEWLINE_BEASTHEADER
|
||||||
|
#include "text/beast_NewLine.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_STRING_BEASTHEADER
|
||||||
|
#include "text/beast_String.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_STRINGARRAY_BEASTHEADER
|
||||||
|
#include "text/beast_StringArray.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_STRINGPAIRARRAY_BEASTHEADER
|
||||||
|
#include "text/beast_StringPairArray.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_STRINGPOOL_BEASTHEADER
|
||||||
|
#include "text/beast_StringPool.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_TEXTDIFF_BEASTHEADER
|
||||||
|
#include "text/beast_TextDiff.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_CHILDPROCESS_BEASTHEADER
|
||||||
|
#include "threads/beast_ChildProcess.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_CRITICALSECTION_BEASTHEADER
|
||||||
|
#include "threads/beast_CriticalSection.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_DYNAMICLIBRARY_BEASTHEADER
|
||||||
|
#include "threads/beast_DynamicLibrary.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_HIGHRESOLUTIONTIMER_BEASTHEADER
|
||||||
|
#include "threads/beast_HighResolutionTimer.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_INTERPROCESSLOCK_BEASTHEADER
|
||||||
|
#include "threads/beast_InterProcessLock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_PROCESS_BEASTHEADER
|
||||||
|
#include "threads/beast_Process.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_READWRITELOCK_BEASTHEADER
|
||||||
|
#include "threads/beast_ReadWriteLock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SCOPEDLOCK_BEASTHEADER
|
||||||
|
#include "threads/beast_ScopedLock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SCOPEDREADLOCK_BEASTHEADER
|
||||||
|
#include "threads/beast_ScopedReadLock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SCOPEDWRITELOCK_BEASTHEADER
|
||||||
|
#include "threads/beast_ScopedWriteLock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_SPINLOCK_BEASTHEADER
|
||||||
|
#include "threads/beast_SpinLock.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_THREAD_BEASTHEADER
|
||||||
|
#include "threads/beast_Thread.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_THREADLOCALVALUE_BEASTHEADER
|
||||||
|
#include "threads/beast_ThreadLocalValue.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_THREADPOOL_BEASTHEADER
|
||||||
|
#include "threads/beast_ThreadPool.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_TIMESLICETHREAD_BEASTHEADER
|
||||||
|
#include "threads/beast_TimeSliceThread.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_WAITABLEEVENT_BEASTHEADER
|
||||||
|
#include "threads/beast_WaitableEvent.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_PERFORMANCECOUNTER_BEASTHEADER
|
||||||
|
#include "time/beast_PerformanceCounter.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_RELATIVETIME_BEASTHEADER
|
||||||
|
#include "time/beast_RelativeTime.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_TIME_BEASTHEADER
|
||||||
|
#include "time/beast_Time.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_UNITTEST_BEASTHEADER
|
||||||
|
#include "unit_tests/beast_UnitTest.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_XMLDOCUMENT_BEASTHEADER
|
||||||
|
#include "xml/beast_XmlDocument.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_XMLELEMENT_BEASTHEADER
|
||||||
|
#include "xml/beast_XmlElement.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_GZIPCOMPRESSOROUTPUTSTREAM_BEASTHEADER
|
||||||
|
#include "zip/beast_GZIPCompressorOutputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_GZIPDECOMPRESSORINPUTSTREAM_BEASTHEADER
|
||||||
|
#include "zip/beast_GZIPDecompressorInputStream.h"
|
||||||
|
#endif
|
||||||
|
#ifndef BEAST_ZIPFILE_BEASTHEADER
|
||||||
|
#include "zip/beast_ZipFile.h"
|
||||||
|
#endif
|
||||||
|
// END_AUTOINCLUDE
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BEAST_CORE_BEASTHEADER
|
||||||
|
|||||||
@@ -1 +1,24 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
#include "beast_core.cpp"
|
#include "beast_core.cpp"
|
||||||
|
|||||||
@@ -0,0 +1,229 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
AbstractFifo::AbstractFifo (const int capacity) noexcept
|
||||||
|
: bufferSize (capacity)
|
||||||
|
{
|
||||||
|
bassert (bufferSize > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractFifo::~AbstractFifo() {}
|
||||||
|
|
||||||
|
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
|
||||||
|
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
|
||||||
|
|
||||||
|
int AbstractFifo::getNumReady() const noexcept
|
||||||
|
{
|
||||||
|
const int vs = validStart.get();
|
||||||
|
const int ve = validEnd.get();
|
||||||
|
return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::reset() noexcept
|
||||||
|
{
|
||||||
|
validEnd = 0;
|
||||||
|
validStart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::setTotalSize (int newSize) noexcept
|
||||||
|
{
|
||||||
|
bassert (newSize > 0);
|
||||||
|
reset();
|
||||||
|
bufferSize = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||||
|
{
|
||||||
|
const int vs = validStart.get();
|
||||||
|
const int ve = validEnd.value;
|
||||||
|
|
||||||
|
const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
|
||||||
|
numToWrite = bmin (numToWrite, freeSpace - 1);
|
||||||
|
|
||||||
|
if (numToWrite <= 0)
|
||||||
|
{
|
||||||
|
startIndex1 = 0;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = 0;
|
||||||
|
blockSize2 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startIndex1 = ve;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = bmin (bufferSize - ve, numToWrite);
|
||||||
|
numToWrite -= blockSize1;
|
||||||
|
blockSize2 = numToWrite <= 0 ? 0 : bmin (numToWrite, vs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::finishedWrite (int numWritten) noexcept
|
||||||
|
{
|
||||||
|
bassert (numWritten >= 0 && numWritten < bufferSize);
|
||||||
|
int newEnd = validEnd.value + numWritten;
|
||||||
|
if (newEnd >= bufferSize)
|
||||||
|
newEnd -= bufferSize;
|
||||||
|
|
||||||
|
validEnd = newEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||||
|
{
|
||||||
|
const int vs = validStart.value;
|
||||||
|
const int ve = validEnd.get();
|
||||||
|
|
||||||
|
const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||||
|
numWanted = bmin (numWanted, numReady);
|
||||||
|
|
||||||
|
if (numWanted <= 0)
|
||||||
|
{
|
||||||
|
startIndex1 = 0;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = 0;
|
||||||
|
blockSize2 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startIndex1 = vs;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = bmin (bufferSize - vs, numWanted);
|
||||||
|
numWanted -= blockSize1;
|
||||||
|
blockSize2 = numWanted <= 0 ? 0 : bmin (numWanted, ve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::finishedRead (int numRead) noexcept
|
||||||
|
{
|
||||||
|
bassert (numRead >= 0 && numRead <= bufferSize);
|
||||||
|
|
||||||
|
int newStart = validStart.value + numRead;
|
||||||
|
if (newStart >= bufferSize)
|
||||||
|
newStart -= bufferSize;
|
||||||
|
|
||||||
|
validStart = newStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_UNIT_TESTS
|
||||||
|
|
||||||
|
class AbstractFifoTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AbstractFifoTests() : UnitTest ("Abstract Fifo") {}
|
||||||
|
|
||||||
|
class WriteThread : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WriteThread (AbstractFifo& fifo_, int* buffer_)
|
||||||
|
: Thread ("fifo writer"), fifo (fifo_), buffer (buffer_)
|
||||||
|
{
|
||||||
|
startThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
~WriteThread()
|
||||||
|
{
|
||||||
|
stopThread (5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
Random r;
|
||||||
|
|
||||||
|
while (! threadShouldExit())
|
||||||
|
{
|
||||||
|
int num = r.nextInt (2000) + 1;
|
||||||
|
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
fifo.prepareToWrite (num, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
bassert (size1 >= 0 && size2 >= 0);
|
||||||
|
bassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
|
||||||
|
bassert (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()));
|
||||||
|
|
||||||
|
for (int i = 0; i < size1; ++i)
|
||||||
|
buffer [start1 + i] = n++;
|
||||||
|
|
||||||
|
for (int i = 0; i < size2; ++i)
|
||||||
|
buffer [start2 + i] = n++;
|
||||||
|
|
||||||
|
fifo.finishedWrite (size1 + size2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbstractFifo& fifo;
|
||||||
|
int* buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
void runTest()
|
||||||
|
{
|
||||||
|
beginTest ("AbstractFifo");
|
||||||
|
|
||||||
|
int buffer [5000];
|
||||||
|
AbstractFifo fifo (numElementsInArray (buffer));
|
||||||
|
|
||||||
|
WriteThread writer (fifo, buffer);
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
Random r;
|
||||||
|
|
||||||
|
for (int count = 100000; --count >= 0;)
|
||||||
|
{
|
||||||
|
int num = r.nextInt (6000) + 1;
|
||||||
|
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
fifo.prepareToRead (num, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (! (size1 >= 0 && size2 >= 0)
|
||||||
|
&& (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()))
|
||||||
|
&& (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize())))
|
||||||
|
{
|
||||||
|
expect (false, "prepareToRead returned -ve values");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool failed = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < size1; ++i)
|
||||||
|
failed = (buffer [start1 + i] != n++) || failed;
|
||||||
|
|
||||||
|
for (int i = 0; i < size2; ++i)
|
||||||
|
failed = (buffer [start2 + i] != n++) || failed;
|
||||||
|
|
||||||
|
if (failed)
|
||||||
|
{
|
||||||
|
expect (false, "read values were incorrect");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fifo.finishedRead (size1 + size2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static AbstractFifoTests fifoUnitTests;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||||
|
#define BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../memory/beast_Atomic.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Encapsulates the logic required to implement a lock-free FIFO.
|
||||||
|
|
||||||
|
This class handles the logic needed when building a single-reader, single-writer FIFO.
|
||||||
|
|
||||||
|
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
|
||||||
|
its position and status when reading or writing to it.
|
||||||
|
|
||||||
|
To use it, you can call prepareToWrite() to determine the position within your own buffer that
|
||||||
|
an incoming block of data should be stored, and prepareToRead() to find out when the next
|
||||||
|
outgoing block should be read from.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
@code
|
||||||
|
class MyFifo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyFifo() : abstractFifo (1024)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToFifo (const int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (myBuffer + start1, someData, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||||
|
|
||||||
|
abstractFifo.finishedWrite (size1 + size2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFromFifo (int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (someData, myBuffer + start1, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||||
|
|
||||||
|
abstractFifo.finishedRead (size1 + size2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbstractFifo abstractFifo;
|
||||||
|
int myBuffer [1024];
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
class BEAST_API AbstractFifo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||||
|
AbstractFifo (int capacity) noexcept;
|
||||||
|
|
||||||
|
/** Destructor */
|
||||||
|
~AbstractFifo();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the total size of the buffer being managed. */
|
||||||
|
int getTotalSize() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||||
|
int getFreeSpace() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the number of items that can currently be read from the buffer. */
|
||||||
|
int getNumReady() const noexcept;
|
||||||
|
|
||||||
|
/** Clears the buffer positions, so that it appears empty. */
|
||||||
|
void reset() noexcept;
|
||||||
|
|
||||||
|
/** Changes the buffer's total size.
|
||||||
|
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||||
|
might overlap with a call to any other method in this class!
|
||||||
|
*/
|
||||||
|
void setTotalSize (int newSize) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||||
|
|
||||||
|
Because the section of data that you want to add to the buffer may overlap the end
|
||||||
|
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||||
|
should copy your data into the first one, with any remaining data spilling over into
|
||||||
|
the second.
|
||||||
|
|
||||||
|
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||||
|
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
|
||||||
|
may decide to keep waiting and re-trying the method until there's enough space available.
|
||||||
|
|
||||||
|
After calling this method, if you choose to write your data into the blocks returned, you
|
||||||
|
must call finishedWrite() to tell the FIFO how much data you actually added.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
@code
|
||||||
|
void addToFifo (const int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (myBuffer + start1, someData, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||||
|
|
||||||
|
finishedWrite (size1 + size2);
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||||
|
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||||
|
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||||
|
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||||
|
the first block should be written
|
||||||
|
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||||
|
@see finishedWrite
|
||||||
|
*/
|
||||||
|
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||||
|
|
||||||
|
/** Called after writing from the FIFO, to indicate that this many items have been added.
|
||||||
|
@see prepareToWrite
|
||||||
|
*/
|
||||||
|
void finishedWrite (int numWritten) noexcept;
|
||||||
|
|
||||||
|
/** Returns the location within the buffer from which the next block of data should be read.
|
||||||
|
|
||||||
|
Because the section of data that you want to read from the buffer may overlap the end
|
||||||
|
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||||
|
should read from both of them.
|
||||||
|
|
||||||
|
If the number of items you ask for is greater than the amount of data available, then
|
||||||
|
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
|
||||||
|
may decide to keep waiting and re-trying the method until there's enough data available.
|
||||||
|
|
||||||
|
After calling this method, if you choose to read the data, you must call finishedRead() to
|
||||||
|
tell the FIFO how much data you have consumed.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
@code
|
||||||
|
void readFromFifo (int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (someData, myBuffer + start1, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||||
|
|
||||||
|
finishedRead (size1 + size2);
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@param numWanted indicates how many items you'd like to add to the buffer
|
||||||
|
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||||
|
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||||
|
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||||
|
the first block should be written
|
||||||
|
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||||
|
@see finishedRead
|
||||||
|
*/
|
||||||
|
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||||
|
|
||||||
|
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||||
|
@see prepareToRead
|
||||||
|
*/
|
||||||
|
void finishedRead (int numRead) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
int bufferSize;
|
||||||
|
Atomic <int> validStart, validEnd;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_ABSTRACTFIFO_BEASTHEADER
|
||||||
1047
Subtrees/beast/modules/beast_core/containers/beast_Array.h
Normal file
1047
Subtrees/beast/modules/beast_core/containers/beast_Array.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,133 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||||
|
#define BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../memory/beast_HeapBlock.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Implements some basic array storage allocation functions.
|
||||||
|
|
||||||
|
This class isn't really for public use - it's used by the other
|
||||||
|
array classes, but might come in handy for some purposes.
|
||||||
|
|
||||||
|
It inherits from a critical section class to allow the arrays to use
|
||||||
|
the "empty base class optimisation" pattern to reduce their footprint.
|
||||||
|
|
||||||
|
@see Array, OwnedArray, ReferenceCountedArray
|
||||||
|
*/
|
||||||
|
template <class ElementType, class TypeOfCriticalSectionToUse>
|
||||||
|
class ArrayAllocationBase : public TypeOfCriticalSectionToUse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty array. */
|
||||||
|
ArrayAllocationBase() noexcept
|
||||||
|
: numAllocated (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~ArrayAllocationBase() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
ArrayAllocationBase (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
|
||||||
|
: elements (static_cast <HeapBlock <ElementType>&&> (other.elements)),
|
||||||
|
numAllocated (other.numAllocated)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
|
||||||
|
{
|
||||||
|
elements = static_cast <HeapBlock <ElementType>&&> (other.elements);
|
||||||
|
numAllocated = other.numAllocated;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Changes the amount of storage allocated.
|
||||||
|
|
||||||
|
This will retain any data currently held in the array, and either add or
|
||||||
|
remove extra space at the end.
|
||||||
|
|
||||||
|
@param numElements the number of elements that are needed
|
||||||
|
*/
|
||||||
|
void setAllocatedSize (const int numElements)
|
||||||
|
{
|
||||||
|
if (numAllocated != numElements)
|
||||||
|
{
|
||||||
|
if (numElements > 0)
|
||||||
|
elements.realloc ((size_t) numElements);
|
||||||
|
else
|
||||||
|
elements.free();
|
||||||
|
|
||||||
|
numAllocated = numElements;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the amount of storage allocated if it is less than a given amount.
|
||||||
|
|
||||||
|
This will retain any data currently held in the array, but will add
|
||||||
|
extra space at the end to make sure there it's at least as big as the size
|
||||||
|
passed in. If it's already bigger, no action is taken.
|
||||||
|
|
||||||
|
@param minNumElements the minimum number of elements that are needed
|
||||||
|
*/
|
||||||
|
void ensureAllocatedSize (const int minNumElements)
|
||||||
|
{
|
||||||
|
if (minNumElements > numAllocated)
|
||||||
|
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Minimises the amount of storage allocated so that it's no more than
|
||||||
|
the given number of elements.
|
||||||
|
*/
|
||||||
|
void shrinkToNoMoreThan (const int maxNumElements)
|
||||||
|
{
|
||||||
|
if (maxNumElements < numAllocated)
|
||||||
|
setAllocatedSize (maxNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swap the contents of two objects. */
|
||||||
|
void swapWith (ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
|
||||||
|
{
|
||||||
|
elements.swapWith (other.elements);
|
||||||
|
std::swap (numAllocated, other.numAllocated);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
HeapBlock <ElementType> elements;
|
||||||
|
int numAllocated;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (ArrayAllocationBase)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_ARRAYALLOCATIONBASE_BEASTHEADER
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
DynamicObject::DynamicObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicObject::~DynamicObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynamicObject::hasProperty (const Identifier& propertyName) const
|
||||||
|
{
|
||||||
|
const var* const v = properties.getVarPointer (propertyName);
|
||||||
|
return v != nullptr && ! v->isMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
var DynamicObject::getProperty (const Identifier& propertyName) const
|
||||||
|
{
|
||||||
|
return properties [propertyName];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::setProperty (const Identifier& propertyName, const var& newValue)
|
||||||
|
{
|
||||||
|
properties.set (propertyName, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::removeProperty (const Identifier& propertyName)
|
||||||
|
{
|
||||||
|
properties.remove (propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynamicObject::hasMethod (const Identifier& methodName) const
|
||||||
|
{
|
||||||
|
return getProperty (methodName).isMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
var DynamicObject::invokeMethod (const Identifier& methodName,
|
||||||
|
const var* parameters,
|
||||||
|
int numParameters)
|
||||||
|
{
|
||||||
|
return properties [methodName].invokeMethod (this, parameters, numParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::setMethod (const Identifier& name,
|
||||||
|
var::MethodFunction methodFunction)
|
||||||
|
{
|
||||||
|
properties.set (name, var (methodFunction));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::clear()
|
||||||
|
{
|
||||||
|
properties.clear();
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||||
|
#define BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_NamedValueSet.h"
|
||||||
|
#include "../memory/beast_ReferenceCountedObject.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents a dynamically implemented object.
|
||||||
|
|
||||||
|
This class is primarily intended for wrapping scripting language objects,
|
||||||
|
but could be used for other purposes.
|
||||||
|
|
||||||
|
An instance of a DynamicObject can be used to store named properties, and
|
||||||
|
by subclassing hasMethod() and invokeMethod(), you can give your object
|
||||||
|
methods.
|
||||||
|
*/
|
||||||
|
class BEAST_API DynamicObject : public ReferenceCountedObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
DynamicObject();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~DynamicObject();
|
||||||
|
|
||||||
|
typedef ReferenceCountedObjectPtr<DynamicObject> Ptr;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the object has a property with this name.
|
||||||
|
Note that if the property is actually a method, this will return false.
|
||||||
|
*/
|
||||||
|
virtual bool hasProperty (const Identifier& propertyName) const;
|
||||||
|
|
||||||
|
/** Returns a named property.
|
||||||
|
This returns a void if no such property exists.
|
||||||
|
*/
|
||||||
|
virtual var getProperty (const Identifier& propertyName) const;
|
||||||
|
|
||||||
|
/** Sets a named property. */
|
||||||
|
virtual void setProperty (const Identifier& propertyName, const var& newValue);
|
||||||
|
|
||||||
|
/** Removes a named property. */
|
||||||
|
virtual void removeProperty (const Identifier& propertyName);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Checks whether this object has the specified method.
|
||||||
|
|
||||||
|
The default implementation of this just checks whether there's a property
|
||||||
|
with this name that's actually a method, but this can be overridden for
|
||||||
|
building objects with dynamic invocation.
|
||||||
|
*/
|
||||||
|
virtual bool hasMethod (const Identifier& methodName) const;
|
||||||
|
|
||||||
|
/** Invokes a named method on this object.
|
||||||
|
|
||||||
|
The default implementation looks up the named property, and if it's a method
|
||||||
|
call, then it invokes it.
|
||||||
|
|
||||||
|
This method is virtual to allow more dynamic invocation to used for objects
|
||||||
|
where the methods may not already be set as properies.
|
||||||
|
*/
|
||||||
|
virtual var invokeMethod (const Identifier& methodName,
|
||||||
|
const var* parameters,
|
||||||
|
int numParameters);
|
||||||
|
|
||||||
|
/** Sets up a method.
|
||||||
|
|
||||||
|
This is basically the same as calling setProperty (methodName, (var::MethodFunction) myFunction), but
|
||||||
|
helps to avoid accidentally invoking the wrong type of var constructor. It also makes
|
||||||
|
the code easier to read,
|
||||||
|
|
||||||
|
The compiler will probably force you to use an explicit cast your method to a (var::MethodFunction), e.g.
|
||||||
|
@code
|
||||||
|
setMethod ("doSomething", (var::MethodFunction) &MyClass::doSomething);
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
void setMethod (const Identifier& methodName,
|
||||||
|
var::MethodFunction methodFunction);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all properties and methods from the object. */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** Returns the NamedValueSet that holds the object's properties. */
|
||||||
|
NamedValueSet& getProperties() noexcept { return properties; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
NamedValueSet properties;
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (DynamicObject)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_DYNAMICOBJECT_BEASTHEADER
|
||||||
@@ -0,0 +1,274 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||||
|
#define BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Sorts a range of elements in an array.
|
||||||
|
|
||||||
|
The comparator object that is passed-in must define a public method with the following
|
||||||
|
signature:
|
||||||
|
@code
|
||||||
|
int compareElements (ElementType first, ElementType second);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator an object which defines a compareElements() method
|
||||||
|
@param array the array to sort
|
||||||
|
@param firstElement the index of the first element of the range to be sorted
|
||||||
|
@param lastElement the index of the last element in the range that needs
|
||||||
|
sorting (this is inclusive)
|
||||||
|
@param retainOrderOfEquivalentItems if true, the order of items that the
|
||||||
|
comparator deems the same will be maintained - this will be
|
||||||
|
a slower algorithm than if they are allowed to be moved around.
|
||||||
|
|
||||||
|
@see sortArrayRetainingOrder
|
||||||
|
*/
|
||||||
|
template <class ElementType, class ElementComparator>
|
||||||
|
static void sortArray (ElementComparator& comparator,
|
||||||
|
ElementType* const array,
|
||||||
|
int firstElement,
|
||||||
|
int lastElement,
|
||||||
|
const bool retainOrderOfEquivalentItems)
|
||||||
|
{
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
|
||||||
|
if (lastElement > firstElement)
|
||||||
|
{
|
||||||
|
if (retainOrderOfEquivalentItems)
|
||||||
|
{
|
||||||
|
for (int i = firstElement; i < lastElement; ++i)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (array[i], array [i + 1]) > 0)
|
||||||
|
{
|
||||||
|
std::swap (array[i], array[i + 1]);
|
||||||
|
|
||||||
|
if (i > firstElement)
|
||||||
|
i -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int fromStack[30], toStack[30];
|
||||||
|
int stackIndex = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const int size = (lastElement - firstElement) + 1;
|
||||||
|
|
||||||
|
if (size <= 8)
|
||||||
|
{
|
||||||
|
int j = lastElement;
|
||||||
|
int maxIndex;
|
||||||
|
|
||||||
|
while (j > firstElement)
|
||||||
|
{
|
||||||
|
maxIndex = firstElement;
|
||||||
|
for (int k = firstElement + 1; k <= j; ++k)
|
||||||
|
if (comparator.compareElements (array[k], array [maxIndex]) > 0)
|
||||||
|
maxIndex = k;
|
||||||
|
|
||||||
|
std::swap (array[j], array[maxIndex]);
|
||||||
|
--j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int mid = firstElement + (size >> 1);
|
||||||
|
std::swap (array[mid], array[firstElement]);
|
||||||
|
|
||||||
|
int i = firstElement;
|
||||||
|
int j = lastElement + 1;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
while (++i <= lastElement
|
||||||
|
&& comparator.compareElements (array[i], array [firstElement]) <= 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
while (--j > firstElement
|
||||||
|
&& comparator.compareElements (array[j], array [firstElement]) >= 0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
if (j < i)
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::swap (array[i], array[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::swap (array[j], array[firstElement]);
|
||||||
|
|
||||||
|
if (j - 1 - firstElement >= lastElement - i)
|
||||||
|
{
|
||||||
|
if (firstElement + 1 < j)
|
||||||
|
{
|
||||||
|
fromStack [stackIndex] = firstElement;
|
||||||
|
toStack [stackIndex] = j - 1;
|
||||||
|
++stackIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < lastElement)
|
||||||
|
{
|
||||||
|
firstElement = i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (i < lastElement)
|
||||||
|
{
|
||||||
|
fromStack [stackIndex] = i;
|
||||||
|
toStack [stackIndex] = lastElement;
|
||||||
|
++stackIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstElement + 1 < j)
|
||||||
|
{
|
||||||
|
lastElement = j - 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (--stackIndex < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bassert (stackIndex < numElementsInArray (fromStack));
|
||||||
|
|
||||||
|
firstElement = fromStack [stackIndex];
|
||||||
|
lastElement = toStack [stackIndex];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Searches a sorted array of elements, looking for the index at which a specified value
|
||||||
|
should be inserted for it to be in the correct order.
|
||||||
|
|
||||||
|
The comparator object that is passed-in must define a public method with the following
|
||||||
|
signature:
|
||||||
|
@code
|
||||||
|
int compareElements (ElementType first, ElementType second);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator an object which defines a compareElements() method
|
||||||
|
@param array the array to search
|
||||||
|
@param newElement the value that is going to be inserted
|
||||||
|
@param firstElement the index of the first element to search
|
||||||
|
@param lastElement the index of the last element in the range (this is non-inclusive)
|
||||||
|
*/
|
||||||
|
template <class ElementType, class ElementComparator>
|
||||||
|
static int findInsertIndexInSortedArray (ElementComparator& comparator,
|
||||||
|
ElementType* const array,
|
||||||
|
const ElementType newElement,
|
||||||
|
int firstElement,
|
||||||
|
int lastElement)
|
||||||
|
{
|
||||||
|
bassert (firstElement <= lastElement);
|
||||||
|
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
|
||||||
|
while (firstElement < lastElement)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (newElement, array [firstElement]) == 0)
|
||||||
|
{
|
||||||
|
++firstElement;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int halfway = (firstElement + lastElement) >> 1;
|
||||||
|
|
||||||
|
if (halfway == firstElement)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||||
|
++firstElement;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||||
|
{
|
||||||
|
firstElement = halfway;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastElement = halfway;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A simple ElementComparator class that can be used to sort an array of
|
||||||
|
objects that support the '<' operator.
|
||||||
|
|
||||||
|
This will work for primitive types and objects that implement operator<().
|
||||||
|
|
||||||
|
Example: @code
|
||||||
|
Array <int> myArray;
|
||||||
|
DefaultElementComparator<int> sorter;
|
||||||
|
myArray.sort (sorter);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see ElementComparator
|
||||||
|
*/
|
||||||
|
template <class ElementType>
|
||||||
|
class DefaultElementComparator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef PARAMETER_TYPE (ElementType) ParameterType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int compareElements (ParameterType first, ParameterType second)
|
||||||
|
{
|
||||||
|
return (first < second) ? -1 : ((second < first) ? 1 : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_ELEMENTCOMPARATOR_BEASTHEADER
|
||||||
447
Subtrees/beast/modules/beast_core/containers/beast_HashMap.h
Normal file
447
Subtrees/beast/modules/beast_core/containers/beast_HashMap.h
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HASHMAP_BEASTHEADER
|
||||||
|
#define BEAST_HASHMAP_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_OwnedArray.h"
|
||||||
|
#include "beast_LinkedListPointer.h"
|
||||||
|
#include "../memory/beast_ScopedPointer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A simple class to generate hash functions for some primitive types, intended for
|
||||||
|
use with the HashMap class.
|
||||||
|
@see HashMap
|
||||||
|
*/
|
||||||
|
class DefaultHashFunctions
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Generates a simple hash from an integer. */
|
||||||
|
static int generateHash (const int key, const int upperLimit) noexcept { return std::abs (key) % upperLimit; }
|
||||||
|
/** Generates a simple hash from an int64. */
|
||||||
|
static int generateHash (const int64 key, const int upperLimit) noexcept { return std::abs ((int) key) % upperLimit; }
|
||||||
|
/** Generates a simple hash from a string. */
|
||||||
|
static int generateHash (const String& key, const int upperLimit) noexcept { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); }
|
||||||
|
/** Generates a simple hash from a variant. */
|
||||||
|
static int generateHash (const var& key, const int upperLimit) noexcept { return generateHash (key.toString(), upperLimit); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a set of mappings between some key/value pairs.
|
||||||
|
|
||||||
|
The types of the key and value objects are set as template parameters.
|
||||||
|
You can also specify a class to supply a hash function that converts a key value
|
||||||
|
into an hashed integer. This class must have the form:
|
||||||
|
|
||||||
|
@code
|
||||||
|
struct MyHashGenerator
|
||||||
|
{
|
||||||
|
static int generateHash (MyKeyType key, int upperLimit)
|
||||||
|
{
|
||||||
|
// The function must return a value 0 <= x < upperLimit
|
||||||
|
return someFunctionOfMyKeyType (key) % upperLimit;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Like the Array class, the key and value types are expected to be copy-by-value types, so
|
||||||
|
if you define them to be pointer types, this class won't delete the objects that they
|
||||||
|
point to.
|
||||||
|
|
||||||
|
If you don't supply a class for the HashFunctionToUse template parameter, the
|
||||||
|
default one provides some simple mappings for strings and ints.
|
||||||
|
|
||||||
|
@code
|
||||||
|
HashMap<int, String> hash;
|
||||||
|
hash.set (1, "item1");
|
||||||
|
hash.set (2, "item2");
|
||||||
|
|
||||||
|
DBG (hash [1]); // prints "item1"
|
||||||
|
DBG (hash [2]); // prints "item2"
|
||||||
|
|
||||||
|
// This iterates the map, printing all of its key -> value pairs..
|
||||||
|
for (HashMap<int, String>::Iterator i (hash); i.next();)
|
||||||
|
DBG (i.getKey() << " -> " << i.getValue());
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
|
||||||
|
*/
|
||||||
|
template <typename KeyType,
|
||||||
|
typename ValueType,
|
||||||
|
class HashFunctionToUse = DefaultHashFunctions,
|
||||||
|
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
class HashMap
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef PARAMETER_TYPE (KeyType) KeyTypeParameter;
|
||||||
|
typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty hash-map.
|
||||||
|
|
||||||
|
The numberOfSlots parameter specifies the number of hash entries the map will use. This
|
||||||
|
will be the "upperLimit" parameter that is passed to your generateHash() function. The number
|
||||||
|
of hash slots will grow automatically if necessary, or it can be remapped manually using remapTable().
|
||||||
|
*/
|
||||||
|
explicit HashMap (const int numberOfSlots = defaultHashTableSize)
|
||||||
|
: totalNumItems (0)
|
||||||
|
{
|
||||||
|
slots.insertMultiple (0, nullptr, numberOfSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~HashMap()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all values from the map.
|
||||||
|
Note that this will clear the content, but won't affect the number of slots (see
|
||||||
|
remapTable and getNumSlots).
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (int i = slots.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
HashEntry* h = slots.getUnchecked(i);
|
||||||
|
|
||||||
|
while (h != nullptr)
|
||||||
|
{
|
||||||
|
const ScopedPointer<HashEntry> deleter (h);
|
||||||
|
h = h->nextEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
slots.set (i, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalNumItems = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the current number of items in the map. */
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return totalNumItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the value corresponding to a given key.
|
||||||
|
If the map doesn't contain the key, a default instance of the value type is returned.
|
||||||
|
@param keyToLookFor the key of the item being requested
|
||||||
|
*/
|
||||||
|
inline ValueType operator[] (KeyTypeParameter keyToLookFor) const
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
if (entry->key == keyToLookFor)
|
||||||
|
return entry->value;
|
||||||
|
|
||||||
|
return ValueType();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the map contains an item with the specied key. */
|
||||||
|
bool contains (KeyTypeParameter keyToLookFor) const
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
if (entry->key == keyToLookFor)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the hash contains at least one occurrence of a given value. */
|
||||||
|
bool containsValue (ValueTypeParameter valueToLookFor) const
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (int i = getNumSlots(); --i >= 0;)
|
||||||
|
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
if (entry->value == valueToLookFor)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds or replaces an element in the hash-map.
|
||||||
|
If there's already an item with the given key, this will replace its value. Otherwise, a new item
|
||||||
|
will be added to the map.
|
||||||
|
*/
|
||||||
|
void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
const int hashIndex = generateHashFor (newKey);
|
||||||
|
|
||||||
|
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
|
||||||
|
|
||||||
|
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
|
||||||
|
{
|
||||||
|
if (entry->key == newKey)
|
||||||
|
{
|
||||||
|
entry->value = newValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
|
||||||
|
++totalNumItems;
|
||||||
|
|
||||||
|
if (totalNumItems > (getNumSlots() * 3) / 2)
|
||||||
|
remapTable (getNumSlots() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes an item with the given key. */
|
||||||
|
void remove (KeyTypeParameter keyToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
const int hashIndex = generateHashFor (keyToRemove);
|
||||||
|
HashEntry* entry = slots.getUnchecked (hashIndex);
|
||||||
|
HashEntry* previous = nullptr;
|
||||||
|
|
||||||
|
while (entry != nullptr)
|
||||||
|
{
|
||||||
|
if (entry->key == keyToRemove)
|
||||||
|
{
|
||||||
|
const ScopedPointer<HashEntry> deleter (entry);
|
||||||
|
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
|
||||||
|
if (previous != nullptr)
|
||||||
|
previous->nextEntry = entry;
|
||||||
|
else
|
||||||
|
slots.set (hashIndex, entry);
|
||||||
|
|
||||||
|
--totalNumItems;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previous = entry;
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes all items with the given value. */
|
||||||
|
void removeValue (ValueTypeParameter valueToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (int i = getNumSlots(); --i >= 0;)
|
||||||
|
{
|
||||||
|
HashEntry* entry = slots.getUnchecked(i);
|
||||||
|
HashEntry* previous = nullptr;
|
||||||
|
|
||||||
|
while (entry != nullptr)
|
||||||
|
{
|
||||||
|
if (entry->value == valueToRemove)
|
||||||
|
{
|
||||||
|
const ScopedPointer<HashEntry> deleter (entry);
|
||||||
|
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
|
||||||
|
if (previous != nullptr)
|
||||||
|
previous->nextEntry = entry;
|
||||||
|
else
|
||||||
|
slots.set (i, entry);
|
||||||
|
|
||||||
|
--totalNumItems;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previous = entry;
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remaps the hash-map to use a different number of slots for its hash function.
|
||||||
|
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||||
|
@see getNumSlots()
|
||||||
|
*/
|
||||||
|
void remapTable (int newNumberOfSlots)
|
||||||
|
{
|
||||||
|
HashMap newTable (newNumberOfSlots);
|
||||||
|
|
||||||
|
for (int i = getNumSlots(); --i >= 0;)
|
||||||
|
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
newTable.set (entry->key, entry->value);
|
||||||
|
|
||||||
|
swapWith (newTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of slots which are available for hashing.
|
||||||
|
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||||
|
@see getNumSlots()
|
||||||
|
*/
|
||||||
|
inline int getNumSlots() const noexcept
|
||||||
|
{
|
||||||
|
return slots.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Efficiently swaps the contents of two hash-maps. */
|
||||||
|
void swapWith (HashMap& otherHashMap) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
const ScopedLockType lock2 (otherHashMap.getLock());
|
||||||
|
|
||||||
|
slots.swapWithArray (otherHashMap.slots);
|
||||||
|
std::swap (totalNumItems, otherHashMap.totalNumItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this structure.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class HashEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashEntry (KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next)
|
||||||
|
: key (k), value (val), nextEntry (next)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const KeyType key;
|
||||||
|
ValueType value;
|
||||||
|
HashEntry* nextEntry;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (HashEntry)
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Iterates over the items in a HashMap.
|
||||||
|
|
||||||
|
To use it, repeatedly call next() until it returns false, e.g.
|
||||||
|
@code
|
||||||
|
HashMap <String, String> myMap;
|
||||||
|
|
||||||
|
HashMap<String, String>::Iterator i (myMap);
|
||||||
|
|
||||||
|
while (i.next())
|
||||||
|
{
|
||||||
|
DBG (i.getKey() << " -> " << i.getValue());
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The order in which items are iterated bears no resemblence to the order in which
|
||||||
|
they were originally added!
|
||||||
|
|
||||||
|
Obviously as soon as you call any non-const methods on the original hash-map, any
|
||||||
|
iterators that were created beforehand will cease to be valid, and should not be used.
|
||||||
|
|
||||||
|
@see HashMap
|
||||||
|
*/
|
||||||
|
class Iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
Iterator (const HashMap& hashMapToIterate)
|
||||||
|
: hashMap (hashMapToIterate), entry (nullptr), index (0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/** Moves to the next item, if one is available.
|
||||||
|
When this returns true, you can get the item's key and value using getKey() and
|
||||||
|
getValue(). If it returns false, the iteration has finished and you should stop.
|
||||||
|
*/
|
||||||
|
bool next()
|
||||||
|
{
|
||||||
|
if (entry != nullptr)
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
|
||||||
|
while (entry == nullptr)
|
||||||
|
{
|
||||||
|
if (index >= hashMap.getNumSlots())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entry = hashMap.slots.getUnchecked (index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current item's key.
|
||||||
|
This should only be called when a call to next() has just returned true.
|
||||||
|
*/
|
||||||
|
KeyType getKey() const
|
||||||
|
{
|
||||||
|
return entry != nullptr ? entry->key : KeyType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current item's value.
|
||||||
|
This should only be called when a call to next() has just returned true.
|
||||||
|
*/
|
||||||
|
ValueType getValue() const
|
||||||
|
{
|
||||||
|
return entry != nullptr ? entry->value : ValueType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
const HashMap& hashMap;
|
||||||
|
HashEntry* entry;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator)
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
enum { defaultHashTableSize = 101 };
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
|
Array <HashEntry*> slots;
|
||||||
|
int totalNumItems;
|
||||||
|
TypeOfCriticalSectionToUse lock;
|
||||||
|
|
||||||
|
int generateHashFor (KeyTypeParameter key) const
|
||||||
|
{
|
||||||
|
const int hash = HashFunctionToUse::generateHash (key, getNumSlots());
|
||||||
|
bassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_HASHMAP_BEASTHEADER
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||||
|
#define BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Helps to manipulate singly-linked lists of objects.
|
||||||
|
|
||||||
|
For objects that are designed to contain a pointer to the subsequent item in the
|
||||||
|
list, this class contains methods to deal with the list. To use it, the ObjectType
|
||||||
|
class that it points to must contain a LinkedListPointer called nextListItem, e.g.
|
||||||
|
|
||||||
|
@code
|
||||||
|
struct MyObject
|
||||||
|
{
|
||||||
|
int x, y, z;
|
||||||
|
|
||||||
|
// A linkable object must contain a member with this name and type, which must be
|
||||||
|
// accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
|
||||||
|
// you could make your class a friend of a LinkedListPointer<MyObject> instead).
|
||||||
|
LinkedListPointer<MyObject> nextListItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkedListPointer<MyObject> myList;
|
||||||
|
myList.append (new MyObject());
|
||||||
|
myList.append (new MyObject());
|
||||||
|
|
||||||
|
int numItems = myList.size(); // returns 2
|
||||||
|
MyObject* lastInList = myList.getLast();
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <class ObjectType>
|
||||||
|
class LinkedListPointer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a null pointer to an empty list. */
|
||||||
|
LinkedListPointer() noexcept
|
||||||
|
: item (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a pointer to a list whose head is the item provided. */
|
||||||
|
explicit LinkedListPointer (ObjectType* const headItem) noexcept
|
||||||
|
: item (headItem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets this pointer to point to a new list. */
|
||||||
|
LinkedListPointer& operator= (ObjectType* const newItem) noexcept
|
||||||
|
{
|
||||||
|
item = newItem;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
LinkedListPointer (LinkedListPointer&& other) noexcept
|
||||||
|
: item (other.item)
|
||||||
|
{
|
||||||
|
other.item = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
|
||||||
|
{
|
||||||
|
bassert (this != &other); // hopefully the compiler should make this situation impossible!
|
||||||
|
|
||||||
|
item = other.item;
|
||||||
|
other.item = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the item which this pointer points to. */
|
||||||
|
inline operator ObjectType*() const noexcept
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the item which this pointer points to. */
|
||||||
|
inline ObjectType* get() const noexcept
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the last item in the list which this pointer points to.
|
||||||
|
This will iterate the list and return the last item found. Obviously the speed
|
||||||
|
of this operation will be proportional to the size of the list. If the list is
|
||||||
|
empty the return value will be this object.
|
||||||
|
If you're planning on appending a number of items to your list, it's much more
|
||||||
|
efficient to use the Appender class than to repeatedly call getLast() to find the end.
|
||||||
|
*/
|
||||||
|
LinkedListPointer& getLast() noexcept
|
||||||
|
{
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (l->item != nullptr)
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
|
||||||
|
return *l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of items in the list.
|
||||||
|
Obviously with a simple linked list, getting the size involves iterating the list, so
|
||||||
|
this can be a lengthy operation - be careful when using this method in your code.
|
||||||
|
*/
|
||||||
|
int size() const noexcept
|
||||||
|
{
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||||
|
++total;
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the item at a given index in the list.
|
||||||
|
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||||
|
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||||
|
*/
|
||||||
|
LinkedListPointer& operator[] (int index) noexcept
|
||||||
|
{
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (--index >= 0 && l->item != nullptr)
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
|
||||||
|
return *l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the item at a given index in the list.
|
||||||
|
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||||
|
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||||
|
*/
|
||||||
|
const LinkedListPointer& operator[] (int index) const noexcept
|
||||||
|
{
|
||||||
|
const LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (--index >= 0 && l->item != nullptr)
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
|
||||||
|
return *l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the list contains the given item. */
|
||||||
|
bool contains (const ObjectType* const itemToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||||
|
if (itemToLookFor == i)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Inserts an item into the list, placing it before the item that this pointer
|
||||||
|
currently points to.
|
||||||
|
*/
|
||||||
|
void insertNext (ObjectType* const newItem)
|
||||||
|
{
|
||||||
|
bassert (newItem != nullptr);
|
||||||
|
bassert (newItem->nextListItem == nullptr);
|
||||||
|
newItem->nextListItem = item;
|
||||||
|
item = newItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts an item at a numeric index in the list.
|
||||||
|
Obviously this will involve iterating the list to find the item at the given index,
|
||||||
|
so be careful about the impact this may have on execution time.
|
||||||
|
*/
|
||||||
|
void insertAtIndex (int index, ObjectType* newItem)
|
||||||
|
{
|
||||||
|
bassert (newItem != nullptr);
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (index != 0 && l->item != nullptr)
|
||||||
|
{
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->insertNext (newItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replaces the object that this pointer points to, appending the rest of the list to
|
||||||
|
the new object, and returning the old one.
|
||||||
|
*/
|
||||||
|
ObjectType* replaceNext (ObjectType* const newItem) noexcept
|
||||||
|
{
|
||||||
|
bassert (newItem != nullptr);
|
||||||
|
bassert (newItem->nextListItem == nullptr);
|
||||||
|
|
||||||
|
ObjectType* const oldItem = item;
|
||||||
|
item = newItem;
|
||||||
|
item->nextListItem = oldItem->nextListItem.item;
|
||||||
|
oldItem->nextListItem.item = nullptr;
|
||||||
|
return oldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds an item to the end of the list.
|
||||||
|
|
||||||
|
This operation involves iterating the whole list, so can be slow - if you need to
|
||||||
|
append a number of items to your list, it's much more efficient to use the Appender
|
||||||
|
class than to repeatedly call append().
|
||||||
|
*/
|
||||||
|
void append (ObjectType* const newItem)
|
||||||
|
{
|
||||||
|
getLast().item = newItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates copies of all the items in another list and adds them to this one.
|
||||||
|
This will use the ObjectType's copy constructor to try to create copies of each
|
||||||
|
item in the other list, and appends them to this list.
|
||||||
|
*/
|
||||||
|
void addCopyOfList (const LinkedListPointer& other)
|
||||||
|
{
|
||||||
|
LinkedListPointer* insertPoint = this;
|
||||||
|
|
||||||
|
for (ObjectType* i = other.item; i != nullptr; i = i->nextListItem)
|
||||||
|
{
|
||||||
|
insertPoint->insertNext (new ObjectType (*i));
|
||||||
|
insertPoint = &(insertPoint->item->nextListItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the head item from the list.
|
||||||
|
This won't delete the object that is removed, but returns it, so the caller can
|
||||||
|
delete it if necessary.
|
||||||
|
*/
|
||||||
|
ObjectType* removeNext() noexcept
|
||||||
|
{
|
||||||
|
ObjectType* const oldItem = item;
|
||||||
|
|
||||||
|
if (oldItem != nullptr)
|
||||||
|
{
|
||||||
|
item = oldItem->nextListItem;
|
||||||
|
oldItem->nextListItem.item = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a specific item from the list.
|
||||||
|
Note that this will not delete the item, it simply unlinks it from the list.
|
||||||
|
*/
|
||||||
|
void remove (ObjectType* const itemToRemove)
|
||||||
|
{
|
||||||
|
if (LinkedListPointer* const l = findPointerTo (itemToRemove))
|
||||||
|
l->removeNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Iterates the list, calling the delete operator on all of its elements and
|
||||||
|
leaving this pointer empty.
|
||||||
|
*/
|
||||||
|
void deleteAll()
|
||||||
|
{
|
||||||
|
while (item != nullptr)
|
||||||
|
{
|
||||||
|
ObjectType* const oldItem = item;
|
||||||
|
item = oldItem->nextListItem;
|
||||||
|
delete oldItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finds a pointer to a given item.
|
||||||
|
If the item is found in the list, this returns the pointer that points to it. If
|
||||||
|
the item isn't found, this returns null.
|
||||||
|
*/
|
||||||
|
LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) noexcept
|
||||||
|
{
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (l->item != nullptr)
|
||||||
|
{
|
||||||
|
if (l->item == itemToLookFor)
|
||||||
|
return l;
|
||||||
|
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies the items in the list to an array.
|
||||||
|
The destArray must contain enough elements to hold the entire list - no checks are
|
||||||
|
made for this!
|
||||||
|
*/
|
||||||
|
void copyToArray (ObjectType** destArray) const noexcept
|
||||||
|
{
|
||||||
|
bassert (destArray != nullptr);
|
||||||
|
|
||||||
|
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||||
|
*destArray++ = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps this pointer with another one */
|
||||||
|
void swapWith (LinkedListPointer& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (item, other.item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Allows efficient repeated insertions into a list.
|
||||||
|
|
||||||
|
You can create an Appender object which points to the last element in your
|
||||||
|
list, and then repeatedly call Appender::append() to add items to the end
|
||||||
|
of the list in O(1) time.
|
||||||
|
*/
|
||||||
|
class Appender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates an appender which will add items to the given list.
|
||||||
|
*/
|
||||||
|
Appender (LinkedListPointer& endOfListPointer) noexcept
|
||||||
|
: endOfList (&endOfListPointer)
|
||||||
|
{
|
||||||
|
// This can only be used to add to the end of a list.
|
||||||
|
bassert (endOfListPointer.item == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends an item to the list. */
|
||||||
|
void append (ObjectType* const newItem) noexcept
|
||||||
|
{
|
||||||
|
*endOfList = newItem;
|
||||||
|
endOfList = &(newItem->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LinkedListPointer* endOfList;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (Appender)
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ObjectType* item;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (LinkedListPointer)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_LINKEDLISTPOINTER_BEASTHEADER
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
NamedValueSet::NamedValue::NamedValue() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NamedValueSet::NamedValue::NamedValue (const Identifier n, const var& v)
|
||||||
|
: name (n), value (v)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet::NamedValue::NamedValue (const NamedValue& other)
|
||||||
|
: name (other.name), value (other.value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (const NamedValueSet::NamedValue& other)
|
||||||
|
{
|
||||||
|
name = other.name;
|
||||||
|
value = other.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
|
||||||
|
: nextListItem (static_cast <LinkedListPointer<NamedValue>&&> (other.nextListItem)),
|
||||||
|
name (static_cast <Identifier&&> (other.name)),
|
||||||
|
value (static_cast <var&&> (other.value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NamedValueSet::NamedValue::NamedValue (const Identifier n, var&& v)
|
||||||
|
: name (n), value (static_cast <var&&> (v))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
|
||||||
|
{
|
||||||
|
nextListItem = static_cast <LinkedListPointer<NamedValue>&&> (other.nextListItem);
|
||||||
|
name = static_cast <Identifier&&> (other.name);
|
||||||
|
value = static_cast <var&&> (other.value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const noexcept
|
||||||
|
{
|
||||||
|
return name == other.name && value == other.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
NamedValueSet::NamedValueSet() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet::NamedValueSet (const NamedValueSet& other)
|
||||||
|
{
|
||||||
|
values.addCopyOfList (other.values);
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
values.addCopyOfList (other.values);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
|
||||||
|
: values (static_cast <LinkedListPointer<NamedValue>&&> (other.values))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
|
||||||
|
{
|
||||||
|
other.values.swapWith (values);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NamedValueSet::~NamedValueSet()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NamedValueSet::clear()
|
||||||
|
{
|
||||||
|
values.deleteAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::operator== (const NamedValueSet& other) const
|
||||||
|
{
|
||||||
|
const NamedValue* i1 = values;
|
||||||
|
const NamedValue* i2 = other.values;
|
||||||
|
|
||||||
|
while (i1 != nullptr && i2 != nullptr)
|
||||||
|
{
|
||||||
|
if (! (*i1 == *i2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
i1 = i1->nextListItem;
|
||||||
|
i2 = i2->nextListItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::operator!= (const NamedValueSet& other) const
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
int NamedValueSet::size() const noexcept
|
||||||
|
{
|
||||||
|
return values.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const var& NamedValueSet::operator[] (const Identifier name) const
|
||||||
|
{
|
||||||
|
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||||
|
if (i->name == name)
|
||||||
|
return i->value;
|
||||||
|
|
||||||
|
return var::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var NamedValueSet::getWithDefault (const Identifier name, const var& defaultReturnValue) const
|
||||||
|
{
|
||||||
|
if (const var* const v = getVarPointer (name))
|
||||||
|
return *v;
|
||||||
|
|
||||||
|
return defaultReturnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var* NamedValueSet::getVarPointer (const Identifier name) const noexcept
|
||||||
|
{
|
||||||
|
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||||
|
if (i->name == name)
|
||||||
|
return &(i->value);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
bool NamedValueSet::set (const Identifier name, var&& newValue)
|
||||||
|
{
|
||||||
|
LinkedListPointer<NamedValue>* i = &values;
|
||||||
|
|
||||||
|
while (i->get() != nullptr)
|
||||||
|
{
|
||||||
|
NamedValue* const v = i->get();
|
||||||
|
|
||||||
|
if (v->name == name)
|
||||||
|
{
|
||||||
|
if (v->value.equalsWithSameType (newValue))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
v->value = static_cast <var&&> (newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = &(v->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
i->insertNext (new NamedValue (name, static_cast <var&&> (newValue)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool NamedValueSet::set (const Identifier name, const var& newValue)
|
||||||
|
{
|
||||||
|
LinkedListPointer<NamedValue>* i = &values;
|
||||||
|
|
||||||
|
while (i->get() != nullptr)
|
||||||
|
{
|
||||||
|
NamedValue* const v = i->get();
|
||||||
|
|
||||||
|
if (v->name == name)
|
||||||
|
{
|
||||||
|
if (v->value.equalsWithSameType (newValue))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
v->value = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = &(v->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
i->insertNext (new NamedValue (name, newValue));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::contains (const Identifier name) const
|
||||||
|
{
|
||||||
|
return getVarPointer (name) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::remove (const Identifier name)
|
||||||
|
{
|
||||||
|
LinkedListPointer<NamedValue>* i = &values;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
NamedValue* const v = i->get();
|
||||||
|
|
||||||
|
if (v == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (v->name == name)
|
||||||
|
{
|
||||||
|
delete i->removeNext();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = &(v->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Identifier NamedValueSet::getName (const int index) const
|
||||||
|
{
|
||||||
|
const NamedValue* const v = values[index];
|
||||||
|
bassert (v != nullptr);
|
||||||
|
return v->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const var& NamedValueSet::getValueAt (const int index) const
|
||||||
|
{
|
||||||
|
const NamedValue* const v = values[index];
|
||||||
|
bassert (v != nullptr);
|
||||||
|
return v->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
LinkedListPointer<NamedValue>::Appender appender (values);
|
||||||
|
|
||||||
|
const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..
|
||||||
|
|
||||||
|
for (int i = 0; i < numAtts; ++i)
|
||||||
|
{
|
||||||
|
const String& name = xml.getAttributeName (i);
|
||||||
|
const String& value = xml.getAttributeValue (i);
|
||||||
|
|
||||||
|
if (name.startsWith ("base64:"))
|
||||||
|
{
|
||||||
|
MemoryBlock mb;
|
||||||
|
|
||||||
|
if (mb.fromBase64Encoding (value))
|
||||||
|
{
|
||||||
|
appender.append (new NamedValue (name.substring (7), var (mb)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
appender.append (new NamedValue (name, var (value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
|
||||||
|
{
|
||||||
|
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
|
||||||
|
{
|
||||||
|
if (const MemoryBlock* mb = i->value.getBinaryData())
|
||||||
|
{
|
||||||
|
xml.setAttribute ("base64:" + i->name.toString(),
|
||||||
|
mb->toBase64Encoding());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// These types can't be stored as XML!
|
||||||
|
bassert (! i->value.isObject());
|
||||||
|
bassert (! i->value.isMethod());
|
||||||
|
bassert (! i->value.isArray());
|
||||||
|
|
||||||
|
xml.setAttribute (i->name.toString(),
|
||||||
|
i->value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_NAMEDVALUESET_BEASTHEADER
|
||||||
|
#define BEAST_NAMEDVALUESET_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_Variant.h"
|
||||||
|
#include "../containers/beast_LinkedListPointer.h"
|
||||||
|
class XmlElement;
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
class JSONFormatter;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Holds a set of named var objects.
|
||||||
|
|
||||||
|
This can be used as a basic structure to hold a set of var object, which can
|
||||||
|
be retrieved by using their identifier.
|
||||||
|
*/
|
||||||
|
class BEAST_API NamedValueSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates an empty set. */
|
||||||
|
NamedValueSet() noexcept;
|
||||||
|
|
||||||
|
/** Creates a copy of another set. */
|
||||||
|
NamedValueSet (const NamedValueSet& other);
|
||||||
|
|
||||||
|
/** Replaces this set with a copy of another set. */
|
||||||
|
NamedValueSet& operator= (const NamedValueSet& other);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
NamedValueSet (NamedValueSet&& other) noexcept;
|
||||||
|
NamedValueSet& operator= (NamedValueSet&& other) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~NamedValueSet();
|
||||||
|
|
||||||
|
bool operator== (const NamedValueSet& other) const;
|
||||||
|
bool operator!= (const NamedValueSet& other) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the total number of values that the set contains. */
|
||||||
|
int size() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the value of a named item.
|
||||||
|
If the name isn't found, this will return a void variant.
|
||||||
|
@see getProperty
|
||||||
|
*/
|
||||||
|
const var& operator[] (const Identifier name) const;
|
||||||
|
|
||||||
|
/** Tries to return the named value, but if no such value is found, this will
|
||||||
|
instead return the supplied default value.
|
||||||
|
*/
|
||||||
|
var getWithDefault (const Identifier name, const var& defaultReturnValue) const;
|
||||||
|
|
||||||
|
/** Changes or adds a named value.
|
||||||
|
@returns true if a value was changed or added; false if the
|
||||||
|
value was already set the the value passed-in.
|
||||||
|
*/
|
||||||
|
bool set (const Identifier name, const var& newValue);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
/** Changes or adds a named value.
|
||||||
|
@returns true if a value was changed or added; false if the
|
||||||
|
value was already set the the value passed-in.
|
||||||
|
*/
|
||||||
|
bool set (const Identifier name, var&& newValue);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Returns true if the set contains an item with the specified name. */
|
||||||
|
bool contains (const Identifier name) const;
|
||||||
|
|
||||||
|
/** Removes a value from the set.
|
||||||
|
@returns true if a value was removed; false if there was no value
|
||||||
|
with the name that was given.
|
||||||
|
*/
|
||||||
|
bool remove (const Identifier name);
|
||||||
|
|
||||||
|
/** Returns the name of the value at a given index.
|
||||||
|
The index must be between 0 and size() - 1.
|
||||||
|
*/
|
||||||
|
const Identifier getName (int index) const;
|
||||||
|
|
||||||
|
/** Returns the value of the item at a given index.
|
||||||
|
The index must be between 0 and size() - 1.
|
||||||
|
*/
|
||||||
|
const var& getValueAt (int index) const;
|
||||||
|
|
||||||
|
/** Removes all values. */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the var that holds a named value, or null if there is
|
||||||
|
no value with this name.
|
||||||
|
|
||||||
|
Do not use this method unless you really need access to the internal var object
|
||||||
|
for some reason - for normal reading and writing always prefer operator[]() and set().
|
||||||
|
*/
|
||||||
|
var* getVarPointer (const Identifier name) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets properties to the values of all of an XML element's attributes. */
|
||||||
|
void setFromXmlAttributes (const XmlElement& xml);
|
||||||
|
|
||||||
|
/** Sets attributes in an XML element corresponding to each of this object's
|
||||||
|
properties.
|
||||||
|
*/
|
||||||
|
void copyToXmlAttributes (XmlElement& xml) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class NamedValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NamedValue() noexcept;
|
||||||
|
NamedValue (const NamedValue&);
|
||||||
|
NamedValue (const Identifier name, const var& value);
|
||||||
|
NamedValue& operator= (const NamedValue&);
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
NamedValue (NamedValue&&) noexcept;
|
||||||
|
NamedValue (const Identifier name, var&& value);
|
||||||
|
NamedValue& operator= (NamedValue&&) noexcept;
|
||||||
|
#endif
|
||||||
|
bool operator== (const NamedValue& other) const noexcept;
|
||||||
|
|
||||||
|
LinkedListPointer<NamedValue> nextListItem;
|
||||||
|
Identifier name;
|
||||||
|
var value;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BEAST_LEAK_DETECTOR (NamedValue)
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class LinkedListPointer<NamedValue>;
|
||||||
|
LinkedListPointer<NamedValue> values;
|
||||||
|
|
||||||
|
friend class JSONFormatter;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_NAMEDVALUESET_BEASTHEADER
|
||||||
865
Subtrees/beast/modules/beast_core/containers/beast_OwnedArray.h
Normal file
865
Subtrees/beast/modules/beast_core/containers/beast_OwnedArray.h
Normal file
@@ -0,0 +1,865 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_OWNEDARRAY_BEASTHEADER
|
||||||
|
#define BEAST_OWNEDARRAY_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_ArrayAllocationBase.h"
|
||||||
|
#include "beast_ElementComparator.h"
|
||||||
|
#include "../threads/beast_CriticalSection.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** An array designed for holding objects.
|
||||||
|
|
||||||
|
This holds a list of pointers to objects, and will automatically
|
||||||
|
delete the objects when they are removed from the array, or when the
|
||||||
|
array is itself deleted.
|
||||||
|
|
||||||
|
Declare it in the form: OwnedArray<MyObjectClass>
|
||||||
|
|
||||||
|
..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass());
|
||||||
|
|
||||||
|
After adding objects, they are 'owned' by the array and will be deleted when
|
||||||
|
removed or replaced.
|
||||||
|
|
||||||
|
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||||
|
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||||
|
|
||||||
|
@see Array, ReferenceCountedArray, StringArray, CriticalSection
|
||||||
|
*/
|
||||||
|
template <class ObjectClass,
|
||||||
|
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
|
||||||
|
class OwnedArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty array. */
|
||||||
|
OwnedArray() noexcept
|
||||||
|
: numUsed (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes the array and also deletes any objects inside it.
|
||||||
|
|
||||||
|
To get rid of the array without deleting its objects, use its
|
||||||
|
clear (false) method before deleting it.
|
||||||
|
*/
|
||||||
|
~OwnedArray()
|
||||||
|
{
|
||||||
|
deleteAllObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
OwnedArray (OwnedArray&& other) noexcept
|
||||||
|
: data (static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data)),
|
||||||
|
numUsed (other.numUsed)
|
||||||
|
{
|
||||||
|
other.numUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnedArray& operator= (OwnedArray&& other) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
deleteAllObjects();
|
||||||
|
|
||||||
|
data = static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data);
|
||||||
|
numUsed = other.numUsed;
|
||||||
|
other.numUsed = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Clears the array, optionally deleting the objects inside it first. */
|
||||||
|
void clear (const bool deleteObjects = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (deleteObjects)
|
||||||
|
deleteAllObjects();
|
||||||
|
|
||||||
|
data.setAllocatedSize (0);
|
||||||
|
numUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the number of items currently in the array.
|
||||||
|
@see operator[]
|
||||||
|
*/
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array.
|
||||||
|
|
||||||
|
If the index is out-of-range, this will return a null pointer, (and
|
||||||
|
it could be null anyway, because it's ok for the array to hold null
|
||||||
|
pointers as well as objects).
|
||||||
|
|
||||||
|
@see getUnchecked
|
||||||
|
*/
|
||||||
|
inline ObjectClass* operator[] (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
||||||
|
: static_cast <ObjectClass*> (nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
|
||||||
|
|
||||||
|
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||||
|
it can be used when you're sure the index is always going to be legal.
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
bassert (isPositiveAndBelow (index, numUsed));
|
||||||
|
return data.elements [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the first object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getLast
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getFirst() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
return numUsed > 0 ? data.elements [0]
|
||||||
|
: static_cast <ObjectClass*> (nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the last object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getFirst
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getLast() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
return numUsed > 0 ? data.elements [numUsed - 1]
|
||||||
|
: static_cast <ObjectClass*> (nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the actual array data.
|
||||||
|
This pointer will only be valid until the next time a non-const method
|
||||||
|
is called on the array.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** getRawDataPointer() noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the first element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** begin() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the element which follows the last element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** end() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements + numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds the index of an object which might be in the array.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns the index at which the object was found, or -1 if it's not found
|
||||||
|
*/
|
||||||
|
int indexOf (const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass* const* e = data.elements.getData();
|
||||||
|
ObjectClass* const* const end_ = e + numUsed;
|
||||||
|
|
||||||
|
for (; e != end_; ++e)
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return static_cast <int> (e - data.elements.getData());
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the array contains a specified object.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns true if the object is in the array
|
||||||
|
*/
|
||||||
|
bool contains (const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass* const* e = data.elements.getData();
|
||||||
|
ObjectClass* const* const end_ = e + numUsed;
|
||||||
|
|
||||||
|
for (; e != end_; ++e)
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Appends a new object to the end of the array.
|
||||||
|
|
||||||
|
Note that the this object will be deleted by the OwnedArray when it
|
||||||
|
is removed, so be careful not to delete it somewhere else.
|
||||||
|
|
||||||
|
Also be careful not to add the same object to the array more than once,
|
||||||
|
as this will obviously cause deletion of dangling pointers.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@see set, insert, addIfNotAlreadyThere, addSorted
|
||||||
|
*/
|
||||||
|
void add (const ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
data.elements [numUsed++] = const_cast <ObjectClass*> (newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array at the given index.
|
||||||
|
|
||||||
|
Note that the this object will be deleted by the OwnedArray when it
|
||||||
|
is removed, so be careful not to delete it somewhere else.
|
||||||
|
|
||||||
|
If the index is less than 0 or greater than the size of the array, the
|
||||||
|
element will be added to the end of the array.
|
||||||
|
Otherwise, it will be inserted into the array, moving all the later elements
|
||||||
|
along to make room.
|
||||||
|
|
||||||
|
Be careful not to add the same object to the array more than once,
|
||||||
|
as this will obviously cause deletion of dangling pointers.
|
||||||
|
|
||||||
|
@param indexToInsertAt the index at which the new element should be inserted
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@see add, addSorted, addIfNotAlreadyThere, set
|
||||||
|
*/
|
||||||
|
void insert (int indexToInsertAt,
|
||||||
|
const ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
if (indexToInsertAt >= 0)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (indexToInsertAt > numUsed)
|
||||||
|
indexToInsertAt = numUsed;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
|
||||||
|
ObjectClass** const e = data.elements + indexToInsertAt;
|
||||||
|
const int numToMove = numUsed - indexToInsertAt;
|
||||||
|
|
||||||
|
if (numToMove > 0)
|
||||||
|
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
|
||||||
|
|
||||||
|
*e = const_cast <ObjectClass*> (newObject);
|
||||||
|
++numUsed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
add (newObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts an array of values into this array at a given position.
|
||||||
|
|
||||||
|
If the index is less than 0 or greater than the size of the array, the
|
||||||
|
new elements will be added to the end of the array.
|
||||||
|
Otherwise, they will be inserted into the array, moving all the later elements
|
||||||
|
along to make room.
|
||||||
|
|
||||||
|
@param indexToInsertAt the index at which the first new element should be inserted
|
||||||
|
@param newObjects the new values to add to the array
|
||||||
|
@param numberOfElements how many items are in the array
|
||||||
|
@see insert, add, addSorted, set
|
||||||
|
*/
|
||||||
|
void insertArray (int indexToInsertAt,
|
||||||
|
ObjectClass* const* newObjects,
|
||||||
|
int numberOfElements)
|
||||||
|
{
|
||||||
|
if (numberOfElements > 0)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (numUsed + numberOfElements);
|
||||||
|
ObjectClass** insertPos = data.elements;
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToInsertAt, numUsed))
|
||||||
|
{
|
||||||
|
insertPos += indexToInsertAt;
|
||||||
|
const size_t numberToMove = (size_t) (numUsed - indexToInsertAt);
|
||||||
|
memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ObjectClass*));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
insertPos += numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
numUsed += numberOfElements;
|
||||||
|
|
||||||
|
while (--numberOfElements >= 0)
|
||||||
|
*insertPos++ = *newObjects++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends a new object at the end of the array as long as the array doesn't
|
||||||
|
already contain it.
|
||||||
|
|
||||||
|
If the array already contains a matching object, nothing will be done.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
*/
|
||||||
|
void addIfNotAlreadyThere (const ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (! contains (newObject))
|
||||||
|
add (newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replaces an object in the array with a different one.
|
||||||
|
|
||||||
|
If the index is less than zero, this method does nothing.
|
||||||
|
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||||
|
|
||||||
|
Be careful not to add the same object to the array more than once,
|
||||||
|
as this will obviously cause deletion of dangling pointers.
|
||||||
|
|
||||||
|
@param indexToChange the index whose value you want to change
|
||||||
|
@param newObject the new value to set for this index.
|
||||||
|
@param deleteOldElement whether to delete the object that's being replaced with the new one
|
||||||
|
@see add, insert, remove
|
||||||
|
*/
|
||||||
|
void set (const int indexToChange,
|
||||||
|
const ObjectClass* const newObject,
|
||||||
|
const bool deleteOldElement = true)
|
||||||
|
{
|
||||||
|
if (indexToChange >= 0)
|
||||||
|
{
|
||||||
|
ObjectClass* toDelete = nullptr;
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (indexToChange < numUsed)
|
||||||
|
{
|
||||||
|
if (deleteOldElement)
|
||||||
|
{
|
||||||
|
toDelete = data.elements [indexToChange];
|
||||||
|
|
||||||
|
if (toDelete == newObject)
|
||||||
|
toDelete = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.elements [indexToChange] = const_cast <ObjectClass*> (newObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
data.elements [numUsed++] = const_cast <ObjectClass*> (newObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete toDelete; // don't want to use a ScopedPointer here because if the
|
||||||
|
// object has a private destructor, both OwnedArray and
|
||||||
|
// ScopedPointer would need to be friend classes..
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jassertfalse; // 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..
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from another array to the end of this array.
|
||||||
|
|
||||||
|
@param arrayToAddFrom the array from which to copy the elements
|
||||||
|
@param startIndex the first element of the other array to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other array. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
template <class OtherArrayType>
|
||||||
|
void addArray (const OtherArrayType& arrayToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1)
|
||||||
|
{
|
||||||
|
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||||
|
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
{
|
||||||
|
data.elements [numUsed] = arrayToAddFrom.getUnchecked (startIndex++);
|
||||||
|
++numUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds copies of the elements in another array to the end of this array.
|
||||||
|
|
||||||
|
The other array must be either an OwnedArray of a compatible type of object, or an Array
|
||||||
|
containing pointers to the same kind of object. The objects involved must provide
|
||||||
|
a copy constructor, and this will be used to create new copies of each element, and
|
||||||
|
add them to this array.
|
||||||
|
|
||||||
|
@param arrayToAddFrom the array from which to copy the elements
|
||||||
|
@param startIndex the first element of the other array to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other array. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
template <class OtherArrayType>
|
||||||
|
void addCopiesOf (const OtherArrayType& arrayToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1)
|
||||||
|
{
|
||||||
|
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||||
|
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
{
|
||||||
|
data.elements [numUsed] = new ObjectClass (*arrayToAddFrom.getUnchecked (startIndex++));
|
||||||
|
++numUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to find the position at which the new object
|
||||||
|
should go. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator to use to compare the elements - see the sort method
|
||||||
|
for details about this object's structure
|
||||||
|
@param newObject the new object to insert to the array
|
||||||
|
@returns the index at which the new object was added
|
||||||
|
@see add, sort, indexOfSorted
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||||
|
insert (index, newObject);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to do a binary-chop to find the index of the given
|
||||||
|
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator to use to compare the elements - see the sort()
|
||||||
|
method for details about the form this object should take
|
||||||
|
@param objectToLookFor the object to search for
|
||||||
|
@returns the index of the element, or -1 if it's not found
|
||||||
|
@see addSorted, sort
|
||||||
|
*/
|
||||||
|
template <typename ElementComparator>
|
||||||
|
int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
int s = 0, e = numUsed;
|
||||||
|
|
||||||
|
while (s < e)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
if (halfway == s)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
|
||||||
|
s = halfway;
|
||||||
|
else
|
||||||
|
e = halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes an object from the array.
|
||||||
|
|
||||||
|
This will remove the object at a given index (optionally also
|
||||||
|
deleting it) and move back all the subsequent objects to close the gap.
|
||||||
|
If the index passed in is out-of-range, nothing will happen.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@param deleteObject whether to delete the object that is removed
|
||||||
|
@see removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void remove (const int indexToRemove,
|
||||||
|
const bool deleteObject = true)
|
||||||
|
{
|
||||||
|
ObjectClass* toDelete = nullptr;
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
|
||||||
|
if (deleteObject)
|
||||||
|
toDelete = *e;
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete toDelete; // don't want to use a ScopedPointer here because if the
|
||||||
|
// object has a private destructor, both OwnedArray and
|
||||||
|
// ScopedPointer would need to be friend classes..
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes and returns an object from the array without deleting it.
|
||||||
|
|
||||||
|
This will remove the object at a given index and return it, moving back all
|
||||||
|
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||||
|
nothing will happen.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
ObjectClass* removeAndReturn (const int indexToRemove)
|
||||||
|
{
|
||||||
|
ObjectClass* removedItem = nullptr;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
removedItem = *e;
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
return removedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a specified object from the array.
|
||||||
|
|
||||||
|
If the item isn't found, no action is taken.
|
||||||
|
|
||||||
|
@param objectToRemove the object to try to remove
|
||||||
|
@param deleteObject whether to delete the object (if it's found)
|
||||||
|
@see remove, removeRange
|
||||||
|
*/
|
||||||
|
void removeObject (const ObjectClass* const objectToRemove,
|
||||||
|
const bool deleteObject = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass** const e = data.elements.getData();
|
||||||
|
|
||||||
|
for (int i = 0; i < numUsed; ++i)
|
||||||
|
{
|
||||||
|
if (objectToRemove == e[i])
|
||||||
|
{
|
||||||
|
remove (i, deleteObject);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a range of objects from the array.
|
||||||
|
|
||||||
|
This will remove a set of objects, starting from the given index,
|
||||||
|
and move any subsequent elements down to close the gap.
|
||||||
|
|
||||||
|
If the range extends beyond the bounds of the array, it will
|
||||||
|
be safely clipped to the size of the array.
|
||||||
|
|
||||||
|
@param startIndex the index of the first object to remove
|
||||||
|
@param numberToRemove how many objects should be removed
|
||||||
|
@param deleteObjects whether to delete the objects that get removed
|
||||||
|
@see remove, removeObject
|
||||||
|
*/
|
||||||
|
void removeRange (int startIndex,
|
||||||
|
const int numberToRemove,
|
||||||
|
const bool deleteObjects = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int endIndex = blimit (0, numUsed, startIndex + numberToRemove);
|
||||||
|
startIndex = blimit (0, numUsed, startIndex);
|
||||||
|
|
||||||
|
if (endIndex > startIndex)
|
||||||
|
{
|
||||||
|
if (deleteObjects)
|
||||||
|
{
|
||||||
|
for (int i = startIndex; i < endIndex; ++i)
|
||||||
|
{
|
||||||
|
delete data.elements [i];
|
||||||
|
data.elements [i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int rangeSize = endIndex - startIndex;
|
||||||
|
ObjectClass** e = data.elements + startIndex;
|
||||||
|
int numToShift = numUsed - endIndex;
|
||||||
|
numUsed -= rangeSize;
|
||||||
|
|
||||||
|
while (--numToShift >= 0)
|
||||||
|
{
|
||||||
|
*e = e [rangeSize];
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the last n objects from the array.
|
||||||
|
|
||||||
|
@param howManyToRemove how many objects to remove from the end of the array
|
||||||
|
@param deleteObjects whether to also delete the objects that are removed
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void removeLast (int howManyToRemove = 1,
|
||||||
|
const bool deleteObjects = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (howManyToRemove >= numUsed)
|
||||||
|
clear (deleteObjects);
|
||||||
|
else
|
||||||
|
removeRange (numUsed - howManyToRemove, howManyToRemove, deleteObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps a pair of objects in the array.
|
||||||
|
|
||||||
|
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||||
|
otherwise the two objects at these positions will be exchanged.
|
||||||
|
*/
|
||||||
|
void swap (const int index1,
|
||||||
|
const int index2) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (index1, numUsed)
|
||||||
|
&& isPositiveAndBelow (index2, numUsed))
|
||||||
|
{
|
||||||
|
std::swap (data.elements [index1],
|
||||||
|
data.elements [index2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Moves one of the objects to a different position.
|
||||||
|
|
||||||
|
This will move the object to a specified index, shuffling along
|
||||||
|
any intervening elements as required.
|
||||||
|
|
||||||
|
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||||
|
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||||
|
|
||||||
|
@param currentIndex the index of the object to be moved. If this isn't a
|
||||||
|
valid index, then nothing will be done
|
||||||
|
@param newIndex the index at which you'd like this object to end up. If this
|
||||||
|
is less than zero, it will be moved to the end of the array
|
||||||
|
*/
|
||||||
|
void move (const int currentIndex,
|
||||||
|
int newIndex) noexcept
|
||||||
|
{
|
||||||
|
if (currentIndex != newIndex)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (currentIndex, numUsed))
|
||||||
|
{
|
||||||
|
if (! isPositiveAndBelow (newIndex, numUsed))
|
||||||
|
newIndex = numUsed - 1;
|
||||||
|
|
||||||
|
ObjectClass* const value = data.elements [currentIndex];
|
||||||
|
|
||||||
|
if (newIndex > currentIndex)
|
||||||
|
{
|
||||||
|
memmove (data.elements + currentIndex,
|
||||||
|
data.elements + currentIndex + 1,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove (data.elements + newIndex + 1,
|
||||||
|
data.elements + newIndex,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.elements [newIndex] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This swaps the contents of this array with those of another array.
|
||||||
|
|
||||||
|
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||||
|
because it just swaps their internal pointers.
|
||||||
|
*/
|
||||||
|
void swapWithArray (OwnedArray& otherArray) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
const ScopedLockType lock2 (otherArray.getLock());
|
||||||
|
|
||||||
|
data.swapWith (otherArray.data);
|
||||||
|
std::swap (numUsed, otherArray.numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Reduces the amount of storage being used by the array.
|
||||||
|
|
||||||
|
Arrays typically allocate slightly more storage than they need, and after
|
||||||
|
removing elements, they may have quite a lot of unused space allocated.
|
||||||
|
This method will reduce the amount of allocated storage to a minimum.
|
||||||
|
*/
|
||||||
|
void minimiseStorageOverheads() noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.shrinkToNoMoreThan (numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||||
|
|
||||||
|
Calling this before adding a large known number of elements means that
|
||||||
|
the array won't have to keep dynamically resizing itself as the elements
|
||||||
|
are added, and it'll therefore be more efficient.
|
||||||
|
*/
|
||||||
|
void ensureStorageAllocated (const int minNumElements) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (minNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sorts the elements in the array.
|
||||||
|
|
||||||
|
This will use a comparator object to sort the elements into order. The object
|
||||||
|
passed must have a method of the form:
|
||||||
|
@code
|
||||||
|
int compareElements (ElementType first, ElementType second);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator the comparator to use for comparing elements.
|
||||||
|
@param retainOrderOfEquivalentItems if this is true, then items
|
||||||
|
which the comparator says are equivalent will be
|
||||||
|
kept in the order in which they currently appear
|
||||||
|
in the array. This is slower to perform, but may
|
||||||
|
be important in some cases. If it's false, a faster
|
||||||
|
algorithm is used, but equivalent elements may be
|
||||||
|
rearranged.
|
||||||
|
@see sortArray, indexOfSorted
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
void sort (ElementComparator& comparator,
|
||||||
|
const bool retainOrderOfEquivalentItems = false) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this array.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
||||||
|
int numUsed;
|
||||||
|
|
||||||
|
void deleteAllObjects()
|
||||||
|
{
|
||||||
|
while (numUsed > 0)
|
||||||
|
delete data.elements [--numUsed];
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_OWNEDARRAY_BEASTHEADER
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
PropertySet::PropertySet (const bool ignoreCaseOfKeyNames)
|
||||||
|
: properties (ignoreCaseOfKeyNames),
|
||||||
|
fallbackProperties (nullptr),
|
||||||
|
ignoreCaseOfKeys (ignoreCaseOfKeyNames)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertySet::PropertySet (const PropertySet& other)
|
||||||
|
: properties (other.properties),
|
||||||
|
fallbackProperties (other.fallbackProperties),
|
||||||
|
ignoreCaseOfKeys (other.ignoreCaseOfKeys)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertySet& PropertySet::operator= (const PropertySet& other)
|
||||||
|
{
|
||||||
|
properties = other.properties;
|
||||||
|
fallbackProperties = other.fallbackProperties;
|
||||||
|
ignoreCaseOfKeys = other.ignoreCaseOfKeys;
|
||||||
|
|
||||||
|
propertyChanged();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertySet::~PropertySet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::clear()
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
if (properties.size() > 0)
|
||||||
|
{
|
||||||
|
properties.clear();
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String PropertySet::getValue (const String& keyName,
|
||||||
|
const String& defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues() [index];
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PropertySet::getIntValue (const String& keyName,
|
||||||
|
const int defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues() [index].getIntValue();
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getIntValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double PropertySet::getDoubleValue (const String& keyName,
|
||||||
|
const double defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues()[index].getDoubleValue();
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getDoubleValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertySet::getBoolValue (const String& keyName,
|
||||||
|
const bool defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues() [index].getIntValue() != 0;
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getBoolValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlElement* PropertySet::getXmlValue (const String& keyName) const
|
||||||
|
{
|
||||||
|
return XmlDocument::parse (getValue (keyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::setValue (const String& keyName, const var& v)
|
||||||
|
{
|
||||||
|
bassert (keyName.isNotEmpty()); // shouldn't use an empty key name!
|
||||||
|
|
||||||
|
if (keyName.isNotEmpty())
|
||||||
|
{
|
||||||
|
const String value (v.toString());
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index < 0 || properties.getAllValues() [index] != value)
|
||||||
|
{
|
||||||
|
properties.set (keyName, value);
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::removeValue (const String& keyName)
|
||||||
|
{
|
||||||
|
if (keyName.isNotEmpty())
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
properties.remove (keyName);
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::setValue (const String& keyName, const XmlElement* const xml)
|
||||||
|
{
|
||||||
|
setValue (keyName, xml == nullptr ? var::null
|
||||||
|
: var (xml->createDocument (String::empty, true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertySet::containsKey (const String& keyName) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::addAllPropertiesFrom (const PropertySet& source)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (source.getLock());
|
||||||
|
|
||||||
|
for (int i = 0; i < source.properties.size(); ++i)
|
||||||
|
setValue (source.properties.getAllKeys() [i],
|
||||||
|
source.properties.getAllValues() [i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::setFallbackPropertySet (PropertySet* fallbackProperties_) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
fallbackProperties = fallbackProperties_;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlElement* PropertySet::createXml (const String& nodeName) const
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
XmlElement* const xml = new XmlElement (nodeName);
|
||||||
|
|
||||||
|
for (int i = 0; i < properties.getAllKeys().size(); ++i)
|
||||||
|
{
|
||||||
|
XmlElement* const e = xml->createNewChildElement ("VALUE");
|
||||||
|
e->setAttribute ("name", properties.getAllKeys()[i]);
|
||||||
|
e->setAttribute ("val", properties.getAllValues()[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::restoreFromXml (const XmlElement& xml)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
clear();
|
||||||
|
|
||||||
|
forEachXmlChildElementWithTagName (xml, e, "VALUE")
|
||||||
|
{
|
||||||
|
if (e->hasAttribute ("name")
|
||||||
|
&& e->hasAttribute ("val"))
|
||||||
|
{
|
||||||
|
properties.set (e->getStringAttribute ("name"),
|
||||||
|
e->getStringAttribute ("val"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.size() > 0)
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::propertyChanged()
|
||||||
|
{
|
||||||
|
}
|
||||||
214
Subtrees/beast/modules/beast_core/containers/beast_PropertySet.h
Normal file
214
Subtrees/beast/modules/beast_core/containers/beast_PropertySet.h
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_PROPERTYSET_BEASTHEADER
|
||||||
|
#define BEAST_PROPERTYSET_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_StringPairArray.h"
|
||||||
|
#include "../xml/beast_XmlElement.h"
|
||||||
|
#include "../containers/beast_Variant.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A set of named property values, which can be strings, integers, floating point, etc.
|
||||||
|
|
||||||
|
Effectively, this just wraps a StringPairArray in an interface that makes it easier
|
||||||
|
to load and save types other than strings.
|
||||||
|
|
||||||
|
See the PropertiesFile class for a subclass of this, which automatically broadcasts change
|
||||||
|
messages and saves/loads the list from a file.
|
||||||
|
*/
|
||||||
|
class BEAST_API PropertySet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty PropertySet.
|
||||||
|
@param ignoreCaseOfKeyNames if true, the names of properties are compared in a
|
||||||
|
case-insensitive way
|
||||||
|
*/
|
||||||
|
PropertySet (bool ignoreCaseOfKeyNames = false);
|
||||||
|
|
||||||
|
/** Creates a copy of another PropertySet. */
|
||||||
|
PropertySet (const PropertySet& other);
|
||||||
|
|
||||||
|
/** Copies another PropertySet over this one. */
|
||||||
|
PropertySet& operator= (const PropertySet& other);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~PropertySet();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns one of the properties as a string.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
String getValue (const String& keyName,
|
||||||
|
const String& defaultReturnValue = String::empty) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an integer.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
int getIntValue (const String& keyName,
|
||||||
|
const int defaultReturnValue = 0) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an double.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
double getDoubleValue (const String& keyName,
|
||||||
|
const double defaultReturnValue = 0.0) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an boolean.
|
||||||
|
|
||||||
|
The result will be true if the string found for this key name can be parsed as a non-zero
|
||||||
|
integer.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
bool getBoolValue (const String& keyName,
|
||||||
|
const bool defaultReturnValue = false) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an XML element.
|
||||||
|
|
||||||
|
The result will a new XMLElement object that the caller must delete. If may return 0 if the
|
||||||
|
key isn't found, or if the entry contains an string that isn't valid XML.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
*/
|
||||||
|
XmlElement* getXmlValue (const String& keyName) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets a named property.
|
||||||
|
|
||||||
|
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||||
|
@param value the new value to set it to
|
||||||
|
*/
|
||||||
|
void setValue (const String& keyName, const var& value);
|
||||||
|
|
||||||
|
/** Sets a named property to an XML element.
|
||||||
|
|
||||||
|
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||||
|
@param xml the new element to set it to. If this is zero, the value will be set to
|
||||||
|
an empty string
|
||||||
|
@see getXmlValue
|
||||||
|
*/
|
||||||
|
void setValue (const String& keyName, const XmlElement* xml);
|
||||||
|
|
||||||
|
/** This copies all the values from a source PropertySet to this one.
|
||||||
|
This won't remove any existing settings, it just adds any that it finds in the source set.
|
||||||
|
*/
|
||||||
|
void addAllPropertiesFrom (const PropertySet& source);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Deletes a property.
|
||||||
|
@param keyName the name of the property to delete. (This mustn't be an empty string)
|
||||||
|
*/
|
||||||
|
void removeValue (const String& keyName);
|
||||||
|
|
||||||
|
/** Returns true if the properies include the given key. */
|
||||||
|
bool containsKey (const String& keyName) const noexcept;
|
||||||
|
|
||||||
|
/** Removes all values. */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the keys/value pair array containing all the properties. */
|
||||||
|
StringPairArray& getAllProperties() noexcept { return properties; }
|
||||||
|
|
||||||
|
/** Returns the lock used when reading or writing to this set */
|
||||||
|
const CriticalSection& getLock() const noexcept { return lock; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns an XML element which encapsulates all the items in this property set.
|
||||||
|
The string parameter is the tag name that should be used for the node.
|
||||||
|
@see restoreFromXml
|
||||||
|
*/
|
||||||
|
XmlElement* createXml (const String& nodeName) const;
|
||||||
|
|
||||||
|
/** Reloads a set of properties that were previously stored as XML.
|
||||||
|
The node passed in must have been created by the createXml() method.
|
||||||
|
@see createXml
|
||||||
|
*/
|
||||||
|
void restoreFromXml (const XmlElement& xml);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets up a second PopertySet that will be used to look up any values that aren't
|
||||||
|
set in this one.
|
||||||
|
|
||||||
|
If you set this up to be a pointer to a second property set, then whenever one
|
||||||
|
of the getValue() methods fails to find an entry in this set, it will look up that
|
||||||
|
value in the fallback set, and if it finds it, it will return that.
|
||||||
|
|
||||||
|
Make sure that you don't delete the fallback set while it's still being used by
|
||||||
|
another set! To remove the fallback set, just call this method with a null pointer.
|
||||||
|
|
||||||
|
@see getFallbackPropertySet
|
||||||
|
*/
|
||||||
|
void setFallbackPropertySet (PropertySet* fallbackProperties) noexcept;
|
||||||
|
|
||||||
|
/** Returns the fallback property set.
|
||||||
|
@see setFallbackPropertySet
|
||||||
|
*/
|
||||||
|
PropertySet* getFallbackPropertySet() const noexcept { return fallbackProperties; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Subclasses can override this to be told when one of the properies has been changed. */
|
||||||
|
virtual void propertyChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
StringPairArray properties;
|
||||||
|
PropertySet* fallbackProperties;
|
||||||
|
CriticalSection lock;
|
||||||
|
bool ignoreCaseOfKeys;
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (PropertySet)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_PROPERTYSET_BEASTHEADER
|
||||||
@@ -0,0 +1,855 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||||
|
#define BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../memory/beast_ReferenceCountedObject.h"
|
||||||
|
#include "beast_ArrayAllocationBase.h"
|
||||||
|
#include "beast_ElementComparator.h"
|
||||||
|
#include "../threads/beast_CriticalSection.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a list of objects derived from ReferenceCountedObject.
|
||||||
|
|
||||||
|
A ReferenceCountedArray holds objects derived from ReferenceCountedObject,
|
||||||
|
and takes care of incrementing and decrementing their ref counts when they
|
||||||
|
are added and removed from the array.
|
||||||
|
|
||||||
|
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||||
|
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||||
|
|
||||||
|
@see Array, OwnedArray, StringArray
|
||||||
|
*/
|
||||||
|
template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
class ReferenceCountedArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty array.
|
||||||
|
@see ReferenceCountedObject, Array, OwnedArray
|
||||||
|
*/
|
||||||
|
ReferenceCountedArray() noexcept
|
||||||
|
: numUsed (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another array */
|
||||||
|
ReferenceCountedArray (const ReferenceCountedArray& other) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (other.getLock());
|
||||||
|
numUsed = other.size();
|
||||||
|
data.setAllocatedSize (numUsed);
|
||||||
|
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
|
||||||
|
|
||||||
|
for (int i = numUsed; --i >= 0;)
|
||||||
|
if (ObjectClass* o = data.elements[i])
|
||||||
|
o->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another array */
|
||||||
|
template <class OtherObjectClass, class OtherCriticalSection>
|
||||||
|
ReferenceCountedArray (const ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
|
||||||
|
{
|
||||||
|
const typename ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock (other.getLock());
|
||||||
|
numUsed = other.size();
|
||||||
|
data.setAllocatedSize (numUsed);
|
||||||
|
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
|
||||||
|
|
||||||
|
for (int i = numUsed; --i >= 0;)
|
||||||
|
if (ObjectClass* o = data.elements[i])
|
||||||
|
o->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another array into this one.
|
||||||
|
Any existing objects in this array will first be released.
|
||||||
|
*/
|
||||||
|
ReferenceCountedArray& operator= (const ReferenceCountedArray& other) noexcept
|
||||||
|
{
|
||||||
|
ReferenceCountedArray otherCopy (other);
|
||||||
|
swapWithArray (otherCopy);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another array into this one.
|
||||||
|
Any existing objects in this array will first be released.
|
||||||
|
*/
|
||||||
|
template <class OtherObjectClass>
|
||||||
|
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& operator= (const ReferenceCountedArray<OtherObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
|
||||||
|
{
|
||||||
|
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse> otherCopy (other);
|
||||||
|
swapWithArray (otherCopy);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
Any objects in the array will be released, and may be deleted if not referenced from elsewhere.
|
||||||
|
*/
|
||||||
|
~ReferenceCountedArray()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all objects from the array.
|
||||||
|
|
||||||
|
Any objects in the array that are not referenced from elsewhere will be deleted.
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
while (numUsed > 0)
|
||||||
|
if (ObjectClass* o = data.elements [--numUsed])
|
||||||
|
o->decReferenceCount();
|
||||||
|
|
||||||
|
bassert (numUsed == 0);
|
||||||
|
data.setAllocatedSize (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current number of objects in the array. */
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array.
|
||||||
|
|
||||||
|
If the index is out-of-range, this will return a null pointer, (and
|
||||||
|
it could be null anyway, because it's ok for the array to hold null
|
||||||
|
pointers as well as objects).
|
||||||
|
|
||||||
|
@see getUnchecked
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr operator[] (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return getObjectPointer (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array, without checking
|
||||||
|
whether the index is in-range.
|
||||||
|
|
||||||
|
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||||
|
it can be used when you're sure the index is always going to be legal.
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr getUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return getObjectPointerUnchecked (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a raw pointer to the object at this index in the array.
|
||||||
|
|
||||||
|
If the index is out-of-range, this will return a null pointer, (and
|
||||||
|
it could be null anyway, because it's ok for the array to hold null
|
||||||
|
pointers as well as objects).
|
||||||
|
|
||||||
|
@see getUnchecked
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getObjectPointer (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a raw pointer to the object at this index in the array, without checking
|
||||||
|
whether the index is in-range.
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getObjectPointerUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
bassert (isPositiveAndBelow (index, numUsed));
|
||||||
|
return data.elements [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the first object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getLast
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr getFirst() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
return numUsed > 0 ? data.elements [0]
|
||||||
|
: static_cast <ObjectClass*> (nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the last object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getFirst
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr getLast() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
return numUsed > 0 ? data.elements [numUsed - 1]
|
||||||
|
: static_cast <ObjectClass*> (nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the actual array data.
|
||||||
|
This pointer will only be valid until the next time a non-const method
|
||||||
|
is called on the array.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** getRawDataPointer() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the first element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** begin() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the element which follows the last element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** end() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements + numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds the index of the first occurrence of an object in the array.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns the index at which the object was found, or -1 if it's not found
|
||||||
|
*/
|
||||||
|
int indexOf (const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass** e = data.elements.getData();
|
||||||
|
ObjectClass** const endPointer = e + numUsed;
|
||||||
|
|
||||||
|
while (e != endPointer)
|
||||||
|
{
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return static_cast <int> (e - data.elements.getData());
|
||||||
|
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the array contains a specified object.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns true if the object is in the array
|
||||||
|
*/
|
||||||
|
bool contains (const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass** e = data.elements.getData();
|
||||||
|
ObjectClass** const endPointer = e + numUsed;
|
||||||
|
|
||||||
|
while (e != endPointer)
|
||||||
|
{
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends a new object to the end of the array.
|
||||||
|
|
||||||
|
This will increase the new object's reference count.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
|
||||||
|
*/
|
||||||
|
void add (ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
data.elements [numUsed++] = newObject;
|
||||||
|
|
||||||
|
if (newObject != nullptr)
|
||||||
|
newObject->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array at the given index.
|
||||||
|
|
||||||
|
If the index is less than 0 or greater than the size of the array, the
|
||||||
|
element will be added to the end of the array.
|
||||||
|
Otherwise, it will be inserted into the array, moving all the later elements
|
||||||
|
along to make room.
|
||||||
|
|
||||||
|
This will increase the new object's reference count.
|
||||||
|
|
||||||
|
@param indexToInsertAt the index at which the new element should be inserted
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@see add, addSorted, addIfNotAlreadyThere, set
|
||||||
|
*/
|
||||||
|
void insert (int indexToInsertAt,
|
||||||
|
ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
if (indexToInsertAt >= 0)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (indexToInsertAt > numUsed)
|
||||||
|
indexToInsertAt = numUsed;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
|
||||||
|
ObjectClass** const e = data.elements + indexToInsertAt;
|
||||||
|
const int numToMove = numUsed - indexToInsertAt;
|
||||||
|
|
||||||
|
if (numToMove > 0)
|
||||||
|
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
|
||||||
|
|
||||||
|
*e = newObject;
|
||||||
|
|
||||||
|
if (newObject != nullptr)
|
||||||
|
newObject->incReferenceCount();
|
||||||
|
|
||||||
|
++numUsed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
add (newObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends a new object at the end of the array as long as the array doesn't
|
||||||
|
already contain it.
|
||||||
|
|
||||||
|
If the array already contains a matching object, nothing will be done.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
*/
|
||||||
|
void addIfNotAlreadyThere (ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
if (! contains (newObject))
|
||||||
|
add (newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replaces an object in the array with a different one.
|
||||||
|
|
||||||
|
If the index is less than zero, this method does nothing.
|
||||||
|
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||||
|
|
||||||
|
The object being added has its reference count increased, and if it's replacing
|
||||||
|
another object, then that one has its reference count decreased, and may be deleted.
|
||||||
|
|
||||||
|
@param indexToChange the index whose value you want to change
|
||||||
|
@param newObject the new value to set for this index.
|
||||||
|
@see add, insert, remove
|
||||||
|
*/
|
||||||
|
void set (const int indexToChange,
|
||||||
|
ObjectClass* const newObject)
|
||||||
|
{
|
||||||
|
if (indexToChange >= 0)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (newObject != nullptr)
|
||||||
|
newObject->incReferenceCount();
|
||||||
|
|
||||||
|
if (indexToChange < numUsed)
|
||||||
|
{
|
||||||
|
if (ObjectClass* o = data.elements [indexToChange])
|
||||||
|
o->decReferenceCount();
|
||||||
|
|
||||||
|
data.elements [indexToChange] = newObject;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
data.elements [numUsed++] = newObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from another array to the end of this array.
|
||||||
|
|
||||||
|
@param arrayToAddFrom the array from which to copy the elements
|
||||||
|
@param startIndex the first element of the other array to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other array. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
void addArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||||
|
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
if (numElementsToAdd > 0)
|
||||||
|
{
|
||||||
|
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
add (arrayToAddFrom.getUnchecked (startIndex++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to find the position at which the new object
|
||||||
|
should go. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator object to use to compare the elements - see the
|
||||||
|
sort() method for details about this object's form
|
||||||
|
@param newObject the new object to insert to the array
|
||||||
|
@returns the index at which the new object was added
|
||||||
|
@see add, sort
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||||
|
insert (index, newObject);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts or replaces an object in the array, assuming it is sorted.
|
||||||
|
|
||||||
|
This is similar to addSorted, but if a matching element already exists, then it will be
|
||||||
|
replaced by the new one, rather than the new one being added as well.
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
void addOrReplaceSorted (ElementComparator& comparator,
|
||||||
|
ObjectClass* newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||||
|
|
||||||
|
if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0)
|
||||||
|
set (index - 1, newObject); // replace an existing object that matches
|
||||||
|
else
|
||||||
|
insert (index, newObject); // no match, so insert the new one
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to do a binary-chop to find the index of the given
|
||||||
|
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator to use to compare the elements - see the sort()
|
||||||
|
method for details about the form this object should take
|
||||||
|
@param objectToLookFor the object to search for
|
||||||
|
@returns the index of the element, or -1 if it's not found
|
||||||
|
@see addSorted, sort
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
int indexOfSorted (ElementComparator& comparator,
|
||||||
|
const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
int s = 0, e = numUsed;
|
||||||
|
|
||||||
|
while (s < e)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
if (halfway == s)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
|
||||||
|
s = halfway;
|
||||||
|
else
|
||||||
|
e = halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes an object from the array.
|
||||||
|
|
||||||
|
This will remove the object at a given index and move back all the
|
||||||
|
subsequent objects to close the gap.
|
||||||
|
|
||||||
|
If the index passed in is out-of-range, nothing will happen.
|
||||||
|
|
||||||
|
The object that is removed will have its reference count decreased,
|
||||||
|
and may be deleted if not referenced from elsewhere.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@see removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void remove (const int indexToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
|
||||||
|
if (ObjectClass* o = *e)
|
||||||
|
o->decReferenceCount();
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numberToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numberToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes and returns an object from the array.
|
||||||
|
|
||||||
|
This will remove the object at a given index and return it, moving back all
|
||||||
|
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||||
|
nothing will happen and a null pointer will be returned.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
ObjectClassPtr removeAndReturn (const int indexToRemove)
|
||||||
|
{
|
||||||
|
ObjectClassPtr removedItem;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
|
||||||
|
if (ObjectClass* o = *e)
|
||||||
|
{
|
||||||
|
removedItem = o;
|
||||||
|
o->decReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numberToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numberToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
return removedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the first occurrence of a specified object from the array.
|
||||||
|
|
||||||
|
If the item isn't found, no action is taken. If it is found, it is
|
||||||
|
removed and has its reference count decreased.
|
||||||
|
|
||||||
|
@param objectToRemove the object to try to remove
|
||||||
|
@see remove, removeRange
|
||||||
|
*/
|
||||||
|
void removeObject (ObjectClass* const objectToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
remove (indexOf (objectToRemove));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a range of objects from the array.
|
||||||
|
|
||||||
|
This will remove a set of objects, starting from the given index,
|
||||||
|
and move any subsequent elements down to close the gap.
|
||||||
|
|
||||||
|
If the range extends beyond the bounds of the array, it will
|
||||||
|
be safely clipped to the size of the array.
|
||||||
|
|
||||||
|
The objects that are removed will have their reference counts decreased,
|
||||||
|
and may be deleted if not referenced from elsewhere.
|
||||||
|
|
||||||
|
@param startIndex the index of the first object to remove
|
||||||
|
@param numberToRemove how many objects should be removed
|
||||||
|
@see remove, removeObject
|
||||||
|
*/
|
||||||
|
void removeRange (const int startIndex,
|
||||||
|
const int numberToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
const int start = blimit (0, numUsed, startIndex);
|
||||||
|
const int endIndex = blimit (0, numUsed, startIndex + numberToRemove);
|
||||||
|
|
||||||
|
if (endIndex > start)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = start; i < endIndex; ++i)
|
||||||
|
{
|
||||||
|
if (ObjectClass* o = data.elements[i])
|
||||||
|
{
|
||||||
|
o->decReferenceCount();
|
||||||
|
data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int rangeSize = endIndex - start;
|
||||||
|
ObjectClass** e = data.elements + start;
|
||||||
|
i = numUsed - endIndex;
|
||||||
|
numUsed -= rangeSize;
|
||||||
|
|
||||||
|
while (--i >= 0)
|
||||||
|
{
|
||||||
|
*e = e [rangeSize];
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the last n objects from the array.
|
||||||
|
|
||||||
|
The objects that are removed will have their reference counts decreased,
|
||||||
|
and may be deleted if not referenced from elsewhere.
|
||||||
|
|
||||||
|
@param howManyToRemove how many objects to remove from the end of the array
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void removeLast (int howManyToRemove = 1)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (howManyToRemove > numUsed)
|
||||||
|
howManyToRemove = numUsed;
|
||||||
|
|
||||||
|
while (--howManyToRemove >= 0)
|
||||||
|
remove (numUsed - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps a pair of objects in the array.
|
||||||
|
|
||||||
|
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||||
|
otherwise the two objects at these positions will be exchanged.
|
||||||
|
*/
|
||||||
|
void swap (const int index1,
|
||||||
|
const int index2) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (index1, numUsed)
|
||||||
|
&& isPositiveAndBelow (index2, numUsed))
|
||||||
|
{
|
||||||
|
std::swap (data.elements [index1],
|
||||||
|
data.elements [index2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Moves one of the objects to a different position.
|
||||||
|
|
||||||
|
This will move the object to a specified index, shuffling along
|
||||||
|
any intervening elements as required.
|
||||||
|
|
||||||
|
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||||
|
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||||
|
|
||||||
|
@param currentIndex the index of the object to be moved. If this isn't a
|
||||||
|
valid index, then nothing will be done
|
||||||
|
@param newIndex the index at which you'd like this object to end up. If this
|
||||||
|
is less than zero, it will be moved to the end of the array
|
||||||
|
*/
|
||||||
|
void move (const int currentIndex,
|
||||||
|
int newIndex) noexcept
|
||||||
|
{
|
||||||
|
if (currentIndex != newIndex)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (currentIndex, numUsed))
|
||||||
|
{
|
||||||
|
if (! isPositiveAndBelow (newIndex, numUsed))
|
||||||
|
newIndex = numUsed - 1;
|
||||||
|
|
||||||
|
ObjectClass* const value = data.elements [currentIndex];
|
||||||
|
|
||||||
|
if (newIndex > currentIndex)
|
||||||
|
{
|
||||||
|
memmove (data.elements + currentIndex,
|
||||||
|
data.elements + currentIndex + 1,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove (data.elements + newIndex + 1,
|
||||||
|
data.elements + newIndex,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.elements [newIndex] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This swaps the contents of this array with those of another array.
|
||||||
|
|
||||||
|
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||||
|
because it just swaps their internal pointers.
|
||||||
|
*/
|
||||||
|
void swapWithArray (ReferenceCountedArray& otherArray) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
const ScopedLockType lock2 (otherArray.getLock());
|
||||||
|
|
||||||
|
data.swapWith (otherArray.data);
|
||||||
|
std::swap (numUsed, otherArray.numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares this array to another one.
|
||||||
|
|
||||||
|
@returns true only if the other array contains the same objects in the same order
|
||||||
|
*/
|
||||||
|
bool operator== (const ReferenceCountedArray& other) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock2 (other.getLock());
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
|
||||||
|
if (numUsed != other.numUsed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = numUsed; --i >= 0;)
|
||||||
|
if (data.elements [i] != other.data.elements [i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares this array to another one.
|
||||||
|
|
||||||
|
@see operator==
|
||||||
|
*/
|
||||||
|
bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sorts the elements in the array.
|
||||||
|
|
||||||
|
This will use a comparator object to sort the elements into order. The object
|
||||||
|
passed must have a method of the form:
|
||||||
|
@code
|
||||||
|
int compareElements (ElementType first, ElementType second);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator the comparator to use for comparing elements.
|
||||||
|
@param retainOrderOfEquivalentItems if this is true, then items
|
||||||
|
which the comparator says are equivalent will be
|
||||||
|
kept in the order in which they currently appear
|
||||||
|
in the array. This is slower to perform, but may
|
||||||
|
be important in some cases. If it's false, a faster
|
||||||
|
algorithm is used, but equivalent elements may be
|
||||||
|
rearranged.
|
||||||
|
|
||||||
|
@see sortArray
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
void sort (ElementComparator& comparator,
|
||||||
|
const bool retainOrderOfEquivalentItems = false) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Reduces the amount of storage being used by the array.
|
||||||
|
|
||||||
|
Arrays typically allocate slightly more storage than they need, and after
|
||||||
|
removing elements, they may have quite a lot of unused space allocated.
|
||||||
|
This method will reduce the amount of allocated storage to a minimum.
|
||||||
|
*/
|
||||||
|
void minimiseStorageOverheads() noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.shrinkToNoMoreThan (numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||||
|
|
||||||
|
Calling this before adding a large known number of elements means that
|
||||||
|
the array won't have to keep dynamically resizing itself as the elements
|
||||||
|
are added, and it'll therefore be more efficient.
|
||||||
|
*/
|
||||||
|
void ensureStorageAllocated (const int minNumElements)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (minNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this array.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
||||||
|
int numUsed;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_REFERENCECOUNTEDARRAY_BEASTHEADER
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||||
|
#define BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Helper class providing an RAII-based mechanism for temporarily setting and
|
||||||
|
then re-setting a value.
|
||||||
|
|
||||||
|
E.g. @code
|
||||||
|
int x = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopedValueSetter setter (x, 2);
|
||||||
|
|
||||||
|
// x is now 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// x is now 1 again
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopedValueSetter setter (x, 3, 4);
|
||||||
|
|
||||||
|
// x is now 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// x is now 4
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
*/
|
||||||
|
template <typename ValueType>
|
||||||
|
class ScopedValueSetter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||||
|
given new value, and will then reset it to its original value when this object is deleted.
|
||||||
|
*/
|
||||||
|
ScopedValueSetter (ValueType& valueToSet,
|
||||||
|
ValueType newValue)
|
||||||
|
: value (valueToSet),
|
||||||
|
originalValue (valueToSet)
|
||||||
|
{
|
||||||
|
valueToSet = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||||
|
given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
|
||||||
|
*/
|
||||||
|
ScopedValueSetter (ValueType& valueToSet,
|
||||||
|
ValueType newValue,
|
||||||
|
ValueType valueWhenDeleted)
|
||||||
|
: value (valueToSet),
|
||||||
|
originalValue (valueWhenDeleted)
|
||||||
|
{
|
||||||
|
valueToSet = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedValueSetter()
|
||||||
|
{
|
||||||
|
value = originalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ValueType& value;
|
||||||
|
const ValueType originalValue;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (ScopedValueSetter)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_SCOPEDVALUESETTER_BEASTHEADER
|
||||||
494
Subtrees/beast/modules/beast_core/containers/beast_SortedSet.h
Normal file
494
Subtrees/beast/modules/beast_core/containers/beast_SortedSet.h
Normal file
@@ -0,0 +1,494 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_SORTEDSET_BEASTHEADER
|
||||||
|
#define BEAST_SORTEDSET_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_ArrayAllocationBase.h"
|
||||||
|
#include "../threads/beast_CriticalSection.h"
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4512)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a set of unique primitive objects, such as ints or doubles.
|
||||||
|
|
||||||
|
A set can only hold one item with a given value, so if for example it's a
|
||||||
|
set of integers, attempting to add the same integer twice will do nothing
|
||||||
|
the second time.
|
||||||
|
|
||||||
|
Internally, the list of items is kept sorted (which means that whatever
|
||||||
|
kind of primitive type is used must support the ==, <, >, <= and >= operators
|
||||||
|
to determine the order), and searching the set for known values is very fast
|
||||||
|
because it uses a binary-chop method.
|
||||||
|
|
||||||
|
Note that if you're using a class or struct as the element type, it must be
|
||||||
|
capable of being copied or moved with a straightforward memcpy, rather than
|
||||||
|
needing construction and destruction code.
|
||||||
|
|
||||||
|
To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
|
||||||
|
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||||
|
|
||||||
|
@see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
|
||||||
|
*/
|
||||||
|
template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
class SortedSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty set. */
|
||||||
|
SortedSet() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another set.
|
||||||
|
@param other the set to copy
|
||||||
|
*/
|
||||||
|
SortedSet (const SortedSet& other)
|
||||||
|
: data (other.data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~SortedSet() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another set over this one.
|
||||||
|
@param other the set to copy
|
||||||
|
*/
|
||||||
|
SortedSet& operator= (const SortedSet& other) noexcept
|
||||||
|
{
|
||||||
|
data = other.data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares this set to another one.
|
||||||
|
Two sets are considered equal if they both contain the same set of elements.
|
||||||
|
@param other the other set to compare with
|
||||||
|
*/
|
||||||
|
bool operator== (const SortedSet<ElementType>& other) const noexcept
|
||||||
|
{
|
||||||
|
return data == other.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares this set to another one.
|
||||||
|
Two sets are considered equal if they both contain the same set of elements.
|
||||||
|
@param other the other set to compare with
|
||||||
|
*/
|
||||||
|
bool operator!= (const SortedSet<ElementType>& other) const noexcept
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all elements from the set.
|
||||||
|
|
||||||
|
This will remove all the elements, and free any storage that the set is
|
||||||
|
using. To clear it without freeing the storage, use the clearQuick()
|
||||||
|
method instead.
|
||||||
|
|
||||||
|
@see clearQuick
|
||||||
|
*/
|
||||||
|
void clear() noexcept
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes all elements from the set without freeing the array's allocated storage.
|
||||||
|
|
||||||
|
@see clear
|
||||||
|
*/
|
||||||
|
void clearQuick() noexcept
|
||||||
|
{
|
||||||
|
data.clearQuick();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the current number of elements in the set.
|
||||||
|
*/
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the elements in the set.
|
||||||
|
|
||||||
|
If the index passed in is beyond the range of valid elements, this
|
||||||
|
will return zero.
|
||||||
|
|
||||||
|
If you're certain that the index will always be a valid element, you
|
||||||
|
can call getUnchecked() instead, which is faster.
|
||||||
|
|
||||||
|
@param index the index of the element being requested (0 is the first element in the set)
|
||||||
|
@see getUnchecked, getFirst, getLast
|
||||||
|
*/
|
||||||
|
inline ElementType operator[] (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return data [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the elements in the set, without checking the index passed in.
|
||||||
|
Unlike the operator[] method, this will try to return an element without
|
||||||
|
checking that the index is within the bounds of the set, so should only
|
||||||
|
be used when you're confident that it will always be a valid index.
|
||||||
|
|
||||||
|
@param index the index of the element being requested (0 is the first element in the set)
|
||||||
|
@see operator[], getFirst, getLast
|
||||||
|
*/
|
||||||
|
inline ElementType getUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return data.getUnchecked (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
|
||||||
|
|
||||||
|
This is like getUnchecked, but returns a direct reference to the element, so that
|
||||||
|
you can alter it directly. Obviously this can be dangerous, so only use it when
|
||||||
|
absolutely necessary.
|
||||||
|
|
||||||
|
@param index the index of the element being requested (0 is the first element in the array)
|
||||||
|
*/
|
||||||
|
inline ElementType& getReference (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return data.getReference (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first element in the set, or 0 if the set is empty.
|
||||||
|
|
||||||
|
@see operator[], getUnchecked, getLast
|
||||||
|
*/
|
||||||
|
inline ElementType getFirst() const noexcept
|
||||||
|
{
|
||||||
|
return data.getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the last element in the set, or 0 if the set is empty.
|
||||||
|
|
||||||
|
@see operator[], getUnchecked, getFirst
|
||||||
|
*/
|
||||||
|
inline ElementType getLast() const noexcept
|
||||||
|
{
|
||||||
|
return data.getLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the first element in the set.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ElementType* begin() const noexcept
|
||||||
|
{
|
||||||
|
return data.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the element which follows the last element in the set.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ElementType* end() const noexcept
|
||||||
|
{
|
||||||
|
return data.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds the index of the first element which matches the value passed in.
|
||||||
|
|
||||||
|
This will search the set for the given object, and return the index
|
||||||
|
of its first occurrence. If the object isn't found, the method will return -1.
|
||||||
|
|
||||||
|
@param elementToLookFor the value or object to look for
|
||||||
|
@returns the index of the object, or -1 if it's not found
|
||||||
|
*/
|
||||||
|
int indexOf (const ElementType& elementToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (data.getLock());
|
||||||
|
|
||||||
|
int s = 0;
|
||||||
|
int e = data.size();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (s >= e)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (elementToLookFor == data.getReference (s))
|
||||||
|
return s;
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
|
||||||
|
if (halfway == s)
|
||||||
|
return -1;
|
||||||
|
else if (elementToLookFor < data.getReference (halfway))
|
||||||
|
e = halfway;
|
||||||
|
else
|
||||||
|
s = halfway;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the set contains at least one occurrence of an object.
|
||||||
|
|
||||||
|
@param elementToLookFor the value or object to look for
|
||||||
|
@returns true if the item is found
|
||||||
|
*/
|
||||||
|
bool contains (const ElementType& elementToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
return indexOf (elementToLookFor) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds a new element to the set, (as long as it's not already in there).
|
||||||
|
|
||||||
|
Note that if a matching element already exists, the new value will be assigned
|
||||||
|
to the existing one using operator=, so that if there are any differences between
|
||||||
|
the objects which were not recognised by the object's operator==, then the
|
||||||
|
set will always contain a copy of the most recently added one.
|
||||||
|
|
||||||
|
@param newElement the new object to add to the set
|
||||||
|
@returns true if the value was added, or false if it already existed
|
||||||
|
@see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
|
||||||
|
*/
|
||||||
|
bool add (const ElementType& newElement) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
int s = 0;
|
||||||
|
int e = data.size();
|
||||||
|
|
||||||
|
while (s < e)
|
||||||
|
{
|
||||||
|
ElementType& elem = data.getReference (s);
|
||||||
|
if (newElement == elem)
|
||||||
|
{
|
||||||
|
elem = newElement; // force an update in case operator== permits differences.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
const bool isBeforeHalfway = (newElement < data.getReference (halfway));
|
||||||
|
|
||||||
|
if (halfway == s)
|
||||||
|
{
|
||||||
|
if (! isBeforeHalfway)
|
||||||
|
++s;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (isBeforeHalfway)
|
||||||
|
e = halfway;
|
||||||
|
else
|
||||||
|
s = halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.insert (s, newElement);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from an array to this set.
|
||||||
|
|
||||||
|
@param elementsToAdd the array of elements to add
|
||||||
|
@param numElementsToAdd how many elements are in this other array
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
void addArray (const ElementType* elementsToAdd,
|
||||||
|
int numElementsToAdd) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
add (*elementsToAdd++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from another set to this one.
|
||||||
|
|
||||||
|
@param setToAddFrom the set from which to copy the elements
|
||||||
|
@param startIndex the first element of the other set to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other set. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
template <class OtherSetType>
|
||||||
|
void addSet (const OtherSetType& setToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1) noexcept
|
||||||
|
{
|
||||||
|
const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
bassert (this != &setToAddFrom);
|
||||||
|
|
||||||
|
if (this != &setToAddFrom)
|
||||||
|
{
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
|
||||||
|
numElementsToAdd = setToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
if (numElementsToAdd > 0)
|
||||||
|
addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes an element from the set.
|
||||||
|
|
||||||
|
This will remove the element at a given index.
|
||||||
|
If the index passed in is out-of-range, nothing will happen.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@returns the element that has been removed
|
||||||
|
@see removeValue, removeRange
|
||||||
|
*/
|
||||||
|
ElementType remove (const int indexToRemove) noexcept
|
||||||
|
{
|
||||||
|
return data.remove (indexToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes an item from the set.
|
||||||
|
|
||||||
|
This will remove the given element from the set, if it's there.
|
||||||
|
|
||||||
|
@param valueToRemove the object to try to remove
|
||||||
|
@see remove, removeRange
|
||||||
|
*/
|
||||||
|
void removeValue (const ElementType valueToRemove) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.remove (indexOf (valueToRemove));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes any elements which are also in another set.
|
||||||
|
|
||||||
|
@param otherSet the other set in which to look for elements to remove
|
||||||
|
@see removeValuesNotIn, remove, removeValue, removeRange
|
||||||
|
*/
|
||||||
|
template <class OtherSetType>
|
||||||
|
void removeValuesIn (const OtherSetType& otherSet) noexcept
|
||||||
|
{
|
||||||
|
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (this == &otherSet)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
else if (otherSet.size() > 0)
|
||||||
|
{
|
||||||
|
for (int i = data.size(); --i >= 0;)
|
||||||
|
if (otherSet.contains (data.getReference (i)))
|
||||||
|
remove (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes any elements which are not found in another set.
|
||||||
|
|
||||||
|
Only elements which occur in this other set will be retained.
|
||||||
|
|
||||||
|
@param otherSet the set in which to look for elements NOT to remove
|
||||||
|
@see removeValuesIn, remove, removeValue, removeRange
|
||||||
|
*/
|
||||||
|
template <class OtherSetType>
|
||||||
|
void removeValuesNotIn (const OtherSetType& otherSet) noexcept
|
||||||
|
{
|
||||||
|
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (this != &otherSet)
|
||||||
|
{
|
||||||
|
if (otherSet.size() <= 0)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = data.size(); --i >= 0;)
|
||||||
|
if (! otherSet.contains (data.getReference (i)))
|
||||||
|
remove (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This swaps the contents of this array with those of another array.
|
||||||
|
|
||||||
|
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||||
|
because it just swaps their internal pointers.
|
||||||
|
*/
|
||||||
|
void swapWith (SortedSet& otherSet) noexcept
|
||||||
|
{
|
||||||
|
data.swapWithArray (otherSet.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Reduces the amount of storage being used by the set.
|
||||||
|
|
||||||
|
Sets typically allocate slightly more storage than they need, and after
|
||||||
|
removing elements, they may have quite a lot of unused space allocated.
|
||||||
|
This method will reduce the amount of allocated storage to a minimum.
|
||||||
|
*/
|
||||||
|
void minimiseStorageOverheads() noexcept
|
||||||
|
{
|
||||||
|
data.minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the set's internal storage to hold a minimum number of elements.
|
||||||
|
|
||||||
|
Calling this before adding a large known number of elements means that
|
||||||
|
the set won't have to keep dynamically resizing itself as the elements
|
||||||
|
are added, and it'll therefore be more efficient.
|
||||||
|
*/
|
||||||
|
void ensureStorageAllocated (const int minNumElements)
|
||||||
|
{
|
||||||
|
data.ensureStorageAllocated (minNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this array.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data.getLock(); }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
Array <ElementType, TypeOfCriticalSectionToUse> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BEAST_SORTEDSET_BEASTHEADER
|
||||||
296
Subtrees/beast/modules/beast_core/containers/beast_SparseSet.h
Normal file
296
Subtrees/beast/modules/beast_core/containers/beast_SparseSet.h
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_SPARSESET_BEASTHEADER
|
||||||
|
#define BEAST_SPARSESET_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../maths/beast_Range.h"
|
||||||
|
#include "../threads/beast_CriticalSection.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a set of primitive values, storing them as a set of ranges.
|
||||||
|
|
||||||
|
This container acts like an array, but can efficiently hold large contiguous
|
||||||
|
ranges of values. It's quite a specialised class, mostly useful for things
|
||||||
|
like keeping the set of selected rows in a listbox.
|
||||||
|
|
||||||
|
The type used as a template paramter must be an integer type, such as int, short,
|
||||||
|
int64, etc.
|
||||||
|
*/
|
||||||
|
template <class Type>
|
||||||
|
class SparseSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a new empty set. */
|
||||||
|
SparseSet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another SparseSet. */
|
||||||
|
SparseSet (const SparseSet<Type>& other)
|
||||||
|
: values (other.values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Clears the set. */
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
values.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether the set is empty.
|
||||||
|
|
||||||
|
This is much quicker than using (size() == 0).
|
||||||
|
*/
|
||||||
|
bool isEmpty() const noexcept
|
||||||
|
{
|
||||||
|
return values.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of values in the set.
|
||||||
|
|
||||||
|
Because of the way the data is stored, this method can take longer if there
|
||||||
|
are a lot of items in the set. Use isEmpty() for a quick test of whether there
|
||||||
|
are any items.
|
||||||
|
*/
|
||||||
|
Type size() const
|
||||||
|
{
|
||||||
|
Type total (0);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); i += 2)
|
||||||
|
total += values.getUnchecked (i + 1) - values.getUnchecked (i);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the values in the set.
|
||||||
|
|
||||||
|
@param index the index of the value to retrieve, in the range 0 to (size() - 1).
|
||||||
|
@returns the value at this index, or 0 if it's out-of-range
|
||||||
|
*/
|
||||||
|
Type operator[] (Type index) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < values.size(); i += 2)
|
||||||
|
{
|
||||||
|
const Type start (values.getUnchecked (i));
|
||||||
|
const Type len (values.getUnchecked (i + 1) - start);
|
||||||
|
|
||||||
|
if (index < len)
|
||||||
|
return start + index;
|
||||||
|
|
||||||
|
index -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Type();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether a particular value is in the set. */
|
||||||
|
bool contains (const Type valueToLookFor) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < values.size(); ++i)
|
||||||
|
if (valueToLookFor < values.getUnchecked(i))
|
||||||
|
return (i & 1) != 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the number of contiguous blocks of values.
|
||||||
|
@see getRange
|
||||||
|
*/
|
||||||
|
int getNumRanges() const noexcept
|
||||||
|
{
|
||||||
|
return values.size() >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the contiguous ranges of values stored.
|
||||||
|
@param rangeIndex the index of the range to look up, between 0
|
||||||
|
and (getNumRanges() - 1)
|
||||||
|
@see getTotalRange
|
||||||
|
*/
|
||||||
|
const Range<Type> getRange (const int rangeIndex) const
|
||||||
|
{
|
||||||
|
if (isPositiveAndBelow (rangeIndex, getNumRanges()))
|
||||||
|
return Range<Type> (values.getUnchecked (rangeIndex << 1),
|
||||||
|
values.getUnchecked ((rangeIndex << 1) + 1));
|
||||||
|
|
||||||
|
return Range<Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the range between the lowest and highest values in the set.
|
||||||
|
@see getRange
|
||||||
|
*/
|
||||||
|
Range<Type> getTotalRange() const
|
||||||
|
{
|
||||||
|
if (values.size() > 0)
|
||||||
|
{
|
||||||
|
bassert ((values.size() & 1) == 0);
|
||||||
|
return Range<Type> (values.getUnchecked (0),
|
||||||
|
values.getUnchecked (values.size() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Range<Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds a range of contiguous values to the set.
|
||||||
|
e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
|
||||||
|
*/
|
||||||
|
void addRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
bassert (range.getLength() >= 0);
|
||||||
|
if (range.getLength() > 0)
|
||||||
|
{
|
||||||
|
removeRange (range);
|
||||||
|
|
||||||
|
values.addUsingDefaultSort (range.getStart());
|
||||||
|
values.addUsingDefaultSort (range.getEnd());
|
||||||
|
|
||||||
|
simplify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a range of values from the set.
|
||||||
|
e.g. removeRange (Range\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
|
||||||
|
*/
|
||||||
|
void removeRange (const Range<Type> rangeToRemove)
|
||||||
|
{
|
||||||
|
bassert (rangeToRemove.getLength() >= 0);
|
||||||
|
|
||||||
|
if (rangeToRemove.getLength() > 0
|
||||||
|
&& values.size() > 0
|
||||||
|
&& rangeToRemove.getStart() < values.getUnchecked (values.size() - 1)
|
||||||
|
&& values.getUnchecked(0) < rangeToRemove.getEnd())
|
||||||
|
{
|
||||||
|
const bool onAtStart = contains (rangeToRemove.getStart() - 1);
|
||||||
|
const Type lastValue (bmin (rangeToRemove.getEnd(), values.getLast()));
|
||||||
|
const bool onAtEnd = contains (lastValue);
|
||||||
|
|
||||||
|
for (int i = values.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
if (values.getUnchecked(i) <= lastValue)
|
||||||
|
{
|
||||||
|
while (values.getUnchecked(i) >= rangeToRemove.getStart())
|
||||||
|
{
|
||||||
|
values.remove (i);
|
||||||
|
|
||||||
|
if (--i < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onAtStart) values.addUsingDefaultSort (rangeToRemove.getStart());
|
||||||
|
if (onAtEnd) values.addUsingDefaultSort (lastValue);
|
||||||
|
|
||||||
|
simplify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Does an XOR of the values in a given range. */
|
||||||
|
void invertRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
SparseSet newItems;
|
||||||
|
newItems.addRange (range);
|
||||||
|
|
||||||
|
for (int i = getNumRanges(); --i >= 0;)
|
||||||
|
newItems.removeRange (getRange (i));
|
||||||
|
|
||||||
|
removeRange (range);
|
||||||
|
|
||||||
|
for (int i = newItems.getNumRanges(); --i >= 0;)
|
||||||
|
addRange (newItems.getRange(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether any part of a given range overlaps any part of this set. */
|
||||||
|
bool overlapsRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
if (range.getLength() > 0)
|
||||||
|
{
|
||||||
|
for (int i = getNumRanges(); --i >= 0;)
|
||||||
|
{
|
||||||
|
if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (values.getUnchecked (i << 1) < range.getEnd())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether the whole of a given range is contained within this one. */
|
||||||
|
bool containsRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
if (range.getLength() > 0)
|
||||||
|
{
|
||||||
|
for (int i = getNumRanges(); --i >= 0;)
|
||||||
|
{
|
||||||
|
if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (values.getUnchecked (i << 1) <= range.getStart()
|
||||||
|
&& range.getEnd() <= values.getUnchecked ((i << 1) + 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool operator== (const SparseSet<Type>& other) noexcept
|
||||||
|
{
|
||||||
|
return values == other.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (const SparseSet<Type>& other) noexcept
|
||||||
|
{
|
||||||
|
return values != other.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
// alternating start/end values of ranges of values that are present.
|
||||||
|
Array<Type, DummyCriticalSection> values;
|
||||||
|
|
||||||
|
void simplify()
|
||||||
|
{
|
||||||
|
bassert ((values.size() & 1) == 0);
|
||||||
|
|
||||||
|
for (int i = values.size(); --i > 0;)
|
||||||
|
if (values.getUnchecked(i) == values.getUnchecked (i - 1))
|
||||||
|
values.removeRange (--i, 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_SPARSESET_BEASTHEADER
|
||||||
704
Subtrees/beast/modules/beast_core/containers/beast_Variant.cpp
Normal file
704
Subtrees/beast/modules/beast_core/containers/beast_Variant.cpp
Normal file
@@ -0,0 +1,704 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
enum VariantStreamMarkers
|
||||||
|
{
|
||||||
|
varMarker_Int = 1,
|
||||||
|
varMarker_BoolTrue = 2,
|
||||||
|
varMarker_BoolFalse = 3,
|
||||||
|
varMarker_Double = 4,
|
||||||
|
varMarker_String = 5,
|
||||||
|
varMarker_Int64 = 6,
|
||||||
|
varMarker_Array = 7,
|
||||||
|
varMarker_Binary = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType() noexcept {}
|
||||||
|
virtual ~VariantType() noexcept {}
|
||||||
|
|
||||||
|
virtual int toInt (const ValueUnion&) const noexcept { return 0; }
|
||||||
|
virtual int64 toInt64 (const ValueUnion&) const noexcept { return 0; }
|
||||||
|
virtual double toDouble (const ValueUnion&) const noexcept { return 0; }
|
||||||
|
virtual String toString (const ValueUnion&) const { return String::empty; }
|
||||||
|
virtual bool toBool (const ValueUnion&) const noexcept { return false; }
|
||||||
|
virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
|
||||||
|
virtual Array<var>* toArray (const ValueUnion&) const noexcept { return nullptr; }
|
||||||
|
virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; }
|
||||||
|
|
||||||
|
virtual bool isVoid() const noexcept { return false; }
|
||||||
|
virtual bool isInt() const noexcept { return false; }
|
||||||
|
virtual bool isInt64() const noexcept { return false; }
|
||||||
|
virtual bool isBool() const noexcept { return false; }
|
||||||
|
virtual bool isDouble() const noexcept { return false; }
|
||||||
|
virtual bool isString() const noexcept { return false; }
|
||||||
|
virtual bool isObject() const noexcept { return false; }
|
||||||
|
virtual bool isArray() const noexcept { return false; }
|
||||||
|
virtual bool isBinary() const noexcept { return false; }
|
||||||
|
virtual bool isMethod() const noexcept { return false; }
|
||||||
|
|
||||||
|
virtual void cleanUp (ValueUnion&) const noexcept {}
|
||||||
|
virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; }
|
||||||
|
virtual bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept = 0;
|
||||||
|
virtual void writeToStream (const ValueUnion& data, OutputStream& output) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Void : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Void() noexcept {}
|
||||||
|
static const VariantType_Void instance;
|
||||||
|
|
||||||
|
bool isVoid() const noexcept { return true; }
|
||||||
|
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept { return otherType.isVoid(); }
|
||||||
|
void writeToStream (const ValueUnion&, OutputStream& output) const { output.writeCompressedInt (0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Int : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Int() noexcept {}
|
||||||
|
static const VariantType_Int instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept { return data.intValue; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.intValue; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept { return (double) data.intValue; }
|
||||||
|
String toString (const ValueUnion& data) const { return String (data.intValue); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept { return data.intValue != 0; }
|
||||||
|
bool isInt() const noexcept { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
return otherType.toInt (otherData) == data.intValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (5);
|
||||||
|
output.writeByte (varMarker_Int);
|
||||||
|
output.writeInt (data.intValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Int64 : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Int64() noexcept {}
|
||||||
|
static const VariantType_Int64 instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept { return (int) data.int64Value; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept { return data.int64Value; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept { return (double) data.int64Value; }
|
||||||
|
String toString (const ValueUnion& data) const { return String (data.int64Value); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept { return data.int64Value != 0; }
|
||||||
|
bool isInt64() const noexcept { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
return otherType.toInt64 (otherData) == data.int64Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (9);
|
||||||
|
output.writeByte (varMarker_Int64);
|
||||||
|
output.writeInt64 (data.int64Value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Double : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Double() noexcept {}
|
||||||
|
static const VariantType_Double instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept { return (int) data.doubleValue; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept { return (int64) data.doubleValue; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept { return data.doubleValue; }
|
||||||
|
String toString (const ValueUnion& data) const { return String (data.doubleValue); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept { return data.doubleValue != 0; }
|
||||||
|
bool isDouble() const noexcept { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (9);
|
||||||
|
output.writeByte (varMarker_Double);
|
||||||
|
output.writeDouble (data.doubleValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Bool : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Bool() noexcept {}
|
||||||
|
static const VariantType_Bool instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept { return data.boolValue ? 1 : 0; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept { return data.boolValue ? 1.0 : 0.0; }
|
||||||
|
String toString (const ValueUnion& data) const { return String::charToString (data.boolValue ? (beast_wchar) '1' : (beast_wchar) '0'); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept { return data.boolValue; }
|
||||||
|
bool isBool() const noexcept { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
return otherType.toBool (otherData) == data.boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (1);
|
||||||
|
output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_String : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_String() noexcept {}
|
||||||
|
static const VariantType_String instance;
|
||||||
|
|
||||||
|
void cleanUp (ValueUnion& data) const noexcept { getString (data)-> ~String(); }
|
||||||
|
void createCopy (ValueUnion& dest, const ValueUnion& source) const { new (dest.stringValue) String (*getString (source)); }
|
||||||
|
|
||||||
|
bool isString() const noexcept { return true; }
|
||||||
|
int toInt (const ValueUnion& data) const noexcept { return getString (data)->getIntValue(); };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept { return getString (data)->getLargeIntValue(); };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept { return getString (data)->getDoubleValue(); }
|
||||||
|
String toString (const ValueUnion& data) const { return *getString (data); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept { return getString (data)->getIntValue() != 0
|
||||||
|
|| getString (data)->trim().equalsIgnoreCase ("true")
|
||||||
|
|| getString (data)->trim().equalsIgnoreCase ("yes"); }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
return otherType.toString (otherData) == *getString (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||||
|
{
|
||||||
|
const String* const s = getString (data);
|
||||||
|
const size_t len = s->getNumBytesAsUTF8() + 1;
|
||||||
|
HeapBlock<char> temp (len);
|
||||||
|
s->copyToUTF8 (temp, len);
|
||||||
|
output.writeCompressedInt ((int) (len + 1));
|
||||||
|
output.writeByte (varMarker_String);
|
||||||
|
output.write (temp, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast <const String*> (data.stringValue); }
|
||||||
|
static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast <String*> (data.stringValue); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Object : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Object() noexcept {}
|
||||||
|
static const VariantType_Object instance;
|
||||||
|
|
||||||
|
void cleanUp (ValueUnion& data) const noexcept { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
|
||||||
|
|
||||||
|
void createCopy (ValueUnion& dest, const ValueUnion& source) const
|
||||||
|
{
|
||||||
|
dest.objectValue = source.objectValue;
|
||||||
|
if (dest.objectValue != nullptr)
|
||||||
|
dest.objectValue->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
String toString (const ValueUnion& data) const { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept { return data.objectValue != 0; }
|
||||||
|
ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept { return data.objectValue; }
|
||||||
|
bool isObject() const noexcept { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
return otherType.toObject (otherData) == data.objectValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion&, OutputStream& output) const
|
||||||
|
{
|
||||||
|
jassertfalse; // Can't write an object to a stream!
|
||||||
|
output.writeCompressedInt (0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Array : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Array() noexcept {}
|
||||||
|
static const VariantType_Array instance;
|
||||||
|
|
||||||
|
void cleanUp (ValueUnion& data) const noexcept { delete data.arrayValue; }
|
||||||
|
void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.arrayValue = new Array<var> (*(source.arrayValue)); }
|
||||||
|
|
||||||
|
String toString (const ValueUnion&) const { return "[Array]"; }
|
||||||
|
bool isArray() const noexcept { return true; }
|
||||||
|
Array<var>* toArray (const ValueUnion& data) const noexcept { return data.arrayValue; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
const Array<var>* const otherArray = otherType.toArray (otherData);
|
||||||
|
return otherArray != nullptr && *otherArray == *(data.arrayValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||||
|
{
|
||||||
|
MemoryOutputStream buffer (512);
|
||||||
|
const int numItems = data.arrayValue->size();
|
||||||
|
buffer.writeCompressedInt (numItems);
|
||||||
|
|
||||||
|
for (int i = 0; i < numItems; ++i)
|
||||||
|
data.arrayValue->getReference(i).writeToStream (buffer);
|
||||||
|
|
||||||
|
output.writeCompressedInt (1 + (int) buffer.getDataSize());
|
||||||
|
output.writeByte (varMarker_Array);
|
||||||
|
output << buffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Binary : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Binary() noexcept {}
|
||||||
|
|
||||||
|
static const VariantType_Binary instance;
|
||||||
|
|
||||||
|
void cleanUp (ValueUnion& data) const noexcept { delete data.binaryValue; }
|
||||||
|
void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
|
||||||
|
|
||||||
|
String toString (const ValueUnion& data) const { return data.binaryValue->toBase64Encoding(); }
|
||||||
|
bool isBinary() const noexcept { return true; }
|
||||||
|
MemoryBlock* toBinary (const ValueUnion& data) const noexcept { return data.binaryValue; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
|
||||||
|
return otherBlock != nullptr && *otherBlock == *data.binaryValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
|
||||||
|
output.writeByte (varMarker_Binary);
|
||||||
|
output << *data.binaryValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Method : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Method() noexcept {}
|
||||||
|
static const VariantType_Method instance;
|
||||||
|
|
||||||
|
String toString (const ValueUnion&) const { return "Method"; }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept { return data.methodValue != nullptr; }
|
||||||
|
bool isMethod() const noexcept { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept
|
||||||
|
{
|
||||||
|
return otherType.isMethod() && otherData.methodValue == data.methodValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion&, OutputStream& output) const
|
||||||
|
{
|
||||||
|
jassertfalse; // Can't write a method to a stream!
|
||||||
|
output.writeCompressedInt (0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
const var::VariantType_Void var::VariantType_Void::instance;
|
||||||
|
const var::VariantType_Int var::VariantType_Int::instance;
|
||||||
|
const var::VariantType_Int64 var::VariantType_Int64::instance;
|
||||||
|
const var::VariantType_Bool var::VariantType_Bool::instance;
|
||||||
|
const var::VariantType_Double var::VariantType_Double::instance;
|
||||||
|
const var::VariantType_String var::VariantType_String::instance;
|
||||||
|
const var::VariantType_Object var::VariantType_Object::instance;
|
||||||
|
const var::VariantType_Array var::VariantType_Array::instance;
|
||||||
|
const var::VariantType_Binary var::VariantType_Binary::instance;
|
||||||
|
const var::VariantType_Method var::VariantType_Method::instance;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var::var() noexcept : type (&VariantType_Void::instance)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
var::~var() noexcept
|
||||||
|
{
|
||||||
|
type->cleanUp (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const var var::null;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var::var (const var& valueToCopy) : type (valueToCopy.type)
|
||||||
|
{
|
||||||
|
type->createCopy (value, valueToCopy.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var::var (const int v) noexcept : type (&VariantType_Int::instance) { value.intValue = v; }
|
||||||
|
var::var (const int64 v) noexcept : type (&VariantType_Int64::instance) { value.int64Value = v; }
|
||||||
|
var::var (const bool v) noexcept : type (&VariantType_Bool::instance) { value.boolValue = v; }
|
||||||
|
var::var (const double v) noexcept : type (&VariantType_Double::instance) { value.doubleValue = v; }
|
||||||
|
var::var (MethodFunction m) noexcept : type (&VariantType_Method::instance) { value.methodValue = m; }
|
||||||
|
var::var (const Array<var>& v) : type (&VariantType_Array::instance) { value.arrayValue = new Array<var> (v); }
|
||||||
|
var::var (const String& v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||||
|
var::var (const char* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||||
|
var::var (const wchar_t* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||||
|
var::var (const void* v, size_t sz) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v, sz); }
|
||||||
|
var::var (const MemoryBlock& v) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v); }
|
||||||
|
|
||||||
|
var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::instance)
|
||||||
|
{
|
||||||
|
value.objectValue = object;
|
||||||
|
|
||||||
|
if (object != nullptr)
|
||||||
|
object->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool var::isVoid() const noexcept { return type->isVoid(); }
|
||||||
|
bool var::isInt() const noexcept { return type->isInt(); }
|
||||||
|
bool var::isInt64() const noexcept { return type->isInt64(); }
|
||||||
|
bool var::isBool() const noexcept { return type->isBool(); }
|
||||||
|
bool var::isDouble() const noexcept { return type->isDouble(); }
|
||||||
|
bool var::isString() const noexcept { return type->isString(); }
|
||||||
|
bool var::isObject() const noexcept { return type->isObject(); }
|
||||||
|
bool var::isArray() const noexcept { return type->isArray(); }
|
||||||
|
bool var::isBinaryData() const noexcept { return type->isBinary(); }
|
||||||
|
bool var::isMethod() const noexcept { return type->isMethod(); }
|
||||||
|
|
||||||
|
var::operator int() const noexcept { return type->toInt (value); }
|
||||||
|
var::operator int64() const noexcept { return type->toInt64 (value); }
|
||||||
|
var::operator bool() const noexcept { return type->toBool (value); }
|
||||||
|
var::operator float() const noexcept { return (float) type->toDouble (value); }
|
||||||
|
var::operator double() const noexcept { return type->toDouble (value); }
|
||||||
|
String var::toString() const { return type->toString (value); }
|
||||||
|
var::operator String() const { return type->toString (value); }
|
||||||
|
ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
|
||||||
|
Array<var>* var::getArray() const noexcept { return type->toArray (value); }
|
||||||
|
MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
|
||||||
|
DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast <DynamicObject*> (getObject()); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void var::swapWith (var& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (type, other.type);
|
||||||
|
std::swap (value, other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator= (const var& v) { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
|
||||||
|
var& var::operator= (const int v) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = v; return *this; }
|
||||||
|
var& var::operator= (const int64 v) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = v; return *this; }
|
||||||
|
var& var::operator= (const bool v) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = v; return *this; }
|
||||||
|
var& var::operator= (const double v) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = v; return *this; }
|
||||||
|
var& var::operator= (const char* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||||
|
var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||||
|
var& var::operator= (const String& v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||||
|
var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
|
||||||
|
var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
|
||||||
|
var& var::operator= (MethodFunction v) { var v2 (v); swapWith (v2); return *this; }
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
var::var (var&& other) noexcept
|
||||||
|
: type (other.type),
|
||||||
|
value (other.value)
|
||||||
|
{
|
||||||
|
other.type = &VariantType_Void::instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator= (var&& other) noexcept
|
||||||
|
{
|
||||||
|
swapWith (other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var::var (String&& v) : type (&VariantType_String::instance)
|
||||||
|
{
|
||||||
|
new (value.stringValue) String (static_cast<String&&> (v));
|
||||||
|
}
|
||||||
|
|
||||||
|
var::var (MemoryBlock&& v) : type (&VariantType_Binary::instance)
|
||||||
|
{
|
||||||
|
value.binaryValue = new MemoryBlock (static_cast<MemoryBlock&&> (v));
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator= (String&& v)
|
||||||
|
{
|
||||||
|
type->cleanUp (value);
|
||||||
|
type = &VariantType_String::instance;
|
||||||
|
new (value.stringValue) String (static_cast<String&&> (v));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool var::equals (const var& other) const noexcept
|
||||||
|
{
|
||||||
|
return type->equals (value, other.value, *other.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool var::equalsWithSameType (const var& other) const noexcept
|
||||||
|
{
|
||||||
|
return type == other.type && equals (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const var& v1, const var& v2) noexcept { return v1.equals (v2); }
|
||||||
|
bool operator!= (const var& v1, const var& v2) noexcept { return ! v1.equals (v2); }
|
||||||
|
bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
|
||||||
|
bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
|
||||||
|
bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; }
|
||||||
|
bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; }
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var var::operator[] (const Identifier propertyName) const
|
||||||
|
{
|
||||||
|
if (DynamicObject* const o = getDynamicObject())
|
||||||
|
return o->getProperty (propertyName);
|
||||||
|
|
||||||
|
return var::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::operator[] (const char* const propertyName) const
|
||||||
|
{
|
||||||
|
return operator[] (Identifier (propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::getProperty (const Identifier propertyName, const var& defaultReturnValue) const
|
||||||
|
{
|
||||||
|
if (DynamicObject* const o = getDynamicObject())
|
||||||
|
return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
|
||||||
|
|
||||||
|
return defaultReturnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::invoke (const Identifier method, const var* arguments, int numArguments) const
|
||||||
|
{
|
||||||
|
if (DynamicObject* const o = getDynamicObject())
|
||||||
|
return o->invokeMethod (method, arguments, numArguments);
|
||||||
|
|
||||||
|
return var::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::invokeMethod (DynamicObject* const target, const var* const arguments, const int numArguments) const
|
||||||
|
{
|
||||||
|
bassert (target != nullptr);
|
||||||
|
|
||||||
|
if (isMethod())
|
||||||
|
return (target->*(value.methodValue)) (arguments, numArguments);
|
||||||
|
|
||||||
|
return var::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method) const
|
||||||
|
{
|
||||||
|
return invoke (method, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1) const
|
||||||
|
{
|
||||||
|
return invoke (method, &arg1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2) const
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2 };
|
||||||
|
return invoke (method, args, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3)
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2, arg3 };
|
||||||
|
return invoke (method, args, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2, arg3, arg4 };
|
||||||
|
return invoke (method, args, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2, arg3, arg4, arg5 };
|
||||||
|
return invoke (method, args, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int var::size() const
|
||||||
|
{
|
||||||
|
if (const Array<var>* const array = getArray())
|
||||||
|
return array->size();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const var& var::operator[] (int arrayIndex) const
|
||||||
|
{
|
||||||
|
const Array<var>* const array = getArray();
|
||||||
|
|
||||||
|
// When using this method, the var must actually be an array, and the index
|
||||||
|
// must be in-range!
|
||||||
|
bassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||||
|
|
||||||
|
return array->getReference (arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator[] (int arrayIndex)
|
||||||
|
{
|
||||||
|
const Array<var>* const array = getArray();
|
||||||
|
|
||||||
|
// When using this method, the var must actually be an array, and the index
|
||||||
|
// must be in-range!
|
||||||
|
bassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||||
|
|
||||||
|
return array->getReference (arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<var>* var::convertToArray()
|
||||||
|
{
|
||||||
|
Array<var>* array = getArray();
|
||||||
|
|
||||||
|
if (array == nullptr)
|
||||||
|
{
|
||||||
|
const Array<var> tempVar;
|
||||||
|
var v (tempVar);
|
||||||
|
array = v.value.arrayValue;
|
||||||
|
|
||||||
|
if (! isVoid())
|
||||||
|
array->add (*this);
|
||||||
|
|
||||||
|
swapWith (v);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::append (const var& n)
|
||||||
|
{
|
||||||
|
convertToArray()->add (n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::remove (const int index)
|
||||||
|
{
|
||||||
|
if (Array<var>* const array = getArray())
|
||||||
|
array->remove (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::insert (const int index, const var& n)
|
||||||
|
{
|
||||||
|
convertToArray()->insert (index, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::resize (const int numArrayElementsWanted)
|
||||||
|
{
|
||||||
|
convertToArray()->resize (numArrayElementsWanted);
|
||||||
|
}
|
||||||
|
|
||||||
|
int var::indexOf (const var& n) const
|
||||||
|
{
|
||||||
|
if (const Array<var>* const array = getArray())
|
||||||
|
return array->indexOf (n);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void var::writeToStream (OutputStream& output) const
|
||||||
|
{
|
||||||
|
type->writeToStream (value, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::readFromStream (InputStream& input)
|
||||||
|
{
|
||||||
|
const int numBytes = input.readCompressedInt();
|
||||||
|
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
switch (input.readByte())
|
||||||
|
{
|
||||||
|
case varMarker_Int: return var (input.readInt());
|
||||||
|
case varMarker_Int64: return var (input.readInt64());
|
||||||
|
case varMarker_BoolTrue: return var (true);
|
||||||
|
case varMarker_BoolFalse: return var (false);
|
||||||
|
case varMarker_Double: return var (input.readDouble());
|
||||||
|
case varMarker_String:
|
||||||
|
{
|
||||||
|
MemoryOutputStream mo;
|
||||||
|
mo.writeFromInputStream (input, numBytes - 1);
|
||||||
|
return var (mo.toUTF8());
|
||||||
|
}
|
||||||
|
|
||||||
|
case varMarker_Binary:
|
||||||
|
{
|
||||||
|
MemoryBlock mb (numBytes - 1);
|
||||||
|
|
||||||
|
if (numBytes > 1)
|
||||||
|
{
|
||||||
|
const int numRead = input.read (mb.getData(), numBytes - 1);
|
||||||
|
mb.setSize (numRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
return var (mb);
|
||||||
|
}
|
||||||
|
|
||||||
|
case varMarker_Array:
|
||||||
|
{
|
||||||
|
var v;
|
||||||
|
Array<var>* const destArray = v.convertToArray();
|
||||||
|
|
||||||
|
for (int i = input.readCompressedInt(); --i >= 0;)
|
||||||
|
destArray->add (readFromStream (input));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
input.skipNextBytes (numBytes - 1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return var::null;
|
||||||
|
}
|
||||||
302
Subtrees/beast/modules/beast_core/containers/beast_Variant.h
Normal file
302
Subtrees/beast/modules/beast_core/containers/beast_Variant.h
Normal file
@@ -0,0 +1,302 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_VARIANT_BEASTHEADER
|
||||||
|
#define BEAST_VARIANT_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_Identifier.h"
|
||||||
|
#include "../streams/beast_OutputStream.h"
|
||||||
|
#include "../streams/beast_InputStream.h"
|
||||||
|
#include "../containers/beast_Array.h"
|
||||||
|
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
class ReferenceCountedObject;
|
||||||
|
class DynamicObject;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A variant class, that can be used to hold a range of primitive values.
|
||||||
|
|
||||||
|
A var object can hold a range of simple primitive values, strings, or
|
||||||
|
any kind of ReferenceCountedObject. The var class is intended to act like
|
||||||
|
the kind of values used in dynamic scripting languages.
|
||||||
|
|
||||||
|
You can save/load var objects either in a small, proprietary binary format
|
||||||
|
using writeToStream()/readFromStream(), or as JSON by using the JSON class.
|
||||||
|
|
||||||
|
@see JSON, DynamicObject
|
||||||
|
*/
|
||||||
|
class BEAST_API var
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
typedef const var (DynamicObject::*MethodFunction) (const var* arguments, int numArguments);
|
||||||
|
typedef Identifier identifier;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a void variant. */
|
||||||
|
var() noexcept;
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~var() noexcept;
|
||||||
|
|
||||||
|
/** A static var object that can be used where you need an empty variant object. */
|
||||||
|
static const var null;
|
||||||
|
|
||||||
|
var (const var& valueToCopy);
|
||||||
|
var (int value) noexcept;
|
||||||
|
var (int64 value) noexcept;
|
||||||
|
var (bool value) noexcept;
|
||||||
|
var (double value) noexcept;
|
||||||
|
var (const char* value);
|
||||||
|
var (const wchar_t* value);
|
||||||
|
var (const String& value);
|
||||||
|
var (const Array<var>& value);
|
||||||
|
var (ReferenceCountedObject* object);
|
||||||
|
var (MethodFunction method) noexcept;
|
||||||
|
var (const void* binaryData, size_t dataSize);
|
||||||
|
var (const MemoryBlock& binaryData);
|
||||||
|
|
||||||
|
var& operator= (const var& valueToCopy);
|
||||||
|
var& operator= (int value);
|
||||||
|
var& operator= (int64 value);
|
||||||
|
var& operator= (bool value);
|
||||||
|
var& operator= (double value);
|
||||||
|
var& operator= (const char* value);
|
||||||
|
var& operator= (const wchar_t* value);
|
||||||
|
var& operator= (const String& value);
|
||||||
|
var& operator= (const Array<var>& value);
|
||||||
|
var& operator= (ReferenceCountedObject* object);
|
||||||
|
var& operator= (MethodFunction method);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
var (var&& other) noexcept;
|
||||||
|
var (String&& value);
|
||||||
|
var (MemoryBlock&& binaryData);
|
||||||
|
var& operator= (var&& other) noexcept;
|
||||||
|
var& operator= (String&& value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void swapWith (var& other) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
operator int() const noexcept;
|
||||||
|
operator int64() const noexcept;
|
||||||
|
operator bool() const noexcept;
|
||||||
|
operator float() const noexcept;
|
||||||
|
operator double() const noexcept;
|
||||||
|
operator String() const;
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
/** If this variant holds an array, this provides access to it.
|
||||||
|
NOTE: Beware when you use this - the array pointer is only valid for the lifetime
|
||||||
|
of the variant that returned it, so be very careful not to call this method on temporary
|
||||||
|
var objects that are the return-value of a function, and which may go out of scope before
|
||||||
|
you use the array!
|
||||||
|
*/
|
||||||
|
Array<var>* getArray() const noexcept;
|
||||||
|
|
||||||
|
/** If this variant holds a memory block, this provides access to it.
|
||||||
|
NOTE: Beware when you use this - the MemoryBlock pointer is only valid for the lifetime
|
||||||
|
of the variant that returned it, so be very careful not to call this method on temporary
|
||||||
|
var objects that are the return-value of a function, and which may go out of scope before
|
||||||
|
you use the MemoryBlock!
|
||||||
|
*/
|
||||||
|
MemoryBlock* getBinaryData() const noexcept;
|
||||||
|
|
||||||
|
ReferenceCountedObject* getObject() const noexcept;
|
||||||
|
DynamicObject* getDynamicObject() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isVoid() const noexcept;
|
||||||
|
bool isInt() const noexcept;
|
||||||
|
bool isInt64() const noexcept;
|
||||||
|
bool isBool() const noexcept;
|
||||||
|
bool isDouble() const noexcept;
|
||||||
|
bool isString() const noexcept;
|
||||||
|
bool isObject() const noexcept;
|
||||||
|
bool isArray() const noexcept;
|
||||||
|
bool isBinaryData() const noexcept;
|
||||||
|
bool isMethod() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this var has the same value as the one supplied.
|
||||||
|
Note that this ignores the type, so a string var "123" and an integer var with the
|
||||||
|
value 123 are considered to be equal.
|
||||||
|
@see equalsWithSameType
|
||||||
|
*/
|
||||||
|
bool equals (const var& other) const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this var has the same value and type as the one supplied.
|
||||||
|
This differs from equals() because e.g. "123" and 123 will be considered different.
|
||||||
|
@see equals
|
||||||
|
*/
|
||||||
|
bool equalsWithSameType (const var& other) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** If the var is an array, this returns the number of elements.
|
||||||
|
If the var isn't actually an array, this will return 0.
|
||||||
|
*/
|
||||||
|
int size() const;
|
||||||
|
|
||||||
|
/** If the var is an array, this can be used to return one of its elements.
|
||||||
|
To call this method, you must make sure that the var is actually an array, and
|
||||||
|
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||||
|
undefined.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
const var& operator[] (int arrayIndex) const;
|
||||||
|
|
||||||
|
/** If the var is an array, this can be used to return one of its elements.
|
||||||
|
To call this method, you must make sure that the var is actually an array, and
|
||||||
|
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||||
|
undefined.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
var& operator[] (int arrayIndex);
|
||||||
|
|
||||||
|
/** Appends an element to the var, converting it to an array if it isn't already one.
|
||||||
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||||
|
this value will be kept as the first element of the new array. The parameter value
|
||||||
|
will then be appended to it.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void append (const var& valueToAppend);
|
||||||
|
|
||||||
|
/** Inserts an element to the var, converting it to an array if it isn't already one.
|
||||||
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||||
|
this value will be kept as the first element of the new array. The parameter value
|
||||||
|
will then be inserted into it.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void insert (int index, const var& value);
|
||||||
|
|
||||||
|
/** If the var is an array, this removes one of its elements.
|
||||||
|
If the index is out-of-range or the var isn't an array, nothing will be done.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void remove (int index);
|
||||||
|
|
||||||
|
/** Treating the var as an array, this resizes it to contain the specified number of elements.
|
||||||
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||||
|
this value will be kept as the first element of the new array before resizing.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void resize (int numArrayElementsWanted);
|
||||||
|
|
||||||
|
/** If the var is an array, this searches it for the first occurrence of the specified value,
|
||||||
|
and returns its index.
|
||||||
|
If the var isn't an array, or if the value isn't found, this returns -1.
|
||||||
|
*/
|
||||||
|
int indexOf (const var& value) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** If this variant is an object, this returns one of its properties. */
|
||||||
|
var operator[] (const Identifier propertyName) const;
|
||||||
|
/** If this variant is an object, this returns one of its properties. */
|
||||||
|
var operator[] (const char* propertyName) const;
|
||||||
|
/** If this variant is an object, this returns one of its properties, or a default
|
||||||
|
fallback value if the property is not set. */
|
||||||
|
var getProperty (const Identifier propertyName, const var& defaultReturnValue) const;
|
||||||
|
|
||||||
|
/** If this variant is an object, this invokes one of its methods with no arguments. */
|
||||||
|
var call (const Identifier method) const;
|
||||||
|
/** If this variant is an object, this invokes one of its methods with one argument. */
|
||||||
|
var call (const Identifier method, const var& arg1) const;
|
||||||
|
/** If this variant is an object, this invokes one of its methods with 2 arguments. */
|
||||||
|
var call (const Identifier method, const var& arg1, const var& arg2) const;
|
||||||
|
/** If this variant is an object, this invokes one of its methods with 3 arguments. */
|
||||||
|
var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3);
|
||||||
|
/** If this variant is an object, this invokes one of its methods with 4 arguments. */
|
||||||
|
var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const;
|
||||||
|
/** If this variant is an object, this invokes one of its methods with 5 arguments. */
|
||||||
|
var call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const;
|
||||||
|
/** If this variant is an object, this invokes one of its methods with a list of arguments. */
|
||||||
|
var invoke (const Identifier method, const var* arguments, int numArguments) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Writes a binary representation of this value to a stream.
|
||||||
|
The data can be read back later using readFromStream().
|
||||||
|
@see JSON
|
||||||
|
*/
|
||||||
|
void writeToStream (OutputStream& output) const;
|
||||||
|
|
||||||
|
/** Reads back a stored binary representation of a value.
|
||||||
|
The data in the stream must have been written using writeToStream(), or this
|
||||||
|
will have unpredictable results.
|
||||||
|
@see JSON
|
||||||
|
*/
|
||||||
|
static var readFromStream (InputStream& input);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class VariantType; friend class VariantType;
|
||||||
|
class VariantType_Void; friend class VariantType_Void;
|
||||||
|
class VariantType_Int; friend class VariantType_Int;
|
||||||
|
class VariantType_Int64; friend class VariantType_Int64;
|
||||||
|
class VariantType_Double; friend class VariantType_Double;
|
||||||
|
class VariantType_Bool; friend class VariantType_Bool;
|
||||||
|
class VariantType_String; friend class VariantType_String;
|
||||||
|
class VariantType_Object; friend class VariantType_Object;
|
||||||
|
class VariantType_Array; friend class VariantType_Array;
|
||||||
|
class VariantType_Binary; friend class VariantType_Binary;
|
||||||
|
class VariantType_Method; friend class VariantType_Method;
|
||||||
|
|
||||||
|
union ValueUnion
|
||||||
|
{
|
||||||
|
int intValue;
|
||||||
|
int64 int64Value;
|
||||||
|
bool boolValue;
|
||||||
|
double doubleValue;
|
||||||
|
char stringValue [sizeof (String)];
|
||||||
|
ReferenceCountedObject* objectValue;
|
||||||
|
Array<var>* arrayValue;
|
||||||
|
MemoryBlock* binaryValue;
|
||||||
|
MethodFunction methodValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
const VariantType* type;
|
||||||
|
ValueUnion value;
|
||||||
|
|
||||||
|
Array<var>* convertToArray();
|
||||||
|
friend class DynamicObject;
|
||||||
|
var invokeMethod (DynamicObject*, const var*, int) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||||
|
bool operator== (const var& v1, const var& v2) noexcept;
|
||||||
|
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||||
|
bool operator!= (const var& v1, const var& v2) noexcept;
|
||||||
|
bool operator== (const var& v1, const String& v2);
|
||||||
|
bool operator!= (const var& v1, const String& v2);
|
||||||
|
bool operator== (const var& v1, const char* v2);
|
||||||
|
bool operator!= (const var& v1, const char* v2);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_VARIANT_BEASTHEADER
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
static StringArray parseWildcards (const String& pattern)
|
||||||
|
{
|
||||||
|
StringArray s;
|
||||||
|
s.addTokens (pattern, ";,", "\"'");
|
||||||
|
s.trim();
|
||||||
|
s.removeEmptyStrings();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool fileMatches (const StringArray& wildCards, const String& filename)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < wildCards.size(); ++i)
|
||||||
|
if (filename.matchesWildcard (wildCards[i], ! File::areFileNamesCaseSensitive()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::DirectoryIterator (const File& directory, bool recursive,
|
||||||
|
const String& pattern, const int type)
|
||||||
|
: wildCards (parseWildcards (pattern)),
|
||||||
|
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
|
||||||
|
wildCard (pattern),
|
||||||
|
path (File::addTrailingSeparator (directory.getFullPathName())),
|
||||||
|
index (-1),
|
||||||
|
totalNumFiles (-1),
|
||||||
|
whatToLookFor (type),
|
||||||
|
isRecursive (recursive),
|
||||||
|
hasBeenAdvanced (false)
|
||||||
|
{
|
||||||
|
// you have to specify the type of files you're looking for!
|
||||||
|
bassert ((type & (File::findFiles | File::findDirectories)) != 0);
|
||||||
|
bassert (type > 0 && type <= 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::~DirectoryIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::next()
|
||||||
|
{
|
||||||
|
return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
hasBeenAdvanced = true;
|
||||||
|
|
||||||
|
if (subIterator != nullptr)
|
||||||
|
{
|
||||||
|
if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
subIterator = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
String filename;
|
||||||
|
bool isDirectory, isHidden = false;
|
||||||
|
|
||||||
|
while (fileFinder.next (filename, &isDirectory,
|
||||||
|
(isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
|
||||||
|
fileSize, modTime, creationTime, isReadOnly))
|
||||||
|
{
|
||||||
|
++index;
|
||||||
|
|
||||||
|
if (! filename.containsOnly ("."))
|
||||||
|
{
|
||||||
|
bool matches = false;
|
||||||
|
|
||||||
|
if (isDirectory)
|
||||||
|
{
|
||||||
|
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
|
||||||
|
subIterator = new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
|
||||||
|
true, wildCard, whatToLookFor);
|
||||||
|
|
||||||
|
matches = (whatToLookFor & File::findDirectories) != 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matches = (whatToLookFor & File::findFiles) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if recursive, we're not relying on the OS iterator to do the wildcard match, so do it now..
|
||||||
|
if (matches && isRecursive)
|
||||||
|
matches = fileMatches (wildCards, filename);
|
||||||
|
|
||||||
|
if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
|
||||||
|
matches = ! isHidden;
|
||||||
|
|
||||||
|
if (matches)
|
||||||
|
{
|
||||||
|
currentFile = File::createFileWithoutCheckingPath (path + filename);
|
||||||
|
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
|
||||||
|
if (isDirResult != nullptr) *isDirResult = isDirectory;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subIterator != nullptr)
|
||||||
|
return next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const File& DirectoryIterator::getFile() const
|
||||||
|
{
|
||||||
|
if (subIterator != nullptr && subIterator->hasBeenAdvanced)
|
||||||
|
return subIterator->getFile();
|
||||||
|
|
||||||
|
// You need to call DirectoryIterator::next() before asking it for the file that it found!
|
||||||
|
bassert (hasBeenAdvanced);
|
||||||
|
|
||||||
|
return currentFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DirectoryIterator::getEstimatedProgress() const
|
||||||
|
{
|
||||||
|
if (totalNumFiles < 0)
|
||||||
|
totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
|
||||||
|
|
||||||
|
if (totalNumFiles <= 0)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
const float detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress()
|
||||||
|
: (float) index;
|
||||||
|
|
||||||
|
return detailedIndex / totalNumFiles;
|
||||||
|
}
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||||
|
#define BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_File.h"
|
||||||
|
#include "../memory/beast_ScopedPointer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Searches through a the files in a directory, returning each file that is found.
|
||||||
|
|
||||||
|
A DirectoryIterator will search through a directory and its subdirectories using
|
||||||
|
a wildcard filepattern match.
|
||||||
|
|
||||||
|
If you may be finding a large number of files, this is better than
|
||||||
|
using File::findChildFiles() because it doesn't block while it finds them
|
||||||
|
all, and this is more memory-efficient.
|
||||||
|
|
||||||
|
It can also guess how far it's got using a wildly inaccurate algorithm.
|
||||||
|
*/
|
||||||
|
class BEAST_API DirectoryIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a DirectoryIterator for a given directory.
|
||||||
|
|
||||||
|
After creating one of these, call its next() method to get the
|
||||||
|
first file - e.g. @code
|
||||||
|
|
||||||
|
DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
|
||||||
|
|
||||||
|
while (iter.next())
|
||||||
|
{
|
||||||
|
File theFileItFound (iter.getFile());
|
||||||
|
|
||||||
|
... etc
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@param directory the directory to search in
|
||||||
|
@param isRecursive whether all the subdirectories should also be searched
|
||||||
|
@param wildCard the file pattern to match. This may contain multiple patterns
|
||||||
|
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
|
||||||
|
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
|
||||||
|
whether to look for files, directories, or both.
|
||||||
|
*/
|
||||||
|
DirectoryIterator (const File& directory,
|
||||||
|
bool isRecursive,
|
||||||
|
const String& wildCard = "*",
|
||||||
|
int whatToLookFor = File::findFiles);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~DirectoryIterator();
|
||||||
|
|
||||||
|
/** Moves the iterator along to the next file.
|
||||||
|
|
||||||
|
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||||
|
false if there are no more matching files.
|
||||||
|
*/
|
||||||
|
bool next();
|
||||||
|
|
||||||
|
/** Moves the iterator along to the next file, and returns various properties of that file.
|
||||||
|
|
||||||
|
If you need to find out details about the file, it's more efficient to call this method than
|
||||||
|
to call the normal next() method and then find out the details afterwards.
|
||||||
|
|
||||||
|
All the parameters are optional, so pass null pointers for any items that you're not
|
||||||
|
interested in.
|
||||||
|
|
||||||
|
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||||
|
false if there are no more matching files. If it returns false, then none of the
|
||||||
|
parameters will be filled-in.
|
||||||
|
*/
|
||||||
|
bool next (bool* isDirectory,
|
||||||
|
bool* isHidden,
|
||||||
|
int64* fileSize,
|
||||||
|
Time* modTime,
|
||||||
|
Time* creationTime,
|
||||||
|
bool* isReadOnly);
|
||||||
|
|
||||||
|
/** Returns the file that the iterator is currently pointing at.
|
||||||
|
|
||||||
|
The result of this call is only valid after a call to next() has returned true.
|
||||||
|
*/
|
||||||
|
const File& getFile() const;
|
||||||
|
|
||||||
|
/** Returns a guess of how far through the search the iterator has got.
|
||||||
|
|
||||||
|
@returns a value 0.0 to 1.0 to show the progress, although this won't be
|
||||||
|
very accurate.
|
||||||
|
*/
|
||||||
|
float getEstimatedProgress() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class NativeIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NativeIterator (const File& directory, const String& wildCard);
|
||||||
|
~NativeIterator();
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* isDirectory, bool* isHidden, int64* fileSize,
|
||||||
|
Time* modTime, Time* creationTime, bool* isReadOnly);
|
||||||
|
|
||||||
|
class Pimpl;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class DirectoryIterator;
|
||||||
|
friend class ScopedPointer<Pimpl>;
|
||||||
|
ScopedPointer<Pimpl> pimpl;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeIterator)
|
||||||
|
};
|
||||||
|
|
||||||
|
friend class ScopedPointer<NativeIterator::Pimpl>;
|
||||||
|
StringArray wildCards;
|
||||||
|
NativeIterator fileFinder;
|
||||||
|
String wildCard, path;
|
||||||
|
int index;
|
||||||
|
mutable int totalNumFiles;
|
||||||
|
const int whatToLookFor;
|
||||||
|
const bool isRecursive;
|
||||||
|
bool hasBeenAdvanced;
|
||||||
|
ScopedPointer <DirectoryIterator> subIterator;
|
||||||
|
File currentFile;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_DIRECTORYITERATOR_BEASTHEADER
|
||||||
1086
Subtrees/beast/modules/beast_core/files/beast_File.cpp
Normal file
1086
Subtrees/beast/modules/beast_core/files/beast_File.cpp
Normal file
File diff suppressed because it is too large
Load Diff
955
Subtrees/beast/modules/beast_core/files/beast_File.h
Normal file
955
Subtrees/beast/modules/beast_core/files/beast_File.h
Normal file
@@ -0,0 +1,955 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_FILE_BEASTHEADER
|
||||||
|
#define BEAST_FILE_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../containers/beast_Array.h"
|
||||||
|
#include "../time/beast_Time.h"
|
||||||
|
#include "../text/beast_StringArray.h"
|
||||||
|
#include "../memory/beast_MemoryBlock.h"
|
||||||
|
#include "../memory/beast_ScopedPointer.h"
|
||||||
|
#include "../misc/beast_Result.h"
|
||||||
|
class FileInputStream;
|
||||||
|
class FileOutputStream;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents a local file or directory.
|
||||||
|
|
||||||
|
This class encapsulates the absolute pathname of a file or directory, and
|
||||||
|
has methods for finding out about the file and changing its properties.
|
||||||
|
|
||||||
|
To read or write to the file, there are methods for returning an input or
|
||||||
|
output stream.
|
||||||
|
|
||||||
|
@see FileInputStream, FileOutputStream
|
||||||
|
*/
|
||||||
|
class BEAST_API File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an (invalid) file object.
|
||||||
|
|
||||||
|
The file is initially set to an empty path, so getFullPath() will return
|
||||||
|
an empty string, and comparing the file to File::nonexistent will return
|
||||||
|
true.
|
||||||
|
|
||||||
|
You can use its operator= method to point it at a proper file.
|
||||||
|
*/
|
||||||
|
File() noexcept {}
|
||||||
|
|
||||||
|
/** Creates a file from an absolute path.
|
||||||
|
|
||||||
|
If the path supplied is a relative path, it is taken to be relative
|
||||||
|
to the current working directory (see File::getCurrentWorkingDirectory()),
|
||||||
|
but this isn't a recommended way of creating a file, because you
|
||||||
|
never know what the CWD is going to be.
|
||||||
|
|
||||||
|
On the Mac/Linux, the path can include "~" notation for referring to
|
||||||
|
user home directories.
|
||||||
|
*/
|
||||||
|
File (const String& path);
|
||||||
|
|
||||||
|
/** Creates a copy of another file object. */
|
||||||
|
File (const File& other);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~File() noexcept {}
|
||||||
|
|
||||||
|
/** Sets the file based on an absolute pathname.
|
||||||
|
|
||||||
|
If the path supplied is a relative path, it is taken to be relative
|
||||||
|
to the current working directory (see File::getCurrentWorkingDirectory()),
|
||||||
|
but this isn't a recommended way of creating a file, because you
|
||||||
|
never know what the CWD is going to be.
|
||||||
|
|
||||||
|
On the Mac/Linux, the path can include "~" notation for referring to
|
||||||
|
user home directories.
|
||||||
|
*/
|
||||||
|
File& operator= (const String& newFilePath);
|
||||||
|
|
||||||
|
/** Copies from another file object. */
|
||||||
|
File& operator= (const File& otherFile);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
File (File&& otherFile) noexcept;
|
||||||
|
File& operator= (File&& otherFile) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This static constant is used for referring to an 'invalid' file. */
|
||||||
|
static const File nonexistent;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Checks whether the file actually exists.
|
||||||
|
|
||||||
|
@returns true if the file exists, either as a file or a directory.
|
||||||
|
@see existsAsFile, isDirectory
|
||||||
|
*/
|
||||||
|
bool exists() const;
|
||||||
|
|
||||||
|
/** Checks whether the file exists and is a file rather than a directory.
|
||||||
|
|
||||||
|
@returns true only if this is a real file, false if it's a directory
|
||||||
|
or doesn't exist
|
||||||
|
@see exists, isDirectory
|
||||||
|
*/
|
||||||
|
bool existsAsFile() const;
|
||||||
|
|
||||||
|
/** Checks whether the file is a directory that exists.
|
||||||
|
|
||||||
|
@returns true only if the file is a directory which actually exists, so
|
||||||
|
false if it's a file or doesn't exist at all
|
||||||
|
@see exists, existsAsFile
|
||||||
|
*/
|
||||||
|
bool isDirectory() const;
|
||||||
|
|
||||||
|
/** Returns the size of the file in bytes.
|
||||||
|
|
||||||
|
@returns the number of bytes in the file, or 0 if it doesn't exist.
|
||||||
|
*/
|
||||||
|
int64 getSize() const;
|
||||||
|
|
||||||
|
/** Utility function to convert a file size in bytes to a neat string description.
|
||||||
|
|
||||||
|
So for example 100 would return "100 bytes", 2000 would return "2 KB",
|
||||||
|
2000000 would produce "2 MB", etc.
|
||||||
|
*/
|
||||||
|
static String descriptionOfSizeInBytes (int64 bytes);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the complete, absolute path of this file.
|
||||||
|
|
||||||
|
This includes the filename and all its parent folders. On Windows it'll
|
||||||
|
also include the drive letter prefix; on Mac or Linux it'll be a complete
|
||||||
|
path starting from the root folder.
|
||||||
|
|
||||||
|
If you just want the file's name, you should use getFileName() or
|
||||||
|
getFileNameWithoutExtension().
|
||||||
|
|
||||||
|
@see getFileName, getRelativePathFrom
|
||||||
|
*/
|
||||||
|
const String& getFullPathName() const noexcept { return fullPath; }
|
||||||
|
|
||||||
|
/** Returns the last section of the pathname.
|
||||||
|
|
||||||
|
Returns just the final part of the path - e.g. if the whole path
|
||||||
|
is "/moose/fish/foo.txt" this will return "foo.txt".
|
||||||
|
|
||||||
|
For a directory, it returns the final part of the path - e.g. for the
|
||||||
|
directory "/moose/fish" it'll return "fish".
|
||||||
|
|
||||||
|
If the filename begins with a dot, it'll return the whole filename, e.g. for
|
||||||
|
"/moose/.fish", it'll return ".fish"
|
||||||
|
|
||||||
|
@see getFullPathName, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
String getFileName() const;
|
||||||
|
|
||||||
|
/** Creates a relative path that refers to a file relatively to a given directory.
|
||||||
|
|
||||||
|
e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock"))
|
||||||
|
would return "../../foo.txt".
|
||||||
|
|
||||||
|
If it's not possible to navigate from one file to the other, an absolute
|
||||||
|
path is returned. If the paths are invalid, an empty string may also be
|
||||||
|
returned.
|
||||||
|
|
||||||
|
@param directoryToBeRelativeTo the directory which the resultant string will
|
||||||
|
be relative to. If this is actually a file rather than
|
||||||
|
a directory, its parent directory will be used instead.
|
||||||
|
If it doesn't exist, it's assumed to be a directory.
|
||||||
|
@see getChildFile, isAbsolutePath
|
||||||
|
*/
|
||||||
|
String getRelativePathFrom (const File& directoryToBeRelativeTo) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file's extension.
|
||||||
|
|
||||||
|
Returns the file extension of this file, also including the dot.
|
||||||
|
|
||||||
|
e.g. "/moose/fish/foo.txt" would return ".txt"
|
||||||
|
|
||||||
|
@see hasFileExtension, withFileExtension, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
String getFileExtension() const;
|
||||||
|
|
||||||
|
/** Checks whether the file has a given extension.
|
||||||
|
|
||||||
|
@param extensionToTest the extension to look for - it doesn't matter whether or
|
||||||
|
not this string has a dot at the start, so ".wav" and "wav"
|
||||||
|
will have the same effect. The comparison used is
|
||||||
|
case-insensitve. To compare with multiple extensions, this
|
||||||
|
parameter can contain multiple strings, separated by semi-colons -
|
||||||
|
so, for example: hasFileExtension (".jpeg;png;gif") would return
|
||||||
|
true if the file has any of those three extensions.
|
||||||
|
|
||||||
|
@see getFileExtension, withFileExtension, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
bool hasFileExtension (const String& extensionToTest) const;
|
||||||
|
|
||||||
|
/** Returns a version of this file with a different file extension.
|
||||||
|
|
||||||
|
e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
|
||||||
|
|
||||||
|
@param newExtension the new extension, either with or without a dot at the start (this
|
||||||
|
doesn't make any difference). To get remove a file's extension altogether,
|
||||||
|
pass an empty string into this function.
|
||||||
|
|
||||||
|
@see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
File withFileExtension (const String& newExtension) const;
|
||||||
|
|
||||||
|
/** Returns the last part of the filename, without its file extension.
|
||||||
|
|
||||||
|
e.g. for "/moose/fish/foo.txt" this will return "foo".
|
||||||
|
|
||||||
|
@see getFileName, getFileExtension, hasFileExtension, withFileExtension
|
||||||
|
*/
|
||||||
|
String getFileNameWithoutExtension() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a 32-bit hash-code that identifies this file.
|
||||||
|
|
||||||
|
This is based on the filename. Obviously it's possible, although unlikely, that
|
||||||
|
two files will have the same hash-code.
|
||||||
|
*/
|
||||||
|
int hashCode() const;
|
||||||
|
|
||||||
|
/** Returns a 64-bit hash-code that identifies this file.
|
||||||
|
|
||||||
|
This is based on the filename. Obviously it's possible, although unlikely, that
|
||||||
|
two files will have the same hash-code.
|
||||||
|
*/
|
||||||
|
int64 hashCode64() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a file based on a relative path.
|
||||||
|
|
||||||
|
This will find a child file or directory of the current object.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
|
||||||
|
File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
|
||||||
|
|
||||||
|
If the string is actually an absolute path, it will be treated as such, e.g.
|
||||||
|
File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
|
||||||
|
|
||||||
|
@see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf
|
||||||
|
*/
|
||||||
|
File getChildFile (String relativePath) const;
|
||||||
|
|
||||||
|
/** Returns a file which is in the same directory as this one.
|
||||||
|
|
||||||
|
This is equivalent to getParentDirectory().getChildFile (name).
|
||||||
|
|
||||||
|
@see getChildFile, getParentDirectory
|
||||||
|
*/
|
||||||
|
File getSiblingFile (const String& siblingFileName) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the directory that contains this file or directory.
|
||||||
|
|
||||||
|
e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
|
||||||
|
*/
|
||||||
|
File getParentDirectory() const;
|
||||||
|
|
||||||
|
/** Checks whether a file is somewhere inside a directory.
|
||||||
|
|
||||||
|
Returns true if this file is somewhere inside a subdirectory of the directory
|
||||||
|
that is passed in. Neither file actually has to exist, because the function
|
||||||
|
just checks the paths for similarities.
|
||||||
|
|
||||||
|
e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
|
||||||
|
File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
|
||||||
|
*/
|
||||||
|
bool isAChildOf (const File& potentialParentDirectory) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Chooses a filename relative to this one that doesn't already exist.
|
||||||
|
|
||||||
|
If this file is a directory, this will return a child file of this
|
||||||
|
directory that doesn't exist, by adding numbers to a prefix and suffix until
|
||||||
|
it finds one that isn't already there.
|
||||||
|
|
||||||
|
If the prefix + the suffix doesn't exist, it won't bother adding a number.
|
||||||
|
|
||||||
|
e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might
|
||||||
|
return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt".
|
||||||
|
|
||||||
|
@param prefix the string to use for the filename before the number
|
||||||
|
@param suffix the string to add to the filename after the number
|
||||||
|
@param putNumbersInBrackets if true, this will create filenames in the
|
||||||
|
format "prefix(number)suffix", if false, it will leave the
|
||||||
|
brackets out.
|
||||||
|
*/
|
||||||
|
File getNonexistentChildFile (const String& prefix,
|
||||||
|
const String& suffix,
|
||||||
|
bool putNumbersInBrackets = true) const;
|
||||||
|
|
||||||
|
/** Chooses a filename for a sibling file to this one that doesn't already exist.
|
||||||
|
|
||||||
|
If this file doesn't exist, this will just return itself, otherwise it
|
||||||
|
will return an appropriate sibling that doesn't exist, e.g. if a file
|
||||||
|
"/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt".
|
||||||
|
|
||||||
|
@param putNumbersInBrackets whether to add brackets around the numbers that
|
||||||
|
get appended to the new filename.
|
||||||
|
*/
|
||||||
|
File getNonexistentSibling (bool putNumbersInBrackets = true) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator== (const File& otherFile) const;
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator!= (const File& otherFile) const;
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator< (const File& otherFile) const;
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator> (const File& otherFile) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Checks whether a file can be created or written to.
|
||||||
|
|
||||||
|
@returns true if it's possible to create and write to this file. If the file
|
||||||
|
doesn't already exist, this will check its parent directory to
|
||||||
|
see if writing is allowed.
|
||||||
|
@see setReadOnly
|
||||||
|
*/
|
||||||
|
bool hasWriteAccess() const;
|
||||||
|
|
||||||
|
/** Changes the write-permission of a file or directory.
|
||||||
|
|
||||||
|
@param shouldBeReadOnly whether to add or remove write-permission
|
||||||
|
@param applyRecursively if the file is a directory and this is true, it will
|
||||||
|
recurse through all the subfolders changing the permissions
|
||||||
|
of all files
|
||||||
|
@returns true if it manages to change the file's permissions.
|
||||||
|
@see hasWriteAccess
|
||||||
|
*/
|
||||||
|
bool setReadOnly (bool shouldBeReadOnly,
|
||||||
|
bool applyRecursively = false) const;
|
||||||
|
|
||||||
|
/** Returns true if this file is a hidden or system file.
|
||||||
|
The criteria for deciding whether a file is hidden are platform-dependent.
|
||||||
|
*/
|
||||||
|
bool isHidden() const;
|
||||||
|
|
||||||
|
/** If this file is a link, this returns the file that it points to.
|
||||||
|
If this file isn't actually link, it'll just return itself.
|
||||||
|
*/
|
||||||
|
File getLinkedTarget() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the last modification time of this file.
|
||||||
|
|
||||||
|
@returns the time, or an invalid time if the file doesn't exist.
|
||||||
|
@see setLastModificationTime, getLastAccessTime, getCreationTime
|
||||||
|
*/
|
||||||
|
Time getLastModificationTime() const;
|
||||||
|
|
||||||
|
/** Returns the last time this file was accessed.
|
||||||
|
|
||||||
|
@returns the time, or an invalid time if the file doesn't exist.
|
||||||
|
@see setLastAccessTime, getLastModificationTime, getCreationTime
|
||||||
|
*/
|
||||||
|
Time getLastAccessTime() const;
|
||||||
|
|
||||||
|
/** Returns the time that this file was created.
|
||||||
|
|
||||||
|
@returns the time, or an invalid time if the file doesn't exist.
|
||||||
|
@see getLastModificationTime, getLastAccessTime
|
||||||
|
*/
|
||||||
|
Time getCreationTime() const;
|
||||||
|
|
||||||
|
/** Changes the modification time for this file.
|
||||||
|
|
||||||
|
@param newTime the time to apply to the file
|
||||||
|
@returns true if it manages to change the file's time.
|
||||||
|
@see getLastModificationTime, setLastAccessTime, setCreationTime
|
||||||
|
*/
|
||||||
|
bool setLastModificationTime (Time newTime) const;
|
||||||
|
|
||||||
|
/** Changes the last-access time for this file.
|
||||||
|
|
||||||
|
@param newTime the time to apply to the file
|
||||||
|
@returns true if it manages to change the file's time.
|
||||||
|
@see getLastAccessTime, setLastModificationTime, setCreationTime
|
||||||
|
*/
|
||||||
|
bool setLastAccessTime (Time newTime) const;
|
||||||
|
|
||||||
|
/** Changes the creation date for this file.
|
||||||
|
|
||||||
|
@param newTime the time to apply to the file
|
||||||
|
@returns true if it manages to change the file's time.
|
||||||
|
@see getCreationTime, setLastModificationTime, setLastAccessTime
|
||||||
|
*/
|
||||||
|
bool setCreationTime (Time newTime) const;
|
||||||
|
|
||||||
|
/** If possible, this will try to create a version string for the given file.
|
||||||
|
|
||||||
|
The OS may be able to look at the file and give a version for it - e.g. with
|
||||||
|
executables, bundles, dlls, etc. If no version is available, this will
|
||||||
|
return an empty string.
|
||||||
|
*/
|
||||||
|
String getVersion() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty file if it doesn't already exist.
|
||||||
|
|
||||||
|
If the file that this object refers to doesn't exist, this will create a file
|
||||||
|
of zero size.
|
||||||
|
|
||||||
|
If it already exists or is a directory, this method will do nothing.
|
||||||
|
|
||||||
|
@returns true if the file has been created (or if it already existed).
|
||||||
|
@see createDirectory
|
||||||
|
*/
|
||||||
|
Result create() const;
|
||||||
|
|
||||||
|
/** Creates a new directory for this filename.
|
||||||
|
|
||||||
|
This will try to create the file as a directory, and fill also create
|
||||||
|
any parent directories it needs in order to complete the operation.
|
||||||
|
|
||||||
|
@returns a result to indicate whether the directory was created successfully, or
|
||||||
|
an error message if it failed.
|
||||||
|
@see create
|
||||||
|
*/
|
||||||
|
Result createDirectory() const;
|
||||||
|
|
||||||
|
/** Deletes a file.
|
||||||
|
|
||||||
|
If this file is actually a directory, it may not be deleted correctly if it
|
||||||
|
contains files. See deleteRecursively() as a better way of deleting directories.
|
||||||
|
|
||||||
|
@returns true if the file has been successfully deleted (or if it didn't exist to
|
||||||
|
begin with).
|
||||||
|
@see deleteRecursively
|
||||||
|
*/
|
||||||
|
bool deleteFile() const;
|
||||||
|
|
||||||
|
/** Deletes a file or directory and all its subdirectories.
|
||||||
|
|
||||||
|
If this file is a directory, this will try to delete it and all its subfolders. If
|
||||||
|
it's just a file, it will just try to delete the file.
|
||||||
|
|
||||||
|
@returns true if the file and all its subfolders have been successfully deleted
|
||||||
|
(or if it didn't exist to begin with).
|
||||||
|
@see deleteFile
|
||||||
|
*/
|
||||||
|
bool deleteRecursively() const;
|
||||||
|
|
||||||
|
/** Moves this file or folder to the trash.
|
||||||
|
|
||||||
|
@returns true if the operation succeeded. It could fail if the trash is full, or
|
||||||
|
if the file is write-protected, so you should check the return value
|
||||||
|
and act appropriately.
|
||||||
|
*/
|
||||||
|
bool moveToTrash() const;
|
||||||
|
|
||||||
|
/** Moves or renames a file.
|
||||||
|
|
||||||
|
Tries to move a file to a different location.
|
||||||
|
If the target file already exists, this will attempt to delete it first, and
|
||||||
|
will fail if this can't be done.
|
||||||
|
|
||||||
|
Note that the destination file isn't the directory to put it in, it's the actual
|
||||||
|
filename that you want the new file to have.
|
||||||
|
|
||||||
|
@returns true if the operation succeeds
|
||||||
|
*/
|
||||||
|
bool moveFileTo (const File& targetLocation) const;
|
||||||
|
|
||||||
|
/** Copies a file.
|
||||||
|
|
||||||
|
Tries to copy a file to a different location.
|
||||||
|
If the target file already exists, this will attempt to delete it first, and
|
||||||
|
will fail if this can't be done.
|
||||||
|
|
||||||
|
@returns true if the operation succeeds
|
||||||
|
*/
|
||||||
|
bool copyFileTo (const File& targetLocation) const;
|
||||||
|
|
||||||
|
/** Copies a directory.
|
||||||
|
|
||||||
|
Tries to copy an entire directory, recursively.
|
||||||
|
|
||||||
|
If this file isn't a directory or if any target files can't be created, this
|
||||||
|
will return false.
|
||||||
|
|
||||||
|
@param newDirectory the directory that this one should be copied to. Note that this
|
||||||
|
is the name of the actual directory to create, not the directory
|
||||||
|
into which the new one should be placed, so there must be enough
|
||||||
|
write privileges to create it if it doesn't exist. Any files inside
|
||||||
|
it will be overwritten by similarly named ones that are copied.
|
||||||
|
*/
|
||||||
|
bool copyDirectoryTo (const File& newDirectory) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Used in file searching, to specify whether to return files, directories, or both.
|
||||||
|
*/
|
||||||
|
enum TypesOfFileToFind
|
||||||
|
{
|
||||||
|
findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */
|
||||||
|
findFiles = 2, /**< Use this flag to indicate that you want to find files. */
|
||||||
|
findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */
|
||||||
|
ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Searches inside a directory for files matching a wildcard pattern.
|
||||||
|
|
||||||
|
Assuming that this file is a directory, this method will search it
|
||||||
|
for either files or subdirectories whose names match a filename pattern.
|
||||||
|
|
||||||
|
@param results an array to which File objects will be added for the
|
||||||
|
files that the search comes up with
|
||||||
|
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
|
||||||
|
return files, directories, or both. If the ignoreHiddenFiles flag
|
||||||
|
is also added to this value, hidden files won't be returned
|
||||||
|
@param searchRecursively if true, all subdirectories will be recursed into to do
|
||||||
|
an exhaustive search
|
||||||
|
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
|
||||||
|
@returns the number of results that have been found
|
||||||
|
|
||||||
|
@see getNumberOfChildFiles, DirectoryIterator
|
||||||
|
*/
|
||||||
|
int findChildFiles (Array<File>& results,
|
||||||
|
int whatToLookFor,
|
||||||
|
bool searchRecursively,
|
||||||
|
const String& wildCardPattern = "*") const;
|
||||||
|
|
||||||
|
/** Searches inside a directory and counts how many files match a wildcard pattern.
|
||||||
|
|
||||||
|
Assuming that this file is a directory, this method will search it
|
||||||
|
for either files or subdirectories whose names match a filename pattern,
|
||||||
|
and will return the number of matches found.
|
||||||
|
|
||||||
|
This isn't a recursive call, and will only search this directory, not
|
||||||
|
its children.
|
||||||
|
|
||||||
|
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
|
||||||
|
count files, directories, or both. If the ignoreHiddenFiles flag
|
||||||
|
is also added to this value, hidden files won't be counted
|
||||||
|
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
|
||||||
|
@returns the number of matches found
|
||||||
|
@see findChildFiles, DirectoryIterator
|
||||||
|
*/
|
||||||
|
int getNumberOfChildFiles (int whatToLookFor,
|
||||||
|
const String& wildCardPattern = "*") const;
|
||||||
|
|
||||||
|
/** Returns true if this file is a directory that contains one or more subdirectories.
|
||||||
|
@see isDirectory, findChildFiles
|
||||||
|
*/
|
||||||
|
bool containsSubDirectories() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a stream to read from this file.
|
||||||
|
|
||||||
|
@returns a stream that will read from this file (initially positioned at the
|
||||||
|
start of the file), or nullptr if the file can't be opened for some reason
|
||||||
|
@see createOutputStream, loadFileAsData
|
||||||
|
*/
|
||||||
|
FileInputStream* createInputStream() const;
|
||||||
|
|
||||||
|
/** Creates a stream to write to this file.
|
||||||
|
|
||||||
|
If the file exists, the stream that is returned will be positioned ready for
|
||||||
|
writing at the end of the file, so you might want to use deleteFile() first
|
||||||
|
to write to an empty file.
|
||||||
|
|
||||||
|
@returns a stream that will write to this file (initially positioned at the
|
||||||
|
end of the file), or nullptr if the file can't be opened for some reason
|
||||||
|
@see createInputStream, appendData, appendText
|
||||||
|
*/
|
||||||
|
FileOutputStream* createOutputStream (int bufferSize = 0x8000) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Loads a file's contents into memory as a block of binary data.
|
||||||
|
|
||||||
|
Of course, trying to load a very large file into memory will blow up, so
|
||||||
|
it's better to check first.
|
||||||
|
|
||||||
|
@param result the data block to which the file's contents should be appended - note
|
||||||
|
that if the memory block might already contain some data, you
|
||||||
|
might want to clear it first
|
||||||
|
@returns true if the file could all be read into memory
|
||||||
|
*/
|
||||||
|
bool loadFileAsData (MemoryBlock& result) const;
|
||||||
|
|
||||||
|
/** Reads a file into memory as a string.
|
||||||
|
|
||||||
|
Attempts to load the entire file as a zero-terminated string.
|
||||||
|
|
||||||
|
This makes use of InputStream::readEntireStreamAsString, which can
|
||||||
|
read either UTF-16 or UTF-8 file formats.
|
||||||
|
*/
|
||||||
|
String loadFileAsString() const;
|
||||||
|
|
||||||
|
/** Reads the contents of this file as text and splits it into lines, which are
|
||||||
|
appended to the given StringArray.
|
||||||
|
*/
|
||||||
|
void readLines (StringArray& destLines) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Appends a block of binary data to the end of the file.
|
||||||
|
|
||||||
|
This will try to write the given buffer to the end of the file.
|
||||||
|
|
||||||
|
@returns false if it can't write to the file for some reason
|
||||||
|
*/
|
||||||
|
bool appendData (const void* dataToAppend,
|
||||||
|
size_t numberOfBytes) const;
|
||||||
|
|
||||||
|
/** Replaces this file's contents with a given block of data.
|
||||||
|
|
||||||
|
This will delete the file and replace it with the given data.
|
||||||
|
|
||||||
|
A nice feature of this method is that it's safe - instead of deleting
|
||||||
|
the file first and then re-writing it, it creates a new temporary file,
|
||||||
|
writes the data to that, and then moves the new file to replace the existing
|
||||||
|
file. This means that if the power gets pulled out or something crashes,
|
||||||
|
you're a lot less likely to end up with a corrupted or unfinished file..
|
||||||
|
|
||||||
|
Returns true if the operation succeeds, or false if it fails.
|
||||||
|
|
||||||
|
@see appendText
|
||||||
|
*/
|
||||||
|
bool replaceWithData (const void* dataToWrite,
|
||||||
|
size_t numberOfBytes) const;
|
||||||
|
|
||||||
|
/** Appends a string to the end of the file.
|
||||||
|
|
||||||
|
This will try to append a text string to the file, as either 16-bit unicode
|
||||||
|
or 8-bit characters in the default system encoding.
|
||||||
|
|
||||||
|
It can also write the 'ff fe' unicode header bytes before the text to indicate
|
||||||
|
the endianness of the file.
|
||||||
|
|
||||||
|
Any single \\n characters in the string are replaced with \\r\\n before it is written.
|
||||||
|
|
||||||
|
@see replaceWithText
|
||||||
|
*/
|
||||||
|
bool appendText (const String& textToAppend,
|
||||||
|
bool asUnicode = false,
|
||||||
|
bool writeUnicodeHeaderBytes = false) const;
|
||||||
|
|
||||||
|
/** Replaces this file's contents with a given text string.
|
||||||
|
|
||||||
|
This will delete the file and replace it with the given text.
|
||||||
|
|
||||||
|
A nice feature of this method is that it's safe - instead of deleting
|
||||||
|
the file first and then re-writing it, it creates a new temporary file,
|
||||||
|
writes the text to that, and then moves the new file to replace the existing
|
||||||
|
file. This means that if the power gets pulled out or something crashes,
|
||||||
|
you're a lot less likely to end up with an empty file..
|
||||||
|
|
||||||
|
For an explanation of the parameters here, see the appendText() method.
|
||||||
|
|
||||||
|
Returns true if the operation succeeds, or false if it fails.
|
||||||
|
|
||||||
|
@see appendText
|
||||||
|
*/
|
||||||
|
bool replaceWithText (const String& textToWrite,
|
||||||
|
bool asUnicode = false,
|
||||||
|
bool writeUnicodeHeaderBytes = false) const;
|
||||||
|
|
||||||
|
/** Attempts to scan the contents of this file and compare it to another file, returning
|
||||||
|
true if this is possible and they match byte-for-byte.
|
||||||
|
*/
|
||||||
|
bool hasIdenticalContentTo (const File& other) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a set of files to represent each file root.
|
||||||
|
|
||||||
|
e.g. on Windows this will create files for "c:\", "d:\" etc according
|
||||||
|
to which ones are available. On the Mac/Linux, this will probably
|
||||||
|
just add a single entry for "/".
|
||||||
|
*/
|
||||||
|
static void findFileSystemRoots (Array<File>& results);
|
||||||
|
|
||||||
|
/** Finds the name of the drive on which this file lives.
|
||||||
|
@returns the volume label of the drive, or an empty string if this isn't possible
|
||||||
|
*/
|
||||||
|
String getVolumeLabel() const;
|
||||||
|
|
||||||
|
/** Returns the serial number of the volume on which this file lives.
|
||||||
|
@returns the serial number, or zero if there's a problem doing this
|
||||||
|
*/
|
||||||
|
int getVolumeSerialNumber() const;
|
||||||
|
|
||||||
|
/** Returns the number of bytes free on the drive that this file lives on.
|
||||||
|
|
||||||
|
@returns the number of bytes free, or 0 if there's a problem finding this out
|
||||||
|
@see getVolumeTotalSize
|
||||||
|
*/
|
||||||
|
int64 getBytesFreeOnVolume() const;
|
||||||
|
|
||||||
|
/** Returns the total size of the drive that contains this file.
|
||||||
|
|
||||||
|
@returns the total number of bytes that the volume can hold
|
||||||
|
@see getBytesFreeOnVolume
|
||||||
|
*/
|
||||||
|
int64 getVolumeTotalSize() const;
|
||||||
|
|
||||||
|
/** Returns true if this file is on a CD or DVD drive. */
|
||||||
|
bool isOnCDRomDrive() const;
|
||||||
|
|
||||||
|
/** Returns true if this file is on a hard disk.
|
||||||
|
|
||||||
|
This will fail if it's a network drive, but will still be true for
|
||||||
|
removable hard-disks.
|
||||||
|
*/
|
||||||
|
bool isOnHardDisk() const;
|
||||||
|
|
||||||
|
/** Returns true if this file is on a removable disk drive.
|
||||||
|
|
||||||
|
This might be a usb-drive, a CD-rom, or maybe a network drive.
|
||||||
|
*/
|
||||||
|
bool isOnRemovableDrive() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Launches the file as a process.
|
||||||
|
|
||||||
|
- if the file is executable, this will run it.
|
||||||
|
|
||||||
|
- if it's a document of some kind, it will launch the document with its
|
||||||
|
default viewer application.
|
||||||
|
|
||||||
|
- if it's a folder, it will be opened in Explorer, Finder, or equivalent.
|
||||||
|
|
||||||
|
@see revealToUser
|
||||||
|
*/
|
||||||
|
bool startAsProcess (const String& parameters = String::empty) const;
|
||||||
|
|
||||||
|
/** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location.
|
||||||
|
@see startAsProcess
|
||||||
|
*/
|
||||||
|
void revealToUser() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** A set of types of location that can be passed to the getSpecialLocation() method.
|
||||||
|
*/
|
||||||
|
enum SpecialLocationType
|
||||||
|
{
|
||||||
|
/** The user's home folder. This is the same as using File ("~"). */
|
||||||
|
userHomeDirectory,
|
||||||
|
|
||||||
|
/** The user's default documents folder. On Windows, this might be the user's
|
||||||
|
"My Documents" folder. On the Mac it'll be their "Documents" folder. Linux
|
||||||
|
doesn't tend to have one of these, so it might just return their home folder.
|
||||||
|
*/
|
||||||
|
userDocumentsDirectory,
|
||||||
|
|
||||||
|
/** The folder that contains the user's desktop objects. */
|
||||||
|
userDesktopDirectory,
|
||||||
|
|
||||||
|
/** The folder in which applications store their persistent user-specific settings.
|
||||||
|
On Windows, this might be "\Documents and Settings\username\Application Data".
|
||||||
|
On the Mac, it might be "~/Library". If you're going to store your settings in here,
|
||||||
|
always create your own sub-folder to put them in, to avoid making a mess.
|
||||||
|
*/
|
||||||
|
userApplicationDataDirectory,
|
||||||
|
|
||||||
|
/** An equivalent of the userApplicationDataDirectory folder that is shared by all users
|
||||||
|
of the computer, rather than just the current user.
|
||||||
|
|
||||||
|
On the Mac it'll be "/Library", on Windows, it could be something like
|
||||||
|
"\Documents and Settings\All Users\Application Data".
|
||||||
|
|
||||||
|
Depending on the setup, this folder may be read-only.
|
||||||
|
*/
|
||||||
|
commonApplicationDataDirectory,
|
||||||
|
|
||||||
|
/** The folder that should be used for temporary files.
|
||||||
|
Always delete them when you're finished, to keep the user's computer tidy!
|
||||||
|
*/
|
||||||
|
tempDirectory,
|
||||||
|
|
||||||
|
/** Returns this application's executable file.
|
||||||
|
|
||||||
|
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
|
||||||
|
host app.
|
||||||
|
|
||||||
|
On the mac this will return the unix binary, not the package folder - see
|
||||||
|
currentApplicationFile for that.
|
||||||
|
|
||||||
|
See also invokedExecutableFile, which is similar, but if the exe was launched from a
|
||||||
|
file link, invokedExecutableFile will return the name of the link.
|
||||||
|
*/
|
||||||
|
currentExecutableFile,
|
||||||
|
|
||||||
|
/** Returns this application's location.
|
||||||
|
|
||||||
|
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
|
||||||
|
host app.
|
||||||
|
|
||||||
|
On the mac this will return the package folder (if it's in one), not the unix binary
|
||||||
|
that's inside it - compare with currentExecutableFile.
|
||||||
|
*/
|
||||||
|
currentApplicationFile,
|
||||||
|
|
||||||
|
/** Returns the file that was invoked to launch this executable.
|
||||||
|
This may differ from currentExecutableFile if the app was started from e.g. a link - this
|
||||||
|
will return the name of the link that was used, whereas currentExecutableFile will return
|
||||||
|
the actual location of the target executable.
|
||||||
|
*/
|
||||||
|
invokedExecutableFile,
|
||||||
|
|
||||||
|
/** In a plugin, this will return the path of the host executable. */
|
||||||
|
hostApplicationPath,
|
||||||
|
|
||||||
|
/** The directory in which applications normally get installed.
|
||||||
|
So on windows, this would be something like "c:\program files", on the
|
||||||
|
Mac "/Applications", or "/usr" on linux.
|
||||||
|
*/
|
||||||
|
globalApplicationsDirectory,
|
||||||
|
|
||||||
|
/** The most likely place where a user might store their music files. */
|
||||||
|
userMusicDirectory,
|
||||||
|
|
||||||
|
/** The most likely place where a user might store their movie files. */
|
||||||
|
userMoviesDirectory,
|
||||||
|
|
||||||
|
/** The most likely place where a user might store their picture files. */
|
||||||
|
userPicturesDirectory
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Finds the location of a special type of file or directory, such as a home folder or
|
||||||
|
documents folder.
|
||||||
|
|
||||||
|
@see SpecialLocationType
|
||||||
|
*/
|
||||||
|
static File BEAST_CALLTYPE getSpecialLocation (const SpecialLocationType type);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a temporary file in the system's temp directory.
|
||||||
|
This will try to return the name of a non-existent temp file.
|
||||||
|
To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
|
||||||
|
*/
|
||||||
|
static File createTempFile (const String& fileNameEnding);
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the current working directory.
|
||||||
|
@see setAsCurrentWorkingDirectory
|
||||||
|
*/
|
||||||
|
static File getCurrentWorkingDirectory();
|
||||||
|
|
||||||
|
/** Sets the current working directory to be this file.
|
||||||
|
|
||||||
|
For this to work the file must point to a valid directory.
|
||||||
|
|
||||||
|
@returns true if the current directory has been changed.
|
||||||
|
@see getCurrentWorkingDirectory
|
||||||
|
*/
|
||||||
|
bool setAsCurrentWorkingDirectory() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** The system-specific file separator character.
|
||||||
|
On Windows, this will be '\', on Mac/Linux, it'll be '/'
|
||||||
|
*/
|
||||||
|
static const beast_wchar separator;
|
||||||
|
|
||||||
|
/** The system-specific file separator character, as a string.
|
||||||
|
On Windows, this will be '\', on Mac/Linux, it'll be '/'
|
||||||
|
*/
|
||||||
|
static const String separatorString;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes illegal characters from a filename.
|
||||||
|
|
||||||
|
This will return a copy of the given string after removing characters
|
||||||
|
that are not allowed in a legal filename, and possibly shortening the
|
||||||
|
string if it's too long.
|
||||||
|
|
||||||
|
Because this will remove slashes, don't use it on an absolute pathname.
|
||||||
|
|
||||||
|
@see createLegalPathName
|
||||||
|
*/
|
||||||
|
static String createLegalFileName (const String& fileNameToFix);
|
||||||
|
|
||||||
|
/** Removes illegal characters from a pathname.
|
||||||
|
|
||||||
|
Similar to createLegalFileName(), but this won't remove slashes, so can
|
||||||
|
be used on a complete pathname.
|
||||||
|
|
||||||
|
@see createLegalFileName
|
||||||
|
*/
|
||||||
|
static String createLegalPathName (const String& pathNameToFix);
|
||||||
|
|
||||||
|
/** Indicates whether filenames are case-sensitive on the current operating system. */
|
||||||
|
static bool areFileNamesCaseSensitive();
|
||||||
|
|
||||||
|
/** Returns true if the string seems to be a fully-specified absolute path. */
|
||||||
|
static bool isAbsolutePath (const String& path);
|
||||||
|
|
||||||
|
/** Creates a file that simply contains this string, without doing the sanity-checking
|
||||||
|
that the normal constructors do.
|
||||||
|
|
||||||
|
Best to avoid this unless you really know what you're doing.
|
||||||
|
*/
|
||||||
|
static File createFileWithoutCheckingPath (const String& path) noexcept;
|
||||||
|
|
||||||
|
/** Adds a separator character to the end of a path if it doesn't already have one. */
|
||||||
|
static String addTrailingSeparator (const String& path);
|
||||||
|
|
||||||
|
#if BEAST_MAC || BEAST_IOS || DOXYGEN
|
||||||
|
//==============================================================================
|
||||||
|
/** OSX ONLY - Finds the OSType of a file from the its resources. */
|
||||||
|
OSType getMacOSType() const;
|
||||||
|
|
||||||
|
/** OSX ONLY - Returns true if this file is actually a bundle. */
|
||||||
|
bool isBundle() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_MAC || DOXYGEN
|
||||||
|
/** OSX ONLY - Adds this file to the OSX dock */
|
||||||
|
void addToDock() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_WINDOWS
|
||||||
|
/** Windows ONLY - Creates a win32 .LNK shortcut file that links to this file. */
|
||||||
|
bool createLink (const String& description, const File& linkFileToCreate) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
String fullPath;
|
||||||
|
|
||||||
|
static String parseAbsolutePath (const String&);
|
||||||
|
String getPathUpToLastSlash() const;
|
||||||
|
|
||||||
|
Result createDirectoryInternal (const String&) const;
|
||||||
|
bool copyInternal (const File&) const;
|
||||||
|
bool moveInternal (const File&) const;
|
||||||
|
bool setFileTimesInternal (int64 m, int64 a, int64 c) const;
|
||||||
|
void getFileTimesInternal (int64& m, int64& a, int64& c) const;
|
||||||
|
bool setFileReadOnlyInternal (bool) const;
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (File)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_FILE_BEASTHEADER
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
int64 beast_fileSetPosition (void* handle, int64 pos);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
FileInputStream::FileInputStream (const File& f)
|
||||||
|
: file (f),
|
||||||
|
fileHandle (nullptr),
|
||||||
|
currentPosition (0),
|
||||||
|
status (Result::ok()),
|
||||||
|
needToSeek (true)
|
||||||
|
{
|
||||||
|
openHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileInputStream::~FileInputStream()
|
||||||
|
{
|
||||||
|
closeHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int64 FileInputStream::getTotalLength()
|
||||||
|
{
|
||||||
|
return file.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileInputStream::read (void* buffer, int bytesToRead)
|
||||||
|
{
|
||||||
|
bassert (openedOk());
|
||||||
|
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||||
|
|
||||||
|
if (needToSeek)
|
||||||
|
{
|
||||||
|
if (beast_fileSetPosition (fileHandle, currentPosition) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
needToSeek = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t num = readInternal (buffer, (size_t) bytesToRead);
|
||||||
|
currentPosition += num;
|
||||||
|
|
||||||
|
return (int) num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileInputStream::isExhausted()
|
||||||
|
{
|
||||||
|
return currentPosition >= getTotalLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 FileInputStream::getPosition()
|
||||||
|
{
|
||||||
|
return currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileInputStream::setPosition (int64 pos)
|
||||||
|
{
|
||||||
|
bassert (openedOk());
|
||||||
|
|
||||||
|
if (pos != currentPosition)
|
||||||
|
{
|
||||||
|
pos = blimit ((int64) 0, getTotalLength(), pos);
|
||||||
|
|
||||||
|
needToSeek |= (currentPosition != pos);
|
||||||
|
currentPosition = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||||
|
#define BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_File.h"
|
||||||
|
#include "../streams/beast_InputStream.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
An input stream that reads from a local file.
|
||||||
|
|
||||||
|
@see InputStream, FileOutputStream, File::createInputStream
|
||||||
|
*/
|
||||||
|
class BEAST_API FileInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FileInputStream.
|
||||||
|
|
||||||
|
@param fileToRead the file to read from - if the file can't be accessed for some
|
||||||
|
reason, then the stream will just contain no data
|
||||||
|
*/
|
||||||
|
explicit FileInputStream (const File& fileToRead);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileInputStream();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file that this stream is reading from. */
|
||||||
|
const File& getFile() const noexcept { return file; }
|
||||||
|
|
||||||
|
/** Returns the status of the file stream.
|
||||||
|
The result will be ok if the file opened successfully. If an error occurs while
|
||||||
|
opening or reading from the file, this will contain an error message.
|
||||||
|
*/
|
||||||
|
const Result& getStatus() const noexcept { return status; }
|
||||||
|
|
||||||
|
/** Returns true if the stream couldn't be opened for some reason.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool failedToOpen() const noexcept { return status.failed(); }
|
||||||
|
|
||||||
|
/** Returns true if the stream opened without problems.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool openedOk() const noexcept { return status.wasOk(); }
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int64 getTotalLength();
|
||||||
|
int read (void* destBuffer, int maxBytesToRead);
|
||||||
|
bool isExhausted();
|
||||||
|
int64 getPosition();
|
||||||
|
bool setPosition (int64 pos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
File file;
|
||||||
|
void* fileHandle;
|
||||||
|
int64 currentPosition;
|
||||||
|
Result status;
|
||||||
|
bool needToSeek;
|
||||||
|
|
||||||
|
void openHandle();
|
||||||
|
void closeHandle();
|
||||||
|
size_t readInternal (void* buffer, size_t numBytes);
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_FILEINPUTSTREAM_BEASTHEADER
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
int64 beast_fileSetPosition (void* handle, int64 pos);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
FileOutputStream::FileOutputStream (const File& f, const int bufferSize_)
|
||||||
|
: file (f),
|
||||||
|
fileHandle (nullptr),
|
||||||
|
status (Result::ok()),
|
||||||
|
currentPosition (0),
|
||||||
|
bufferSize (bufferSize_),
|
||||||
|
bytesInBuffer (0),
|
||||||
|
buffer ((size_t) bmax (bufferSize_, 16))
|
||||||
|
{
|
||||||
|
openHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream::~FileOutputStream()
|
||||||
|
{
|
||||||
|
flushBuffer();
|
||||||
|
flushInternal();
|
||||||
|
closeHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 FileOutputStream::getPosition()
|
||||||
|
{
|
||||||
|
return currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputStream::setPosition (int64 newPosition)
|
||||||
|
{
|
||||||
|
if (newPosition != currentPosition)
|
||||||
|
{
|
||||||
|
flushBuffer();
|
||||||
|
currentPosition = beast_fileSetPosition (fileHandle, newPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPosition == currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputStream::flushBuffer()
|
||||||
|
{
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
if (bytesInBuffer > 0)
|
||||||
|
{
|
||||||
|
ok = (writeInternal (buffer, bytesInBuffer) == (ssize_t) bytesInBuffer);
|
||||||
|
bytesInBuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileOutputStream::flush()
|
||||||
|
{
|
||||||
|
flushBuffer();
|
||||||
|
flushInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputStream::write (const void* const src, const size_t numBytes)
|
||||||
|
{
|
||||||
|
bassert (src != nullptr && ((ssize_t) numBytes) >= 0);
|
||||||
|
|
||||||
|
if (bytesInBuffer + numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (! flushBuffer())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ssize_t bytesWritten = writeInternal (src, numBytes);
|
||||||
|
|
||||||
|
if (bytesWritten < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
currentPosition += bytesWritten;
|
||||||
|
return bytesWritten == (ssize_t) numBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileOutputStream::writeRepeatedByte (uint8 byte, size_t numBytes)
|
||||||
|
{
|
||||||
|
bassert (((ssize_t) numBytes) >= 0);
|
||||||
|
|
||||||
|
if (bytesInBuffer + numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
memset (buffer + bytesInBuffer, byte, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OutputStream::writeRepeatedByte (byte, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
114
Subtrees/beast/modules/beast_core/files/beast_FileOutputStream.h
Normal file
114
Subtrees/beast/modules/beast_core/files/beast_FileOutputStream.h
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||||
|
#define BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_File.h"
|
||||||
|
#include "../streams/beast_OutputStream.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
An output stream that writes into a local file.
|
||||||
|
|
||||||
|
@see OutputStream, FileInputStream, File::createOutputStream
|
||||||
|
*/
|
||||||
|
class BEAST_API FileOutputStream : public OutputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FileOutputStream.
|
||||||
|
|
||||||
|
If the file doesn't exist, it will first be created. If the file can't be
|
||||||
|
created or opened, the failedToOpen() method will return
|
||||||
|
true.
|
||||||
|
|
||||||
|
If the file already exists when opened, the stream's write-postion will
|
||||||
|
be set to the end of the file. To overwrite an existing file,
|
||||||
|
use File::deleteFile() before opening the stream, or use setPosition(0)
|
||||||
|
after it's opened (although this won't truncate the file).
|
||||||
|
|
||||||
|
@see TemporaryFile
|
||||||
|
*/
|
||||||
|
FileOutputStream (const File& fileToWriteTo,
|
||||||
|
int bufferSizeToUse = 16384);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileOutputStream();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file that this stream is writing to.
|
||||||
|
*/
|
||||||
|
const File& getFile() const { return file; }
|
||||||
|
|
||||||
|
/** Returns the status of the file stream.
|
||||||
|
The result will be ok if the file opened successfully. If an error occurs while
|
||||||
|
opening or writing to the file, this will contain an error message.
|
||||||
|
*/
|
||||||
|
const Result& getStatus() const noexcept { return status; }
|
||||||
|
|
||||||
|
/** Returns true if the stream couldn't be opened for some reason.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool failedToOpen() const noexcept { return status.failed(); }
|
||||||
|
|
||||||
|
/** Returns true if the stream opened without problems.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool openedOk() const noexcept { return status.wasOk(); }
|
||||||
|
|
||||||
|
/** Attempts to truncate the file to the current write position.
|
||||||
|
To truncate a file to a specific size, first use setPosition() to seek to the
|
||||||
|
appropriate location, and then call this method.
|
||||||
|
*/
|
||||||
|
Result truncate();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void flush();
|
||||||
|
int64 getPosition();
|
||||||
|
bool setPosition (int64 pos);
|
||||||
|
bool write (const void* data, size_t numBytes);
|
||||||
|
void writeRepeatedByte (uint8 byte, size_t numTimesToRepeat);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
File file;
|
||||||
|
void* fileHandle;
|
||||||
|
Result status;
|
||||||
|
int64 currentPosition;
|
||||||
|
size_t bufferSize, bytesInBuffer;
|
||||||
|
HeapBlock <char> buffer;
|
||||||
|
|
||||||
|
void openHandle();
|
||||||
|
void closeHandle();
|
||||||
|
void flushInternal();
|
||||||
|
bool flushBuffer();
|
||||||
|
int64 setPositionInternal (int64);
|
||||||
|
ssize_t writeInternal (const void*, size_t);
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileOutputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_FILEOUTPUTSTREAM_BEASTHEADER
|
||||||
166
Subtrees/beast/modules/beast_core/files/beast_FileSearchPath.cpp
Normal file
166
Subtrees/beast/modules/beast_core/files/beast_FileSearchPath.cpp
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
FileSearchPath::FileSearchPath()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSearchPath::FileSearchPath (const String& path)
|
||||||
|
{
|
||||||
|
init (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSearchPath::FileSearchPath (const FileSearchPath& other)
|
||||||
|
: directories (other.directories)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSearchPath::~FileSearchPath()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSearchPath& FileSearchPath::operator= (const String& path)
|
||||||
|
{
|
||||||
|
init (path);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::init (const String& path)
|
||||||
|
{
|
||||||
|
directories.clear();
|
||||||
|
directories.addTokens (path, ";", "\"");
|
||||||
|
directories.trim();
|
||||||
|
directories.removeEmptyStrings();
|
||||||
|
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
directories.set (i, directories[i].unquoted());
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileSearchPath::getNumPaths() const
|
||||||
|
{
|
||||||
|
return directories.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
File FileSearchPath::operator[] (const int index) const
|
||||||
|
{
|
||||||
|
return File (directories [index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
String FileSearchPath::toString() const
|
||||||
|
{
|
||||||
|
StringArray directories2 (directories);
|
||||||
|
for (int i = directories2.size(); --i >= 0;)
|
||||||
|
if (directories2[i].containsChar (';'))
|
||||||
|
directories2.set (i, directories2[i].quoted());
|
||||||
|
|
||||||
|
return directories2.joinIntoString (";");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::add (const File& dir, const int insertIndex)
|
||||||
|
{
|
||||||
|
directories.insert (insertIndex, dir.getFullPathName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::addIfNotAlreadyThere (const File& dir)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < directories.size(); ++i)
|
||||||
|
if (File (directories[i]) == dir)
|
||||||
|
return;
|
||||||
|
|
||||||
|
add (dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::remove (const int index)
|
||||||
|
{
|
||||||
|
directories.remove (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::addPath (const FileSearchPath& other)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < other.getNumPaths(); ++i)
|
||||||
|
addIfNotAlreadyThere (other[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::removeRedundantPaths()
|
||||||
|
{
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
const File d1 (directories[i]);
|
||||||
|
|
||||||
|
for (int j = directories.size(); --j >= 0;)
|
||||||
|
{
|
||||||
|
const File d2 (directories[j]);
|
||||||
|
|
||||||
|
if ((i != j) && (d1.isAChildOf (d2) || d1 == d2))
|
||||||
|
{
|
||||||
|
directories.remove (i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::removeNonExistentPaths()
|
||||||
|
{
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
if (! File (directories[i]).isDirectory())
|
||||||
|
directories.remove (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileSearchPath::findChildFiles (Array<File>& results,
|
||||||
|
const int whatToLookFor,
|
||||||
|
const bool searchRecursively,
|
||||||
|
const String& wildCardPattern) const
|
||||||
|
{
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < directories.size(); ++i)
|
||||||
|
total += operator[] (i).findChildFiles (results,
|
||||||
|
whatToLookFor,
|
||||||
|
searchRecursively,
|
||||||
|
wildCardPattern);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSearchPath::isFileInPath (const File& fileToCheck,
|
||||||
|
const bool checkRecursively) const
|
||||||
|
{
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
const File d (directories[i]);
|
||||||
|
|
||||||
|
if (checkRecursively)
|
||||||
|
{
|
||||||
|
if (fileToCheck.isAChildOf (d))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fileToCheck.getParentDirectory() == d)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
164
Subtrees/beast/modules/beast_core/files/beast_FileSearchPath.h
Normal file
164
Subtrees/beast/modules/beast_core/files/beast_FileSearchPath.h
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_FILESEARCHPATH_BEASTHEADER
|
||||||
|
#define BEAST_FILESEARCHPATH_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_File.h"
|
||||||
|
#include "../text/beast_StringArray.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Encapsulates a set of folders that make up a search path.
|
||||||
|
|
||||||
|
@see File
|
||||||
|
*/
|
||||||
|
class BEAST_API FileSearchPath
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty search path. */
|
||||||
|
FileSearchPath();
|
||||||
|
|
||||||
|
/** Creates a search path from a string of pathnames.
|
||||||
|
|
||||||
|
The path can be semicolon- or comma-separated, e.g.
|
||||||
|
"/foo/bar;/foo/moose;/fish/moose"
|
||||||
|
|
||||||
|
The separate folders are tokenised and added to the search path.
|
||||||
|
*/
|
||||||
|
FileSearchPath (const String& path);
|
||||||
|
|
||||||
|
/** Creates a copy of another search path. */
|
||||||
|
FileSearchPath (const FileSearchPath& other);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileSearchPath();
|
||||||
|
|
||||||
|
/** Uses a string containing a list of pathnames to re-initialise this list.
|
||||||
|
|
||||||
|
This search path is cleared and the semicolon- or comma-separated folders
|
||||||
|
in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose"
|
||||||
|
*/
|
||||||
|
FileSearchPath& operator= (const String& path);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the number of folders in this search path.
|
||||||
|
|
||||||
|
@see operator[]
|
||||||
|
*/
|
||||||
|
int getNumPaths() const;
|
||||||
|
|
||||||
|
/** Returns one of the folders in this search path.
|
||||||
|
|
||||||
|
The file returned isn't guaranteed to actually be a valid directory.
|
||||||
|
|
||||||
|
@see getNumPaths
|
||||||
|
*/
|
||||||
|
File operator[] (int index) const;
|
||||||
|
|
||||||
|
/** Returns the search path as a semicolon-separated list of directories. */
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds a new directory to the search path.
|
||||||
|
|
||||||
|
The new directory is added to the end of the list if the insertIndex parameter is
|
||||||
|
less than zero, otherwise it is inserted at the given index.
|
||||||
|
*/
|
||||||
|
void add (const File& directoryToAdd,
|
||||||
|
int insertIndex = -1);
|
||||||
|
|
||||||
|
/** Adds a new directory to the search path if it's not already in there. */
|
||||||
|
void addIfNotAlreadyThere (const File& directoryToAdd);
|
||||||
|
|
||||||
|
/** Removes a directory from the search path. */
|
||||||
|
void remove (int indexToRemove);
|
||||||
|
|
||||||
|
/** Merges another search path into this one.
|
||||||
|
|
||||||
|
This will remove any duplicate directories.
|
||||||
|
*/
|
||||||
|
void addPath (const FileSearchPath& other);
|
||||||
|
|
||||||
|
/** Removes any directories that are actually subdirectories of one of the other directories in the search path.
|
||||||
|
|
||||||
|
If the search is intended to be recursive, there's no point having nested folders in the search
|
||||||
|
path, because they'll just get searched twice and you'll get duplicate results.
|
||||||
|
|
||||||
|
e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc"
|
||||||
|
*/
|
||||||
|
void removeRedundantPaths();
|
||||||
|
|
||||||
|
/** Removes any directories that don't actually exist. */
|
||||||
|
void removeNonExistentPaths();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Searches the path for a wildcard.
|
||||||
|
|
||||||
|
This will search all the directories in the search path in order, adding any
|
||||||
|
matching files to the results array.
|
||||||
|
|
||||||
|
@param results an array to append the results to
|
||||||
|
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to
|
||||||
|
return files, directories, or both.
|
||||||
|
@param searchRecursively whether to recursively search the subdirectories too
|
||||||
|
@param wildCardPattern a pattern to match against the filenames
|
||||||
|
@returns the number of files added to the array
|
||||||
|
@see File::findChildFiles
|
||||||
|
*/
|
||||||
|
int findChildFiles (Array<File>& results,
|
||||||
|
int whatToLookFor,
|
||||||
|
bool searchRecursively,
|
||||||
|
const String& wildCardPattern = "*") const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds out whether a file is inside one of the path's directories.
|
||||||
|
|
||||||
|
This will return true if the specified file is a child of one of the
|
||||||
|
directories specified by this path. Note that this doesn't actually do any
|
||||||
|
searching or check that the files exist - it just looks at the pathnames
|
||||||
|
to work out whether the file would be inside a directory.
|
||||||
|
|
||||||
|
@param fileToCheck the file to look for
|
||||||
|
@param checkRecursively if true, then this will return true if the file is inside a
|
||||||
|
subfolder of one of the path's directories (at any depth). If false
|
||||||
|
it will only return true if the file is actually a direct child
|
||||||
|
of one of the directories.
|
||||||
|
@see File::isAChildOf
|
||||||
|
|
||||||
|
*/
|
||||||
|
bool isFileInPath (const File& fileToCheck,
|
||||||
|
bool checkRecursively) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
StringArray directories;
|
||||||
|
|
||||||
|
void init (const String& path);
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (FileSearchPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_FILESEARCHPATH_BEASTHEADER
|
||||||
111
Subtrees/beast/modules/beast_core/files/beast_MemoryMappedFile.h
Normal file
111
Subtrees/beast/modules/beast_core/files/beast_MemoryMappedFile.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||||
|
#define BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_File.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Maps a file into virtual memory for easy reading and/or writing.
|
||||||
|
*/
|
||||||
|
class BEAST_API MemoryMappedFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The read/write flags used when opening a memory mapped file. */
|
||||||
|
enum AccessMode
|
||||||
|
{
|
||||||
|
readOnly, /**< Indicates that the memory can only be read. */
|
||||||
|
readWrite /**< Indicates that the memory can be read and written to - changes that are
|
||||||
|
made will be flushed back to disk at the whim of the OS. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Opens a file and maps it to an area of virtual memory.
|
||||||
|
|
||||||
|
The file should already exist, and should already be the size that you want to work with
|
||||||
|
when you call this. If the file is resized after being opened, the behaviour is undefined.
|
||||||
|
|
||||||
|
If the file exists and the operation succeeds, the getData() and getSize() methods will
|
||||||
|
return the location and size of the data that can be read or written. Note that the entire
|
||||||
|
file is not read into memory immediately - the OS simply creates a virtual mapping, which
|
||||||
|
will lazily pull the data into memory when blocks are accessed.
|
||||||
|
|
||||||
|
If the file can't be opened for some reason, the getData() method will return a null pointer.
|
||||||
|
*/
|
||||||
|
MemoryMappedFile (const File& file, AccessMode mode);
|
||||||
|
|
||||||
|
/** Opens a section of a file and maps it to an area of virtual memory.
|
||||||
|
|
||||||
|
The file should already exist, and should already be the size that you want to work with
|
||||||
|
when you call this. If the file is resized after being opened, the behaviour is undefined.
|
||||||
|
|
||||||
|
If the file exists and the operation succeeds, the getData() and getSize() methods will
|
||||||
|
return the location and size of the data that can be read or written. Note that the entire
|
||||||
|
file is not read into memory immediately - the OS simply creates a virtual mapping, which
|
||||||
|
will lazily pull the data into memory when blocks are accessed.
|
||||||
|
|
||||||
|
If the file can't be opened for some reason, the getData() method will return a null pointer.
|
||||||
|
|
||||||
|
NOTE: the start of the actual range used may be rounded-down to a multiple of the OS's page-size,
|
||||||
|
so do not assume that the mapped memory will begin at exactly the position you requested - always
|
||||||
|
use getRange() to check the actual range that is being used.
|
||||||
|
*/
|
||||||
|
MemoryMappedFile (const File& file,
|
||||||
|
const Range<int64>& fileRange,
|
||||||
|
AccessMode mode);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~MemoryMappedFile();
|
||||||
|
|
||||||
|
/** Returns the address at which this file has been mapped, or a null pointer if
|
||||||
|
the file couldn't be successfully mapped.
|
||||||
|
*/
|
||||||
|
void* getData() const noexcept { return address; }
|
||||||
|
|
||||||
|
/** Returns the number of bytes of data that are available for reading or writing.
|
||||||
|
This will normally be the size of the file.
|
||||||
|
*/
|
||||||
|
size_t getSize() const noexcept { return (size_t) range.getLength(); }
|
||||||
|
|
||||||
|
/** Returns the section of the file at which the mapped memory represents. */
|
||||||
|
Range<int64> getRange() const noexcept { return range; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
void* address;
|
||||||
|
Range<int64> range;
|
||||||
|
|
||||||
|
#if BEAST_WINDOWS
|
||||||
|
void* fileHandle;
|
||||||
|
#else
|
||||||
|
int fileHandle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void openInternal (const File&, AccessMode);
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_MEMORYMAPPEDFILE_BEASTHEADER
|
||||||
112
Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.cpp
Normal file
112
Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.cpp
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
static File createTempFile (const File& parentDirectory, String name,
|
||||||
|
const String& suffix, const int optionFlags)
|
||||||
|
{
|
||||||
|
if ((optionFlags & TemporaryFile::useHiddenFile) != 0)
|
||||||
|
name = "." + name;
|
||||||
|
|
||||||
|
return parentDirectory.getNonexistentChildFile (name, suffix, (optionFlags & TemporaryFile::putNumbersInBrackets) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags)
|
||||||
|
: temporaryFile (createTempFile (File::getSpecialLocation (File::tempDirectory),
|
||||||
|
"temp_" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||||
|
suffix, optionFlags))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::TemporaryFile (const File& target, const int optionFlags)
|
||||||
|
: temporaryFile (createTempFile (target.getParentDirectory(),
|
||||||
|
target.getFileNameWithoutExtension()
|
||||||
|
+ "_temp" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||||
|
target.getFileExtension(), optionFlags)),
|
||||||
|
targetFile (target)
|
||||||
|
{
|
||||||
|
// If you use this constructor, you need to give it a valid target file!
|
||||||
|
bassert (targetFile != File::nonexistent);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::TemporaryFile (const File& target, const File& temporary)
|
||||||
|
: temporaryFile (temporary), targetFile (target)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::~TemporaryFile()
|
||||||
|
{
|
||||||
|
if (! deleteTemporaryFile())
|
||||||
|
{
|
||||||
|
/* Failed to delete our temporary file! The most likely reason for this would be
|
||||||
|
that you've not closed an output stream that was being used to write to file.
|
||||||
|
|
||||||
|
If you find that something beyond your control is changing permissions on
|
||||||
|
your temporary files and preventing them from being deleted, you may want to
|
||||||
|
call TemporaryFile::deleteTemporaryFile() to detect those error cases and
|
||||||
|
handle them appropriately.
|
||||||
|
*/
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool TemporaryFile::overwriteTargetFileWithTemporary() const
|
||||||
|
{
|
||||||
|
// This method only works if you created this object with the constructor
|
||||||
|
// that takes a target file!
|
||||||
|
bassert (targetFile != File::nonexistent);
|
||||||
|
|
||||||
|
if (temporaryFile.exists())
|
||||||
|
{
|
||||||
|
// Have a few attempts at overwriting the file before giving up..
|
||||||
|
for (int i = 5; --i >= 0;)
|
||||||
|
{
|
||||||
|
if (temporaryFile.moveFileTo (targetFile))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Thread::sleep (100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// There's no temporary file to use. If your write failed, you should
|
||||||
|
// probably check, and not bother calling this method.
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemporaryFile::deleteTemporaryFile() const
|
||||||
|
{
|
||||||
|
// Have a few attempts at deleting the file before giving up..
|
||||||
|
for (int i = 5; --i >= 0;)
|
||||||
|
{
|
||||||
|
if (temporaryFile.deleteFile())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Thread::sleep (50);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
166
Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.h
Normal file
166
Subtrees/beast/modules/beast_core/files/beast_TemporaryFile.h
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_TEMPORARYFILE_BEASTHEADER
|
||||||
|
#define BEAST_TEMPORARYFILE_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_File.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Manages a temporary file, which will be deleted when this object is deleted.
|
||||||
|
|
||||||
|
This object is intended to be used as a stack based object, using its scope
|
||||||
|
to make sure the temporary file isn't left lying around.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
File myTargetFile ("~/myfile.txt");
|
||||||
|
|
||||||
|
// this will choose a file called something like "~/myfile_temp239348.txt"
|
||||||
|
// which definitely doesn't exist at the time the constructor is called.
|
||||||
|
TemporaryFile temp (myTargetFile);
|
||||||
|
|
||||||
|
// create a stream to the temporary file, and write some data to it...
|
||||||
|
ScopedPointer <FileOutputStream> out (temp.getFile().createOutputStream());
|
||||||
|
|
||||||
|
if (out != nullptr)
|
||||||
|
{
|
||||||
|
out->write ( ...etc )
|
||||||
|
out = nullptr; // (deletes the stream)
|
||||||
|
|
||||||
|
// ..now we've finished writing, this will rename the temp file to
|
||||||
|
// make it replace the target file we specified above.
|
||||||
|
bool succeeded = temp.overwriteTargetFileWithTemporary();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ..and even if something went wrong and our overwrite failed,
|
||||||
|
// as the TemporaryFile object goes out of scope here, it'll make sure
|
||||||
|
// that the temp file gets deleted.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see File, FileOutputStream
|
||||||
|
*/
|
||||||
|
class BEAST_API TemporaryFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
enum OptionFlags
|
||||||
|
{
|
||||||
|
useHiddenFile = 1, /**< Indicates that the temporary file should be hidden -
|
||||||
|
i.e. its name should start with a dot. */
|
||||||
|
putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure
|
||||||
|
the file is unique, they should go in brackets rather
|
||||||
|
than just being appended (see File::getNonexistentSibling() )*/
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a randomly-named temporary file in the default temp directory.
|
||||||
|
|
||||||
|
@param suffix a file suffix to use for the file
|
||||||
|
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||||
|
The file will not be created until you write to it. And remember that when
|
||||||
|
this object is deleted, the file will also be deleted!
|
||||||
|
*/
|
||||||
|
TemporaryFile (const String& suffix = String::empty,
|
||||||
|
int optionFlags = 0);
|
||||||
|
|
||||||
|
/** Creates a temporary file in the same directory as a specified file.
|
||||||
|
|
||||||
|
This is useful if you have a file that you want to overwrite, but don't
|
||||||
|
want to harm the original file if the write operation fails. You can
|
||||||
|
use this to create a temporary file next to the target file, then
|
||||||
|
write to the temporary file, and finally use overwriteTargetFileWithTemporary()
|
||||||
|
to replace the target file with the one you've just written.
|
||||||
|
|
||||||
|
This class won't create any files until you actually write to them. And remember
|
||||||
|
that when this object is deleted, the temporary file will also be deleted!
|
||||||
|
|
||||||
|
@param targetFile the file that you intend to overwrite - the temporary
|
||||||
|
file will be created in the same directory as this
|
||||||
|
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||||
|
*/
|
||||||
|
TemporaryFile (const File& targetFile,
|
||||||
|
int optionFlags = 0);
|
||||||
|
|
||||||
|
/** Creates a temporary file using an explicit filename.
|
||||||
|
The other constructors are a better choice than this one, unless for some reason
|
||||||
|
you need to explicitly specify the temporary file you want to use.
|
||||||
|
|
||||||
|
@param targetFile the file that you intend to overwrite
|
||||||
|
@param temporaryFile the temporary file to be used
|
||||||
|
*/
|
||||||
|
TemporaryFile (const File& targetFile,
|
||||||
|
const File& temporaryFile);
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
|
||||||
|
When this object is deleted it will make sure that its temporary file is
|
||||||
|
also deleted! If the operation fails, it'll throw an assertion in debug
|
||||||
|
mode.
|
||||||
|
*/
|
||||||
|
~TemporaryFile();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the temporary file. */
|
||||||
|
const File& getFile() const noexcept { return temporaryFile; }
|
||||||
|
|
||||||
|
/** Returns the target file that was specified in the constructor. */
|
||||||
|
const File& getTargetFile() const noexcept { return targetFile; }
|
||||||
|
|
||||||
|
/** Tries to move the temporary file to overwrite the target file that was
|
||||||
|
specified in the constructor.
|
||||||
|
|
||||||
|
If you used the constructor that specified a target file, this will attempt
|
||||||
|
to replace that file with the temporary one.
|
||||||
|
|
||||||
|
Before calling this, make sure:
|
||||||
|
- that you've actually written to the temporary file
|
||||||
|
- that you've closed any open streams that you were using to write to it
|
||||||
|
- and that you don't have any streams open to the target file, which would
|
||||||
|
prevent it being overwritten
|
||||||
|
|
||||||
|
If the file move succeeds, this returns false, and the temporary file will
|
||||||
|
have disappeared. If it fails, the temporary file will probably still exist,
|
||||||
|
but will be deleted when this object is destroyed.
|
||||||
|
*/
|
||||||
|
bool overwriteTargetFileWithTemporary() const;
|
||||||
|
|
||||||
|
/** Attempts to delete the temporary file, if it exists.
|
||||||
|
@returns true if the file is successfully deleted (or if it didn't exist).
|
||||||
|
*/
|
||||||
|
bool deleteTemporaryFile() const;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
const File temporaryFile, targetFile;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryFile)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_TEMPORARYFILE_BEASTHEADER
|
||||||
645
Subtrees/beast/modules/beast_core/json/beast_JSON.cpp
Normal file
645
Subtrees/beast/modules/beast_core/json/beast_JSON.cpp
Normal file
@@ -0,0 +1,645 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
class JSONParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Result parseObjectOrArray (String::CharPointerType t, var& result)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
|
||||||
|
switch (t.getAndAdvance())
|
||||||
|
{
|
||||||
|
case 0: result = var::null; return Result::ok();
|
||||||
|
case '{': return parseObject (t, result);
|
||||||
|
case '[': return parseArray (t, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Expected '{' or '['", &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Result parseAny (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
String::CharPointerType t2 (t);
|
||||||
|
|
||||||
|
switch (t2.getAndAdvance())
|
||||||
|
{
|
||||||
|
case '{': t = t2; return parseObject (t, result);
|
||||||
|
case '[': t = t2; return parseArray (t, result);
|
||||||
|
case '"': t = t2; return parseString (t, result);
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
t2 = t2.findEndOfWhitespace();
|
||||||
|
if (! CharacterFunctions::isDigit (*t2))
|
||||||
|
break;
|
||||||
|
|
||||||
|
t = t2;
|
||||||
|
return parseNumber (t, result, true);
|
||||||
|
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
return parseNumber (t, result, false);
|
||||||
|
|
||||||
|
case 't': // "true"
|
||||||
|
if (t2.getAndAdvance() == 'r' && t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'e')
|
||||||
|
{
|
||||||
|
t = t2;
|
||||||
|
result = var (true);
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f': // "false"
|
||||||
|
if (t2.getAndAdvance() == 'a' && t2.getAndAdvance() == 'l'
|
||||||
|
&& t2.getAndAdvance() == 's' && t2.getAndAdvance() == 'e')
|
||||||
|
{
|
||||||
|
t = t2;
|
||||||
|
result = var (false);
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n': // "null"
|
||||||
|
if (t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'l' && t2.getAndAdvance() == 'l')
|
||||||
|
{
|
||||||
|
t = t2;
|
||||||
|
result = var::null;
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Syntax error", &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result createFail (const char* const message, const String::CharPointerType* location = nullptr)
|
||||||
|
{
|
||||||
|
String m (message);
|
||||||
|
if (location != nullptr)
|
||||||
|
m << ": \"" << String (*location, 20) << '"';
|
||||||
|
|
||||||
|
return Result::fail (m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseNumber (String::CharPointerType& t, var& result, const bool isNegative)
|
||||||
|
{
|
||||||
|
String::CharPointerType oldT (t);
|
||||||
|
|
||||||
|
int64 intValue = t.getAndAdvance() - '0';
|
||||||
|
bassert (intValue >= 0 && intValue < 10);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
String::CharPointerType previousChar (t);
|
||||||
|
const beast_wchar c = t.getAndAdvance();
|
||||||
|
const int digit = ((int) c) - '0';
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (digit, 10))
|
||||||
|
{
|
||||||
|
intValue = intValue * 10 + digit;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'e' || c == 'E' || c == '.')
|
||||||
|
{
|
||||||
|
t = oldT;
|
||||||
|
const double asDouble = CharacterFunctions::readDoubleValue (t);
|
||||||
|
result = isNegative ? -asDouble : asDouble;
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CharacterFunctions::isWhitespace (c)
|
||||||
|
|| c == ',' || c == '}' || c == ']' || c == 0)
|
||||||
|
{
|
||||||
|
t = previousChar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Syntax error in number", &oldT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int64 correctedValue = isNegative ? -intValue : intValue;
|
||||||
|
|
||||||
|
if ((intValue >> 31) != 0)
|
||||||
|
result = correctedValue;
|
||||||
|
else
|
||||||
|
result = (int) correctedValue;
|
||||||
|
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseObject (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
DynamicObject* const resultObject = new DynamicObject();
|
||||||
|
result = resultObject;
|
||||||
|
NamedValueSet& resultProperties = resultObject->getProperties();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
|
||||||
|
String::CharPointerType oldT (t);
|
||||||
|
const beast_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c == '}')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return createFail ("Unexpected end-of-input in object declaration");
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
var propertyNameVar;
|
||||||
|
Result r (parseString (t, propertyNameVar));
|
||||||
|
|
||||||
|
if (r.failed())
|
||||||
|
return r;
|
||||||
|
|
||||||
|
const String propertyName (propertyNameVar.toString());
|
||||||
|
|
||||||
|
if (propertyName.isNotEmpty())
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
oldT = t;
|
||||||
|
|
||||||
|
const beast_wchar c2 = t.getAndAdvance();
|
||||||
|
if (c2 != ':')
|
||||||
|
return createFail ("Expected ':', but found", &oldT);
|
||||||
|
|
||||||
|
resultProperties.set (propertyName, var::null);
|
||||||
|
var* propertyValue = resultProperties.getVarPointer (propertyName);
|
||||||
|
|
||||||
|
Result r2 (parseAny (t, *propertyValue));
|
||||||
|
|
||||||
|
if (r2.failed())
|
||||||
|
return r2;
|
||||||
|
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
oldT = t;
|
||||||
|
|
||||||
|
const beast_wchar nextChar = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (nextChar == ',')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nextChar == '}')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Expected object member declaration, but found", &oldT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseArray (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
result = var (Array<var>());
|
||||||
|
Array<var>* const destArray = result.getArray();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
|
||||||
|
String::CharPointerType oldT (t);
|
||||||
|
const beast_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c == ']')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return createFail ("Unexpected end-of-input in array declaration");
|
||||||
|
|
||||||
|
t = oldT;
|
||||||
|
destArray->add (var::null);
|
||||||
|
Result r (parseAny (t, destArray->getReference (destArray->size() - 1)));
|
||||||
|
|
||||||
|
if (r.failed())
|
||||||
|
return r;
|
||||||
|
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
oldT = t;
|
||||||
|
|
||||||
|
const beast_wchar nextChar = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (nextChar == ',')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nextChar == ']')
|
||||||
|
break;
|
||||||
|
|
||||||
|
return createFail ("Expected object array item, but found", &oldT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseString (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
MemoryOutputStream buffer (256);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
beast_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
c = t.getAndAdvance();
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
case '/': break;
|
||||||
|
|
||||||
|
case 'b': c = '\b'; break;
|
||||||
|
case 'f': c = '\f'; break;
|
||||||
|
case 'n': c = '\n'; break;
|
||||||
|
case 'r': c = '\r'; break;
|
||||||
|
case 't': c = '\t'; break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
{
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
for (int i = 4; --i >= 0;)
|
||||||
|
{
|
||||||
|
const int digitValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
|
||||||
|
if (digitValue < 0)
|
||||||
|
return createFail ("Syntax error in unicode escape sequence");
|
||||||
|
|
||||||
|
c = (beast_wchar) ((c << 4) + digitValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return createFail ("Unexpected end-of-input in string constant");
|
||||||
|
|
||||||
|
buffer.appendUTF8Char (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = buffer.toString();
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class JSONFormatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void write (OutputStream& out, const var& v,
|
||||||
|
const int indentLevel, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
if (v.isString())
|
||||||
|
{
|
||||||
|
writeString (out, v.toString().getCharPointer());
|
||||||
|
}
|
||||||
|
else if (v.isVoid())
|
||||||
|
{
|
||||||
|
out << "null";
|
||||||
|
}
|
||||||
|
else if (v.isBool())
|
||||||
|
{
|
||||||
|
out << (static_cast<bool> (v) ? "true" : "false");
|
||||||
|
}
|
||||||
|
else if (v.isArray())
|
||||||
|
{
|
||||||
|
writeArray (out, *v.getArray(), indentLevel, allOnOneLine);
|
||||||
|
}
|
||||||
|
else if (v.isObject())
|
||||||
|
{
|
||||||
|
if (DynamicObject* const object = v.getDynamicObject())
|
||||||
|
writeObject (out, *object, indentLevel, allOnOneLine);
|
||||||
|
else
|
||||||
|
jassertfalse; // Only DynamicObjects can be converted to JSON!
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can't convert these other types of object to JSON!
|
||||||
|
bassert (! (v.isMethod() || v.isBinaryData()));
|
||||||
|
|
||||||
|
out << v.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum { indentSize = 2 };
|
||||||
|
|
||||||
|
static void writeEscapedChar (OutputStream& out, const unsigned short value)
|
||||||
|
{
|
||||||
|
out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeString (OutputStream& out, String::CharPointerType t)
|
||||||
|
{
|
||||||
|
out << '"';
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const beast_wchar c (t.getAndAdvance());
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0: out << '"'; return;
|
||||||
|
|
||||||
|
case '\"': out << "\\\""; break;
|
||||||
|
case '\\': out << "\\\\"; break;
|
||||||
|
case '\b': out << "\\b"; break;
|
||||||
|
case '\f': out << "\\f"; break;
|
||||||
|
case '\t': out << "\\t"; break;
|
||||||
|
case '\r': out << "\\r"; break;
|
||||||
|
case '\n': out << "\\n"; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (c >= 32 && c < 127)
|
||||||
|
{
|
||||||
|
out << (char) c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CharPointer_UTF16::getBytesRequiredFor (c) > 2)
|
||||||
|
{
|
||||||
|
CharPointer_UTF16::CharType chars[2];
|
||||||
|
CharPointer_UTF16 utf16 (chars);
|
||||||
|
utf16.write (c);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
writeEscapedChar (out, (unsigned short) chars[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeEscapedChar (out, (unsigned short) c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeSpaces (OutputStream& out, int numSpaces)
|
||||||
|
{
|
||||||
|
out.writeRepeatedByte (' ', (size_t) numSpaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeArray (OutputStream& out, const Array<var>& array,
|
||||||
|
const int indentLevel, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
out << '[';
|
||||||
|
if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
|
||||||
|
for (int i = 0; i < array.size(); ++i)
|
||||||
|
{
|
||||||
|
if (! allOnOneLine)
|
||||||
|
writeSpaces (out, indentLevel + indentSize);
|
||||||
|
|
||||||
|
write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine);
|
||||||
|
|
||||||
|
if (i < array.size() - 1)
|
||||||
|
{
|
||||||
|
if (allOnOneLine)
|
||||||
|
out << ", ";
|
||||||
|
else
|
||||||
|
out << ',' << newLine;
|
||||||
|
}
|
||||||
|
else if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! allOnOneLine)
|
||||||
|
writeSpaces (out, indentLevel);
|
||||||
|
|
||||||
|
out << ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeObject (OutputStream& out, DynamicObject& object,
|
||||||
|
const int indentLevel, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
NamedValueSet& props = object.getProperties();
|
||||||
|
|
||||||
|
out << '{';
|
||||||
|
if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
|
||||||
|
LinkedListPointer<NamedValueSet::NamedValue>* i = &(props.values);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
NamedValueSet::NamedValue* const v = i->get();
|
||||||
|
|
||||||
|
if (v == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (! allOnOneLine)
|
||||||
|
writeSpaces (out, indentLevel + indentSize);
|
||||||
|
|
||||||
|
writeString (out, v->name);
|
||||||
|
out << ": ";
|
||||||
|
write (out, v->value, indentLevel + indentSize, allOnOneLine);
|
||||||
|
|
||||||
|
if (v->nextListItem.get() != nullptr)
|
||||||
|
{
|
||||||
|
if (allOnOneLine)
|
||||||
|
out << ", ";
|
||||||
|
else
|
||||||
|
out << ',' << newLine;
|
||||||
|
}
|
||||||
|
else if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
|
||||||
|
i = &(v->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! allOnOneLine)
|
||||||
|
writeSpaces (out, indentLevel);
|
||||||
|
|
||||||
|
out << '}';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var JSON::parse (const String& text)
|
||||||
|
{
|
||||||
|
var result;
|
||||||
|
|
||||||
|
if (! JSONParser::parseObjectOrArray (text.getCharPointer(), result))
|
||||||
|
result = var::null;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var JSON::parse (InputStream& input)
|
||||||
|
{
|
||||||
|
return parse (input.readEntireStreamAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var JSON::parse (const File& file)
|
||||||
|
{
|
||||||
|
return parse (file.loadFileAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JSON::parse (const String& text, var& result)
|
||||||
|
{
|
||||||
|
return JSONParser::parseObjectOrArray (text.getCharPointer(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
String JSON::toString (const var& data, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
MemoryOutputStream mo (1024);
|
||||||
|
JSONFormatter::write (mo, data, 0, allOnOneLine);
|
||||||
|
return mo.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
JSONFormatter::write (output, data, 0, allOnOneLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_UNIT_TESTS
|
||||||
|
|
||||||
|
class JSONTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JSONTests() : UnitTest ("JSON") {}
|
||||||
|
|
||||||
|
static String createRandomWideCharString (Random& r)
|
||||||
|
{
|
||||||
|
beast_wchar buffer[40] = { 0 };
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||||
|
{
|
||||||
|
if (r.nextBool())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
buffer[i] = (beast_wchar) (1 + r.nextInt (0x10ffff - 1));
|
||||||
|
}
|
||||||
|
while (! CharPointer_UTF16::canRepresent (buffer[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buffer[i] = (beast_wchar) (1 + r.nextInt (0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharPointer_UTF32 (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String createRandomIdentifier (Random& r)
|
||||||
|
{
|
||||||
|
char buffer[30] = { 0 };
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||||
|
{
|
||||||
|
static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
|
||||||
|
buffer[i] = chars [r.nextInt (sizeof (chars) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharPointer_ASCII (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static var createRandomVar (Random& r, int depth)
|
||||||
|
{
|
||||||
|
switch (r.nextInt (depth > 3 ? 6 : 8))
|
||||||
|
{
|
||||||
|
case 0: return var::null;
|
||||||
|
case 1: return r.nextInt();
|
||||||
|
case 2: return r.nextInt64();
|
||||||
|
case 3: return r.nextBool();
|
||||||
|
case 4: return r.nextDouble();
|
||||||
|
case 5: return createRandomWideCharString (r);
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
{
|
||||||
|
var v (createRandomVar (r, depth + 1));
|
||||||
|
|
||||||
|
for (int i = 1 + r.nextInt (30); --i >= 0;)
|
||||||
|
v.append (createRandomVar (r, depth + 1));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
{
|
||||||
|
DynamicObject* o = new DynamicObject();
|
||||||
|
|
||||||
|
for (int i = r.nextInt (30); --i >= 0;)
|
||||||
|
o->setProperty (createRandomIdentifier (r), createRandomVar (r, depth + 1));
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return var::null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runTest()
|
||||||
|
{
|
||||||
|
beginTest ("JSON");
|
||||||
|
Random r;
|
||||||
|
r.setSeedRandomly();
|
||||||
|
|
||||||
|
expect (JSON::parse (String::empty) == var::null);
|
||||||
|
expect (JSON::parse ("{}").isObject());
|
||||||
|
expect (JSON::parse ("[]").isArray());
|
||||||
|
expect (JSON::parse ("[ 1234 ]")[0].isInt());
|
||||||
|
expect (JSON::parse ("[ 12345678901234 ]")[0].isInt64());
|
||||||
|
expect (JSON::parse ("[ 1.123e3 ]")[0].isDouble());
|
||||||
|
expect (JSON::parse ("[ -1234]")[0].isInt());
|
||||||
|
expect (JSON::parse ("[-12345678901234]")[0].isInt64());
|
||||||
|
expect (JSON::parse ("[-1.123e3]")[0].isDouble());
|
||||||
|
|
||||||
|
for (int i = 100; --i >= 0;)
|
||||||
|
{
|
||||||
|
var v;
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
v = createRandomVar (r, 0);
|
||||||
|
|
||||||
|
const bool oneLine = r.nextBool();
|
||||||
|
String asString (JSON::toString (v, oneLine));
|
||||||
|
var parsed = JSON::parse ("[" + asString + "]")[0];
|
||||||
|
String parsedString (JSON::toString (parsed, oneLine));
|
||||||
|
expect (asString.isNotEmpty() && parsedString == asString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static JSONTests JSONUnitTests;
|
||||||
|
|
||||||
|
#endif
|
||||||
113
Subtrees/beast/modules/beast_core/json/beast_JSON.h
Normal file
113
Subtrees/beast/modules/beast_core/json/beast_JSON.h
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_JSON_BEASTHEADER
|
||||||
|
#define BEAST_JSON_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../misc/beast_Result.h"
|
||||||
|
#include "../containers/beast_Variant.h"
|
||||||
|
class InputStream;
|
||||||
|
class OutputStream;
|
||||||
|
class File;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Contains static methods for converting JSON-formatted text to and from var objects.
|
||||||
|
|
||||||
|
The var class is structurally compatible with JSON-formatted data, so these
|
||||||
|
functions allow you to parse JSON into a var object, and to convert a var
|
||||||
|
object to JSON-formatted text.
|
||||||
|
|
||||||
|
@see var
|
||||||
|
*/
|
||||||
|
class BEAST_API JSON
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Parses a string of JSON-formatted text, and returns a result code containing
|
||||||
|
any parse errors.
|
||||||
|
|
||||||
|
This will return the parsed structure in the parsedResult parameter, and will
|
||||||
|
return a Result object to indicate whether parsing was successful, and if not,
|
||||||
|
it will contain an error message.
|
||||||
|
|
||||||
|
If you're not interested in the error message, you can use one of the other
|
||||||
|
shortcut parse methods, which simply return a var::null if the parsing fails.
|
||||||
|
*/
|
||||||
|
static Result parse (const String& text, var& parsedResult);
|
||||||
|
|
||||||
|
/** Attempts to parse some JSON-formatted text, and returns the result as a var object.
|
||||||
|
|
||||||
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||||
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||||
|
*/
|
||||||
|
static var parse (const String& text);
|
||||||
|
|
||||||
|
/** Attempts to parse some JSON-formatted text from a file, and returns the result
|
||||||
|
as a var object.
|
||||||
|
|
||||||
|
Note that this is just a short-cut for reading the entire file into a string and
|
||||||
|
parsing the result.
|
||||||
|
|
||||||
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||||
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||||
|
*/
|
||||||
|
static var parse (const File& file);
|
||||||
|
|
||||||
|
/** Attempts to parse some JSON-formatted text from a stream, and returns the result
|
||||||
|
as a var object.
|
||||||
|
|
||||||
|
Note that this is just a short-cut for reading the entire stream into a string and
|
||||||
|
parsing the result.
|
||||||
|
|
||||||
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||||
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||||
|
*/
|
||||||
|
static var parse (InputStream& input);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a string which contains a JSON-formatted representation of the var object.
|
||||||
|
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||||
|
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||||
|
@see writeToStream
|
||||||
|
*/
|
||||||
|
static String toString (const var& objectToFormat,
|
||||||
|
bool allOnOneLine = false);
|
||||||
|
|
||||||
|
/** Writes a JSON-formatted representation of the var object to the given stream.
|
||||||
|
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||||
|
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||||
|
@see toString
|
||||||
|
*/
|
||||||
|
static void writeToStream (OutputStream& output,
|
||||||
|
const var& objectToFormat,
|
||||||
|
bool allOnOneLine = false);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
JSON(); // This class can't be instantiated - just use its static methods.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_JSON_BEASTHEADER
|
||||||
129
Subtrees/beast/modules/beast_core/logging/beast_FileLogger.cpp
Normal file
129
Subtrees/beast/modules/beast_core/logging/beast_FileLogger.cpp
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
FileLogger::FileLogger (const File& file,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes)
|
||||||
|
: logFile (file)
|
||||||
|
{
|
||||||
|
if (maxInitialFileSizeBytes >= 0)
|
||||||
|
trimFileSize (maxInitialFileSizeBytes);
|
||||||
|
|
||||||
|
if (! file.exists())
|
||||||
|
file.create(); // (to create the parent directories)
|
||||||
|
|
||||||
|
String welcome;
|
||||||
|
welcome << newLine
|
||||||
|
<< "**********************************************************" << newLine
|
||||||
|
<< welcomeMessage << newLine
|
||||||
|
<< "Log started: " << Time::getCurrentTime().toString (true, true) << newLine;
|
||||||
|
|
||||||
|
FileLogger::logMessage (welcome);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileLogger::~FileLogger() {}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void FileLogger::logMessage (const String& message)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (logLock);
|
||||||
|
DBG (message);
|
||||||
|
FileOutputStream out (logFile, 256);
|
||||||
|
out << message << newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLogger::trimFileSize (int64 maxFileSizeBytes) const
|
||||||
|
{
|
||||||
|
if (maxFileSizeBytes <= 0)
|
||||||
|
{
|
||||||
|
logFile.deleteFile();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int64 fileSize = logFile.getSize();
|
||||||
|
|
||||||
|
if (fileSize > maxFileSizeBytes)
|
||||||
|
{
|
||||||
|
TemporaryFile tempFile (logFile);
|
||||||
|
|
||||||
|
{
|
||||||
|
FileOutputStream out (tempFile.getFile());
|
||||||
|
FileInputStream in (logFile);
|
||||||
|
|
||||||
|
if (! (out.openedOk() && in.openedOk()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
in.setPosition (fileSize - maxFileSizeBytes);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const char c = in.readByte();
|
||||||
|
if (c == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (c == '\n' || c == '\r')
|
||||||
|
{
|
||||||
|
out << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.writeFromInputStream (in, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempFile.overwriteTargetFileWithTemporary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
File FileLogger::getSystemLogFileFolder()
|
||||||
|
{
|
||||||
|
#if BEAST_MAC
|
||||||
|
return File ("~/Library/Logs");
|
||||||
|
#else
|
||||||
|
return File::getSpecialLocation (File::userApplicationDataDirectory);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
FileLogger* FileLogger::createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileName,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes)
|
||||||
|
{
|
||||||
|
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||||
|
.getChildFile (logFileName),
|
||||||
|
welcomeMessage, maxInitialFileSizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileLogger* FileLogger::createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileNameRoot,
|
||||||
|
const String& logFileNameSuffix,
|
||||||
|
const String& welcomeMessage)
|
||||||
|
{
|
||||||
|
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||||
|
.getChildFile (logFileNameRoot + Time::getCurrentTime().formatted ("%Y-%m-%d_%H-%M-%S"))
|
||||||
|
.withFileExtension (logFileNameSuffix)
|
||||||
|
.getNonexistentSibling(),
|
||||||
|
welcomeMessage, 0);
|
||||||
|
}
|
||||||
134
Subtrees/beast/modules/beast_core/logging/beast_FileLogger.h
Normal file
134
Subtrees/beast/modules/beast_core/logging/beast_FileLogger.h
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_FILELOGGER_BEASTHEADER
|
||||||
|
#define BEAST_FILELOGGER_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_Logger.h"
|
||||||
|
#include "../files/beast_File.h"
|
||||||
|
#include "../memory/beast_ScopedPointer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A simple implementation of a Logger that writes to a file.
|
||||||
|
|
||||||
|
@see Logger
|
||||||
|
*/
|
||||||
|
class BEAST_API FileLogger : public Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FileLogger for a given file.
|
||||||
|
|
||||||
|
@param fileToWriteTo the file that to use - new messages will be appended
|
||||||
|
to the file. If the file doesn't exist, it will be created,
|
||||||
|
along with any parent directories that are needed.
|
||||||
|
@param welcomeMessage when opened, the logger will write a header to the log, along
|
||||||
|
with the current date and time, and this welcome message
|
||||||
|
@param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists
|
||||||
|
but is larger than this number of bytes, then the start of the
|
||||||
|
file will be truncated to keep the size down. This prevents a log
|
||||||
|
file getting ridiculously large over time. The file will be truncated
|
||||||
|
at a new-line boundary. If this value is less than zero, no size limit
|
||||||
|
will be imposed; if it's zero, the file will always be deleted. Note that
|
||||||
|
the size is only checked once when this object is created - any logging
|
||||||
|
that is done later will be appended without any checking
|
||||||
|
*/
|
||||||
|
FileLogger (const File& fileToWriteTo,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileLogger();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file that this logger is writing to. */
|
||||||
|
const File& getLogFile() const noexcept { return logFile; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Helper function to create a log file in the correct place for this platform.
|
||||||
|
|
||||||
|
The method might return nullptr if the file can't be created for some reason.
|
||||||
|
|
||||||
|
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||||
|
returned by getSystemLogFileFolder). It's best to use something
|
||||||
|
like the name of your application here.
|
||||||
|
@param logFileName the name of the file to create, e.g. "MyAppLog.txt".
|
||||||
|
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||||
|
@param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this)
|
||||||
|
*/
|
||||||
|
static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileName,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||||
|
|
||||||
|
/** Helper function to create a log file in the correct place for this platform.
|
||||||
|
|
||||||
|
The filename used is based on the root and suffix strings provided, along with a
|
||||||
|
time and date string, meaning that a new, empty log file will be always be created
|
||||||
|
rather than appending to an exising one.
|
||||||
|
|
||||||
|
The method might return nullptr if the file can't be created for some reason.
|
||||||
|
|
||||||
|
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||||
|
returned by getSystemLogFileFolder). It's best to use something
|
||||||
|
like the name of your application here.
|
||||||
|
@param logFileNameRoot the start of the filename to use, e.g. "MyAppLog_". This will have
|
||||||
|
a timestamp and the logFileNameSuffix appended to it
|
||||||
|
@param logFileNameSuffix the file suffix to use, e.g. ".txt"
|
||||||
|
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||||
|
*/
|
||||||
|
static FileLogger* createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileNameRoot,
|
||||||
|
const String& logFileNameSuffix,
|
||||||
|
const String& welcomeMessage);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns an OS-specific folder where log-files should be stored.
|
||||||
|
|
||||||
|
On Windows this will return a logger with a path such as:
|
||||||
|
c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
|
||||||
|
|
||||||
|
On the Mac it'll create something like:
|
||||||
|
~/Library/Logs/[logFileSubDirectoryName]/[logFileName]
|
||||||
|
|
||||||
|
@see createDefaultAppLogger
|
||||||
|
*/
|
||||||
|
static File getSystemLogFileFolder();
|
||||||
|
|
||||||
|
// (implementation of the Logger virtual method)
|
||||||
|
void logMessage (const String&);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
File logFile;
|
||||||
|
CriticalSection logLock;
|
||||||
|
|
||||||
|
void trimFileSize (int64 maxFileSizeBytes) const;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_FILELOGGER_BEASTHEADER
|
||||||
58
Subtrees/beast/modules/beast_core/logging/beast_Logger.cpp
Normal file
58
Subtrees/beast/modules/beast_core/logging/beast_Logger.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
Logger::Logger() {}
|
||||||
|
|
||||||
|
Logger::~Logger()
|
||||||
|
{
|
||||||
|
// You're deleting this logger while it's still being used!
|
||||||
|
// Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
|
||||||
|
bassert (currentLogger != this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger* Logger::currentLogger = nullptr;
|
||||||
|
|
||||||
|
void Logger::setCurrentLogger (Logger* const newLogger) noexcept { currentLogger = newLogger; }
|
||||||
|
Logger* Logger::getCurrentLogger() noexcept { return currentLogger; }
|
||||||
|
|
||||||
|
void Logger::writeToLog (const String& message)
|
||||||
|
{
|
||||||
|
if (currentLogger != nullptr)
|
||||||
|
currentLogger->logMessage (message);
|
||||||
|
else
|
||||||
|
outputDebugString (message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_LOG_ASSERTIONS || BEAST_DEBUG
|
||||||
|
void BEAST_API BEAST_CALLTYPE logAssertion (const char* const filename, const int lineNum) noexcept
|
||||||
|
{
|
||||||
|
String m ("BEAST Assertion failure in ");
|
||||||
|
m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum;
|
||||||
|
|
||||||
|
#if BEAST_LOG_ASSERTIONS
|
||||||
|
Logger::writeToLog (m);
|
||||||
|
#else
|
||||||
|
DBG (m);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
94
Subtrees/beast/modules/beast_core/logging/beast_Logger.h
Normal file
94
Subtrees/beast/modules/beast_core/logging/beast_Logger.h
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_LOGGER_BEASTHEADER
|
||||||
|
#define BEAST_LOGGER_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_String.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Acts as an application-wide logging class.
|
||||||
|
|
||||||
|
A subclass of Logger can be created and passed into the Logger::setCurrentLogger
|
||||||
|
method and this will then be used by all calls to writeToLog.
|
||||||
|
|
||||||
|
The logger class also contains methods for writing messages to the debugger's
|
||||||
|
output stream.
|
||||||
|
|
||||||
|
@see FileLogger
|
||||||
|
*/
|
||||||
|
class BEAST_API Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~Logger();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets the current logging class to use.
|
||||||
|
|
||||||
|
Note that the object passed in will not be owned or deleted by the logger, so
|
||||||
|
the caller must make sure that it is not deleted while still being used.
|
||||||
|
A null pointer can be passed-in to disable any logging.
|
||||||
|
*/
|
||||||
|
static void BEAST_CALLTYPE setCurrentLogger (Logger* newLogger) noexcept;
|
||||||
|
|
||||||
|
/** Returns the current logger, or nullptr if none has been set. */
|
||||||
|
static Logger* getCurrentLogger() noexcept;
|
||||||
|
|
||||||
|
/** Writes a string to the current logger.
|
||||||
|
|
||||||
|
This will pass the string to the logger's logMessage() method if a logger
|
||||||
|
has been set.
|
||||||
|
|
||||||
|
@see logMessage
|
||||||
|
*/
|
||||||
|
static void BEAST_CALLTYPE writeToLog (const String& message);
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Writes a message to the standard error stream.
|
||||||
|
|
||||||
|
This can be called directly, or by using the DBG() macro in
|
||||||
|
beast_PlatformDefs.h (which will avoid calling the method in non-debug builds).
|
||||||
|
*/
|
||||||
|
static void BEAST_CALLTYPE outputDebugString (const String& text);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//==============================================================================
|
||||||
|
Logger();
|
||||||
|
|
||||||
|
/** This is overloaded by subclasses to implement custom logging behaviour.
|
||||||
|
@see setCurrentLogger
|
||||||
|
*/
|
||||||
|
virtual void logMessage (const String& message) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Logger* currentLogger;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_LOGGER_BEASTHEADER
|
||||||
1016
Subtrees/beast/modules/beast_core/maths/beast_BigInteger.cpp
Normal file
1016
Subtrees/beast/modules/beast_core/maths/beast_BigInteger.cpp
Normal file
File diff suppressed because it is too large
Load Diff
329
Subtrees/beast/modules/beast_core/maths/beast_BigInteger.h
Normal file
329
Subtrees/beast/modules/beast_core/maths/beast_BigInteger.h
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_BIGINTEGER_BEASTHEADER
|
||||||
|
#define BEAST_BIGINTEGER_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_String.h"
|
||||||
|
#include "../memory/beast_HeapBlock.h"
|
||||||
|
class MemoryBlock;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
An arbitrarily large integer class.
|
||||||
|
|
||||||
|
A BigInteger can be used in a similar way to a normal integer, but has no size
|
||||||
|
limit (except for memory and performance constraints).
|
||||||
|
|
||||||
|
Negative values are possible, but the value isn't stored as 2s-complement, so
|
||||||
|
be careful if you use negative values and look at the values of individual bits.
|
||||||
|
*/
|
||||||
|
class BEAST_API BigInteger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty BigInteger */
|
||||||
|
BigInteger();
|
||||||
|
|
||||||
|
/** Creates a BigInteger containing an integer value in its low bits.
|
||||||
|
The low 32 bits of the number are initialised with this value.
|
||||||
|
*/
|
||||||
|
BigInteger (uint32 value);
|
||||||
|
|
||||||
|
/** Creates a BigInteger containing an integer value in its low bits.
|
||||||
|
The low 32 bits of the number are initialised with the absolute value
|
||||||
|
passed in, and its sign is set to reflect the sign of the number.
|
||||||
|
*/
|
||||||
|
BigInteger (int32 value);
|
||||||
|
|
||||||
|
/** Creates a BigInteger containing an integer value in its low bits.
|
||||||
|
The low 64 bits of the number are initialised with the absolute value
|
||||||
|
passed in, and its sign is set to reflect the sign of the number.
|
||||||
|
*/
|
||||||
|
BigInteger (int64 value);
|
||||||
|
|
||||||
|
/** Creates a copy of another BigInteger. */
|
||||||
|
BigInteger (const BigInteger& other);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
BigInteger (BigInteger&& other) noexcept;
|
||||||
|
BigInteger& operator= (BigInteger&& other) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~BigInteger();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Copies another BigInteger onto this one. */
|
||||||
|
BigInteger& operator= (const BigInteger& other);
|
||||||
|
|
||||||
|
/** Swaps the internal contents of this with another object. */
|
||||||
|
void swapWith (BigInteger& other) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the value of a specified bit in the number.
|
||||||
|
If the index is out-of-range, the result will be false.
|
||||||
|
*/
|
||||||
|
bool operator[] (int bit) const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if no bits are set. */
|
||||||
|
bool isZero() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if the value is 1. */
|
||||||
|
bool isOne() const noexcept;
|
||||||
|
|
||||||
|
/** Attempts to get the lowest bits of the value as an integer.
|
||||||
|
If the value is bigger than the integer limits, this will return only the lower bits.
|
||||||
|
*/
|
||||||
|
int toInteger() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Resets the value to 0. */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** Clears a particular bit in the number. */
|
||||||
|
void clearBit (int bitNumber) noexcept;
|
||||||
|
|
||||||
|
/** Sets a specified bit to 1. */
|
||||||
|
void setBit (int bitNumber);
|
||||||
|
|
||||||
|
/** Sets or clears a specified bit. */
|
||||||
|
void setBit (int bitNumber, bool shouldBeSet);
|
||||||
|
|
||||||
|
/** Sets a range of bits to be either on or off.
|
||||||
|
|
||||||
|
@param startBit the first bit to change
|
||||||
|
@param numBits the number of bits to change
|
||||||
|
@param shouldBeSet whether to turn these bits on or off
|
||||||
|
*/
|
||||||
|
void setRange (int startBit, int numBits, bool shouldBeSet);
|
||||||
|
|
||||||
|
/** Inserts a bit an a given position, shifting up any bits above it. */
|
||||||
|
void insertBit (int bitNumber, bool shouldBeSet);
|
||||||
|
|
||||||
|
/** Returns a range of bits as a new BigInteger.
|
||||||
|
|
||||||
|
e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits.
|
||||||
|
@see getBitRangeAsInt
|
||||||
|
*/
|
||||||
|
BigInteger getBitRange (int startBit, int numBits) const;
|
||||||
|
|
||||||
|
/** Returns a range of bits as an integer value.
|
||||||
|
|
||||||
|
e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits.
|
||||||
|
|
||||||
|
Asking for more than 32 bits isn't allowed (obviously) - for that, use
|
||||||
|
getBitRange().
|
||||||
|
*/
|
||||||
|
uint32 getBitRangeAsInt (int startBit, int numBits) const noexcept;
|
||||||
|
|
||||||
|
/** Sets a range of bits to an integer value.
|
||||||
|
|
||||||
|
Copies the given integer onto a range of bits, starting at startBit,
|
||||||
|
and using up to numBits of the available bits.
|
||||||
|
*/
|
||||||
|
void setBitRangeAsInt (int startBit, int numBits, uint32 valueToSet);
|
||||||
|
|
||||||
|
/** Shifts a section of bits left or right.
|
||||||
|
|
||||||
|
@param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right).
|
||||||
|
@param startBit the first bit to affect - if this is > 0, only bits above that index will be affected.
|
||||||
|
*/
|
||||||
|
void shiftBits (int howManyBitsLeft, int startBit);
|
||||||
|
|
||||||
|
/** Returns the total number of set bits in the value. */
|
||||||
|
int countNumberOfSetBits() const noexcept;
|
||||||
|
|
||||||
|
/** Looks for the index of the next set bit after a given starting point.
|
||||||
|
|
||||||
|
This searches from startIndex (inclusive) upwards for the first set bit,
|
||||||
|
and returns its index. If no set bits are found, it returns -1.
|
||||||
|
*/
|
||||||
|
int findNextSetBit (int startIndex) const noexcept;
|
||||||
|
|
||||||
|
/** Looks for the index of the next clear bit after a given starting point.
|
||||||
|
|
||||||
|
This searches from startIndex (inclusive) upwards for the first clear bit,
|
||||||
|
and returns its index.
|
||||||
|
*/
|
||||||
|
int findNextClearBit (int startIndex) const noexcept;
|
||||||
|
|
||||||
|
/** Returns the index of the highest set bit in the number.
|
||||||
|
If the value is zero, this will return -1.
|
||||||
|
*/
|
||||||
|
int getHighestBit() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// All the standard arithmetic ops...
|
||||||
|
|
||||||
|
BigInteger& operator+= (const BigInteger& other);
|
||||||
|
BigInteger& operator-= (const BigInteger& other);
|
||||||
|
BigInteger& operator*= (const BigInteger& other);
|
||||||
|
BigInteger& operator/= (const BigInteger& other);
|
||||||
|
BigInteger& operator|= (const BigInteger& other);
|
||||||
|
BigInteger& operator&= (const BigInteger& other);
|
||||||
|
BigInteger& operator^= (const BigInteger& other);
|
||||||
|
BigInteger& operator%= (const BigInteger& other);
|
||||||
|
BigInteger& operator<<= (int numBitsToShift);
|
||||||
|
BigInteger& operator>>= (int numBitsToShift);
|
||||||
|
BigInteger& operator++();
|
||||||
|
BigInteger& operator--();
|
||||||
|
BigInteger operator++ (int);
|
||||||
|
BigInteger operator-- (int);
|
||||||
|
|
||||||
|
BigInteger operator-() const;
|
||||||
|
BigInteger operator+ (const BigInteger& other) const;
|
||||||
|
BigInteger operator- (const BigInteger& other) const;
|
||||||
|
BigInteger operator* (const BigInteger& other) const;
|
||||||
|
BigInteger operator/ (const BigInteger& other) const;
|
||||||
|
BigInteger operator| (const BigInteger& other) const;
|
||||||
|
BigInteger operator& (const BigInteger& other) const;
|
||||||
|
BigInteger operator^ (const BigInteger& other) const;
|
||||||
|
BigInteger operator% (const BigInteger& other) const;
|
||||||
|
BigInteger operator<< (int numBitsToShift) const;
|
||||||
|
BigInteger operator>> (int numBitsToShift) const;
|
||||||
|
|
||||||
|
bool operator== (const BigInteger& other) const noexcept;
|
||||||
|
bool operator!= (const BigInteger& other) const noexcept;
|
||||||
|
bool operator< (const BigInteger& other) const noexcept;
|
||||||
|
bool operator<= (const BigInteger& other) const noexcept;
|
||||||
|
bool operator> (const BigInteger& other) const noexcept;
|
||||||
|
bool operator>= (const BigInteger& other) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Does a signed comparison of two BigIntegers.
|
||||||
|
|
||||||
|
Return values are:
|
||||||
|
- 0 if the numbers are the same
|
||||||
|
- < 0 if this number is smaller than the other
|
||||||
|
- > 0 if this number is bigger than the other
|
||||||
|
*/
|
||||||
|
int compare (const BigInteger& other) const noexcept;
|
||||||
|
|
||||||
|
/** Compares the magnitudes of two BigIntegers, ignoring their signs.
|
||||||
|
|
||||||
|
Return values are:
|
||||||
|
- 0 if the numbers are the same
|
||||||
|
- < 0 if this number is smaller than the other
|
||||||
|
- > 0 if this number is bigger than the other
|
||||||
|
*/
|
||||||
|
int compareAbsolute (const BigInteger& other) const noexcept;
|
||||||
|
|
||||||
|
/** Divides this value by another one and returns the remainder.
|
||||||
|
|
||||||
|
This number is divided by other, leaving the quotient in this number,
|
||||||
|
with the remainder being copied to the other BigInteger passed in.
|
||||||
|
*/
|
||||||
|
void divideBy (const BigInteger& divisor, BigInteger& remainder);
|
||||||
|
|
||||||
|
/** Returns the largest value that will divide both this value and the one passed-in.
|
||||||
|
*/
|
||||||
|
BigInteger findGreatestCommonDivisor (BigInteger other) const;
|
||||||
|
|
||||||
|
/** Performs a combined exponent and modulo operation.
|
||||||
|
This BigInteger's value becomes (this ^ exponent) % modulus.
|
||||||
|
*/
|
||||||
|
void exponentModulo (const BigInteger& exponent, const BigInteger& modulus);
|
||||||
|
|
||||||
|
/** Performs an inverse modulo on the value.
|
||||||
|
i.e. the result is (this ^ -1) mod (modulus).
|
||||||
|
*/
|
||||||
|
void inverseModulo (const BigInteger& modulus);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the value is less than zero.
|
||||||
|
@see setNegative, negate
|
||||||
|
*/
|
||||||
|
bool isNegative() const noexcept;
|
||||||
|
|
||||||
|
/** Changes the sign of the number to be positive or negative.
|
||||||
|
@see isNegative, negate
|
||||||
|
*/
|
||||||
|
void setNegative (bool shouldBeNegative) noexcept;
|
||||||
|
|
||||||
|
/** Inverts the sign of the number.
|
||||||
|
@see isNegative, setNegative
|
||||||
|
*/
|
||||||
|
void negate() noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Converts the number to a string.
|
||||||
|
|
||||||
|
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||||
|
If minimumNumCharacters is greater than 0, the returned string will be
|
||||||
|
padded with leading zeros to reach at least that length.
|
||||||
|
*/
|
||||||
|
String toString (int base, int minimumNumCharacters = 1) const;
|
||||||
|
|
||||||
|
/** Reads the numeric value from a string.
|
||||||
|
|
||||||
|
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||||
|
Any invalid characters will be ignored.
|
||||||
|
*/
|
||||||
|
void parseString (const String& text, int base);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Turns the number into a block of binary data.
|
||||||
|
|
||||||
|
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||||
|
of the number, and so on.
|
||||||
|
|
||||||
|
@see loadFromMemoryBlock
|
||||||
|
*/
|
||||||
|
MemoryBlock toMemoryBlock() const;
|
||||||
|
|
||||||
|
/** Converts a block of raw data into a number.
|
||||||
|
|
||||||
|
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||||
|
of the number, and so on.
|
||||||
|
|
||||||
|
@see toMemoryBlock
|
||||||
|
*/
|
||||||
|
void loadFromMemoryBlock (const MemoryBlock& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
HeapBlock <uint32> values;
|
||||||
|
size_t numValues;
|
||||||
|
int highestBit;
|
||||||
|
bool negative;
|
||||||
|
|
||||||
|
void ensureSize (size_t numVals);
|
||||||
|
void shiftLeft (int bits, int startBit);
|
||||||
|
void shiftRight (int bits, int startBit);
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (BigInteger)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */
|
||||||
|
OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
// For backwards compatibility, BitArray is defined as an alias for BigInteger.
|
||||||
|
typedef BigInteger BitArray;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_BIGINTEGER_BEASTHEADER
|
||||||
1180
Subtrees/beast/modules/beast_core/maths/beast_Expression.cpp
Normal file
1180
Subtrees/beast/modules/beast_core/maths/beast_Expression.cpp
Normal file
File diff suppressed because it is too large
Load Diff
269
Subtrees/beast/modules/beast_core/maths/beast_Expression.h
Normal file
269
Subtrees/beast/modules/beast_core/maths/beast_Expression.h
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_EXPRESSION_BEASTHEADER
|
||||||
|
#define BEAST_EXPRESSION_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../memory/beast_ReferenceCountedObject.h"
|
||||||
|
#include "../containers/beast_Array.h"
|
||||||
|
#include "../memory/beast_ScopedPointer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A class for dynamically evaluating simple numeric expressions.
|
||||||
|
|
||||||
|
This class can parse a simple C-style string expression involving floating point
|
||||||
|
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, /
|
||||||
|
are supported, as well as parentheses, and any alphanumeric identifiers are
|
||||||
|
assumed to be named symbols which will be resolved when the expression is
|
||||||
|
evaluated.
|
||||||
|
|
||||||
|
Expressions which use identifiers and functions require a subclass of
|
||||||
|
Expression::Scope to be supplied when evaluating them, and this object
|
||||||
|
is expected to be able to resolve the symbol names and perform the functions that
|
||||||
|
are used.
|
||||||
|
*/
|
||||||
|
class BEAST_API Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a simple expression with a value of 0. */
|
||||||
|
Expression();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~Expression();
|
||||||
|
|
||||||
|
/** Creates a simple expression with a specified constant value. */
|
||||||
|
explicit Expression (double constant);
|
||||||
|
|
||||||
|
/** Creates a copy of an expression. */
|
||||||
|
Expression (const Expression& other);
|
||||||
|
|
||||||
|
/** Copies another expression. */
|
||||||
|
Expression& operator= (const Expression& other);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
Expression (Expression&& other) noexcept;
|
||||||
|
Expression& operator= (Expression&& other) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Creates an expression by parsing a string.
|
||||||
|
If there's a syntax error in the string, this will throw a ParseError exception.
|
||||||
|
@throws ParseError
|
||||||
|
*/
|
||||||
|
explicit Expression (const String& stringToParse);
|
||||||
|
|
||||||
|
/** Returns a string version of the expression. */
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
/** Returns an expression which is an addtion operation of two existing expressions. */
|
||||||
|
Expression operator+ (const Expression& other) const;
|
||||||
|
/** Returns an expression which is a subtraction operation of two existing expressions. */
|
||||||
|
Expression operator- (const Expression& other) const;
|
||||||
|
/** Returns an expression which is a multiplication operation of two existing expressions. */
|
||||||
|
Expression operator* (const Expression& other) const;
|
||||||
|
/** Returns an expression which is a division operation of two existing expressions. */
|
||||||
|
Expression operator/ (const Expression& other) const;
|
||||||
|
/** Returns an expression which performs a negation operation on an existing expression. */
|
||||||
|
Expression operator-() const;
|
||||||
|
|
||||||
|
/** Returns an Expression which is an identifier reference. */
|
||||||
|
static Expression symbol (const String& symbol);
|
||||||
|
|
||||||
|
/** Returns an Expression which is a function call. */
|
||||||
|
static Expression function (const String& functionName, const Array<Expression>& parameters);
|
||||||
|
|
||||||
|
/** Returns an Expression which parses a string from a character pointer, and updates the pointer
|
||||||
|
to indicate where it finished.
|
||||||
|
|
||||||
|
The pointer is incremented so that on return, it indicates the character that follows
|
||||||
|
the end of the expression that was parsed.
|
||||||
|
|
||||||
|
If there's a syntax error in the string, this will throw a ParseError exception.
|
||||||
|
@throws ParseError
|
||||||
|
*/
|
||||||
|
static Expression parse (String::CharPointerType& stringToParse);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** When evaluating an Expression object, this class is used to resolve symbols and
|
||||||
|
perform functions that the expression uses.
|
||||||
|
*/
|
||||||
|
class BEAST_API Scope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Scope();
|
||||||
|
virtual ~Scope();
|
||||||
|
|
||||||
|
/** Returns some kind of globally unique ID that identifies this scope. */
|
||||||
|
virtual String getScopeUID() const;
|
||||||
|
|
||||||
|
/** Returns the value of a symbol.
|
||||||
|
If the symbol is unknown, this can throw an Expression::EvaluationError exception.
|
||||||
|
The member value is set to the part of the symbol that followed the dot, if there is
|
||||||
|
one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
virtual Expression getSymbolValue (const String& symbol) const;
|
||||||
|
|
||||||
|
/** Executes a named function.
|
||||||
|
If the function name is unknown, this can throw an Expression::EvaluationError exception.
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
virtual double evaluateFunction (const String& functionName,
|
||||||
|
const double* parameters, int numParameters) const;
|
||||||
|
|
||||||
|
/** Used as a callback by the Scope::visitRelativeScope() method.
|
||||||
|
You should never create an instance of this class yourself, it's used by the
|
||||||
|
expression evaluation code.
|
||||||
|
*/
|
||||||
|
class Visitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Visitor() {}
|
||||||
|
virtual void visit (const Scope&) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Creates a Scope object for a named scope, and then calls a visitor
|
||||||
|
to do some kind of processing with this new scope.
|
||||||
|
|
||||||
|
If the name is valid, this method must create a suitable (temporary) Scope
|
||||||
|
object to represent it, and must call the Visitor::visit() method with this
|
||||||
|
new scope.
|
||||||
|
*/
|
||||||
|
virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Evaluates this expression, without using a Scope.
|
||||||
|
Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
|
||||||
|
min, max are available.
|
||||||
|
To find out about any errors during evaluation, use the other version of this method which
|
||||||
|
takes a String parameter.
|
||||||
|
*/
|
||||||
|
double evaluate() const;
|
||||||
|
|
||||||
|
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||||
|
or functions that it uses.
|
||||||
|
To find out about any errors during evaluation, use the other version of this method which
|
||||||
|
takes a String parameter.
|
||||||
|
*/
|
||||||
|
double evaluate (const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||||
|
or functions that it uses.
|
||||||
|
*/
|
||||||
|
double evaluate (const Scope& scope, String& evaluationError) const;
|
||||||
|
|
||||||
|
/** Attempts to return an expression which is a copy of this one, but with a constant adjusted
|
||||||
|
to make the expression resolve to a target value.
|
||||||
|
|
||||||
|
E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
|
||||||
|
the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
|
||||||
|
case they might just be adjusted by adding a constant to the original expression.
|
||||||
|
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Represents a symbol that is used in an Expression. */
|
||||||
|
struct Symbol
|
||||||
|
{
|
||||||
|
Symbol (const String& scopeUID, const String& symbolName);
|
||||||
|
bool operator== (const Symbol&) const noexcept;
|
||||||
|
bool operator!= (const Symbol&) const noexcept;
|
||||||
|
|
||||||
|
String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
|
||||||
|
String symbolName; /**< The name of the symbol. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
|
||||||
|
Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Returns true if this expression makes use of the specified symbol.
|
||||||
|
If a suitable scope is supplied, the search will dereference and recursively check
|
||||||
|
all symbols, so that it can be determined whether this expression relies on the given
|
||||||
|
symbol at any level in its evaluation. If the scope parameter is null, this just checks
|
||||||
|
whether the expression contains any direct references to the symbol.
|
||||||
|
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Returns true if this expression contains any symbols. */
|
||||||
|
bool usesAnySymbols() const;
|
||||||
|
|
||||||
|
/** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
|
||||||
|
void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** An exception that can be thrown by Expression::parse(). */
|
||||||
|
class ParseError : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParseError (const String& message);
|
||||||
|
|
||||||
|
String description;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Expression type.
|
||||||
|
@see Expression::getType()
|
||||||
|
*/
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
constantType,
|
||||||
|
functionType,
|
||||||
|
operatorType,
|
||||||
|
symbolType
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Returns the type of this expression. */
|
||||||
|
Type getType() const noexcept;
|
||||||
|
|
||||||
|
/** If this expression is a symbol, function or operator, this returns its identifier. */
|
||||||
|
String getSymbolOrFunction() const;
|
||||||
|
|
||||||
|
/** Returns the number of inputs to this expression.
|
||||||
|
@see getInput
|
||||||
|
*/
|
||||||
|
int getNumInputs() const;
|
||||||
|
|
||||||
|
/** Retrieves one of the inputs to this expression.
|
||||||
|
@see getNumInputs
|
||||||
|
*/
|
||||||
|
Expression getInput (int index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class Term;
|
||||||
|
struct Helpers;
|
||||||
|
friend class Term;
|
||||||
|
friend struct Helpers;
|
||||||
|
friend class ScopedPointer<Term>;
|
||||||
|
friend class ReferenceCountedObjectPtr<Term>;
|
||||||
|
ReferenceCountedObjectPtr<Term> term;
|
||||||
|
|
||||||
|
explicit Expression (Term*);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_EXPRESSION_BEASTHEADER
|
||||||
515
Subtrees/beast/modules/beast_core/maths/beast_MathsFunctions.h
Normal file
515
Subtrees/beast/modules/beast_core/maths/beast_MathsFunctions.h
Normal file
@@ -0,0 +1,515 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||||
|
#define BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/*
|
||||||
|
This file sets up some handy mathematical typdefs and functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Definitions for the int8, int16, int32, int64 and pointer_sized_int types.
|
||||||
|
|
||||||
|
/** A platform-independent 8-bit signed integer type. */
|
||||||
|
typedef signed char int8;
|
||||||
|
/** A platform-independent 8-bit unsigned integer type. */
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
/** A platform-independent 16-bit signed integer type. */
|
||||||
|
typedef signed short int16;
|
||||||
|
/** A platform-independent 16-bit unsigned integer type. */
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
/** A platform-independent 32-bit signed integer type. */
|
||||||
|
typedef signed int int32;
|
||||||
|
/** A platform-independent 32-bit unsigned integer type. */
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
/** A platform-independent 64-bit integer type. */
|
||||||
|
typedef __int64 int64;
|
||||||
|
/** A platform-independent 64-bit unsigned integer type. */
|
||||||
|
typedef unsigned __int64 uint64;
|
||||||
|
/** A platform-independent macro for writing 64-bit literals, needed because
|
||||||
|
different compilers have different syntaxes for this.
|
||||||
|
|
||||||
|
E.g. writing literal64bit (0x1000000000) will translate to 0x1000000000LL for
|
||||||
|
GCC, or 0x1000000000 for MSVC.
|
||||||
|
*/
|
||||||
|
#define literal64bit(longLiteral) ((__int64) longLiteral)
|
||||||
|
#else
|
||||||
|
/** A platform-independent 64-bit integer type. */
|
||||||
|
typedef long long int64;
|
||||||
|
/** A platform-independent 64-bit unsigned integer type. */
|
||||||
|
typedef unsigned long long uint64;
|
||||||
|
/** A platform-independent macro for writing 64-bit literals, needed because
|
||||||
|
different compilers have different syntaxes for this.
|
||||||
|
|
||||||
|
E.g. writing literal64bit (0x1000000000) will translate to 0x1000000000LL for
|
||||||
|
GCC, or 0x1000000000 for MSVC.
|
||||||
|
*/
|
||||||
|
#define literal64bit(longLiteral) (longLiteral##LL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if BEAST_64BIT
|
||||||
|
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef int64 pointer_sized_int;
|
||||||
|
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef uint64 pointer_sized_uint;
|
||||||
|
#elif BEAST_MSVC
|
||||||
|
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef _W64 int pointer_sized_int;
|
||||||
|
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef _W64 unsigned int pointer_sized_uint;
|
||||||
|
#else
|
||||||
|
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef int pointer_sized_int;
|
||||||
|
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef unsigned int pointer_sized_uint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
typedef pointer_sized_int ssize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Some indispensible min/max functions
|
||||||
|
|
||||||
|
/** Returns the larger of two values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type bmax (const Type a, const Type b) { return (a < b) ? b : a; }
|
||||||
|
|
||||||
|
/** Returns the larger of three values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type bmax (const Type a, const Type b, const Type c) { return (a < b) ? ((b < c) ? c : b) : ((a < c) ? c : a); }
|
||||||
|
|
||||||
|
/** Returns the larger of four values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type bmax (const Type a, const Type b, const Type c, const Type d) { return bmax (a, bmax (b, c, d)); }
|
||||||
|
|
||||||
|
/** Returns the smaller of two values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type bmin (const Type a, const Type b) { return (b < a) ? b : a; }
|
||||||
|
|
||||||
|
/** Returns the smaller of three values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type bmin (const Type a, const Type b, const Type c) { return (b < a) ? ((c < b) ? c : b) : ((c < a) ? c : a); }
|
||||||
|
|
||||||
|
/** Returns the smaller of four values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type bmin (const Type a, const Type b, const Type c, const Type d) { return bmin (a, bmin (b, c, d)); }
|
||||||
|
|
||||||
|
/** Scans an array of values, returning the minimum value that it contains. */
|
||||||
|
template <typename Type>
|
||||||
|
const Type findMinimum (const Type* data, int numValues)
|
||||||
|
{
|
||||||
|
if (numValues <= 0)
|
||||||
|
return Type();
|
||||||
|
|
||||||
|
Type result (*data++);
|
||||||
|
|
||||||
|
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||||
|
{
|
||||||
|
const Type& v = *data++;
|
||||||
|
if (v < result) result = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scans an array of values, returning the maximum value that it contains. */
|
||||||
|
template <typename Type>
|
||||||
|
const Type findMaximum (const Type* values, int numValues)
|
||||||
|
{
|
||||||
|
if (numValues <= 0)
|
||||||
|
return Type();
|
||||||
|
|
||||||
|
Type result (*values++);
|
||||||
|
|
||||||
|
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||||
|
{
|
||||||
|
const Type& v = *values++;
|
||||||
|
if (result < v) result = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scans an array of values, returning the minimum and maximum values that it contains. */
|
||||||
|
template <typename Type>
|
||||||
|
void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest)
|
||||||
|
{
|
||||||
|
if (numValues <= 0)
|
||||||
|
{
|
||||||
|
lowest = Type();
|
||||||
|
highest = Type();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Type mn (*values++);
|
||||||
|
Type mx (mn);
|
||||||
|
|
||||||
|
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||||
|
{
|
||||||
|
const Type& v = *values++;
|
||||||
|
|
||||||
|
if (mx < v) mx = v;
|
||||||
|
if (v < mn) mn = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
lowest = mn;
|
||||||
|
highest = mx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Constrains a value to keep it within a given range.
|
||||||
|
|
||||||
|
This will check that the specified value lies between the lower and upper bounds
|
||||||
|
specified, and if not, will return the nearest value that would be in-range. Effectively,
|
||||||
|
it's like calling bmax (lowerLimit, bmin (upperLimit, value)).
|
||||||
|
|
||||||
|
Note that it expects that lowerLimit <= upperLimit. If this isn't true,
|
||||||
|
the results will be unpredictable.
|
||||||
|
|
||||||
|
@param lowerLimit the minimum value to return
|
||||||
|
@param upperLimit the maximum value to return
|
||||||
|
@param valueToConstrain the value to try to return
|
||||||
|
@returns the closest value to valueToConstrain which lies between lowerLimit
|
||||||
|
and upperLimit (inclusive)
|
||||||
|
@see jlimit0To, bmin, bmax
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline Type blimit (const Type lowerLimit,
|
||||||
|
const Type upperLimit,
|
||||||
|
const Type valueToConstrain) noexcept
|
||||||
|
{
|
||||||
|
bassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
|
||||||
|
|
||||||
|
return (valueToConstrain < lowerLimit) ? lowerLimit
|
||||||
|
: ((upperLimit < valueToConstrain) ? upperLimit
|
||||||
|
: valueToConstrain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if a value is at least zero, and also below a specified upper limit.
|
||||||
|
This is basically a quicker way to write:
|
||||||
|
@code valueToTest >= 0 && valueToTest < upperLimit
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline bool isPositiveAndBelow (Type valueToTest, Type upperLimit) noexcept
|
||||||
|
{
|
||||||
|
bassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return Type() <= valueToTest && valueToTest < upperLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) noexcept
|
||||||
|
{
|
||||||
|
bassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (upperLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if a value is at least zero, and also less than or equal to a specified upper limit.
|
||||||
|
This is basically a quicker way to write:
|
||||||
|
@code valueToTest >= 0 && valueToTest <= upperLimit
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline bool isPositiveAndNotGreaterThan (Type valueToTest, Type upperLimit) noexcept
|
||||||
|
{
|
||||||
|
bassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return Type() <= valueToTest && valueToTest <= upperLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool isPositiveAndNotGreaterThan (const int valueToTest, const int upperLimit) noexcept
|
||||||
|
{
|
||||||
|
bassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return static_cast <unsigned int> (valueToTest) <= static_cast <unsigned int> (upperLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Handy function to swap two values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline void swapVariables (Type& variable1, Type& variable2)
|
||||||
|
{
|
||||||
|
std::swap (variable1, variable2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handy function for getting the number of elements in a simple const C array.
|
||||||
|
E.g.
|
||||||
|
@code
|
||||||
|
static int myArray[] = { 1, 2, 3 };
|
||||||
|
|
||||||
|
int numElements = numElementsInArray (myArray) // returns 3
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <typename Type, int N>
|
||||||
|
inline int numElementsInArray (Type (&array)[N])
|
||||||
|
{
|
||||||
|
(void) array; // (required to avoid a spurious warning in MS compilers)
|
||||||
|
(void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Some useful maths functions that aren't always present with all compilers and build settings.
|
||||||
|
|
||||||
|
/** Using beast_hypot is easier than dealing with the different types of hypot function
|
||||||
|
that are provided by the various platforms and compilers. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type beast_hypot (Type a, Type b) noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_MSVC
|
||||||
|
return static_cast <Type> (_hypot (a, b));
|
||||||
|
#else
|
||||||
|
return static_cast <Type> (hypot (a, b));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 64-bit abs function. */
|
||||||
|
inline int64 abs64 (const int64 n) noexcept
|
||||||
|
{
|
||||||
|
return (n >= 0) ? n : -n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** A predefined value for Pi, at double-precision.
|
||||||
|
@see float_Pi
|
||||||
|
*/
|
||||||
|
const double double_Pi = 3.1415926535897932384626433832795;
|
||||||
|
|
||||||
|
/** A predefined value for Pi, at single-precision.
|
||||||
|
@see double_Pi
|
||||||
|
*/
|
||||||
|
const float float_Pi = 3.14159265358979323846f;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** The isfinite() method seems to vary between platforms, so this is a
|
||||||
|
platform-independent function for it.
|
||||||
|
*/
|
||||||
|
template <typename FloatingPointType>
|
||||||
|
inline bool beast_isfinite (FloatingPointType value)
|
||||||
|
{
|
||||||
|
#if BEAST_WINDOWS
|
||||||
|
return _finite (value);
|
||||||
|
#elif BEAST_ANDROID
|
||||||
|
return isfinite (value);
|
||||||
|
#else
|
||||||
|
return std::isfinite (value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma optimize ("t", off)
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma float_control (precise, on, push)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||||
|
it will round the value to the nearest integer, rather than rounding it down
|
||||||
|
like the normal cast does.
|
||||||
|
|
||||||
|
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||||
|
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||||
|
even numbers will be rounded up or down differently.
|
||||||
|
*/
|
||||||
|
template <typename FloatType>
|
||||||
|
inline int roundToInt (const FloatType value) noexcept
|
||||||
|
{
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#pragma float_control (precise, on, push)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
union { int asInt[2]; double asDouble; } n;
|
||||||
|
n.asDouble = ((double) value) + 6755399441055744.0;
|
||||||
|
|
||||||
|
#if BEAST_BIG_ENDIAN
|
||||||
|
return n.asInt [1];
|
||||||
|
#else
|
||||||
|
return n.asInt [0];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma float_control (pop)
|
||||||
|
#endif
|
||||||
|
#pragma optimize ("", on) // resets optimisations to the project defaults
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is a slightly slower and slightly more accurate version of roundDoubleToInt(). It works
|
||||||
|
fine for values above zero, but negative numbers are rounded the wrong way.
|
||||||
|
*/
|
||||||
|
inline int roundToIntAccurate (const double value) noexcept
|
||||||
|
{
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#pragma float_control (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return roundToInt (value + 1.5e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is faster than using the normal c++ cast to convert a double to an int, and
|
||||||
|
it will round the value to the nearest integer, rather than rounding it down
|
||||||
|
like the normal cast does.
|
||||||
|
|
||||||
|
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||||
|
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||||
|
even numbers will be rounded up or down differently. For a more accurate conversion,
|
||||||
|
see roundDoubleToIntAccurate().
|
||||||
|
*/
|
||||||
|
inline int roundDoubleToInt (const double value) noexcept
|
||||||
|
{
|
||||||
|
return roundToInt (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||||
|
it will round the value to the nearest integer, rather than rounding it down
|
||||||
|
like the normal cast does.
|
||||||
|
|
||||||
|
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||||
|
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||||
|
even numbers will be rounded up or down differently.
|
||||||
|
*/
|
||||||
|
inline int roundFloatToInt (const float value) noexcept
|
||||||
|
{
|
||||||
|
return roundToInt (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the specified integer is a power-of-two.
|
||||||
|
*/
|
||||||
|
template <typename IntegerType>
|
||||||
|
bool isPowerOfTwo (IntegerType value)
|
||||||
|
{
|
||||||
|
return (value & (value - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the smallest power-of-two which is equal to or greater than the given integer.
|
||||||
|
*/
|
||||||
|
inline int nextPowerOfTwo (int n) noexcept
|
||||||
|
{
|
||||||
|
--n;
|
||||||
|
n |= (n >> 1);
|
||||||
|
n |= (n >> 2);
|
||||||
|
n |= (n >> 4);
|
||||||
|
n |= (n >> 8);
|
||||||
|
n |= (n >> 16);
|
||||||
|
return n + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Performs a modulo operation, but can cope with the dividend being negative.
|
||||||
|
The divisor must be greater than zero.
|
||||||
|
*/
|
||||||
|
template <typename IntegerType>
|
||||||
|
IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor) noexcept
|
||||||
|
{
|
||||||
|
bassert (divisor > 0);
|
||||||
|
dividend %= divisor;
|
||||||
|
return (dividend < 0) ? (dividend + divisor) : dividend;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if (BEAST_INTEL && BEAST_32BIT) || defined (DOXYGEN)
|
||||||
|
/** This macro can be applied to a float variable to check whether it contains a denormalised
|
||||||
|
value, and to normalise it if necessary.
|
||||||
|
On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
|
||||||
|
*/
|
||||||
|
#define BEAST_UNDENORMALISE(x) x += 1.0f; x -= 1.0f;
|
||||||
|
#else
|
||||||
|
#define BEAST_UNDENORMALISE(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This namespace contains a few template classes for helping work out class type variations.
|
||||||
|
*/
|
||||||
|
namespace TypeHelpers
|
||||||
|
{
|
||||||
|
#if BEAST_VC8_OR_EARLIER
|
||||||
|
#define PARAMETER_TYPE(type) const type&
|
||||||
|
#else
|
||||||
|
/** The ParameterType struct is used to find the best type to use when passing some kind
|
||||||
|
of object as a parameter.
|
||||||
|
|
||||||
|
Of course, this is only likely to be useful in certain esoteric template situations.
|
||||||
|
|
||||||
|
Because "typename TypeHelpers::ParameterType<SomeClass>::type" is a bit of a mouthful, there's
|
||||||
|
a PARAMETER_TYPE(SomeClass) macro that you can use to get the same effect.
|
||||||
|
|
||||||
|
E.g. "myFunction (PARAMETER_TYPE (int), PARAMETER_TYPE (MyObject))"
|
||||||
|
would evaluate to "myfunction (int, const MyObject&)", keeping any primitive types as
|
||||||
|
pass-by-value, but passing objects as a const reference, to avoid copying.
|
||||||
|
*/
|
||||||
|
template <typename Type> struct ParameterType { typedef const Type& type; };
|
||||||
|
|
||||||
|
#if ! DOXYGEN
|
||||||
|
template <typename Type> struct ParameterType <Type&> { typedef Type& type; };
|
||||||
|
template <typename Type> struct ParameterType <Type*> { typedef Type* type; };
|
||||||
|
template <> struct ParameterType <char> { typedef char type; };
|
||||||
|
template <> struct ParameterType <unsigned char> { typedef unsigned char type; };
|
||||||
|
template <> struct ParameterType <short> { typedef short type; };
|
||||||
|
template <> struct ParameterType <unsigned short> { typedef unsigned short type; };
|
||||||
|
template <> struct ParameterType <int> { typedef int type; };
|
||||||
|
template <> struct ParameterType <unsigned int> { typedef unsigned int type; };
|
||||||
|
template <> struct ParameterType <long> { typedef long type; };
|
||||||
|
template <> struct ParameterType <unsigned long> { typedef unsigned long type; };
|
||||||
|
template <> struct ParameterType <int64> { typedef int64 type; };
|
||||||
|
template <> struct ParameterType <uint64> { typedef uint64 type; };
|
||||||
|
template <> struct ParameterType <bool> { typedef bool type; };
|
||||||
|
template <> struct ParameterType <float> { typedef float type; };
|
||||||
|
template <> struct ParameterType <double> { typedef double type; };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** A helpful macro to simplify the use of the ParameterType template.
|
||||||
|
@see ParameterType
|
||||||
|
*/
|
||||||
|
#define PARAMETER_TYPE(a) typename TypeHelpers::ParameterType<a>::type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** These templates are designed to take a type, and if it's a double, they return a double
|
||||||
|
type; for anything else, they return a float type.
|
||||||
|
*/
|
||||||
|
template <typename Type> struct SmallestFloatType { typedef float type; };
|
||||||
|
template <> struct SmallestFloatType <double> { typedef double type; };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#endif // BEAST_MATHSFUNCTIONS_BEASTHEADER
|
||||||
171
Subtrees/beast/modules/beast_core/maths/beast_Random.cpp
Normal file
171
Subtrees/beast/modules/beast_core/maths/beast_Random.cpp
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
Random::Random (const int64 seedValue) noexcept
|
||||||
|
: seed (seedValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Random::Random()
|
||||||
|
: seed (1)
|
||||||
|
{
|
||||||
|
setSeedRandomly();
|
||||||
|
}
|
||||||
|
|
||||||
|
Random::~Random() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::setSeed (const int64 newSeed) noexcept
|
||||||
|
{
|
||||||
|
seed = newSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::combineSeed (const int64 seedValue) noexcept
|
||||||
|
{
|
||||||
|
seed ^= nextInt64() ^ seedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::setSeedRandomly()
|
||||||
|
{
|
||||||
|
static int64 globalSeed = 0;
|
||||||
|
|
||||||
|
combineSeed (globalSeed ^ (int64) (pointer_sized_int) this);
|
||||||
|
combineSeed (Time::getMillisecondCounter());
|
||||||
|
combineSeed (Time::getHighResolutionTicks());
|
||||||
|
combineSeed (Time::getHighResolutionTicksPerSecond());
|
||||||
|
combineSeed (Time::currentTimeMillis());
|
||||||
|
globalSeed ^= seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Random& Random::getSystemRandom() noexcept
|
||||||
|
{
|
||||||
|
static Random sysRand;
|
||||||
|
return sysRand;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int Random::nextInt() noexcept
|
||||||
|
{
|
||||||
|
seed = (seed * literal64bit (0x5deece66d) + 11) & literal64bit (0xffffffffffff);
|
||||||
|
|
||||||
|
return (int) (seed >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::nextInt (const int maxValue) noexcept
|
||||||
|
{
|
||||||
|
bassert (maxValue > 0);
|
||||||
|
return (int) ((((unsigned int) nextInt()) * (uint64) maxValue) >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Random::nextInt64() noexcept
|
||||||
|
{
|
||||||
|
return (((int64) nextInt()) << 32) | (int64) (uint64) (uint32) nextInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Random::nextBool() noexcept
|
||||||
|
{
|
||||||
|
return (nextInt() & 0x40000000) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Random::nextFloat() noexcept
|
||||||
|
{
|
||||||
|
return static_cast <uint32> (nextInt()) / (float) 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
double Random::nextDouble() noexcept
|
||||||
|
{
|
||||||
|
return static_cast <uint32> (nextInt()) / (double) 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger Random::nextLargeNumber (const BigInteger& maximumValue)
|
||||||
|
{
|
||||||
|
BigInteger n;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
fillBitsRandomly (n, 0, maximumValue.getHighestBit() + 1);
|
||||||
|
}
|
||||||
|
while (n >= maximumValue);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits)
|
||||||
|
{
|
||||||
|
arrayToChange.setBit (startBit + numBits - 1, true); // to force the array to pre-allocate space
|
||||||
|
|
||||||
|
while ((startBit & 31) != 0 && numBits > 0)
|
||||||
|
{
|
||||||
|
arrayToChange.setBit (startBit++, nextBool());
|
||||||
|
--numBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (numBits >= 32)
|
||||||
|
{
|
||||||
|
arrayToChange.setBitRangeAsInt (startBit, 32, (unsigned int) nextInt());
|
||||||
|
startBit += 32;
|
||||||
|
numBits -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (--numBits >= 0)
|
||||||
|
arrayToChange.setBit (startBit + numBits, nextBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_UNIT_TESTS
|
||||||
|
|
||||||
|
class RandomTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RandomTests() : UnitTest ("Random") {}
|
||||||
|
|
||||||
|
void runTest()
|
||||||
|
{
|
||||||
|
beginTest ("Random");
|
||||||
|
|
||||||
|
for (int j = 10; --j >= 0;)
|
||||||
|
{
|
||||||
|
Random r;
|
||||||
|
r.setSeedRandomly();
|
||||||
|
|
||||||
|
for (int i = 20; --i >= 0;)
|
||||||
|
{
|
||||||
|
expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
|
||||||
|
expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
|
||||||
|
expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
|
||||||
|
expect (r.nextInt (1) == 0);
|
||||||
|
|
||||||
|
int n = r.nextInt (50) + 1;
|
||||||
|
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||||
|
|
||||||
|
n = r.nextInt (0x7ffffffe) + 1;
|
||||||
|
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static RandomTests randomTests;
|
||||||
|
|
||||||
|
#endif
|
||||||
135
Subtrees/beast/modules/beast_core/maths/beast_Random.h
Normal file
135
Subtrees/beast/modules/beast_core/maths/beast_Random.h
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_RANDOM_BEASTHEADER
|
||||||
|
#define BEAST_RANDOM_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_BigInteger.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A random number generator.
|
||||||
|
|
||||||
|
You can create a Random object and use it to generate a sequence of random numbers.
|
||||||
|
*/
|
||||||
|
class BEAST_API Random
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a Random object based on a seed value.
|
||||||
|
|
||||||
|
For a given seed value, the subsequent numbers generated by this object
|
||||||
|
will be predictable, so a good idea is to set this value based
|
||||||
|
on the time, e.g.
|
||||||
|
|
||||||
|
new Random (Time::currentTimeMillis())
|
||||||
|
*/
|
||||||
|
explicit Random (int64 seedValue) noexcept;
|
||||||
|
|
||||||
|
/** Creates a Random object using a random seed value.
|
||||||
|
Internally, this calls setSeedRandomly() to randomise the seed.
|
||||||
|
*/
|
||||||
|
Random();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~Random() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random 32 bit integer.
|
||||||
|
|
||||||
|
@returns a random integer from the full range 0x80000000 to 0x7fffffff
|
||||||
|
*/
|
||||||
|
int nextInt() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random number, limited to a given range.
|
||||||
|
The maxValue parameter may not be negative, or zero.
|
||||||
|
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
|
||||||
|
*/
|
||||||
|
int nextInt (int maxValue) noexcept;
|
||||||
|
|
||||||
|
/** Returns the next 64-bit random number.
|
||||||
|
|
||||||
|
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
|
||||||
|
*/
|
||||||
|
int64 nextInt64() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random floating-point number.
|
||||||
|
|
||||||
|
@returns a random value in the range 0 to 1.0
|
||||||
|
*/
|
||||||
|
float nextFloat() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random floating-point number.
|
||||||
|
|
||||||
|
@returns a random value in the range 0 to 1.0
|
||||||
|
*/
|
||||||
|
double nextDouble() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random boolean value.
|
||||||
|
*/
|
||||||
|
bool nextBool() noexcept;
|
||||||
|
|
||||||
|
/** Returns a BigInteger containing a random number.
|
||||||
|
|
||||||
|
@returns a random value in the range 0 to (maximumValue - 1).
|
||||||
|
*/
|
||||||
|
BigInteger nextLargeNumber (const BigInteger& maximumValue);
|
||||||
|
|
||||||
|
/** Sets a range of bits in a BigInteger to random values. */
|
||||||
|
void fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Resets this Random object to a given seed value. */
|
||||||
|
void setSeed (int64 newSeed) noexcept;
|
||||||
|
|
||||||
|
/** Merges this object's seed with another value.
|
||||||
|
This sets the seed to be a value created by combining the current seed and this
|
||||||
|
new value.
|
||||||
|
*/
|
||||||
|
void combineSeed (int64 seedValue) noexcept;
|
||||||
|
|
||||||
|
/** Reseeds this generator using a value generated from various semi-random system
|
||||||
|
properties like the current time, etc.
|
||||||
|
|
||||||
|
Because this function convolves the time with the last seed value, calling
|
||||||
|
it repeatedly will increase the randomness of the final result.
|
||||||
|
*/
|
||||||
|
void setSeedRandomly();
|
||||||
|
|
||||||
|
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
|
||||||
|
it, you can call this method to get a global shared Random object.
|
||||||
|
|
||||||
|
It's not thread-safe though, so threads should use their own Random object, otherwise
|
||||||
|
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
|
||||||
|
*/
|
||||||
|
static Random& getSystemRandom() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
int64 seed;
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (Random)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_RANDOM_BEASTHEADER
|
||||||
259
Subtrees/beast/modules/beast_core/maths/beast_Range.h
Normal file
259
Subtrees/beast/modules/beast_core/maths/beast_Range.h
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_RANGE_BEASTHEADER
|
||||||
|
#define BEAST_RANGE_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** A general-purpose range object, that simply represents any linear range with
|
||||||
|
a start and end point.
|
||||||
|
|
||||||
|
The templated parameter is expected to be a primitive integer or floating point
|
||||||
|
type, though class types could also be used if they behave in a number-like way.
|
||||||
|
*/
|
||||||
|
template <typename ValueType>
|
||||||
|
class Range
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Constructs an empty range. */
|
||||||
|
Range() noexcept : start(), end()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructs a range with given start and end values. */
|
||||||
|
Range (const ValueType startValue, const ValueType endValue) noexcept
|
||||||
|
: start (startValue), end (bmax (startValue, endValue))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructs a copy of another range. */
|
||||||
|
Range (const Range& other) noexcept
|
||||||
|
: start (other.start), end (other.end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another range object. */
|
||||||
|
Range& operator= (Range other) noexcept
|
||||||
|
{
|
||||||
|
start = other.start;
|
||||||
|
end = other.end;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the range that lies between two positions (in either order). */
|
||||||
|
static Range between (const ValueType position1, const ValueType position2) noexcept
|
||||||
|
{
|
||||||
|
return position1 < position2 ? Range (position1, position2)
|
||||||
|
: Range (position2, position1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the specified start position and a length of zero. */
|
||||||
|
static Range emptyRange (const ValueType start) noexcept
|
||||||
|
{
|
||||||
|
return Range (start, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the start of the range. */
|
||||||
|
inline ValueType getStart() const noexcept { return start; }
|
||||||
|
|
||||||
|
/** Returns the length of the range. */
|
||||||
|
inline ValueType getLength() const noexcept { return end - start; }
|
||||||
|
|
||||||
|
/** Returns the end of the range. */
|
||||||
|
inline ValueType getEnd() const noexcept { return end; }
|
||||||
|
|
||||||
|
/** Returns true if the range has a length of zero. */
|
||||||
|
inline bool isEmpty() const noexcept { return start == end; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Changes the start position of the range, leaving the end position unchanged.
|
||||||
|
If the new start position is higher than the current end of the range, the end point
|
||||||
|
will be pushed along to equal it, leaving an empty range at the new position.
|
||||||
|
*/
|
||||||
|
void setStart (const ValueType newStart) noexcept
|
||||||
|
{
|
||||||
|
start = newStart;
|
||||||
|
if (end < newStart)
|
||||||
|
end = newStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same end as this one, but a different start.
|
||||||
|
If the new start position is higher than the current end of the range, the end point
|
||||||
|
will be pushed along to equal it, returning an empty range at the new position.
|
||||||
|
*/
|
||||||
|
Range withStart (const ValueType newStart) const noexcept
|
||||||
|
{
|
||||||
|
return Range (newStart, bmax (newStart, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same length as this one, but moved to have the given start position. */
|
||||||
|
Range movedToStartAt (const ValueType newStart) const noexcept
|
||||||
|
{
|
||||||
|
return Range (newStart, end + (newStart - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes the end position of the range, leaving the start unchanged.
|
||||||
|
If the new end position is below the current start of the range, the start point
|
||||||
|
will be pushed back to equal the new end point.
|
||||||
|
*/
|
||||||
|
void setEnd (const ValueType newEnd) noexcept
|
||||||
|
{
|
||||||
|
end = newEnd;
|
||||||
|
if (newEnd < start)
|
||||||
|
start = newEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same start position as this one, but a different end.
|
||||||
|
If the new end position is below the current start of the range, the start point
|
||||||
|
will be pushed back to equal the new end point.
|
||||||
|
*/
|
||||||
|
Range withEnd (const ValueType newEnd) const noexcept
|
||||||
|
{
|
||||||
|
return Range (bmin (start, newEnd), newEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same length as this one, but moved to have the given end position. */
|
||||||
|
Range movedToEndAt (const ValueType newEnd) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start + (newEnd - end), newEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes the length of the range.
|
||||||
|
Lengths less than zero are treated as zero.
|
||||||
|
*/
|
||||||
|
void setLength (const ValueType newLength) noexcept
|
||||||
|
{
|
||||||
|
end = start + bmax (ValueType(), newLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same start as this one, but a different length.
|
||||||
|
Lengths less than zero are treated as zero.
|
||||||
|
*/
|
||||||
|
Range withLength (const ValueType newLength) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start, start + newLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds an amount to the start and end of the range. */
|
||||||
|
inline Range operator+= (const ValueType amountToAdd) noexcept
|
||||||
|
{
|
||||||
|
start += amountToAdd;
|
||||||
|
end += amountToAdd;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Subtracts an amount from the start and end of the range. */
|
||||||
|
inline Range operator-= (const ValueType amountToSubtract) noexcept
|
||||||
|
{
|
||||||
|
start -= amountToSubtract;
|
||||||
|
end -= amountToSubtract;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range that is equal to this one with an amount added to its
|
||||||
|
start and end.
|
||||||
|
*/
|
||||||
|
Range operator+ (const ValueType amountToAdd) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start + amountToAdd, end + amountToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range that is equal to this one with the specified amount
|
||||||
|
subtracted from its start and end. */
|
||||||
|
Range operator- (const ValueType amountToSubtract) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start - amountToSubtract, end - amountToSubtract);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (Range other) const noexcept { return start == other.start && end == other.end; }
|
||||||
|
bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the given position lies inside this range. */
|
||||||
|
bool contains (const ValueType position) const noexcept
|
||||||
|
{
|
||||||
|
return start <= position && position < end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the nearest value to the one supplied, which lies within the range. */
|
||||||
|
ValueType clipValue (const ValueType value) const noexcept
|
||||||
|
{
|
||||||
|
return blimit (start, end, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the given range lies entirely inside this range. */
|
||||||
|
bool contains (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return start <= other.start && end >= other.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the given range intersects this one. */
|
||||||
|
bool intersects (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return other.start < end && start < other.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the range that is the intersection of the two ranges, or an empty range
|
||||||
|
with an undefined start position if they don't overlap. */
|
||||||
|
Range getIntersectionWith (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return Range (bmax (start, other.start),
|
||||||
|
bmin (end, other.end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the smallest range that contains both this one and the other one. */
|
||||||
|
Range getUnionWith (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return Range (bmin (start, other.start),
|
||||||
|
bmax (end, other.end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a given range, after moving it forwards or backwards to fit it
|
||||||
|
within this range.
|
||||||
|
|
||||||
|
If the supplied range has a greater length than this one, the return value
|
||||||
|
will be this range.
|
||||||
|
|
||||||
|
Otherwise, if the supplied range is smaller than this one, the return value
|
||||||
|
will be the new range, shifted forwards or backwards so that it doesn't extend
|
||||||
|
beyond this one, but keeping its original length.
|
||||||
|
*/
|
||||||
|
Range constrainRange (Range rangeToConstrain) const noexcept
|
||||||
|
{
|
||||||
|
const ValueType otherLen = rangeToConstrain.getLength();
|
||||||
|
return getLength() <= otherLen
|
||||||
|
? *this
|
||||||
|
: rangeToConstrain.movedToStartAt (blimit (start, end - otherLen, rangeToConstrain.getStart()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ValueType start, end;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_RANGE_BEASTHEADER
|
||||||
388
Subtrees/beast/modules/beast_core/memory/beast_Atomic.h
Normal file
388
Subtrees/beast/modules/beast_core/memory/beast_Atomic.h
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ATOMIC_BEASTHEADER
|
||||||
|
#define BEAST_ATOMIC_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Simple class to hold a primitive value and perform atomic operations on it.
|
||||||
|
|
||||||
|
The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
|
||||||
|
There are methods to perform most of the basic atomic operations.
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
class Atomic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates a new value, initialised to zero. */
|
||||||
|
inline Atomic() noexcept
|
||||||
|
: value (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a new value, with a given initial value. */
|
||||||
|
inline Atomic (const Type initialValue) noexcept
|
||||||
|
: value (initialValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another value (atomically). */
|
||||||
|
inline Atomic (const Atomic& other) noexcept
|
||||||
|
: value (other.get())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
inline ~Atomic() noexcept
|
||||||
|
{
|
||||||
|
// This class can only be used for types which are 32 or 64 bits in size.
|
||||||
|
static_bassert (sizeof (Type) == 4 || sizeof (Type) == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Atomically reads and returns the current value. */
|
||||||
|
Type get() const noexcept;
|
||||||
|
|
||||||
|
/** Copies another value onto this one (atomically). */
|
||||||
|
inline Atomic& operator= (const Atomic& other) noexcept { exchange (other.get()); return *this; }
|
||||||
|
|
||||||
|
/** Copies another value onto this one (atomically). */
|
||||||
|
inline Atomic& operator= (const Type newValue) noexcept { exchange (newValue); return *this; }
|
||||||
|
|
||||||
|
/** Atomically sets the current value. */
|
||||||
|
void set (Type newValue) noexcept { exchange (newValue); }
|
||||||
|
|
||||||
|
/** Atomically sets the current value, returning the value that was replaced. */
|
||||||
|
Type exchange (Type value) noexcept;
|
||||||
|
|
||||||
|
/** Atomically adds a number to this value, returning the new value. */
|
||||||
|
Type operator+= (Type amountToAdd) noexcept;
|
||||||
|
|
||||||
|
/** Atomically subtracts a number from this value, returning the new value. */
|
||||||
|
Type operator-= (Type amountToSubtract) noexcept;
|
||||||
|
|
||||||
|
/** Atomically increments this value, returning the new value. */
|
||||||
|
Type operator++() noexcept;
|
||||||
|
|
||||||
|
/** Atomically decrements this value, returning the new value. */
|
||||||
|
Type operator--() noexcept;
|
||||||
|
|
||||||
|
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||||
|
this to be equal to a new value.
|
||||||
|
|
||||||
|
This operation is the atomic equivalent of doing this:
|
||||||
|
@code
|
||||||
|
bool compareAndSetBool (Type newValue, Type valueToCompare)
|
||||||
|
{
|
||||||
|
if (get() == valueToCompare)
|
||||||
|
{
|
||||||
|
set (newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@returns true if the comparison was true and the value was replaced; false if
|
||||||
|
the comparison failed and the value was left unchanged.
|
||||||
|
@see compareAndSetValue
|
||||||
|
*/
|
||||||
|
bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
|
||||||
|
|
||||||
|
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||||
|
this to be equal to a new value.
|
||||||
|
|
||||||
|
This operation is the atomic equivalent of doing this:
|
||||||
|
@code
|
||||||
|
Type compareAndSetValue (Type newValue, Type valueToCompare)
|
||||||
|
{
|
||||||
|
Type oldValue = get();
|
||||||
|
if (oldValue == valueToCompare)
|
||||||
|
set (newValue);
|
||||||
|
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@returns the old value before it was changed.
|
||||||
|
@see compareAndSetBool
|
||||||
|
*/
|
||||||
|
Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
|
||||||
|
|
||||||
|
/** Implements a memory read/write barrier. */
|
||||||
|
static void memoryBarrier() noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_64BIT
|
||||||
|
BEAST_ALIGN (8)
|
||||||
|
#else
|
||||||
|
BEAST_ALIGN (4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** The raw value that this class operates on.
|
||||||
|
This is exposed publically in case you need to manipulate it directly
|
||||||
|
for performance reasons.
|
||||||
|
*/
|
||||||
|
volatile Type value;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline Type castFrom32Bit (int32 value) noexcept { return *(Type*) &value; }
|
||||||
|
static inline Type castFrom64Bit (int64 value) noexcept { return *(Type*) &value; }
|
||||||
|
static inline int32 castTo32Bit (Type value) noexcept { return *(int32*) &value; }
|
||||||
|
static inline int64 castTo64Bit (Type value) noexcept { return *(int64*) &value; }
|
||||||
|
|
||||||
|
Type operator++ (int); // better to just use pre-increment with atomics..
|
||||||
|
Type operator-- (int);
|
||||||
|
|
||||||
|
/** This templated negate function will negate pointers as well as integers */
|
||||||
|
template <typename ValueType>
|
||||||
|
inline ValueType negateValue (ValueType n) noexcept
|
||||||
|
{
|
||||||
|
return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
|
||||||
|
: (sizeof (ValueType) == 2 ? (ValueType) -(short) n
|
||||||
|
: (sizeof (ValueType) == 4 ? (ValueType) -(int) n
|
||||||
|
: ((ValueType) -(int64) n)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This templated negate function will negate pointers as well as integers */
|
||||||
|
template <typename PointerType>
|
||||||
|
inline PointerType* negateValue (PointerType* n) noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast <PointerType*> (-reinterpret_cast <pointer_sized_int> (n));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/*
|
||||||
|
The following code is in the header so that the atomics can be inlined where possible...
|
||||||
|
*/
|
||||||
|
#if BEAST_IOS || (BEAST_MAC && (BEAST_PPC || BEAST_CLANG || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)))
|
||||||
|
#define BEAST_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier
|
||||||
|
|
||||||
|
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||||
|
#define BEAST_MAC_ATOMICS_VOLATILE
|
||||||
|
#else
|
||||||
|
#define BEAST_MAC_ATOMICS_VOLATILE volatile
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, BEAST_MAC_ATOMICS_VOLATILE Type* value) noexcept
|
||||||
|
{ jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
||||||
|
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif BEAST_GCC
|
||||||
|
#define BEAST_ATOMICS_GCC 1 // GCC with intrinsics
|
||||||
|
|
||||||
|
#if BEAST_IOS || BEAST_ANDROID // (64-bit ops will compile but not link on these mobile OSes)
|
||||||
|
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#else
|
||||||
|
#define BEAST_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||||
|
|
||||||
|
#if BEAST_USE_INTRINSICS
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||||
|
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||||
|
#endif
|
||||||
|
#define beast_InterlockedExchange(a, b) _InterlockedExchange(a, b)
|
||||||
|
#define beast_InterlockedIncrement(a) _InterlockedIncrement(a)
|
||||||
|
#define beast_InterlockedDecrement(a) _InterlockedDecrement(a)
|
||||||
|
#define beast_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
|
||||||
|
#define beast_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
|
||||||
|
#define beast_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
|
||||||
|
#define beast_MemoryBarrier _ReadWriteBarrier
|
||||||
|
#else
|
||||||
|
long beast_InterlockedExchange (volatile long* a, long b) noexcept;
|
||||||
|
long beast_InterlockedIncrement (volatile long* a) noexcept;
|
||||||
|
long beast_InterlockedDecrement (volatile long* a) noexcept;
|
||||||
|
long beast_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
|
||||||
|
long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
|
||||||
|
__int64 beast_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
|
||||||
|
inline void beast_MemoryBarrier() noexcept { long x = 0; beast_InterlockedIncrement (&x); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_64BIT
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
||||||
|
#endif
|
||||||
|
#define beast_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
|
||||||
|
#define beast_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
|
||||||
|
#define beast_InterlockedIncrement64(a) _InterlockedIncrement64(a)
|
||||||
|
#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; }
|
||||||
|
#define BEAST_64BIT_ATOMICS_UNAVAILABLE 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4311) // (truncation warning)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::get() const noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value))
|
||||||
|
: castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value));
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) beast_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
|
||||||
|
: castFrom64Bit ((int64) beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
|
||||||
|
#elif BEAST_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0))
|
||||||
|
: castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::exchange (const Type newValue) noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC || BEAST_ATOMICS_GCC
|
||||||
|
Type currentVal = value;
|
||||||
|
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
|
||||||
|
return currentVal;
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) beast_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
|
||||||
|
: castFrom64Bit ((int64) beast_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC
|
||||||
|
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? (Type) (beast_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
|
||||||
|
: (Type) (beast_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
|
||||||
|
#elif BEAST_ATOMICS_GCC
|
||||||
|
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
|
||||||
|
{
|
||||||
|
return operator+= (negateValue (amountToSubtract));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator++() noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC
|
||||||
|
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: (Type) OSAtomicIncrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? (Type) beast_InterlockedIncrement ((volatile long*) &value)
|
||||||
|
: (Type) beast_InterlockedIncrement64 ((volatile __int64*) &value);
|
||||||
|
#elif BEAST_ATOMICS_GCC
|
||||||
|
return (Type) __sync_add_and_fetch (&value, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator--() noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC
|
||||||
|
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: (Type) OSAtomicDecrement64Barrier ((BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? (Type) beast_InterlockedDecrement ((volatile long*) &value)
|
||||||
|
: (Type) beast_InterlockedDecrement64 ((volatile __int64*) &value);
|
||||||
|
#elif BEAST_ATOMICS_GCC
|
||||||
|
return (Type) __sync_add_and_fetch (&value, -1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC
|
||||||
|
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (BEAST_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
|
||||||
|
#elif BEAST_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
|
||||||
|
: __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC
|
||||||
|
for (;;) // Annoying workaround for only having a bool CAS operation..
|
||||||
|
{
|
||||||
|
if (compareAndSetBool (newValue, valueToCompare))
|
||||||
|
return valueToCompare;
|
||||||
|
|
||||||
|
const Type result = value;
|
||||||
|
if (result != valueToCompare)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) beast_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
|
||||||
|
: castFrom64Bit ((int64) beast_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
|
||||||
|
#elif BEAST_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
|
||||||
|
: castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline void Atomic<Type>::memoryBarrier() noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_ATOMICS_MAC
|
||||||
|
OSMemoryBarrier();
|
||||||
|
#elif BEAST_ATOMICS_GCC
|
||||||
|
__sync_synchronize();
|
||||||
|
#elif BEAST_ATOMICS_WINDOWS
|
||||||
|
beast_MemoryBarrier();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // BEAST_ATOMIC_BEASTHEADER
|
||||||
181
Subtrees/beast/modules/beast_core/memory/beast_ByteOrder.h
Normal file
181
Subtrees/beast/modules/beast_core/memory/beast_ByteOrder.h
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_BYTEORDER_BEASTHEADER
|
||||||
|
#define BEAST_BYTEORDER_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Contains static methods for converting the byte order between different
|
||||||
|
endiannesses.
|
||||||
|
*/
|
||||||
|
class BEAST_API ByteOrder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps the upper and lower bytes of a 16-bit integer. */
|
||||||
|
static uint16 swap (uint16 value);
|
||||||
|
|
||||||
|
/** Reverses the order of the 4 bytes in a 32-bit integer. */
|
||||||
|
static uint32 swap (uint32 value);
|
||||||
|
|
||||||
|
/** Reverses the order of the 8 bytes in a 64-bit integer. */
|
||||||
|
static uint64 swap (uint64 value);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps the byte order of a 16-bit int if the CPU is big-endian */
|
||||||
|
static uint16 swapIfBigEndian (uint16 value);
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 32-bit int if the CPU is big-endian */
|
||||||
|
static uint32 swapIfBigEndian (uint32 value);
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 64-bit int if the CPU is big-endian */
|
||||||
|
static uint64 swapIfBigEndian (uint64 value);
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 16-bit int if the CPU is little-endian */
|
||||||
|
static uint16 swapIfLittleEndian (uint16 value);
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 32-bit int if the CPU is little-endian */
|
||||||
|
static uint32 swapIfLittleEndian (uint32 value);
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 64-bit int if the CPU is little-endian */
|
||||||
|
static uint64 swapIfLittleEndian (uint64 value);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Turns 4 bytes into a little-endian integer. */
|
||||||
|
static uint32 littleEndianInt (const void* bytes);
|
||||||
|
|
||||||
|
/** Turns 2 bytes into a little-endian integer. */
|
||||||
|
static uint16 littleEndianShort (const void* bytes);
|
||||||
|
|
||||||
|
/** Turns 4 bytes into a big-endian integer. */
|
||||||
|
static uint32 bigEndianInt (const void* bytes);
|
||||||
|
|
||||||
|
/** Turns 2 bytes into a big-endian integer. */
|
||||||
|
static uint16 bigEndianShort (const void* bytes);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||||
|
static int littleEndian24Bit (const char* bytes);
|
||||||
|
|
||||||
|
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||||
|
static int bigEndian24Bit (const char* bytes);
|
||||||
|
|
||||||
|
/** Copies a 24-bit number to 3 little-endian bytes. */
|
||||||
|
static void littleEndian24BitToChars (int value, char* destBytes);
|
||||||
|
|
||||||
|
/** Copies a 24-bit number to 3 big-endian bytes. */
|
||||||
|
static void bigEndian24BitToChars (int value, char* destBytes);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the current CPU is big-endian. */
|
||||||
|
static bool isBigEndian();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ByteOrder();
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (ByteOrder)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||||
|
#pragma intrinsic (_byteswap_ulong)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline uint16 ByteOrder::swap (uint16 n)
|
||||||
|
{
|
||||||
|
#if BEAST_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
|
||||||
|
return static_cast <uint16> (_byteswap_ushort (n));
|
||||||
|
#else
|
||||||
|
return static_cast <uint16> ((n << 8) | (n >> 8));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 ByteOrder::swap (uint32 n)
|
||||||
|
{
|
||||||
|
#if BEAST_MAC || BEAST_IOS
|
||||||
|
return OSSwapInt32 (n);
|
||||||
|
#elif BEAST_GCC && BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||||
|
asm("bswap %%eax" : "=a"(n) : "a"(n));
|
||||||
|
return n;
|
||||||
|
#elif BEAST_USE_INTRINSICS
|
||||||
|
return _byteswap_ulong (n);
|
||||||
|
#elif BEAST_MSVC && ! BEAST_NO_INLINE_ASM
|
||||||
|
__asm {
|
||||||
|
mov eax, n
|
||||||
|
bswap eax
|
||||||
|
mov n, eax
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
#elif BEAST_ANDROID
|
||||||
|
return bswap_32 (n);
|
||||||
|
#else
|
||||||
|
return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64 ByteOrder::swap (uint64 value)
|
||||||
|
{
|
||||||
|
#if BEAST_MAC || BEAST_IOS
|
||||||
|
return OSSwapInt64 (value);
|
||||||
|
#elif BEAST_USE_INTRINSICS
|
||||||
|
return _byteswap_uint64 (value);
|
||||||
|
#else
|
||||||
|
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_LITTLE_ENDIAN
|
||||||
|
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) { return v; }
|
||||||
|
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) { return v; }
|
||||||
|
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) { return v; }
|
||||||
|
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) { return swap (v); }
|
||||||
|
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) { return swap (v); }
|
||||||
|
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) { return swap (v); }
|
||||||
|
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) { return *static_cast <const uint32*> (bytes); }
|
||||||
|
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return *static_cast <const uint16*> (bytes); }
|
||||||
|
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return swap (*static_cast <const uint32*> (bytes)); }
|
||||||
|
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return swap (*static_cast <const uint16*> (bytes)); }
|
||||||
|
inline bool ByteOrder::isBigEndian() { return false; }
|
||||||
|
#else
|
||||||
|
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) { return swap (v); }
|
||||||
|
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) { return swap (v); }
|
||||||
|
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) { return swap (v); }
|
||||||
|
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) { return v; }
|
||||||
|
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) { return v; }
|
||||||
|
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) { return v; }
|
||||||
|
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) { return swap (*static_cast <const uint32*> (bytes)); }
|
||||||
|
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return swap (*static_cast <const uint16*> (bytes)); }
|
||||||
|
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return *static_cast <const uint32*> (bytes); }
|
||||||
|
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return *static_cast <const uint16*> (bytes); }
|
||||||
|
inline bool ByteOrder::isBigEndian() { return true; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline int ByteOrder::littleEndian24Bit (const char* const bytes) { return (((int) bytes[2]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[0]); }
|
||||||
|
inline int ByteOrder::bigEndian24Bit (const char* const bytes) { return (((int) bytes[0]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[2]); }
|
||||||
|
inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); }
|
||||||
|
inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); }
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_BYTEORDER_BEASTHEADER
|
||||||
303
Subtrees/beast/modules/beast_core/memory/beast_HeapBlock.h
Normal file
303
Subtrees/beast/modules/beast_core/memory/beast_HeapBlock.h
Normal file
@@ -0,0 +1,303 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_HEAPBLOCK_BEASTHEADER
|
||||||
|
#define BEAST_HEAPBLOCK_BEASTHEADER
|
||||||
|
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
namespace HeapBlockHelper
|
||||||
|
{
|
||||||
|
template <bool shouldThrow>
|
||||||
|
struct ThrowOnFail { static void check (void*) {} };
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct ThrowOnFail <true> { static void check (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Very simple container class to hold a pointer to some data on the heap.
|
||||||
|
|
||||||
|
When you need to allocate some heap storage for something, always try to use
|
||||||
|
this class instead of allocating the memory directly using malloc/free.
|
||||||
|
|
||||||
|
A HeapBlock<char> object can be treated in pretty much exactly the same way
|
||||||
|
as an char*, but as long as you allocate it on the stack or as a class member,
|
||||||
|
it's almost impossible for it to leak memory.
|
||||||
|
|
||||||
|
It also makes your code much more concise and readable than doing the same thing
|
||||||
|
using direct allocations,
|
||||||
|
|
||||||
|
E.g. instead of this:
|
||||||
|
@code
|
||||||
|
int* temp = (int*) malloc (1024 * sizeof (int));
|
||||||
|
memcpy (temp, xyz, 1024 * sizeof (int));
|
||||||
|
free (temp);
|
||||||
|
temp = (int*) calloc (2048 * sizeof (int));
|
||||||
|
temp[0] = 1234;
|
||||||
|
memcpy (foobar, temp, 2048 * sizeof (int));
|
||||||
|
free (temp);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..you could just write this:
|
||||||
|
@code
|
||||||
|
HeapBlock <int> temp (1024);
|
||||||
|
memcpy (temp, xyz, 1024 * sizeof (int));
|
||||||
|
temp.calloc (2048);
|
||||||
|
temp[0] = 1234;
|
||||||
|
memcpy (foobar, temp, 2048 * sizeof (int));
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The class is extremely lightweight, containing only a pointer to the
|
||||||
|
data, and exposes malloc/realloc/calloc/free methods that do the same jobs
|
||||||
|
as their less object-oriented counterparts. Despite adding safety, you probably
|
||||||
|
won't sacrifice any performance by using this in place of normal pointers.
|
||||||
|
|
||||||
|
The throwOnFailure template parameter can be set to true if you'd like the class
|
||||||
|
to throw a std::bad_alloc exception when an allocation fails. If this is false,
|
||||||
|
then a failed allocation will just leave the heapblock with a null pointer (assuming
|
||||||
|
that the system's malloc() function doesn't throw).
|
||||||
|
|
||||||
|
@see Array, OwnedArray, MemoryBlock
|
||||||
|
*/
|
||||||
|
template <class ElementType, bool throwOnFailure = false>
|
||||||
|
class HeapBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a HeapBlock which is initially just a null pointer.
|
||||||
|
|
||||||
|
After creation, you can resize the array using the malloc(), calloc(),
|
||||||
|
or realloc() methods.
|
||||||
|
*/
|
||||||
|
HeapBlock() noexcept : data (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a HeapBlock containing a number of elements.
|
||||||
|
|
||||||
|
The contents of the block are undefined, as it will have been created by a
|
||||||
|
malloc call.
|
||||||
|
|
||||||
|
If you want an array of zero values, you can use the calloc() method or the
|
||||||
|
other constructor that takes an InitialisationState parameter.
|
||||||
|
*/
|
||||||
|
explicit HeapBlock (const size_t numElements)
|
||||||
|
: data (static_cast <ElementType*> (std::malloc (numElements * sizeof (ElementType))))
|
||||||
|
{
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a HeapBlock containing a number of elements.
|
||||||
|
|
||||||
|
The initialiseToZero parameter determines whether the new memory should be cleared,
|
||||||
|
or left uninitialised.
|
||||||
|
*/
|
||||||
|
HeapBlock (const size_t numElements, const bool initialiseToZero)
|
||||||
|
: data (static_cast <ElementType*> (initialiseToZero
|
||||||
|
? std::calloc (numElements, sizeof (ElementType))
|
||||||
|
: std::malloc (numElements * sizeof (ElementType))))
|
||||||
|
{
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
This will free the data, if any has been allocated.
|
||||||
|
*/
|
||||||
|
~HeapBlock()
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
HeapBlock (HeapBlock&& other) noexcept
|
||||||
|
: data (other.data)
|
||||||
|
{
|
||||||
|
other.data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapBlock& operator= (HeapBlock&& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (data, other.data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a raw pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline operator ElementType*() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a raw pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline ElementType* getData() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a void pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline operator void*() const noexcept { return static_cast <void*> (data); }
|
||||||
|
|
||||||
|
/** Returns a void pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline operator const void*() const noexcept { return static_cast <const void*> (data); }
|
||||||
|
|
||||||
|
/** Lets you use indirect calls to the first element in the array.
|
||||||
|
Obviously this will cause problems if the array hasn't been initialised, because it'll
|
||||||
|
be referencing a null pointer.
|
||||||
|
*/
|
||||||
|
inline ElementType* operator->() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a reference to one of the data elements.
|
||||||
|
Obviously there's no bounds-checking here, as this object is just a dumb pointer and
|
||||||
|
has no idea of the size it currently has allocated.
|
||||||
|
*/
|
||||||
|
template <typename IndexType>
|
||||||
|
inline ElementType& operator[] (IndexType index) const noexcept { return data [index]; }
|
||||||
|
|
||||||
|
/** Returns a pointer to a data element at an offset from the start of the array.
|
||||||
|
This is the same as doing pointer arithmetic on the raw pointer itself.
|
||||||
|
*/
|
||||||
|
template <typename IndexType>
|
||||||
|
inline ElementType* operator+ (IndexType index) const noexcept { return data + index; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares the pointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
|
inline bool operator== (const ElementType* const otherPointer) const noexcept { return otherPointer == data; }
|
||||||
|
|
||||||
|
/** Compares the pointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
|
inline bool operator!= (const ElementType* const otherPointer) const noexcept { return otherPointer != data; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Allocates a specified amount of memory.
|
||||||
|
|
||||||
|
This uses the normal malloc to allocate an amount of memory for this object.
|
||||||
|
Any previously allocated memory will be freed by this method.
|
||||||
|
|
||||||
|
The number of bytes allocated will be (newNumElements * elementSize). Normally
|
||||||
|
you wouldn't need to specify the second parameter, but it can be handy if you need
|
||||||
|
to allocate a size in bytes rather than in terms of the number of elements.
|
||||||
|
|
||||||
|
The data that is allocated will be freed when this object is deleted, or when you
|
||||||
|
call free() or any of the allocation methods.
|
||||||
|
*/
|
||||||
|
void malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = static_cast <ElementType*> (std::malloc (newNumElements * elementSize));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allocates a specified amount of memory and clears it.
|
||||||
|
This does the same job as the malloc() method, but clears the memory that it allocates.
|
||||||
|
*/
|
||||||
|
void calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = static_cast <ElementType*> (std::calloc (newNumElements, elementSize));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allocates a specified amount of memory and optionally clears it.
|
||||||
|
This does the same job as either malloc() or calloc(), depending on the
|
||||||
|
initialiseToZero parameter.
|
||||||
|
*/
|
||||||
|
void allocate (const size_t newNumElements, bool initialiseToZero)
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = static_cast <ElementType*> (initialiseToZero
|
||||||
|
? std::calloc (newNumElements, sizeof (ElementType))
|
||||||
|
: std::malloc (newNumElements * sizeof (ElementType)));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Re-allocates a specified amount of memory.
|
||||||
|
|
||||||
|
The semantics of this method are the same as malloc() and calloc(), but it
|
||||||
|
uses realloc() to keep as much of the existing data as possible.
|
||||||
|
*/
|
||||||
|
void realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||||
|
{
|
||||||
|
data = static_cast <ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
|
||||||
|
: std::realloc (data, newNumElements * elementSize));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Frees any currently-allocated data.
|
||||||
|
This will free the data and reset this object to be a null pointer.
|
||||||
|
*/
|
||||||
|
void free()
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps this object's data with the data of another HeapBlock.
|
||||||
|
The two objects simply exchange their data pointers.
|
||||||
|
*/
|
||||||
|
template <bool otherBlockThrows>
|
||||||
|
void swapWith (HeapBlock <ElementType, otherBlockThrows>& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (data, other.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This fills the block with zeros, up to the number of elements specified.
|
||||||
|
Since the block has no way of knowing its own size, you must make sure that the number of
|
||||||
|
elements you specify doesn't exceed the allocated size.
|
||||||
|
*/
|
||||||
|
void clear (size_t numElements) noexcept
|
||||||
|
{
|
||||||
|
zeromem (data, sizeof (ElementType) * numElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This typedef can be used to get the type of the heapblock's elements. */
|
||||||
|
typedef ElementType Type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ElementType* data;
|
||||||
|
|
||||||
|
void throwOnAllocationFailure() const
|
||||||
|
{
|
||||||
|
HeapBlockHelper::ThrowOnFail<throwOnFailure>::check (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ! (defined (BEAST_DLL) || defined (BEAST_DLL_BUILD))
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (HeapBlock)
|
||||||
|
BEAST_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_HEAPBLOCK_BEASTHEADER
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||||
|
#define BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_String.h"
|
||||||
|
#include "beast_Atomic.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Embedding an instance of this class inside another class can be used as a low-overhead
|
||||||
|
way of detecting leaked instances.
|
||||||
|
|
||||||
|
This class keeps an internal static count of the number of instances that are
|
||||||
|
active, so that when the app is shutdown and the static destructors are called,
|
||||||
|
it can check whether there are any left-over instances that may have been leaked.
|
||||||
|
|
||||||
|
To use it, use the BEAST_LEAK_DETECTOR macro as a simple way to put one in your
|
||||||
|
class declaration. Have a look through the beast codebase for examples, it's used
|
||||||
|
in most of the classes.
|
||||||
|
*/
|
||||||
|
template <class OwnerClass>
|
||||||
|
class LeakedObjectDetector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
LeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
|
||||||
|
LeakedObjectDetector (const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }
|
||||||
|
|
||||||
|
~LeakedObjectDetector()
|
||||||
|
{
|
||||||
|
if (--(getCounter().numObjects) < 0)
|
||||||
|
{
|
||||||
|
DBG ("*** Dangling pointer deletion! Class: " << getLeakedObjectClassName());
|
||||||
|
|
||||||
|
/** If you hit this, then you've managed to delete more instances of this class than you've
|
||||||
|
created.. That indicates that you're deleting some dangling pointers.
|
||||||
|
|
||||||
|
Note that although this assertion will have been triggered during a destructor, it might
|
||||||
|
not be this particular deletion that's at fault - the incorrect one may have happened
|
||||||
|
at an earlier point in the program, and simply not been detected until now.
|
||||||
|
|
||||||
|
Most errors like this are caused by using old-fashioned, non-RAII techniques for
|
||||||
|
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
|
||||||
|
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
|
||||||
|
*/
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class LeakCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LeakCounter() noexcept {}
|
||||||
|
|
||||||
|
~LeakCounter()
|
||||||
|
{
|
||||||
|
if (numObjects.value > 0)
|
||||||
|
{
|
||||||
|
DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());
|
||||||
|
|
||||||
|
/** If you hit this, then you've leaked one or more objects of the type specified by
|
||||||
|
the 'OwnerClass' template parameter - the name should have been printed by the line above.
|
||||||
|
|
||||||
|
If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
|
||||||
|
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
|
||||||
|
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
|
||||||
|
*/
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Atomic<int> numObjects;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* getLeakedObjectClassName()
|
||||||
|
{
|
||||||
|
return OwnerClass::getLeakedObjectClassName();
|
||||||
|
}
|
||||||
|
|
||||||
|
static LeakCounter& getCounter() noexcept
|
||||||
|
{
|
||||||
|
static LeakCounter counter;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if DOXYGEN || ! defined (BEAST_LEAK_DETECTOR)
|
||||||
|
#if (DOXYGEN || BEAST_CHECK_MEMORY_LEAKS)
|
||||||
|
/** This macro lets you embed a leak-detecting object inside a class.
|
||||||
|
|
||||||
|
To use it, simply declare a BEAST_LEAK_DETECTOR(YourClassName) inside a private section
|
||||||
|
of the class declaration. E.g.
|
||||||
|
|
||||||
|
@code
|
||||||
|
class MyClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyClass();
|
||||||
|
void blahBlah();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BEAST_LEAK_DETECTOR (MyClass)
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector
|
||||||
|
*/
|
||||||
|
#define BEAST_LEAK_DETECTOR(OwnerClass) \
|
||||||
|
friend class beast::LeakedObjectDetector<OwnerClass>; \
|
||||||
|
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
|
||||||
|
beast::LeakedObjectDetector<OwnerClass> BEAST_JOIN_MACRO (leakDetector, __LINE__);
|
||||||
|
#else
|
||||||
|
#define BEAST_LEAK_DETECTOR(OwnerClass)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_LEAKEDOBJECTDETECTOR_BEASTHEADER
|
||||||
121
Subtrees/beast/modules/beast_core/memory/beast_Memory.h
Normal file
121
Subtrees/beast/modules/beast_core/memory/beast_Memory.h
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_MEMORY_BEASTHEADER
|
||||||
|
#define BEAST_MEMORY_BEASTHEADER
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Fills a block of memory with zeros. */
|
||||||
|
inline void zeromem (void* memory, size_t numBytes) noexcept { memset (memory, 0, numBytes); }
|
||||||
|
|
||||||
|
/** Overwrites a structure or object with zeros. */
|
||||||
|
template <typename Type>
|
||||||
|
inline void zerostruct (Type& structure) noexcept { memset (&structure, 0, sizeof (structure)); }
|
||||||
|
|
||||||
|
/** Delete an object pointer, and sets the pointer to null.
|
||||||
|
|
||||||
|
Remember that it's not good c++ practice to use delete directly - always try to use a ScopedPointer
|
||||||
|
or other automatic lifetime-management system rather than resorting to deleting raw pointers!
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline void deleteAndZero (Type& pointer) { delete pointer; pointer = nullptr; }
|
||||||
|
|
||||||
|
/** A handy function which adds a number of bytes to any type of pointer and returns the result.
|
||||||
|
This can be useful to avoid casting pointers to a char* and back when you want to move them by
|
||||||
|
a specific number of bytes,
|
||||||
|
*/
|
||||||
|
template <typename Type, typename IntegerType>
|
||||||
|
inline Type* addBytesToPointer (Type* pointer, IntegerType bytes) noexcept { return (Type*) (((char*) pointer) + bytes); }
|
||||||
|
|
||||||
|
/** A handy function which returns the difference between any two pointers, in bytes.
|
||||||
|
The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
|
||||||
|
*/
|
||||||
|
template <typename Type1, typename Type2>
|
||||||
|
inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { return (int) (((const char*) pointer1) - (const char*) pointer2); }
|
||||||
|
|
||||||
|
/** If a pointer is non-null, this returns a new copy of the object that it points to, or safely returns
|
||||||
|
nullptr if the pointer is null.
|
||||||
|
*/
|
||||||
|
template <class Type>
|
||||||
|
inline Type* createCopyIfNotNull (const Type* pointer) { return pointer != nullptr ? new Type (*pointer) : nullptr; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_MAC || BEAST_IOS || DOXYGEN
|
||||||
|
|
||||||
|
/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII.
|
||||||
|
You should use the BEAST_AUTORELEASEPOOL macro to create a local auto-release pool on the stack.
|
||||||
|
*/
|
||||||
|
class BEAST_API ScopedAutoReleasePool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScopedAutoReleasePool();
|
||||||
|
~ScopedAutoReleasePool();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* pool;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (ScopedAutoReleasePool)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A macro that can be used to easily declare a local ScopedAutoReleasePool
|
||||||
|
object for RAII-based obj-C autoreleasing.
|
||||||
|
Because this may use the \@autoreleasepool syntax, you must follow the macro with
|
||||||
|
a set of braces to mark the scope of the pool.
|
||||||
|
*/
|
||||||
|
#if (BEAST_COMPILER_SUPPORTS_ARC && defined (__OBJC__)) || DOXYGEN
|
||||||
|
#define BEAST_AUTORELEASEPOOL @autoreleasepool
|
||||||
|
#else
|
||||||
|
#define BEAST_AUTORELEASEPOOL const beast::ScopedAutoReleasePool BEAST_JOIN_MACRO (autoReleasePool_, __LINE__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define BEAST_AUTORELEASEPOOL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/* In a Windows DLL build, we'll expose some malloc/free functions that live inside the DLL, and use these for
|
||||||
|
allocating all the objects - that way all beast objects in the DLL and in the host will live in the same heap,
|
||||||
|
avoiding problems when an object is created in one module and passed across to another where it is deleted.
|
||||||
|
By piggy-backing on the BEAST_LEAK_DETECTOR macro, these allocators can be injected into most beast classes.
|
||||||
|
*/
|
||||||
|
#if BEAST_MSVC && (defined (BEAST_DLL) || defined (BEAST_DLL_BUILD)) && ! (BEAST_DISABLE_DLL_ALLOCATORS || DOXYGEN)
|
||||||
|
extern BEAST_API void* beastDLL_malloc (size_t);
|
||||||
|
extern BEAST_API void beastDLL_free (void*);
|
||||||
|
|
||||||
|
#define BEAST_LEAK_DETECTOR(OwnerClass) public:\
|
||||||
|
static void* operator new (size_t sz) { return beast::beastDLL_malloc (sz); } \
|
||||||
|
static void* operator new (size_t, void* p) { return p; } \
|
||||||
|
static void operator delete (void* p) { beast::beastDLL_free (p); } \
|
||||||
|
static void operator delete (void*, void*) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** (Deprecated) This was a Windows-specific way of checking for object leaks - now please
|
||||||
|
use the BEAST_LEAK_DETECTOR instead.
|
||||||
|
*/
|
||||||
|
#ifndef beast_UseDebuggingNewOperator
|
||||||
|
#define beast_UseDebuggingNewOperator
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_MEMORY_BEASTHEADER
|
||||||
416
Subtrees/beast/modules/beast_core/memory/beast_MemoryBlock.cpp
Normal file
416
Subtrees/beast/modules/beast_core/memory/beast_MemoryBlock.cpp
Normal file
@@ -0,0 +1,416 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock() noexcept
|
||||||
|
: size (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock (const size_t initialSize, const bool initialiseToZero)
|
||||||
|
{
|
||||||
|
if (initialSize > 0)
|
||||||
|
{
|
||||||
|
size = initialSize;
|
||||||
|
data.allocate (initialSize, initialiseToZero);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock (const MemoryBlock& other)
|
||||||
|
: size (other.size)
|
||||||
|
{
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
bassert (other.data != nullptr);
|
||||||
|
data.malloc (size);
|
||||||
|
memcpy (data, other.data, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
|
||||||
|
: size (sizeInBytes)
|
||||||
|
{
|
||||||
|
bassert (((ssize_t) sizeInBytes) >= 0);
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
bassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
|
||||||
|
|
||||||
|
data.malloc (size);
|
||||||
|
|
||||||
|
if (dataToInitialiseFrom != nullptr)
|
||||||
|
memcpy (data, dataToInitialiseFrom, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::~MemoryBlock() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
setSize (other.size, false);
|
||||||
|
memcpy (data, other.data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
|
||||||
|
: data (static_cast <HeapBlock <char>&&> (other.data)),
|
||||||
|
size (other.size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
|
||||||
|
{
|
||||||
|
data = static_cast <HeapBlock <char>&&> (other.data);
|
||||||
|
size = other.size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
|
||||||
|
{
|
||||||
|
return matches (other.data, other.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
|
||||||
|
{
|
||||||
|
return size == dataSize
|
||||||
|
&& memcmp (data, dataToCompare, size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// this will resize the block to this size
|
||||||
|
void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
|
||||||
|
{
|
||||||
|
if (size != newSize)
|
||||||
|
{
|
||||||
|
if (newSize <= 0)
|
||||||
|
{
|
||||||
|
data.free();
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (data != nullptr)
|
||||||
|
{
|
||||||
|
data.realloc (newSize);
|
||||||
|
|
||||||
|
if (initialiseToZero && (newSize > size))
|
||||||
|
zeromem (data + size, newSize - size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.allocate (newSize, initialiseToZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = newSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
|
||||||
|
{
|
||||||
|
if (size < minimumSize)
|
||||||
|
setSize (minimumSize, initialiseToZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::swapWith (MemoryBlock& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (size, other.size);
|
||||||
|
data.swapWith (other.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void MemoryBlock::fillWith (const uint8 value) noexcept
|
||||||
|
{
|
||||||
|
memset (data, (int) value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::append (const void* const srcData, const size_t numBytes)
|
||||||
|
{
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
bassert (srcData != nullptr); // this must not be null!
|
||||||
|
const size_t oldSize = size;
|
||||||
|
setSize (size + numBytes);
|
||||||
|
memcpy (data + oldSize, srcData, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::replaceWith (const void* const srcData, const size_t numBytes)
|
||||||
|
{
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
bassert (srcData != nullptr); // this must not be null!
|
||||||
|
setSize (numBytes);
|
||||||
|
memcpy (data, srcData, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::insert (const void* const srcData, const size_t numBytes, size_t insertPosition)
|
||||||
|
{
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
bassert (srcData != nullptr); // this must not be null!
|
||||||
|
insertPosition = bmin (size, insertPosition);
|
||||||
|
const size_t trailingDataSize = size - insertPosition;
|
||||||
|
setSize (size + numBytes, false);
|
||||||
|
|
||||||
|
if (trailingDataSize > 0)
|
||||||
|
memmove (data + insertPosition + numBytes,
|
||||||
|
data + insertPosition,
|
||||||
|
trailingDataSize);
|
||||||
|
|
||||||
|
memcpy (data + insertPosition, srcData, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::removeSection (const size_t startByte, const size_t numBytesToRemove)
|
||||||
|
{
|
||||||
|
if (startByte + numBytesToRemove >= size)
|
||||||
|
{
|
||||||
|
setSize (startByte);
|
||||||
|
}
|
||||||
|
else if (numBytesToRemove > 0)
|
||||||
|
{
|
||||||
|
memmove (data + startByte,
|
||||||
|
data + startByte + numBytesToRemove,
|
||||||
|
size - (startByte + numBytesToRemove));
|
||||||
|
|
||||||
|
setSize (size - numBytesToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
|
||||||
|
{
|
||||||
|
const char* d = static_cast<const char*> (src);
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
d -= offset;
|
||||||
|
num -= offset;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + num > size)
|
||||||
|
num = size - offset;
|
||||||
|
|
||||||
|
if (num > 0)
|
||||||
|
memcpy (data + offset, d, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
|
||||||
|
{
|
||||||
|
char* d = static_cast<char*> (dst);
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
zeromem (d, (size_t) -offset);
|
||||||
|
d -= offset;
|
||||||
|
|
||||||
|
num += offset;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + num > size)
|
||||||
|
{
|
||||||
|
const size_t newNum = size - offset;
|
||||||
|
zeromem (d + newNum, num - newNum);
|
||||||
|
num = newNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num > 0)
|
||||||
|
memcpy (d, data + offset, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
String MemoryBlock::toString() const
|
||||||
|
{
|
||||||
|
return String (CharPointer_UTF8 (data), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int MemoryBlock::getBitRange (const size_t bitRangeStart, size_t numBits) const noexcept
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
size_t byte = bitRangeStart >> 3;
|
||||||
|
int offsetInByte = (int) bitRangeStart & 7;
|
||||||
|
size_t bitsSoFar = 0;
|
||||||
|
|
||||||
|
while (numBits > 0 && (size_t) byte < size)
|
||||||
|
{
|
||||||
|
const int bitsThisTime = bmin ((int) numBits, 8 - offsetInByte);
|
||||||
|
const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
|
||||||
|
|
||||||
|
res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
|
||||||
|
|
||||||
|
bitsSoFar += bitsThisTime;
|
||||||
|
numBits -= bitsThisTime;
|
||||||
|
++byte;
|
||||||
|
offsetInByte = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
|
||||||
|
{
|
||||||
|
size_t byte = bitRangeStart >> 3;
|
||||||
|
int offsetInByte = (int) bitRangeStart & 7;
|
||||||
|
unsigned int mask = ~((((unsigned int) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
|
||||||
|
|
||||||
|
while (numBits > 0 && (size_t) byte < size)
|
||||||
|
{
|
||||||
|
const int bitsThisTime = bmin ((int) numBits, 8 - offsetInByte);
|
||||||
|
|
||||||
|
const unsigned int tempMask = (mask << offsetInByte) | ~((((unsigned int) 0xffffffff) >> offsetInByte) << offsetInByte);
|
||||||
|
const unsigned int tempBits = (unsigned int) bitsToSet << offsetInByte;
|
||||||
|
|
||||||
|
data[byte] = (char) ((data[byte] & tempMask) | tempBits);
|
||||||
|
|
||||||
|
++byte;
|
||||||
|
numBits -= bitsThisTime;
|
||||||
|
bitsToSet >>= bitsThisTime;
|
||||||
|
mask >>= bitsThisTime;
|
||||||
|
offsetInByte = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void MemoryBlock::loadFromHexString (const String& hex)
|
||||||
|
{
|
||||||
|
ensureSize ((size_t) hex.length() >> 1);
|
||||||
|
char* dest = data;
|
||||||
|
String::CharPointerType t (hex.getCharPointer());
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int byte = 0;
|
||||||
|
|
||||||
|
for (int loop = 2; --loop >= 0;)
|
||||||
|
{
|
||||||
|
byte <<= 4;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const beast_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
{
|
||||||
|
byte |= c - '0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (c >= 'a' && c <= 'z')
|
||||||
|
{
|
||||||
|
byte |= c - ('a' - 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (c >= 'A' && c <= 'Z')
|
||||||
|
{
|
||||||
|
byte |= c - ('A' - 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (c == 0)
|
||||||
|
{
|
||||||
|
setSize (static_cast <size_t> (dest - data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest++ = (char) byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
const char* const MemoryBlock::encodingTable = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
|
||||||
|
|
||||||
|
String MemoryBlock::toBase64Encoding() const
|
||||||
|
{
|
||||||
|
const size_t numChars = ((size << 3) + 5) / 6;
|
||||||
|
|
||||||
|
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
|
||||||
|
const int initialLen = destString.length();
|
||||||
|
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) (initialLen + 2 + numChars));
|
||||||
|
|
||||||
|
String::CharPointerType d (destString.getCharPointer());
|
||||||
|
d += initialLen;
|
||||||
|
d.write ('.');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numChars; ++i)
|
||||||
|
d.write ((beast_wchar) (uint8) encodingTable [getBitRange (i * 6, 6)]);
|
||||||
|
|
||||||
|
d.writeNull();
|
||||||
|
return destString;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryBlock::fromBase64Encoding (const String& s)
|
||||||
|
{
|
||||||
|
const int startPos = s.indexOfChar ('.') + 1;
|
||||||
|
|
||||||
|
if (startPos <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int numBytesNeeded = s.substring (0, startPos - 1).getIntValue();
|
||||||
|
|
||||||
|
setSize ((size_t) numBytesNeeded, true);
|
||||||
|
|
||||||
|
const int numChars = s.length() - startPos;
|
||||||
|
|
||||||
|
String::CharPointerType srcChars (s.getCharPointer());
|
||||||
|
srcChars += startPos;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < numChars; ++i)
|
||||||
|
{
|
||||||
|
const char c = (char) srcChars.getAndAdvance();
|
||||||
|
|
||||||
|
for (int j = 0; j < 64; ++j)
|
||||||
|
{
|
||||||
|
if (encodingTable[j] == c)
|
||||||
|
{
|
||||||
|
setBitRange ((size_t) pos, 6, j);
|
||||||
|
pos += 6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
255
Subtrees/beast/modules/beast_core/memory/beast_MemoryBlock.h
Normal file
255
Subtrees/beast/modules/beast_core/memory/beast_MemoryBlock.h
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_MEMORYBLOCK_BEASTHEADER
|
||||||
|
#define BEAST_MEMORYBLOCK_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_String.h"
|
||||||
|
#include "../memory/beast_HeapBlock.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A class to hold a resizable block of raw data.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class BEAST_API MemoryBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Create an uninitialised block with 0 size. */
|
||||||
|
MemoryBlock() noexcept;
|
||||||
|
|
||||||
|
/** Creates a memory block with a given initial size.
|
||||||
|
|
||||||
|
@param initialSize the size of block to create
|
||||||
|
@param initialiseToZero whether to clear the memory or just leave it uninitialised
|
||||||
|
*/
|
||||||
|
MemoryBlock (const size_t initialSize,
|
||||||
|
bool initialiseToZero = false);
|
||||||
|
|
||||||
|
/** Creates a copy of another memory block. */
|
||||||
|
MemoryBlock (const MemoryBlock& other);
|
||||||
|
|
||||||
|
/** Creates a memory block using a copy of a block of data.
|
||||||
|
|
||||||
|
@param dataToInitialiseFrom some data to copy into this block
|
||||||
|
@param sizeInBytes how much space to use
|
||||||
|
*/
|
||||||
|
MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~MemoryBlock() noexcept;
|
||||||
|
|
||||||
|
/** Copies another memory block onto this one.
|
||||||
|
|
||||||
|
This block will be resized and copied to exactly match the other one.
|
||||||
|
*/
|
||||||
|
MemoryBlock& operator= (const MemoryBlock& other);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
MemoryBlock (MemoryBlock&& other) noexcept;
|
||||||
|
MemoryBlock& operator= (MemoryBlock&& other) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares two memory blocks.
|
||||||
|
|
||||||
|
@returns true only if the two blocks are the same size and have identical contents.
|
||||||
|
*/
|
||||||
|
bool operator== (const MemoryBlock& other) const noexcept;
|
||||||
|
|
||||||
|
/** Compares two memory blocks.
|
||||||
|
|
||||||
|
@returns true if the two blocks are different sizes or have different contents.
|
||||||
|
*/
|
||||||
|
bool operator!= (const MemoryBlock& other) const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in.
|
||||||
|
*/
|
||||||
|
bool matches (const void* data, size_t dataSize) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a void pointer to the data.
|
||||||
|
|
||||||
|
Note that the pointer returned will probably become invalid when the
|
||||||
|
block is resized.
|
||||||
|
*/
|
||||||
|
void* getData() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a byte from the memory block.
|
||||||
|
|
||||||
|
This returns a reference, so you can also use it to set a byte.
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
char& operator[] (const Type offset) const noexcept { return data [offset]; }
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the block's current allocated size, in bytes. */
|
||||||
|
size_t getSize() const noexcept { return size; }
|
||||||
|
|
||||||
|
/** Resizes the memory block.
|
||||||
|
|
||||||
|
This will try to keep as much of the block's current content as it can,
|
||||||
|
and can optionally be made to clear any new space that gets allocated at
|
||||||
|
the end of the block.
|
||||||
|
|
||||||
|
@param newSize the new desired size for the block
|
||||||
|
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
|
||||||
|
whether to clear the new section or just leave it
|
||||||
|
uninitialised
|
||||||
|
@see ensureSize
|
||||||
|
*/
|
||||||
|
void setSize (const size_t newSize,
|
||||||
|
bool initialiseNewSpaceToZero = false);
|
||||||
|
|
||||||
|
/** Increases the block's size only if it's smaller than a given size.
|
||||||
|
|
||||||
|
@param minimumSize if the block is already bigger than this size, no action
|
||||||
|
will be taken; otherwise it will be increased to this size
|
||||||
|
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
|
||||||
|
whether to clear the new section or just leave it
|
||||||
|
uninitialised
|
||||||
|
@see setSize
|
||||||
|
*/
|
||||||
|
void ensureSize (const size_t minimumSize,
|
||||||
|
bool initialiseNewSpaceToZero = false);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Fills the entire memory block with a repeated byte value.
|
||||||
|
|
||||||
|
This is handy for clearing a block of memory to zero.
|
||||||
|
*/
|
||||||
|
void fillWith (uint8 valueToUse) noexcept;
|
||||||
|
|
||||||
|
/** Adds another block of data to the end of this one.
|
||||||
|
The data pointer must not be null. This block's size will be increased accordingly.
|
||||||
|
*/
|
||||||
|
void append (const void* data, size_t numBytes);
|
||||||
|
|
||||||
|
/** Resizes this block to the given size and fills its contents from the supplied buffer.
|
||||||
|
The data pointer must not be null.
|
||||||
|
*/
|
||||||
|
void replaceWith (const void* data, size_t numBytes);
|
||||||
|
|
||||||
|
/** Inserts some data into the block.
|
||||||
|
The dataToInsert pointer must not be null. This block's size will be increased accordingly.
|
||||||
|
If the insert position lies outside the valid range of the block, it will be clipped to
|
||||||
|
within the range before being used.
|
||||||
|
*/
|
||||||
|
void insert (const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
|
||||||
|
|
||||||
|
/** Chops out a section of the block.
|
||||||
|
|
||||||
|
This will remove a section of the memory block and close the gap around it,
|
||||||
|
shifting any subsequent data downwards and reducing the size of the block.
|
||||||
|
|
||||||
|
If the range specified goes beyond the size of the block, it will be clipped.
|
||||||
|
*/
|
||||||
|
void removeSection (size_t startByte, size_t numBytesToRemove);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Copies data into this MemoryBlock from a memory address.
|
||||||
|
|
||||||
|
@param srcData the memory location of the data to copy into this block
|
||||||
|
@param destinationOffset the offset in this block at which the data being copied should begin
|
||||||
|
@param numBytes how much to copy in (if this goes beyond the size of the memory block,
|
||||||
|
it will be clipped so not to do anything nasty)
|
||||||
|
*/
|
||||||
|
void copyFrom (const void* srcData,
|
||||||
|
int destinationOffset,
|
||||||
|
size_t numBytes) noexcept;
|
||||||
|
|
||||||
|
/** Copies data from this MemoryBlock to a memory address.
|
||||||
|
|
||||||
|
@param destData the memory location to write to
|
||||||
|
@param sourceOffset the offset within this block from which the copied data will be read
|
||||||
|
@param numBytes how much to copy (if this extends beyond the limits of the memory block,
|
||||||
|
zeros will be used for that portion of the data)
|
||||||
|
*/
|
||||||
|
void copyTo (void* destData,
|
||||||
|
int sourceOffset,
|
||||||
|
size_t numBytes) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Exchanges the contents of this and another memory block.
|
||||||
|
No actual copying is required for this, so it's very fast.
|
||||||
|
*/
|
||||||
|
void swapWith (MemoryBlock& other) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Parses a string of hexadecimal numbers and writes this data into the memory block.
|
||||||
|
|
||||||
|
The block will be resized to the number of valid bytes read from the string.
|
||||||
|
Non-hex characters in the string will be ignored.
|
||||||
|
|
||||||
|
@see String::toHexString()
|
||||||
|
*/
|
||||||
|
void loadFromHexString (const String& sourceHexString);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets a number of bits in the memory block, treating it as a long binary sequence. */
|
||||||
|
void setBitRange (size_t bitRangeStart,
|
||||||
|
size_t numBits,
|
||||||
|
int binaryNumberToApply) noexcept;
|
||||||
|
|
||||||
|
/** Reads a number of bits from the memory block, treating it as one long binary sequence */
|
||||||
|
int getBitRange (size_t bitRangeStart,
|
||||||
|
size_t numBitsToRead) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a string of characters that represent the binary contents of this block.
|
||||||
|
|
||||||
|
Uses a 64-bit encoding system to allow binary data to be turned into a string
|
||||||
|
of simple non-extended characters, e.g. for storage in XML.
|
||||||
|
|
||||||
|
@see fromBase64Encoding
|
||||||
|
*/
|
||||||
|
String toBase64Encoding() const;
|
||||||
|
|
||||||
|
/** Takes a string of encoded characters and turns it into binary data.
|
||||||
|
|
||||||
|
The string passed in must have been created by to64BitEncoding(), and this
|
||||||
|
block will be resized to recreate the original data block.
|
||||||
|
|
||||||
|
@see toBase64Encoding
|
||||||
|
*/
|
||||||
|
bool fromBase64Encoding (const String& encodedString);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
HeapBlock <char> data;
|
||||||
|
size_t size;
|
||||||
|
static const char* const encodingTable;
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (MemoryBlock)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_MEMORYBLOCK_BEASTHEADER
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||||
|
#define BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_ScopedPointer.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a pointer to an object which can optionally be deleted when this pointer
|
||||||
|
goes out of scope.
|
||||||
|
|
||||||
|
This acts in many ways like a ScopedPointer, but allows you to specify whether or
|
||||||
|
not the object is deleted.
|
||||||
|
|
||||||
|
@see ScopedPointer
|
||||||
|
*/
|
||||||
|
template <class ObjectType>
|
||||||
|
class OptionalScopedPointer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty OptionalScopedPointer. */
|
||||||
|
OptionalScopedPointer() : shouldDelete (false) {}
|
||||||
|
|
||||||
|
/** Creates an OptionalScopedPointer to point to a given object, and specifying whether
|
||||||
|
the OptionalScopedPointer will delete it.
|
||||||
|
|
||||||
|
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
|
||||||
|
deleting the object when it is itself deleted. If this parameter is false, then the
|
||||||
|
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
|
||||||
|
*/
|
||||||
|
OptionalScopedPointer (ObjectType* objectToHold, bool takeOwnership)
|
||||||
|
: object (objectToHold), shouldDelete (takeOwnership)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
||||||
|
|
||||||
|
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
||||||
|
as ownership of the managed object is transferred to this object.
|
||||||
|
|
||||||
|
The flag to indicate whether or not to delete the managed object is also
|
||||||
|
copied from the source object.
|
||||||
|
*/
|
||||||
|
OptionalScopedPointer (OptionalScopedPointer& objectToTransferFrom)
|
||||||
|
: object (objectToTransferFrom.release()),
|
||||||
|
shouldDelete (objectToTransferFrom.shouldDelete)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
||||||
|
|
||||||
|
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
||||||
|
as ownership of the managed object is transferred to this object.
|
||||||
|
|
||||||
|
The ownership flag that says whether or not to delete the managed object is also
|
||||||
|
copied from the source object.
|
||||||
|
*/
|
||||||
|
OptionalScopedPointer& operator= (OptionalScopedPointer& objectToTransferFrom)
|
||||||
|
{
|
||||||
|
if (object != objectToTransferFrom.object)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
object = objectToTransferFrom.object;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldDelete = objectToTransferFrom.shouldDelete;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The destructor may or may not delete the object that is being held, depending on the
|
||||||
|
takeOwnership flag that was specified when the object was first passed into an
|
||||||
|
OptionalScopedPointer constructor.
|
||||||
|
*/
|
||||||
|
~OptionalScopedPointer()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the object that this pointer is managing. */
|
||||||
|
inline operator ObjectType*() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer is managing. */
|
||||||
|
inline ObjectType* get() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer is managing. */
|
||||||
|
inline ObjectType& operator*() const noexcept { return *object; }
|
||||||
|
|
||||||
|
/** Lets you access methods and properties of the object that this pointer is holding. */
|
||||||
|
inline ObjectType* operator->() const noexcept { return object; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes the current object from this OptionalScopedPointer without deleting it.
|
||||||
|
This will return the current object, and set this OptionalScopedPointer to a null pointer.
|
||||||
|
*/
|
||||||
|
ObjectType* release() noexcept { return object.release(); }
|
||||||
|
|
||||||
|
/** Resets this pointer to null, possibly deleting the object that it holds, if it has
|
||||||
|
ownership of it.
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (! shouldDelete)
|
||||||
|
object.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes this OptionalScopedPointer point at a new object, specifying whether the
|
||||||
|
OptionalScopedPointer will take ownership of the object.
|
||||||
|
|
||||||
|
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
|
||||||
|
deleting the object when it is itself deleted. If this parameter is false, then the
|
||||||
|
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
|
||||||
|
*/
|
||||||
|
void set (ObjectType* newObject, bool takeOwnership)
|
||||||
|
{
|
||||||
|
if (object != newObject)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
object = newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldDelete = takeOwnership;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes this OptionalScopedPointer point at a new object, and take ownership of that object. */
|
||||||
|
void setOwned (ObjectType* newObject)
|
||||||
|
{
|
||||||
|
set (newObject, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes this OptionalScopedPointer point at a new object, but will not take ownership of that object. */
|
||||||
|
void setNonOwned (ObjectType* newObject)
|
||||||
|
{
|
||||||
|
set (newObject, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the target object will be deleted when this pointer
|
||||||
|
object is deleted.
|
||||||
|
*/
|
||||||
|
bool willDeleteObject() const noexcept { return shouldDelete; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps this object with another OptionalScopedPointer.
|
||||||
|
The two objects simply exchange their states.
|
||||||
|
*/
|
||||||
|
void swapWith (OptionalScopedPointer<ObjectType>& other) noexcept
|
||||||
|
{
|
||||||
|
object.swapWith (other.object);
|
||||||
|
std::swap (shouldDelete, other.shouldDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ScopedPointer<ObjectType> object;
|
||||||
|
bool shouldDelete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_OPTIONALSCOPEDPOINTER_BEASTHEADER
|
||||||
@@ -0,0 +1,395 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||||
|
#define BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_Atomic.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Adds reference-counting to an object.
|
||||||
|
|
||||||
|
To add reference-counting to a class, derive it from this class, and
|
||||||
|
use the ReferenceCountedObjectPtr class to point to it.
|
||||||
|
|
||||||
|
e.g. @code
|
||||||
|
class MyClass : public ReferenceCountedObject
|
||||||
|
{
|
||||||
|
void foo();
|
||||||
|
|
||||||
|
// This is a neat way of declaring a typedef for a pointer class,
|
||||||
|
// rather than typing out the full templated name each time..
|
||||||
|
typedef ReferenceCountedObjectPtr<MyClass> Ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
MyClass::Ptr p = new MyClass();
|
||||||
|
MyClass::Ptr p2 = p;
|
||||||
|
p = nullptr;
|
||||||
|
p2->foo();
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Once a new ReferenceCountedObject has been assigned to a pointer, be
|
||||||
|
careful not to delete the object manually.
|
||||||
|
|
||||||
|
This class uses an Atomic<int> value to hold the reference count, so that it
|
||||||
|
the pointers can be passed between threads safely. For a faster but non-thread-safe
|
||||||
|
version, use SingleThreadedReferenceCountedObject instead.
|
||||||
|
|
||||||
|
@see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
|
||||||
|
*/
|
||||||
|
class BEAST_API ReferenceCountedObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Increments the object's reference count.
|
||||||
|
|
||||||
|
This is done automatically by the smart pointer, but is public just
|
||||||
|
in case it's needed for nefarious purposes.
|
||||||
|
*/
|
||||||
|
inline void incReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
++refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decreases the object's reference count.
|
||||||
|
|
||||||
|
If the count gets to zero, the object will be deleted.
|
||||||
|
*/
|
||||||
|
inline void decReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
bassert (getReferenceCount() > 0);
|
||||||
|
|
||||||
|
if (--refCount == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the object's current reference count. */
|
||||||
|
inline int getReferenceCount() const noexcept { return refCount.get(); }
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates the reference-counted object (with an initial ref count of zero). */
|
||||||
|
ReferenceCountedObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~ReferenceCountedObject()
|
||||||
|
{
|
||||||
|
// it's dangerous to delete an object that's still referenced by something else!
|
||||||
|
bassert (getReferenceCount() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resets the reference count to zero without deleting the object.
|
||||||
|
You should probably never need to use this!
|
||||||
|
*/
|
||||||
|
void resetReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
refCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
Atomic <int> refCount;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (ReferenceCountedObject)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Adds reference-counting to an object.
|
||||||
|
|
||||||
|
This is effectively a version of the ReferenceCountedObject class, but which
|
||||||
|
uses a non-atomic counter, and so is not thread-safe (but which will be more
|
||||||
|
efficient).
|
||||||
|
For more details on how to use it, see the ReferenceCountedObject class notes.
|
||||||
|
|
||||||
|
@see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
|
||||||
|
*/
|
||||||
|
class BEAST_API SingleThreadedReferenceCountedObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Increments the object's reference count.
|
||||||
|
|
||||||
|
This is done automatically by the smart pointer, but is public just
|
||||||
|
in case it's needed for nefarious purposes.
|
||||||
|
*/
|
||||||
|
inline void incReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
++refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decreases the object's reference count.
|
||||||
|
|
||||||
|
If the count gets to zero, the object will be deleted.
|
||||||
|
*/
|
||||||
|
inline void decReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
bassert (getReferenceCount() > 0);
|
||||||
|
|
||||||
|
if (--refCount == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the object's current reference count. */
|
||||||
|
inline int getReferenceCount() const noexcept { return refCount; }
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates the reference-counted object (with an initial ref count of zero). */
|
||||||
|
SingleThreadedReferenceCountedObject() : refCount (0) {}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~SingleThreadedReferenceCountedObject()
|
||||||
|
{
|
||||||
|
// it's dangerous to delete an object that's still referenced by something else!
|
||||||
|
bassert (getReferenceCount() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
int refCount;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (SingleThreadedReferenceCountedObject)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A smart-pointer class which points to a reference-counted object.
|
||||||
|
|
||||||
|
The template parameter specifies the class of the object you want to point to - the easiest
|
||||||
|
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject,
|
||||||
|
but if you need to, you could roll your own reference-countable class by implementing a pair of
|
||||||
|
mathods called incReferenceCount() and decReferenceCount().
|
||||||
|
|
||||||
|
When using this class, you'll probably want to create a typedef to abbreviate the full
|
||||||
|
templated name - e.g.
|
||||||
|
@code typedef ReferenceCountedObjectPtr<MyClass> MyClassPtr;@endcode
|
||||||
|
|
||||||
|
@see ReferenceCountedObject, ReferenceCountedObjectArray
|
||||||
|
*/
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
class ReferenceCountedObjectPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The class being referenced by this pointer. */
|
||||||
|
typedef ReferenceCountedObjectClass ReferencedType;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a pointer to a null object. */
|
||||||
|
inline ReferenceCountedObjectPtr() noexcept
|
||||||
|
: referencedObject (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a pointer to an object.
|
||||||
|
|
||||||
|
This will increment the object's reference-count if it is non-null.
|
||||||
|
*/
|
||||||
|
inline ReferenceCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) noexcept
|
||||||
|
: referencedObject (refCountedObject)
|
||||||
|
{
|
||||||
|
if (refCountedObject != nullptr)
|
||||||
|
refCountedObject->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another pointer.
|
||||||
|
This will increment the object's reference-count (if it is non-null).
|
||||||
|
*/
|
||||||
|
inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
|
||||||
|
: referencedObject (other.referencedObject)
|
||||||
|
{
|
||||||
|
if (referencedObject != nullptr)
|
||||||
|
referencedObject->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
/** Takes-over the object from another pointer. */
|
||||||
|
inline ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
|
||||||
|
: referencedObject (other.referencedObject)
|
||||||
|
{
|
||||||
|
other.referencedObject = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Copies another pointer.
|
||||||
|
This will increment the object's reference-count (if it is non-null).
|
||||||
|
*/
|
||||||
|
template <class DerivedClass>
|
||||||
|
inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<DerivedClass>& other) noexcept
|
||||||
|
: referencedObject (static_cast <ReferenceCountedObjectClass*> (other.get()))
|
||||||
|
{
|
||||||
|
if (referencedObject != nullptr)
|
||||||
|
referencedObject->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes this pointer to point at a different object.
|
||||||
|
|
||||||
|
The reference count of the old object is decremented, and it might be
|
||||||
|
deleted if it hits zero. The new object's count is incremented.
|
||||||
|
*/
|
||||||
|
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
|
||||||
|
{
|
||||||
|
return operator= (other.referencedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes this pointer to point at a different object.
|
||||||
|
|
||||||
|
The reference count of the old object is decremented, and it might be
|
||||||
|
deleted if it hits zero. The new object's count is incremented.
|
||||||
|
*/
|
||||||
|
template <class DerivedClass>
|
||||||
|
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<DerivedClass>& other)
|
||||||
|
{
|
||||||
|
return operator= (static_cast <ReferenceCountedObjectClass*> (other.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
/** Takes-over the object from another pointer. */
|
||||||
|
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other)
|
||||||
|
{
|
||||||
|
std::swap (referencedObject, other.referencedObject);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Changes this pointer to point at a different object.
|
||||||
|
|
||||||
|
The reference count of the old object is decremented, and it might be
|
||||||
|
deleted if it hits zero. The new object's count is incremented.
|
||||||
|
*/
|
||||||
|
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectClass* const newObject)
|
||||||
|
{
|
||||||
|
if (referencedObject != newObject)
|
||||||
|
{
|
||||||
|
if (newObject != nullptr)
|
||||||
|
newObject->incReferenceCount();
|
||||||
|
|
||||||
|
ReferenceCountedObjectClass* const oldObject = referencedObject;
|
||||||
|
referencedObject = newObject;
|
||||||
|
|
||||||
|
if (oldObject != nullptr)
|
||||||
|
oldObject->decReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
|
||||||
|
This will decrement the object's reference-count, and may delete it if it
|
||||||
|
gets to zero.
|
||||||
|
*/
|
||||||
|
inline ~ReferenceCountedObjectPtr()
|
||||||
|
{
|
||||||
|
if (referencedObject != nullptr)
|
||||||
|
referencedObject->decReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the object that this pointer references.
|
||||||
|
The pointer returned may be zero, of course.
|
||||||
|
*/
|
||||||
|
inline operator ReferenceCountedObjectClass*() const noexcept
|
||||||
|
{
|
||||||
|
return referencedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the -> operator is called on the referenced object
|
||||||
|
inline ReferenceCountedObjectClass* operator->() const noexcept
|
||||||
|
{
|
||||||
|
return referencedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the object that this pointer references.
|
||||||
|
The pointer returned may be zero, of course.
|
||||||
|
*/
|
||||||
|
inline ReferenceCountedObjectClass* get() const noexcept
|
||||||
|
{
|
||||||
|
return referencedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the object that this pointer references.
|
||||||
|
The pointer returned may be zero, of course.
|
||||||
|
*/
|
||||||
|
inline ReferenceCountedObjectClass* getObject() const noexcept
|
||||||
|
{
|
||||||
|
return referencedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ReferenceCountedObjectClass* referencedObject;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() == object2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() == object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator== (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1 == object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() != object2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() != object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator!= (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1 != object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_REFERENCECOUNTEDOBJECT_BEASTHEADER
|
||||||
@@ -1,41 +1,132 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef BEAST_SCOPEDPOINTER_BEASTHEADER
|
#ifndef BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||||
#define BEAST_SCOPEDPOINTER_BEASTHEADER
|
#define BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
This class holds a pointer which is automatically deleted when this object goes
|
||||||
|
out of scope.
|
||||||
|
|
||||||
|
Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer
|
||||||
|
gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or
|
||||||
|
as member variables is a good way to use RAII to avoid accidentally leaking dynamically
|
||||||
|
created objects.
|
||||||
|
|
||||||
|
A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer
|
||||||
|
to an object. If you use the assignment operator to assign a different object to a
|
||||||
|
ScopedPointer, the old one will be automatically deleted.
|
||||||
|
|
||||||
|
Important note: The class is designed to hold a pointer to an object, NOT to an array!
|
||||||
|
It calls delete on its payload, not delete[], so do not give it an array to hold! For
|
||||||
|
that kind of purpose, you should be using HeapBlock or Array instead.
|
||||||
|
|
||||||
|
A const ScopedPointer is guaranteed not to lose ownership of its object or change the
|
||||||
|
object to which it points during its lifetime. This means that making a copy of a const
|
||||||
|
ScopedPointer is impossible, as that would involve the new copy taking ownership from the
|
||||||
|
old one.
|
||||||
|
|
||||||
|
If you need to get a pointer out of a ScopedPointer without it being deleted, you
|
||||||
|
can use the release() method.
|
||||||
|
|
||||||
|
Something to note is the main difference between this class and the std::auto_ptr class,
|
||||||
|
which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr
|
||||||
|
requires that you always call get() to retrieve the pointer. The advantages of providing
|
||||||
|
the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much
|
||||||
|
exactly the same way as a raw pointer. The disadvantage is that the compiler is free to
|
||||||
|
use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult
|
||||||
|
to return a ScopedPointer as the result of a function. To avoid this causing errors,
|
||||||
|
ScopedPointer contains an overloaded constructor that should cause a syntax error in these
|
||||||
|
circumstances, but it does mean that instead of returning a ScopedPointer from a function,
|
||||||
|
you'd need to return a raw pointer (or use a std::auto_ptr instead).
|
||||||
|
*/
|
||||||
template <class ObjectType>
|
template <class ObjectType>
|
||||||
class ScopedPointer
|
class ScopedPointer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
inline ScopedPointer() : object (0)
|
//==============================================================================
|
||||||
|
/** Creates a ScopedPointer containing a null pointer. */
|
||||||
|
inline ScopedPointer() noexcept : object (nullptr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ScopedPointer (ObjectType* const objectToTakePossessionOf)
|
/** Creates a ScopedPointer that owns the specified object. */
|
||||||
|
inline ScopedPointer (ObjectType* const objectToTakePossessionOf) noexcept
|
||||||
: object (objectToTakePossessionOf)
|
: object (objectToTakePossessionOf)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopedPointer (ScopedPointer& objectToTransferFrom)
|
/** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
|
||||||
|
|
||||||
|
Because a pointer can only belong to one ScopedPointer, this transfers
|
||||||
|
the pointer from the other object to this one, and the other object is reset to
|
||||||
|
be a null pointer.
|
||||||
|
*/
|
||||||
|
ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept
|
||||||
: object (objectToTransferFrom.object)
|
: object (objectToTransferFrom.object)
|
||||||
{
|
{
|
||||||
objectToTransferFrom.object = 0;
|
objectToTransferFrom.object = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
This will delete the object that this ScopedPointer currently refers to.
|
||||||
|
*/
|
||||||
inline ~ScopedPointer() { delete object; }
|
inline ~ScopedPointer() { delete object; }
|
||||||
|
|
||||||
|
/** Changes this ScopedPointer to point to a new object.
|
||||||
|
|
||||||
|
Because a pointer can only belong to one ScopedPointer, this transfers
|
||||||
|
the pointer from the other object to this one, and the other object is reset to
|
||||||
|
be a null pointer.
|
||||||
|
|
||||||
|
If this ScopedPointer already points to an object, that object
|
||||||
|
will first be deleted.
|
||||||
|
*/
|
||||||
ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
|
ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
|
||||||
{
|
{
|
||||||
if (this != objectToTransferFrom.getAddress())
|
if (this != objectToTransferFrom.getAddress())
|
||||||
{
|
{
|
||||||
|
// Two ScopedPointers should never be able to refer to the same object - if
|
||||||
|
// this happens, you must have done something dodgy!
|
||||||
|
bassert (object == nullptr || object != objectToTransferFrom.object);
|
||||||
|
|
||||||
ObjectType* const oldObject = object;
|
ObjectType* const oldObject = object;
|
||||||
object = objectToTransferFrom.object;
|
object = objectToTransferFrom.object;
|
||||||
objectToTransferFrom.object = 0;
|
objectToTransferFrom.object = nullptr;
|
||||||
delete oldObject;
|
delete oldObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Changes this ScopedPointer to point to a new object.
|
||||||
|
|
||||||
|
If this ScopedPointer already points to an object, that object
|
||||||
|
will first be deleted.
|
||||||
|
|
||||||
|
The pointer that you pass in may be a nullptr.
|
||||||
|
*/
|
||||||
ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf)
|
ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf)
|
||||||
{
|
{
|
||||||
if (object != newObjectToTakePossessionOf)
|
if (object != newObjectToTakePossessionOf)
|
||||||
@@ -48,39 +139,110 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline operator ObjectType*() const { return object; }
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
inline ObjectType* get() const { return object; }
|
ScopedPointer (ScopedPointer&& other) noexcept
|
||||||
inline ObjectType& operator*() const { return *object; }
|
: object (other.object)
|
||||||
inline ObjectType* operator->() const { return object; }
|
|
||||||
|
|
||||||
ObjectType* release() { ObjectType* const o = object; object = 0; return o; }
|
|
||||||
|
|
||||||
void swapWith (ScopedPointer <ObjectType>& other)
|
|
||||||
{
|
{
|
||||||
|
other.object = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedPointer& operator= (ScopedPointer&& other) noexcept
|
||||||
|
{
|
||||||
|
object = other.object;
|
||||||
|
other.object = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the object that this ScopedPointer refers to. */
|
||||||
|
inline operator ObjectType*() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this ScopedPointer refers to. */
|
||||||
|
inline ObjectType* get() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this ScopedPointer refers to. */
|
||||||
|
inline ObjectType& operator*() const noexcept { return *object; }
|
||||||
|
|
||||||
|
/** Lets you access methods and properties of the object that this ScopedPointer refers to. */
|
||||||
|
inline ObjectType* operator->() const noexcept { return object; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes the current object from this ScopedPointer without deleting it.
|
||||||
|
This will return the current object, and set the ScopedPointer to a null pointer.
|
||||||
|
*/
|
||||||
|
ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps this object with that of another ScopedPointer.
|
||||||
|
The two objects simply exchange their pointers.
|
||||||
|
*/
|
||||||
|
void swapWith (ScopedPointer <ObjectType>& other) noexcept
|
||||||
|
{
|
||||||
|
// Two ScopedPointers should never be able to refer to the same object - if
|
||||||
|
// this happens, you must have done something dodgy!
|
||||||
|
bassert (object != other.object || this == other.getAddress());
|
||||||
|
|
||||||
std::swap (object, other.object);
|
std::swap (object, other.object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** If the pointer is non-null, this will attempt to return a new copy of the object that is pointed to.
|
||||||
|
If the pointer is null, this will safely return a nullptr.
|
||||||
|
*/
|
||||||
|
inline ObjectType* createCopy() const { return createCopyIfNotNull (object); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
//==============================================================================
|
||||||
ObjectType* object;
|
ObjectType* object;
|
||||||
|
|
||||||
const ScopedPointer* getAddress() const { return this; }
|
// (Required as an alternative to the overloaded & operator).
|
||||||
|
const ScopedPointer* getAddress() const noexcept { return this; }
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#if ! BEAST_MSVC // (MSVC can't deal with multiple copy constructors)
|
||||||
ScopedPointer (const ScopedPointer&);
|
/* The copy constructors are private to stop people accidentally copying a const ScopedPointer
|
||||||
ScopedPointer& operator= (const ScopedPointer&);
|
(the compiler would let you do so by implicitly casting the source to its raw object pointer).
|
||||||
|
|
||||||
|
A side effect of this is that in a compiler that doesn't support C++11, you may hit an
|
||||||
|
error when you write something like this:
|
||||||
|
|
||||||
|
ScopedPointer<MyClass> m = new MyClass(); // Compile error: copy constructor is private.
|
||||||
|
|
||||||
|
Even though the compiler would normally ignore the assignment here, it can't do so when the
|
||||||
|
copy constructor is private. It's very easy to fix though - just write it like this:
|
||||||
|
|
||||||
|
ScopedPointer<MyClass> m (new MyClass()); // Compiles OK
|
||||||
|
|
||||||
|
It's probably best to use the latter form when writing your object declarations anyway, as
|
||||||
|
this is a better representation of the code that you actually want the compiler to produce.
|
||||||
|
*/
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (ScopedPointer)
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares a ScopedPointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
template <class ObjectType>
|
template <class ObjectType>
|
||||||
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2)
|
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||||
{
|
{
|
||||||
return static_cast <ObjectType*> (pointer1) == pointer2;
|
return static_cast <ObjectType*> (pointer1) == pointer2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Compares a ScopedPointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
template <class ObjectType>
|
template <class ObjectType>
|
||||||
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2)
|
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||||
{
|
{
|
||||||
return static_cast <ObjectType*> (pointer1) != pointer2;
|
return static_cast <ObjectType*> (pointer1) != pointer2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
// NB: This is just here to prevent any silly attempts to call deleteAndZero() on a ScopedPointer.
|
||||||
|
template <typename Type>
|
||||||
|
void deleteAndZero (ScopedPointer<Type>&) { static_bassert (sizeof (Type) == 12345); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // BEAST_SCOPEDPOINTER_BEASTHEADER
|
||||||
|
|||||||
287
Subtrees/beast/modules/beast_core/memory/beast_Singleton.h
Normal file
287
Subtrees/beast/modules/beast_core/memory/beast_Singleton.h
Normal file
@@ -0,0 +1,287 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_SINGLETON_BEASTHEADER
|
||||||
|
#define BEAST_SINGLETON_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Macro to declare member variables and methods for a singleton class.
|
||||||
|
|
||||||
|
To use this, add the line beast_DeclareSingleton (MyClass, doNotRecreateAfterDeletion)
|
||||||
|
to the class's definition.
|
||||||
|
|
||||||
|
Then put a macro beast_ImplementSingleton (MyClass) along with the class's
|
||||||
|
implementation code.
|
||||||
|
|
||||||
|
It's also a very good idea to also add the call clearSingletonInstance() in your class's
|
||||||
|
destructor, in case it is deleted by other means than deleteInstance()
|
||||||
|
|
||||||
|
Clients can then call the static method MyClass::getInstance() to get a pointer
|
||||||
|
to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if
|
||||||
|
no instance currently exists.
|
||||||
|
|
||||||
|
e.g. @code
|
||||||
|
|
||||||
|
class MySingleton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MySingleton()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~MySingleton()
|
||||||
|
{
|
||||||
|
// this ensures that no dangling pointers are left when the
|
||||||
|
// singleton is deleted.
|
||||||
|
clearSingletonInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
beast_DeclareSingleton (MySingleton, false)
|
||||||
|
};
|
||||||
|
|
||||||
|
beast_ImplementSingleton (MySingleton)
|
||||||
|
|
||||||
|
|
||||||
|
// example of usage:
|
||||||
|
MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created).
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
|
||||||
|
than once during the process's lifetime - i.e. after you've created and deleted the
|
||||||
|
object, getInstance() will refuse to create another one. This can be useful to stop
|
||||||
|
objects being accidentally re-created during your app's shutdown code.
|
||||||
|
|
||||||
|
If you know that your object will only be created and deleted by a single thread, you
|
||||||
|
can use the slightly more efficient beast_DeclareSingleton_SingleThreaded() macro instead
|
||||||
|
of this one.
|
||||||
|
|
||||||
|
@see beast_ImplementSingleton, beast_DeclareSingleton_SingleThreaded
|
||||||
|
*/
|
||||||
|
#define beast_DeclareSingleton(classname, doNotRecreateAfterDeletion) \
|
||||||
|
\
|
||||||
|
static classname* _singletonInstance; \
|
||||||
|
static beast::CriticalSection _singletonLock; \
|
||||||
|
\
|
||||||
|
static classname* BEAST_CALLTYPE getInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
{\
|
||||||
|
const beast::ScopedLock sl (_singletonLock); \
|
||||||
|
\
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
{ \
|
||||||
|
static bool alreadyInside = false; \
|
||||||
|
static bool createdOnceAlready = false; \
|
||||||
|
\
|
||||||
|
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
||||||
|
bassert (! problem); \
|
||||||
|
if (! problem) \
|
||||||
|
{ \
|
||||||
|
createdOnceAlready = true; \
|
||||||
|
alreadyInside = true; \
|
||||||
|
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
||||||
|
alreadyInside = false; \
|
||||||
|
\
|
||||||
|
_singletonInstance = newObject; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline classname* BEAST_CALLTYPE getInstanceWithoutCreating() noexcept\
|
||||||
|
{ \
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void BEAST_CALLTYPE deleteInstance() \
|
||||||
|
{ \
|
||||||
|
const beast::ScopedLock sl (_singletonLock); \
|
||||||
|
if (_singletonInstance != nullptr) \
|
||||||
|
{ \
|
||||||
|
classname* const old = _singletonInstance; \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
delete old; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void clearSingletonInstance() noexcept\
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == this) \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This is a counterpart to the beast_DeclareSingleton macro.
|
||||||
|
|
||||||
|
After adding the beast_DeclareSingleton to the class definition, this macro has
|
||||||
|
to be used in the cpp file.
|
||||||
|
*/
|
||||||
|
#define beast_ImplementSingleton(classname) \
|
||||||
|
\
|
||||||
|
classname* classname::_singletonInstance = nullptr; \
|
||||||
|
beast::CriticalSection classname::_singletonLock;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Macro to declare member variables and methods for a singleton class.
|
||||||
|
|
||||||
|
This is exactly the same as beast_DeclareSingleton, but doesn't use a critical
|
||||||
|
section to make access to it thread-safe. If you know that your object will
|
||||||
|
only ever be created or deleted by a single thread, then this is a
|
||||||
|
more efficient version to use.
|
||||||
|
|
||||||
|
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
|
||||||
|
than once during the process's lifetime - i.e. after you've created and deleted the
|
||||||
|
object, getInstance() will refuse to create another one. This can be useful to stop
|
||||||
|
objects being accidentally re-created during your app's shutdown code.
|
||||||
|
|
||||||
|
See the documentation for beast_DeclareSingleton for more information about
|
||||||
|
how to use it, the only difference being that you have to use
|
||||||
|
beast_ImplementSingleton_SingleThreaded instead of beast_ImplementSingleton.
|
||||||
|
|
||||||
|
@see beast_ImplementSingleton_SingleThreaded, beast_DeclareSingleton, beast_DeclareSingleton_SingleThreaded_Minimal
|
||||||
|
*/
|
||||||
|
#define beast_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \
|
||||||
|
\
|
||||||
|
static classname* _singletonInstance; \
|
||||||
|
\
|
||||||
|
static classname* getInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
{ \
|
||||||
|
static bool alreadyInside = false; \
|
||||||
|
static bool createdOnceAlready = false; \
|
||||||
|
\
|
||||||
|
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
||||||
|
bassert (! problem); \
|
||||||
|
if (! problem) \
|
||||||
|
{ \
|
||||||
|
createdOnceAlready = true; \
|
||||||
|
alreadyInside = true; \
|
||||||
|
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
||||||
|
alreadyInside = false; \
|
||||||
|
\
|
||||||
|
_singletonInstance = newObject; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline classname* getInstanceWithoutCreating() noexcept\
|
||||||
|
{ \
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void deleteInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance != nullptr) \
|
||||||
|
{ \
|
||||||
|
classname* const old = _singletonInstance; \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
delete old; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void clearSingletonInstance() noexcept\
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == this) \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Macro to declare member variables and methods for a singleton class.
|
||||||
|
|
||||||
|
This is like beast_DeclareSingleton_SingleThreaded, but doesn't do any checking
|
||||||
|
for recursion or repeated instantiation. It's intended for use as a lightweight
|
||||||
|
version of a singleton, where you're using it in very straightforward
|
||||||
|
circumstances and don't need the extra checking.
|
||||||
|
|
||||||
|
Beast use the normal beast_ImplementSingleton_SingleThreaded as the counterpart
|
||||||
|
to this declaration, as you would with beast_DeclareSingleton_SingleThreaded.
|
||||||
|
|
||||||
|
See the documentation for beast_DeclareSingleton for more information about
|
||||||
|
how to use it, the only difference being that you have to use
|
||||||
|
beast_ImplementSingleton_SingleThreaded instead of beast_ImplementSingleton.
|
||||||
|
|
||||||
|
@see beast_ImplementSingleton_SingleThreaded, beast_DeclareSingleton
|
||||||
|
*/
|
||||||
|
#define beast_DeclareSingleton_SingleThreaded_Minimal(classname) \
|
||||||
|
\
|
||||||
|
static classname* _singletonInstance; \
|
||||||
|
\
|
||||||
|
static classname* getInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
_singletonInstance = new classname(); \
|
||||||
|
\
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline classname* getInstanceWithoutCreating() noexcept\
|
||||||
|
{ \
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void deleteInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance != nullptr) \
|
||||||
|
{ \
|
||||||
|
classname* const old = _singletonInstance; \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
delete old; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void clearSingletonInstance() noexcept\
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == this) \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This is a counterpart to the beast_DeclareSingleton_SingleThreaded macro.
|
||||||
|
|
||||||
|
After adding beast_DeclareSingleton_SingleThreaded or beast_DeclareSingleton_SingleThreaded_Minimal
|
||||||
|
to the class definition, this macro has to be used somewhere in the cpp file.
|
||||||
|
*/
|
||||||
|
#define beast_ImplementSingleton_SingleThreaded(classname) \
|
||||||
|
\
|
||||||
|
classname* classname::_singletonInstance = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_SINGLETON_BEASTHEADER
|
||||||
209
Subtrees/beast/modules/beast_core/memory/beast_WeakReference.h
Normal file
209
Subtrees/beast/modules/beast_core/memory/beast_WeakReference.h
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_WEAKREFERENCE_BEASTHEADER
|
||||||
|
#define BEAST_WEAKREFERENCE_BEASTHEADER
|
||||||
|
|
||||||
|
#include "beast_ReferenceCountedObject.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
This class acts as a pointer which will automatically become null if the object
|
||||||
|
to which it points is deleted.
|
||||||
|
|
||||||
|
To accomplish this, the source object needs to cooperate by performing a couple of simple tasks.
|
||||||
|
It must embed a WeakReference::Master object, which stores a shared pointer object, and must clear
|
||||||
|
this master pointer in its destructor.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
@code
|
||||||
|
class MyObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyObject()
|
||||||
|
{
|
||||||
|
// If you're planning on using your WeakReferences in a multi-threaded situation, you may choose
|
||||||
|
// to create a WeakReference to the object here in the constructor, which will pre-initialise the
|
||||||
|
// embedded object, avoiding an (extremely unlikely) race condition that could occur if multiple
|
||||||
|
// threads overlap while creating the first WeakReference to it.
|
||||||
|
}
|
||||||
|
|
||||||
|
~MyObject()
|
||||||
|
{
|
||||||
|
// This will zero all the references - you need to call this in your destructor.
|
||||||
|
masterReference.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// You need to embed a variable of this type, with the name "masterReference" inside your object. If the
|
||||||
|
// variable is not public, you should make your class a friend of WeakReference<MyObject> so that the
|
||||||
|
// WeakReference class can access it.
|
||||||
|
WeakReference<MyObject>::Master masterReference;
|
||||||
|
friend class WeakReference<MyObject>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Here's an example of using a pointer..
|
||||||
|
|
||||||
|
MyObject* n = new MyObject();
|
||||||
|
WeakReference<MyObject> myObjectRef = n;
|
||||||
|
|
||||||
|
MyObject* pointer1 = myObjectRef; // returns a valid pointer to 'n'
|
||||||
|
delete n;
|
||||||
|
MyObject* pointer2 = myObjectRef; // returns a null pointer
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see WeakReference::Master
|
||||||
|
*/
|
||||||
|
template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject>
|
||||||
|
class WeakReference
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates a null SafePointer. */
|
||||||
|
inline WeakReference() noexcept {}
|
||||||
|
|
||||||
|
/** Creates a WeakReference that points at the given object. */
|
||||||
|
WeakReference (ObjectType* const object) : holder (getRef (object)) {}
|
||||||
|
|
||||||
|
/** Creates a copy of another WeakReference. */
|
||||||
|
WeakReference (const WeakReference& other) noexcept : holder (other.holder) {}
|
||||||
|
|
||||||
|
/** Copies another pointer to this one. */
|
||||||
|
WeakReference& operator= (const WeakReference& other) { holder = other.holder; return *this; }
|
||||||
|
|
||||||
|
/** Copies another pointer to this one. */
|
||||||
|
WeakReference& operator= (ObjectType* const newObject) { holder = getRef (newObject); return *this; }
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
WeakReference (WeakReference&& other) noexcept : holder (static_cast <SharedRef&&> (other.holder)) {}
|
||||||
|
WeakReference& operator= (WeakReference&& other) noexcept { holder = static_cast <SharedRef&&> (other.holder); return *this; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
ObjectType* get() const noexcept { return holder != nullptr ? holder->get() : nullptr; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
operator ObjectType*() const noexcept { return get(); }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
ObjectType* operator->() noexcept { return get(); }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
const ObjectType* operator->() const noexcept { return get(); }
|
||||||
|
|
||||||
|
/** This returns true if this reference has been pointing at an object, but that object has
|
||||||
|
since been deleted.
|
||||||
|
|
||||||
|
If this reference was only ever pointing at a null pointer, this will return false. Using
|
||||||
|
operator=() to make this refer to a different object will reset this flag to match the status
|
||||||
|
of the reference from which you're copying.
|
||||||
|
*/
|
||||||
|
bool wasObjectDeleted() const noexcept { return holder != nullptr && holder->get() == nullptr; }
|
||||||
|
|
||||||
|
bool operator== (ObjectType* const object) const noexcept { return get() == object; }
|
||||||
|
bool operator!= (ObjectType* const object) const noexcept { return get() != object; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This class is used internally by the WeakReference class - don't use it directly
|
||||||
|
in your code!
|
||||||
|
@see WeakReference
|
||||||
|
*/
|
||||||
|
class SharedPointer : public ReferenceCountingType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SharedPointer (ObjectType* const obj) noexcept : owner (obj) {}
|
||||||
|
|
||||||
|
inline ObjectType* get() const noexcept { return owner; }
|
||||||
|
void clearPointer() noexcept { owner = nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ObjectType* volatile owner;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (SharedPointer)
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ReferenceCountedObjectPtr<SharedPointer> SharedRef;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
This class is embedded inside an object to which you want to attach WeakReference pointers.
|
||||||
|
See the WeakReference class notes for an example of how to use this class.
|
||||||
|
@see WeakReference
|
||||||
|
*/
|
||||||
|
class Master
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Master() noexcept {}
|
||||||
|
|
||||||
|
~Master()
|
||||||
|
{
|
||||||
|
// You must remember to call clear() in your source object's destructor! See the notes
|
||||||
|
// for the WeakReference class for an example of how to do this.
|
||||||
|
bassert (sharedPointer == nullptr || sharedPointer->get() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The first call to this method will create an internal object that is shared by all weak
|
||||||
|
references to the object.
|
||||||
|
*/
|
||||||
|
SharedPointer* getSharedPointer (ObjectType* const object)
|
||||||
|
{
|
||||||
|
if (sharedPointer == nullptr)
|
||||||
|
{
|
||||||
|
sharedPointer = new SharedPointer (object);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// You're trying to create a weak reference to an object that has already been deleted!!
|
||||||
|
bassert (sharedPointer->get() != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sharedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The object that owns this master pointer should call this before it gets destroyed,
|
||||||
|
to zero all the references to this object that may be out there. See the WeakReference
|
||||||
|
class notes for an example of how to do this.
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (sharedPointer != nullptr)
|
||||||
|
sharedPointer->clearPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedRef sharedPointer;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (Master)
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedRef holder;
|
||||||
|
|
||||||
|
static inline SharedPointer* getRef (ObjectType* const o)
|
||||||
|
{
|
||||||
|
return (o != nullptr) ? o->masterReference.getSharedPointer (o) : nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_WEAKREFERENCE_BEASTHEADER
|
||||||
81
Subtrees/beast/modules/beast_core/misc/beast_Result.cpp
Normal file
81
Subtrees/beast/modules/beast_core/misc/beast_Result.cpp
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
Result::Result (const String& message) noexcept
|
||||||
|
: errorMessage (message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result::Result (const Result& other)
|
||||||
|
: errorMessage (other.errorMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result& Result::operator= (const Result& other)
|
||||||
|
{
|
||||||
|
errorMessage = other.errorMessage;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
Result::Result (Result&& other) noexcept
|
||||||
|
: errorMessage (static_cast <String&&> (other.errorMessage))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result& Result::operator= (Result&& other) noexcept
|
||||||
|
{
|
||||||
|
errorMessage = static_cast <String&&> (other.errorMessage);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool Result::operator== (const Result& other) const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage == other.errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::operator!= (const Result& other) const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage != other.errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Result::ok() noexcept
|
||||||
|
{
|
||||||
|
return Result (String::empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Result::fail (const String& errorMessage) noexcept
|
||||||
|
{
|
||||||
|
return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const String& Result::getErrorMessage() const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); }
|
||||||
|
Result::operator bool() const noexcept { return errorMessage.isEmpty(); }
|
||||||
|
bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); }
|
||||||
|
bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); }
|
||||||
119
Subtrees/beast/modules/beast_core/misc/beast_Result.h
Normal file
119
Subtrees/beast/modules/beast_core/misc/beast_Result.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_RESULT_BEASTHEADER
|
||||||
|
#define BEAST_RESULT_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_String.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents the 'success' or 'failure' of an operation, and holds an associated
|
||||||
|
error message to describe the error when there's a failure.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
@code
|
||||||
|
Result myOperation()
|
||||||
|
{
|
||||||
|
if (doSomeKindOfFoobar())
|
||||||
|
return Result::ok();
|
||||||
|
else
|
||||||
|
return Result::fail ("foobar didn't work!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Result result (myOperation());
|
||||||
|
|
||||||
|
if (result.wasOk())
|
||||||
|
{
|
||||||
|
...it's all good...
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warnUserAboutFailure ("The foobar operation failed! Error message was: "
|
||||||
|
+ result.getErrorMessage());
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
class BEAST_API Result
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates and returns a 'successful' result. */
|
||||||
|
static Result ok() noexcept;
|
||||||
|
|
||||||
|
/** Creates a 'failure' result.
|
||||||
|
If you pass a blank error message in here, a default "Unknown Error" message
|
||||||
|
will be used instead.
|
||||||
|
*/
|
||||||
|
static Result fail (const String& errorMessage) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if this result indicates a success. */
|
||||||
|
bool wasOk() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this result indicates a failure.
|
||||||
|
You can use getErrorMessage() to retrieve the error message associated
|
||||||
|
with the failure.
|
||||||
|
*/
|
||||||
|
bool failed() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this result indicates a success.
|
||||||
|
This is equivalent to calling wasOk().
|
||||||
|
*/
|
||||||
|
operator bool() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this result indicates a failure.
|
||||||
|
This is equivalent to calling failed().
|
||||||
|
*/
|
||||||
|
bool operator!() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the error message that was set when this result was created.
|
||||||
|
For a successful result, this will be an empty string;
|
||||||
|
*/
|
||||||
|
const String& getErrorMessage() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
Result (const Result& other);
|
||||||
|
Result& operator= (const Result& other);
|
||||||
|
|
||||||
|
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
Result (Result&& other) noexcept;
|
||||||
|
Result& operator= (Result&& other) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool operator== (const Result& other) const noexcept;
|
||||||
|
bool operator!= (const Result& other) const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
String errorMessage;
|
||||||
|
|
||||||
|
explicit Result (const String&) noexcept;
|
||||||
|
|
||||||
|
// These casts are private to prevent people trying to use the Result object in numeric contexts
|
||||||
|
operator int() const;
|
||||||
|
operator void*() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_RESULT_BEASTHEADER
|
||||||
109
Subtrees/beast/modules/beast_core/misc/beast_Uuid.cpp
Normal file
109
Subtrees/beast/modules/beast_core/misc/beast_Uuid.cpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
int64 getRandomSeedFromMACAddresses()
|
||||||
|
{
|
||||||
|
Array<MACAddress> result;
|
||||||
|
MACAddress::findAllAddresses (result);
|
||||||
|
|
||||||
|
Random r;
|
||||||
|
for (int i = 0; i < result.size(); ++i)
|
||||||
|
r.combineSeed (result[i].toInt64());
|
||||||
|
|
||||||
|
return r.nextInt64();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
Uuid::Uuid()
|
||||||
|
{
|
||||||
|
// The normal random seeding is pretty good, but we'll throw some MAC addresses
|
||||||
|
// into the mix too, to make it very very unlikely that two UUIDs will ever be the same..
|
||||||
|
|
||||||
|
static Random r1 (getRandomSeedFromMACAddresses());
|
||||||
|
Random r2;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||||
|
uuid[i] = (uint8) (r1.nextInt() ^ r2.nextInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid::~Uuid() noexcept {}
|
||||||
|
|
||||||
|
Uuid::Uuid (const Uuid& other) noexcept
|
||||||
|
{
|
||||||
|
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid& Uuid::operator= (const Uuid& other) noexcept
|
||||||
|
{
|
||||||
|
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uuid::operator== (const Uuid& other) const noexcept { return memcmp (uuid, other.uuid, sizeof (uuid)) == 0; }
|
||||||
|
bool Uuid::operator!= (const Uuid& other) const noexcept { return ! operator== (other); }
|
||||||
|
|
||||||
|
bool Uuid::isNull() const noexcept
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||||
|
if (uuid[i] != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Uuid::toString() const
|
||||||
|
{
|
||||||
|
return String::toHexString (uuid, sizeof (uuid), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid::Uuid (const String& uuidString)
|
||||||
|
{
|
||||||
|
operator= (uuidString);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid& Uuid::operator= (const String& uuidString)
|
||||||
|
{
|
||||||
|
MemoryBlock mb;
|
||||||
|
mb.loadFromHexString (uuidString);
|
||||||
|
mb.ensureSize (sizeof (uuid), true);
|
||||||
|
mb.copyTo (uuid, 0, sizeof (uuid));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid::Uuid (const uint8* const rawData)
|
||||||
|
{
|
||||||
|
operator= (rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid& Uuid::operator= (const uint8* const rawData) noexcept
|
||||||
|
{
|
||||||
|
if (rawData != nullptr)
|
||||||
|
memcpy (uuid, rawData, sizeof (uuid));
|
||||||
|
else
|
||||||
|
zeromem (uuid, sizeof (uuid));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
109
Subtrees/beast/modules/beast_core/misc/beast_Uuid.h
Normal file
109
Subtrees/beast/modules/beast_core/misc/beast_Uuid.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_UUID_BEASTHEADER
|
||||||
|
#define BEAST_UUID_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../text/beast_String.h"
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A universally unique 128-bit identifier.
|
||||||
|
|
||||||
|
This class generates very random unique numbers based on the system time
|
||||||
|
and MAC addresses if any are available. It's extremely unlikely that two identical
|
||||||
|
UUIDs would ever be created by chance.
|
||||||
|
|
||||||
|
The class includes methods for saving the ID as a string or as raw binary data.
|
||||||
|
*/
|
||||||
|
class BEAST_API Uuid
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a new unique ID. */
|
||||||
|
Uuid();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~Uuid() noexcept;
|
||||||
|
|
||||||
|
/** Creates a copy of another UUID. */
|
||||||
|
Uuid (const Uuid& other) noexcept;
|
||||||
|
|
||||||
|
/** Copies another UUID. */
|
||||||
|
Uuid& operator= (const Uuid& other) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the ID is zero. */
|
||||||
|
bool isNull() const noexcept;
|
||||||
|
|
||||||
|
bool operator== (const Uuid& other) const noexcept;
|
||||||
|
bool operator!= (const Uuid& other) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a stringified version of this UUID.
|
||||||
|
|
||||||
|
A Uuid object can later be reconstructed from this string using operator= or
|
||||||
|
the constructor that takes a string parameter.
|
||||||
|
|
||||||
|
@returns a 32 character hex string.
|
||||||
|
*/
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
/** Creates an ID from an encoded string version.
|
||||||
|
@see toString
|
||||||
|
*/
|
||||||
|
Uuid (const String& uuidString);
|
||||||
|
|
||||||
|
/** Copies from a stringified UUID.
|
||||||
|
The string passed in should be one that was created with the toString() method.
|
||||||
|
*/
|
||||||
|
Uuid& operator= (const String& uuidString);
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the internal binary representation of the ID.
|
||||||
|
|
||||||
|
This is an array of 16 bytes. To reconstruct a Uuid from its data, use
|
||||||
|
the constructor or operator= method that takes an array of uint8s.
|
||||||
|
*/
|
||||||
|
const uint8* getRawData() const noexcept { return uuid; }
|
||||||
|
|
||||||
|
/** Creates a UUID from a 16-byte array.
|
||||||
|
@see getRawData
|
||||||
|
*/
|
||||||
|
Uuid (const uint8* rawData);
|
||||||
|
|
||||||
|
/** Sets this UUID from 16-bytes of raw data. */
|
||||||
|
Uuid& operator= (const uint8* rawData) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
uint8 uuid[16];
|
||||||
|
|
||||||
|
BEAST_LEAK_DETECTOR (Uuid)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_UUID_BEASTHEADER
|
||||||
119
Subtrees/beast/modules/beast_core/misc/beast_WindowsRegistry.h
Normal file
119
Subtrees/beast/modules/beast_core/misc/beast_WindowsRegistry.h
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||||
|
#define BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||||
|
|
||||||
|
#if BEAST_WINDOWS || DOXYGEN
|
||||||
|
|
||||||
|
/**
|
||||||
|
Contains some static helper functions for manipulating the MS Windows registry
|
||||||
|
(Only available on Windows, of course!)
|
||||||
|
*/
|
||||||
|
class WindowsRegistry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a string from the registry.
|
||||||
|
The path is a string for the entire path of a value in the registry,
|
||||||
|
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||||
|
*/
|
||||||
|
static String getValue (const String& regValuePath,
|
||||||
|
const String& defaultValue = String::empty);
|
||||||
|
|
||||||
|
/** Returns a string from the WOW64 registry.
|
||||||
|
The path is a string for the entire path of a value in the registry,
|
||||||
|
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||||
|
*/
|
||||||
|
static String getValueWow64 (const String& regValuePath,
|
||||||
|
const String& defaultValue = String::empty);
|
||||||
|
|
||||||
|
/** Reads a binary block from the registry.
|
||||||
|
The path is a string for the entire path of a value in the registry,
|
||||||
|
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||||
|
@returns a DWORD indicating the type of the key.
|
||||||
|
*/
|
||||||
|
static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& resultData);
|
||||||
|
|
||||||
|
/** Sets a registry value as a string.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool setValue (const String& regValuePath, const String& value);
|
||||||
|
|
||||||
|
/** Sets a registry value as a DWORD.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool setValue (const String& regValuePath, uint32 value);
|
||||||
|
|
||||||
|
/** Sets a registry value as a QWORD.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool setValue (const String& regValuePath, uint64 value);
|
||||||
|
|
||||||
|
/** Sets a registry value as a binary block.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool setValue (const String& regValuePath, const MemoryBlock& value);
|
||||||
|
|
||||||
|
/** Returns true if the given value exists in the registry. */
|
||||||
|
static bool valueExists (const String& regValuePath);
|
||||||
|
|
||||||
|
/** Returns true if the given value exists in the registry. */
|
||||||
|
static bool valueExistsWow64 (const String& regValuePath);
|
||||||
|
|
||||||
|
/** Deletes a registry value. */
|
||||||
|
static void deleteValue (const String& regValuePath);
|
||||||
|
|
||||||
|
/** Deletes a registry key (which is registry-talk for 'folder'). */
|
||||||
|
static void deleteKey (const String& regKeyPath);
|
||||||
|
|
||||||
|
/** Creates a file association in the registry.
|
||||||
|
|
||||||
|
This lets you set the executable that should be launched by a given file extension.
|
||||||
|
@param fileExtension the file extension to associate, including the
|
||||||
|
initial dot, e.g. ".txt"
|
||||||
|
@param symbolicDescription a space-free short token to identify the file type
|
||||||
|
@param fullDescription a human-readable description of the file type
|
||||||
|
@param targetExecutable the executable that should be launched
|
||||||
|
@param iconResourceNumber the icon that gets displayed for the file type will be
|
||||||
|
found by looking up this resource number in the
|
||||||
|
executable. Pass 0 here to not use an icon
|
||||||
|
@param registerForCurrentUserOnly if false, this will try to register the association
|
||||||
|
for all users (you might not have permission to do this
|
||||||
|
unless running in an installer). If true, it will register the
|
||||||
|
association in HKEY_CURRENT_USER.
|
||||||
|
*/
|
||||||
|
static bool registerFileAssociation (const String& fileExtension,
|
||||||
|
const String& symbolicDescription,
|
||||||
|
const String& fullDescription,
|
||||||
|
const File& targetExecutable,
|
||||||
|
int iconResourceNumber,
|
||||||
|
bool registerForCurrentUserOnly);
|
||||||
|
|
||||||
|
private:
|
||||||
|
WindowsRegistry();
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (WindowsRegistry)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif // BEAST_WINDOWSREGISTRY_BEASTHEADER
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_BASICNATIVEHEADERS_BEASTHEADER
|
||||||
|
#define BEAST_BASICNATIVEHEADERS_BEASTHEADER
|
||||||
|
|
||||||
|
#include "../system/beast_TargetPlatform.h"
|
||||||
|
#undef T
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_MAC || BEAST_IOS
|
||||||
|
|
||||||
|
#if BEAST_IOS
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <CoreData/CoreData.h>
|
||||||
|
#import <MobileCoreServices/MobileCoreServices.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#else
|
||||||
|
#define Point CarbonDummyPointName
|
||||||
|
#define Component CarbonDummyCompName
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <CoreAudio/HostTime.h>
|
||||||
|
#undef Point
|
||||||
|
#undef Component
|
||||||
|
#include <sys/dir.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#include <mach-o/dyld.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/message.h>
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif BEAST_WINDOWS
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#ifndef _CPPRTTI
|
||||||
|
#error "You're compiling without RTTI enabled! This is needed for a lot of BEAST classes, please update your compiler settings!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _CPPUNWIND
|
||||||
|
#error "You're compiling without exceptions enabled! This is needed for a lot of BEAST classes, please update your compiler settings!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable : 4100 4201 4514 4312 4995)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRICT 1
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#if BEAST_MINGW
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#else
|
||||||
|
#define _WIN32_WINNT 0x0600
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#define _UNICODE 1
|
||||||
|
#define UNICODE 1
|
||||||
|
#ifndef _WIN32_IE
|
||||||
|
#define _WIN32_IE 0x0400
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ctime>
|
||||||
|
#include <wininet.h>
|
||||||
|
#include <nb30.h>
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
#include <mapi.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
|
||||||
|
#if BEAST_MINGW
|
||||||
|
#include <basetyps.h>
|
||||||
|
#else
|
||||||
|
#include <crtdbg.h>
|
||||||
|
#include <comutil.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef PACKED
|
||||||
|
|
||||||
|
#if BEAST_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#pragma warning (4: 4511 4512 4100 /*4365*/) // (enable some warnings that are turned off in VC8)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_MSVC && ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#pragma comment (lib, "kernel32.lib")
|
||||||
|
#pragma comment (lib, "user32.lib")
|
||||||
|
#pragma comment (lib, "wininet.lib")
|
||||||
|
#pragma comment (lib, "advapi32.lib")
|
||||||
|
#pragma comment (lib, "ws2_32.lib")
|
||||||
|
#pragma comment (lib, "version.lib")
|
||||||
|
#pragma comment (lib, "shlwapi.lib")
|
||||||
|
#pragma comment (lib, "winmm.lib")
|
||||||
|
|
||||||
|
#ifdef _NATIVE_WCHAR_T_DEFINED
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#pragma comment (lib, "comsuppwd.lib")
|
||||||
|
#else
|
||||||
|
#pragma comment (lib, "comsuppw.lib")
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#pragma comment (lib, "comsuppd.lib")
|
||||||
|
#else
|
||||||
|
#pragma comment (lib, "comsupp.lib")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
|
||||||
|
|
||||||
|
dll: the DynamicLibrary object
|
||||||
|
functionName: function to import
|
||||||
|
localFunctionName: name you want to use to actually call it (must be different)
|
||||||
|
returnType: the return type
|
||||||
|
params: list of params (bracketed)
|
||||||
|
*/
|
||||||
|
#define BEAST_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
|
||||||
|
typedef returnType (WINAPI *type##localFunctionName) params; \
|
||||||
|
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif BEAST_LINUX
|
||||||
|
#include <sched.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/dir.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
#include <sys/vfs.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif BEAST_ANDROID
|
||||||
|
#include <jni.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statfs.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Need to clear various moronic redefinitions made by system headers..
|
||||||
|
#undef max
|
||||||
|
#undef min
|
||||||
|
#undef direct
|
||||||
|
#undef check
|
||||||
|
|
||||||
|
#endif // BEAST_BASICNATIVEHEADERS_BEASTHEADER
|
||||||
236
Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp
Normal file
236
Subtrees/beast/modules/beast_core/native/beast_android_Files.cpp
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
bool File::copyInternal (const File& dest) const
|
||||||
|
{
|
||||||
|
FileInputStream in (*this);
|
||||||
|
|
||||||
|
if (dest.deleteFile())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
FileOutputStream out (dest);
|
||||||
|
|
||||||
|
if (out.failedToOpen())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (out.writeFromInputStream (in, -1) == getSize())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.deleteFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::findFileSystemRoots (Array<File>& destArray)
|
||||||
|
{
|
||||||
|
destArray.add (File ("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::isOnCDRomDrive() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnHardDisk() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnRemovableDrive() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isHidden() const
|
||||||
|
{
|
||||||
|
return getFileName().startsWithChar ('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
File beast_readlink (const String& file, const File& defaultFile)
|
||||||
|
{
|
||||||
|
const int size = 8192;
|
||||||
|
HeapBlock<char> buffer;
|
||||||
|
buffer.malloc (size + 4);
|
||||||
|
|
||||||
|
const size_t numBytes = readlink (file.toUTF8(), buffer, size);
|
||||||
|
|
||||||
|
if (numBytes > 0 && numBytes <= size)
|
||||||
|
return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes));
|
||||||
|
|
||||||
|
return defaultFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File File::getLinkedTarget() const
|
||||||
|
{
|
||||||
|
return beast_readlink (getFullPathName().toUTF8(), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
File File::getSpecialLocation (const SpecialLocationType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case userHomeDirectory:
|
||||||
|
case userDocumentsDirectory:
|
||||||
|
case userMusicDirectory:
|
||||||
|
case userMoviesDirectory:
|
||||||
|
case userPicturesDirectory:
|
||||||
|
case userApplicationDataDirectory:
|
||||||
|
case userDesktopDirectory:
|
||||||
|
return File (android.appDataDir);
|
||||||
|
|
||||||
|
case commonApplicationDataDirectory:
|
||||||
|
return File (android.appDataDir);
|
||||||
|
|
||||||
|
case globalApplicationsDirectory:
|
||||||
|
return File ("/system/app");
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
//return File (AndroidStatsHelpers::getSystemProperty ("java.io.tmpdir"));
|
||||||
|
return File (android.appDataDir).getChildFile (".temp");
|
||||||
|
|
||||||
|
case invokedExecutableFile:
|
||||||
|
case currentExecutableFile:
|
||||||
|
case currentApplicationFile:
|
||||||
|
case hostApplicationPath:
|
||||||
|
return beast_getExecutableFile();
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // unknown type?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return File::nonexistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String File::getVersion() const
|
||||||
|
{
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::moveToTrash() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class DirectoryIterator::NativeIterator::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const File& directory, const String& wildCard_)
|
||||||
|
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||||
|
wildCard (wildCard_),
|
||||||
|
dir (opendir (directory.getFullPathName().toUTF8()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
if (dir != 0)
|
||||||
|
closedir (dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
if (dir != 0)
|
||||||
|
{
|
||||||
|
const char* wildcardUTF8 = nullptr;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
struct dirent* const de = readdir (dir);
|
||||||
|
|
||||||
|
if (de == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (wildcardUTF8 == nullptr)
|
||||||
|
wildcardUTF8 = wildCard.toUTF8();
|
||||||
|
|
||||||
|
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||||
|
{
|
||||||
|
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||||
|
|
||||||
|
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
|
||||||
|
if (isHidden != 0)
|
||||||
|
*isHidden = filenameFound.startsWithChar ('.');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
String parentDir, wildCard;
|
||||||
|
DIR* dir;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||||
|
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||||
|
{
|
||||||
|
const LocalRef<jstring> t (javaString (fileName));
|
||||||
|
android.activity.callVoidMethod (BeastAppActivity.launchURL, t.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::revealToUser() const
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,402 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_ANDROID_JNIHELPERS_BEASTHEADER
|
||||||
|
#define BEAST_ANDROID_JNIHELPERS_BEASTHEADER
|
||||||
|
|
||||||
|
#if ! (defined (BEAST_ANDROID_ACTIVITY_CLASSNAME) && defined (BEAST_ANDROID_ACTIVITY_CLASSPATH))
|
||||||
|
#error "The BEAST_ANDROID_ACTIVITY_CLASSNAME and BEAST_ANDROID_ACTIVITY_CLASSPATH macros must be set!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
extern JNIEnv* getEnv() noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class GlobalRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline GlobalRef() noexcept : obj (0) {}
|
||||||
|
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
|
||||||
|
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
|
||||||
|
~GlobalRef() { clear(); }
|
||||||
|
|
||||||
|
inline void clear()
|
||||||
|
{
|
||||||
|
if (obj != 0)
|
||||||
|
{
|
||||||
|
getEnv()->DeleteGlobalRef (obj);
|
||||||
|
obj = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline GlobalRef& operator= (const GlobalRef& other)
|
||||||
|
{
|
||||||
|
jobject newObj = retain (other.obj);
|
||||||
|
clear();
|
||||||
|
obj = newObj;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
inline operator jobject() const noexcept { return obj; }
|
||||||
|
inline jobject get() const noexcept { return obj; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \
|
||||||
|
returnType call##typeName##Method (jmethodID methodID, ... ) const \
|
||||||
|
{ \
|
||||||
|
va_list args; \
|
||||||
|
va_start (args, methodID); \
|
||||||
|
returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \
|
||||||
|
va_end (args); \
|
||||||
|
return result; \
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jobject, Object)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jboolean, Boolean)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jbyte, Byte)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jchar, Char)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jshort, Short)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jint, Int)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jlong, Long)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jfloat, Float)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jdouble, Double)
|
||||||
|
#undef DECLARE_CALL_TYPE_METHOD
|
||||||
|
|
||||||
|
void callVoidMethod (jmethodID methodID, ... ) const
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start (args, methodID);
|
||||||
|
getEnv()->CallVoidMethodV (obj, methodID, args);
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
jobject obj;
|
||||||
|
|
||||||
|
static inline jobject retain (jobject obj)
|
||||||
|
{
|
||||||
|
return obj == 0 ? 0 : getEnv()->NewGlobalRef (obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename JavaType>
|
||||||
|
class LocalRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline LocalRef (JavaType o) noexcept : obj (o) {}
|
||||||
|
inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {}
|
||||||
|
~LocalRef() { clear(); }
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (obj != 0)
|
||||||
|
getEnv()->DeleteLocalRef (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef& operator= (const LocalRef& other)
|
||||||
|
{
|
||||||
|
jobject newObj = retain (other.obj);
|
||||||
|
clear();
|
||||||
|
obj = newObj;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator JavaType() const noexcept { return obj; }
|
||||||
|
inline JavaType get() const noexcept { return obj; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
JavaType obj;
|
||||||
|
|
||||||
|
static JavaType retain (JavaType obj)
|
||||||
|
{
|
||||||
|
return obj == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
String beastString (JNIEnv* env, jstring s)
|
||||||
|
{
|
||||||
|
const char* const utf8 = env->GetStringUTFChars (s, nullptr);
|
||||||
|
CharPointer_UTF8 utf8CP (utf8);
|
||||||
|
const String result (utf8CP);
|
||||||
|
env->ReleaseStringUTFChars (s, utf8);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String beastString (jstring s)
|
||||||
|
{
|
||||||
|
return beastString (getEnv(), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef<jstring> javaString (const String& s)
|
||||||
|
{
|
||||||
|
return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8()));
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef<jstring> javaStringFromChar (const beast_wchar c)
|
||||||
|
{
|
||||||
|
char utf8[8] = { 0 };
|
||||||
|
CharPointer_UTF8 (utf8).write (c);
|
||||||
|
return LocalRef<jstring> (getEnv()->NewStringUTF (utf8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class JNIClassBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit JNIClassBase (const char* classPath);
|
||||||
|
virtual ~JNIClassBase();
|
||||||
|
|
||||||
|
inline operator jclass() const noexcept { return classRef; }
|
||||||
|
|
||||||
|
static void initialiseAllClasses (JNIEnv*);
|
||||||
|
static void releaseAllClasses (JNIEnv*);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void initialiseFields (JNIEnv*) = 0;
|
||||||
|
|
||||||
|
jmethodID resolveMethod (JNIEnv*, const char* methodName, const char* params);
|
||||||
|
jmethodID resolveStaticMethod (JNIEnv*, const char* methodName, const char* params);
|
||||||
|
jfieldID resolveField (JNIEnv*, const char* fieldName, const char* signature);
|
||||||
|
jfieldID resolveStaticField (JNIEnv*, const char* fieldName, const char* signature);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* const classPath;
|
||||||
|
jclass classRef;
|
||||||
|
|
||||||
|
static Array<JNIClassBase*>& getClasses();
|
||||||
|
void initialise (JNIEnv*);
|
||||||
|
void release (JNIEnv*);
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (JNIClassBase)
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define CREATE_JNI_METHOD(methodID, stringName, params) methodID = resolveMethod (env, stringName, params);
|
||||||
|
#define CREATE_JNI_STATICMETHOD(methodID, stringName, params) methodID = resolveStaticMethod (env, stringName, params);
|
||||||
|
#define CREATE_JNI_FIELD(fieldID, stringName, signature) fieldID = resolveField (env, stringName, signature);
|
||||||
|
#define CREATE_JNI_STATICFIELD(fieldID, stringName, signature) fieldID = resolveStaticField (env, stringName, signature);
|
||||||
|
#define DECLARE_JNI_METHOD(methodID, stringName, params) jmethodID methodID;
|
||||||
|
#define DECLARE_JNI_FIELD(fieldID, stringName, signature) jfieldID fieldID;
|
||||||
|
|
||||||
|
#define DECLARE_JNI_CLASS(CppClassName, javaPath) \
|
||||||
|
class CppClassName ## _Class : public JNIClassBase \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
CppClassName ## _Class() : JNIClassBase (javaPath) {} \
|
||||||
|
\
|
||||||
|
void initialiseFields (JNIEnv* env) \
|
||||||
|
{ \
|
||||||
|
JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); \
|
||||||
|
}; \
|
||||||
|
static CppClassName ## _Class CppClassName;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define BEAST_JNI_CALLBACK(className, methodName, returnType, params) \
|
||||||
|
extern "C" __attribute__ ((visibility("default"))) returnType BEAST_JOIN_MACRO (BEAST_JOIN_MACRO (Java_, className), _ ## methodName) params
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class AndroidSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AndroidSystem();
|
||||||
|
|
||||||
|
void initialise (JNIEnv*, jobject activity, jstring appFile, jstring appDataDir);
|
||||||
|
void shutdown (JNIEnv*);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
GlobalRef activity;
|
||||||
|
String appFile, appDataDir;
|
||||||
|
int screenWidth, screenHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern AndroidSystem android;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class ThreadLocalJNIEnvHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThreadLocalJNIEnvHolder()
|
||||||
|
: jvm (nullptr)
|
||||||
|
{
|
||||||
|
zeromem (threads, sizeof (threads));
|
||||||
|
zeromem (envs, sizeof (envs));
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialise (JNIEnv* env)
|
||||||
|
{
|
||||||
|
// NB: the DLL can be left loaded by the JVM, so the same static
|
||||||
|
// objects can end up being reused by subsequent runs of the app
|
||||||
|
zeromem (threads, sizeof (threads));
|
||||||
|
zeromem (envs, sizeof (envs));
|
||||||
|
|
||||||
|
env->GetJavaVM (&jvm);
|
||||||
|
addEnv (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* attach()
|
||||||
|
{
|
||||||
|
JNIEnv* env = nullptr;
|
||||||
|
jvm->AttachCurrentThread (&env, nullptr);
|
||||||
|
|
||||||
|
if (env != nullptr)
|
||||||
|
addEnv (env);
|
||||||
|
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach()
|
||||||
|
{
|
||||||
|
jvm->DetachCurrentThread();
|
||||||
|
|
||||||
|
const pthread_t thisThread = pthread_self();
|
||||||
|
|
||||||
|
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||||
|
for (int i = 0; i < maxThreads; ++i)
|
||||||
|
if (threads[i] == thisThread)
|
||||||
|
threads[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* getOrAttach() noexcept
|
||||||
|
{
|
||||||
|
JNIEnv* env = get();
|
||||||
|
|
||||||
|
if (env == nullptr)
|
||||||
|
env = attach();
|
||||||
|
|
||||||
|
bassert (env != nullptr);
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* get() const noexcept
|
||||||
|
{
|
||||||
|
const pthread_t thisThread = pthread_self();
|
||||||
|
|
||||||
|
for (int i = 0; i < maxThreads; ++i)
|
||||||
|
if (threads[i] == thisThread)
|
||||||
|
return envs[i];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { maxThreads = 32 };
|
||||||
|
|
||||||
|
private:
|
||||||
|
JavaVM* jvm;
|
||||||
|
pthread_t threads [maxThreads];
|
||||||
|
JNIEnv* envs [maxThreads];
|
||||||
|
SpinLock addRemoveLock;
|
||||||
|
|
||||||
|
void addEnv (JNIEnv* env)
|
||||||
|
{
|
||||||
|
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||||
|
|
||||||
|
if (get() == nullptr)
|
||||||
|
{
|
||||||
|
const pthread_t thisThread = pthread_self();
|
||||||
|
|
||||||
|
for (int i = 0; i < maxThreads; ++i)
|
||||||
|
{
|
||||||
|
if (threads[i] == 0)
|
||||||
|
{
|
||||||
|
envs[i] = env;
|
||||||
|
threads[i] = thisThread;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jassertfalse; // too many threads!
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (createNewView, "createNewView", "(Z)L" BEAST_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
|
||||||
|
METHOD (deleteView, "deleteView", "(L" BEAST_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
|
||||||
|
METHOD (postMessage, "postMessage", "(J)V") \
|
||||||
|
METHOD (finish, "finish", "()V") \
|
||||||
|
METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \
|
||||||
|
METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \
|
||||||
|
METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \
|
||||||
|
METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
|
||||||
|
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;ILjava/lang/StringBuffer;)L" BEAST_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
|
||||||
|
METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \
|
||||||
|
METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||||
|
METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||||
|
METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||||
|
STATICMETHOD (getLocaleValue, "getLocaleValue", "(Z)Ljava/lang/String;") \
|
||||||
|
METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V")
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (BeastAppActivity, BEAST_ANDROID_ACTIVITY_CLASSPATH);
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "(I)V") \
|
||||||
|
METHOD (setColor, "setColor", "(I)V") \
|
||||||
|
METHOD (setAlpha, "setAlpha", "(I)V") \
|
||||||
|
METHOD (setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \
|
||||||
|
METHOD (ascent, "ascent", "()F") \
|
||||||
|
METHOD (descent, "descent", "()F") \
|
||||||
|
METHOD (setTextSize, "setTextSize", "(F)V") \
|
||||||
|
METHOD (getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \
|
||||||
|
METHOD (setTextScaleX, "setTextScaleX", "(F)V") \
|
||||||
|
METHOD (getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \
|
||||||
|
METHOD (setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (Paint, "android/graphics/Paint");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "()V") \
|
||||||
|
METHOD (setValues, "setValues", "([F)V") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "(IIII)V") \
|
||||||
|
FIELD (left, "left", "I") \
|
||||||
|
FIELD (right, "right", "I") \
|
||||||
|
FIELD (top, "top", "I") \
|
||||||
|
FIELD (bottom, "bottom", "I") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
#endif // BEAST_ANDROID_JNIHELPERS_BEASTHEADER
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
void Logger::outputDebugString (const String& text)
|
||||||
|
{
|
||||||
|
__android_log_print (ANDROID_LOG_INFO, "BEAST", text.toUTF8());
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "()V") \
|
||||||
|
METHOD (toString, "toString", "()Ljava/lang/String;") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (release, "release", "()V") \
|
||||||
|
METHOD (read, "read", "([BI)I") \
|
||||||
|
METHOD (getPosition, "getPosition", "()J") \
|
||||||
|
METHOD (getTotalLength, "getTotalLength", "()J") \
|
||||||
|
METHOD (isExhausted, "isExhausted", "()Z") \
|
||||||
|
METHOD (setPosition, "setPosition", "(J)Z") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (HTTPStream, BEAST_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||||
|
const String& emailSubject,
|
||||||
|
const String& bodyText,
|
||||||
|
const StringArray& filesToAttach)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WebInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
WebInputStream (String address, bool isPost, const MemoryBlock& postData,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers, int timeOutMs, StringPairArray* responseHeaders)
|
||||||
|
{
|
||||||
|
if (! address.contains ("://"))
|
||||||
|
address = "http://" + address;
|
||||||
|
|
||||||
|
JNIEnv* env = getEnv();
|
||||||
|
|
||||||
|
jbyteArray postDataArray = 0;
|
||||||
|
|
||||||
|
if (postData.getSize() > 0)
|
||||||
|
{
|
||||||
|
postDataArray = env->NewByteArray (postData.getSize());
|
||||||
|
env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef<jobject> responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor));
|
||||||
|
|
||||||
|
stream = GlobalRef (env->CallStaticObjectMethod (BeastAppActivity,
|
||||||
|
BeastAppActivity.createHTTPStream,
|
||||||
|
javaString (address).get(),
|
||||||
|
(jboolean) isPost,
|
||||||
|
postDataArray,
|
||||||
|
javaString (headers).get(),
|
||||||
|
(jint) timeOutMs,
|
||||||
|
responseHeaderBuffer.get()));
|
||||||
|
|
||||||
|
if (postDataArray != 0)
|
||||||
|
env->DeleteLocalRef (postDataArray);
|
||||||
|
|
||||||
|
if (stream != 0)
|
||||||
|
{
|
||||||
|
StringArray headerLines;
|
||||||
|
|
||||||
|
{
|
||||||
|
LocalRef<jstring> headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(),
|
||||||
|
StringBuffer.toString));
|
||||||
|
headerLines.addLines (beastString (env, headersString));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseHeaders != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < headerLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String& header = headerLines[i];
|
||||||
|
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String value (header.fromFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String previousValue ((*responseHeaders) [key]);
|
||||||
|
|
||||||
|
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~WebInputStream()
|
||||||
|
{
|
||||||
|
if (stream != 0)
|
||||||
|
stream.callVoidMethod (HTTPStream.release);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); }
|
||||||
|
int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; }
|
||||||
|
int64 getPosition() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; }
|
||||||
|
bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); }
|
||||||
|
|
||||||
|
int read (void* buffer, int bytesToRead)
|
||||||
|
{
|
||||||
|
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||||
|
|
||||||
|
if (stream == nullptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
JNIEnv* env = getEnv();
|
||||||
|
|
||||||
|
jbyteArray javaArray = env->NewByteArray (bytesToRead);
|
||||||
|
|
||||||
|
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
|
||||||
|
|
||||||
|
if (numBytes > 0)
|
||||||
|
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast <jbyte*> (buffer));
|
||||||
|
|
||||||
|
env->DeleteLocalRef (javaArray);
|
||||||
|
return numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
GlobalRef stream;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||||
|
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||||
|
{
|
||||||
|
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||||
|
progressCallback, progressCallbackContext,
|
||||||
|
headers, timeOutMs, responseHeaders));
|
||||||
|
|
||||||
|
return wi->stream != 0 ? wi.release() : nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
JNIClassBase::JNIClassBase (const char* classPath_)
|
||||||
|
: classPath (classPath_), classRef (0)
|
||||||
|
{
|
||||||
|
getClasses().add (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIClassBase::~JNIClassBase()
|
||||||
|
{
|
||||||
|
getClasses().removeFirstMatchingValue (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<JNIClassBase*>& JNIClassBase::getClasses()
|
||||||
|
{
|
||||||
|
static Array<JNIClassBase*> classes;
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::initialise (JNIEnv* env)
|
||||||
|
{
|
||||||
|
classRef = (jclass) env->NewGlobalRef (env->FindClass (classPath));
|
||||||
|
bassert (classRef != 0);
|
||||||
|
|
||||||
|
initialiseFields (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::release (JNIEnv* env)
|
||||||
|
{
|
||||||
|
env->DeleteGlobalRef (classRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::initialiseAllClasses (JNIEnv* env)
|
||||||
|
{
|
||||||
|
const Array<JNIClassBase*>& classes = getClasses();
|
||||||
|
for (int i = classes.size(); --i >= 0;)
|
||||||
|
classes.getUnchecked(i)->initialise (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::releaseAllClasses (JNIEnv* env)
|
||||||
|
{
|
||||||
|
const Array<JNIClassBase*>& classes = getClasses();
|
||||||
|
for (int i = classes.size(); --i >= 0;)
|
||||||
|
classes.getUnchecked(i)->release (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||||
|
{
|
||||||
|
jmethodID m = env->GetMethodID (classRef, methodName, params);
|
||||||
|
bassert (m != 0);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||||
|
{
|
||||||
|
jmethodID m = env->GetStaticMethodID (classRef, methodName, params);
|
||||||
|
bassert (m != 0);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||||
|
{
|
||||||
|
jfieldID f = env->GetFieldID (classRef, fieldName, signature);
|
||||||
|
bassert (f != 0);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||||
|
{
|
||||||
|
jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature);
|
||||||
|
bassert (f != 0);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||||
|
|
||||||
|
#if BEAST_DEBUG
|
||||||
|
static bool systemInitialised = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JNIEnv* getEnv() noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_DEBUG
|
||||||
|
if (! systemInitialised)
|
||||||
|
{
|
||||||
|
DBG ("*** Call to getEnv() when system not initialised");
|
||||||
|
jassertfalse;
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return threadLocalJNIEnvHolder.getOrAttach();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" jint JNI_OnLoad (JavaVM*, void*)
|
||||||
|
{
|
||||||
|
return JNI_VERSION_1_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidSystem::initialise (JNIEnv* env, jobject activity_,
|
||||||
|
jstring appFile_, jstring appDataDir_)
|
||||||
|
{
|
||||||
|
screenWidth = screenHeight = 0;
|
||||||
|
JNIClassBase::initialiseAllClasses (env);
|
||||||
|
|
||||||
|
threadLocalJNIEnvHolder.initialise (env);
|
||||||
|
#if BEAST_DEBUG
|
||||||
|
systemInitialised = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
activity = GlobalRef (activity_);
|
||||||
|
appFile = beastString (env, appFile_);
|
||||||
|
appDataDir = beastString (env, appDataDir_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidSystem::shutdown (JNIEnv* env)
|
||||||
|
{
|
||||||
|
activity.clear();
|
||||||
|
|
||||||
|
#if BEAST_DEBUG
|
||||||
|
systemInitialised = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JNIClassBase::releaseAllClasses (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidSystem android;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace AndroidStatsHelpers
|
||||||
|
{
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (SystemClass, "java/lang/System");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String getSystemProperty (const String& name)
|
||||||
|
{
|
||||||
|
return beastString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
|
||||||
|
SystemClass.getProperty,
|
||||||
|
javaString (name).get())));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String getLocaleValue (bool isRegion)
|
||||||
|
{
|
||||||
|
return beastString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (BeastAppActivity,
|
||||||
|
BeastAppActivity.getLocaleValue,
|
||||||
|
isRegion)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||||
|
{
|
||||||
|
return Android;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getOperatingSystemName()
|
||||||
|
{
|
||||||
|
return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemStats::isOperatingSystem64Bit()
|
||||||
|
{
|
||||||
|
#if BEAST_64BIT
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
return AndroidStatsHelpers::getSystemProperty ("os.arch");
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getCpuSpeedInMegaherz()
|
||||||
|
{
|
||||||
|
return 0; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getMemorySizeInMegabytes()
|
||||||
|
{
|
||||||
|
#if __ANDROID_API__ >= 9
|
||||||
|
struct sysinfo sysi;
|
||||||
|
|
||||||
|
if (sysinfo (&sysi) == 0)
|
||||||
|
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getPageSize()
|
||||||
|
{
|
||||||
|
return sysconf (_SC_PAGESIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getLogonName()
|
||||||
|
{
|
||||||
|
const char* user = getenv ("USER");
|
||||||
|
|
||||||
|
if (user == 0)
|
||||||
|
{
|
||||||
|
struct passwd* const pw = getpwuid (getuid());
|
||||||
|
if (pw != 0)
|
||||||
|
user = pw->pw_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharPointer_UTF8 (user);
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getFullUserName()
|
||||||
|
{
|
||||||
|
return getLogonName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getComputerName()
|
||||||
|
{
|
||||||
|
char name [256] = { 0 };
|
||||||
|
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||||
|
return name;
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
|
||||||
|
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
|
||||||
|
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::CPUFlags::CPUFlags()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
hasMMX = false;
|
||||||
|
hasSSE = false;
|
||||||
|
hasSSE2 = false;
|
||||||
|
has3DNow = false;
|
||||||
|
|
||||||
|
numCpus = bmax (1, sysconf (_SC_NPROCESSORS_ONLN));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
uint32 beast_millisecondsSinceStartup() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicks() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||||
|
{
|
||||||
|
return 1000000; // (microseconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
double Time::getMillisecondCounterHiRes() noexcept
|
||||||
|
{
|
||||||
|
return getHighResolutionTicks() * 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Time::setSystemTimeToThisTime() const
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in beast_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// sets the process to 0=low priority, 1=normal, 2=high, 3=realtime
|
||||||
|
void Process::setPriority (ProcessPriority prior)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
struct sched_param param;
|
||||||
|
int policy, maxp, minp;
|
||||||
|
|
||||||
|
const int p = (int) prior;
|
||||||
|
|
||||||
|
if (p <= 1)
|
||||||
|
policy = SCHED_OTHER;
|
||||||
|
else
|
||||||
|
policy = SCHED_RR;
|
||||||
|
|
||||||
|
minp = sched_get_priority_min (policy);
|
||||||
|
maxp = sched_get_priority_max (policy);
|
||||||
|
|
||||||
|
if (p < 2)
|
||||||
|
param.sched_priority = 0;
|
||||||
|
else if (p == 2 )
|
||||||
|
// Set to middle of lower realtime priority range
|
||||||
|
param.sched_priority = minp + (maxp - minp) / 4;
|
||||||
|
else
|
||||||
|
// Set to middle of higher realtime priority range
|
||||||
|
param.sched_priority = minp + (3 * (maxp - minp) / 4);
|
||||||
|
|
||||||
|
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::terminate()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_API bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return beast_isRunningUnderDebugger();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::raisePrivilege() {}
|
||||||
|
void Process::lowerPrivilege() {}
|
||||||
373
Subtrees/beast/modules/beast_core/native/beast_linux_Files.cpp
Normal file
373
Subtrees/beast/modules/beast_core/native/beast_linux_Files.cpp
Normal file
@@ -0,0 +1,373 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
|
||||||
|
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
|
||||||
|
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
|
||||||
|
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::copyInternal (const File& dest) const
|
||||||
|
{
|
||||||
|
FileInputStream in (*this);
|
||||||
|
|
||||||
|
if (dest.deleteFile())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
FileOutputStream out (dest);
|
||||||
|
|
||||||
|
if (out.failedToOpen())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (out.writeFromInputStream (in, -1) == getSize())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.deleteFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::findFileSystemRoots (Array<File>& destArray)
|
||||||
|
{
|
||||||
|
destArray.add (File ("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::isOnCDRomDrive() const
|
||||||
|
{
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
return statfs (getFullPathName().toUTF8(), &buf) == 0
|
||||||
|
&& buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnHardDisk() const
|
||||||
|
{
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
|
||||||
|
{
|
||||||
|
switch (buf.f_type)
|
||||||
|
{
|
||||||
|
case U_ISOFS_SUPER_MAGIC: // CD-ROM
|
||||||
|
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
|
||||||
|
case U_NFS_SUPER_MAGIC: // Network NFS
|
||||||
|
case U_SMB_SUPER_MAGIC: // Network Samba
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Assume anything else is a hard-disk (but note it could
|
||||||
|
// be a RAM disk. There isn't a good way of determining
|
||||||
|
// this for sure)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume so if this fails for some reason
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnRemovableDrive() const
|
||||||
|
{
|
||||||
|
jassertfalse; // xxx not implemented for linux!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isHidden() const
|
||||||
|
{
|
||||||
|
return getFileName().startsWithChar ('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
File beast_readlink (const String& file, const File& defaultFile)
|
||||||
|
{
|
||||||
|
const size_t size = 8192;
|
||||||
|
HeapBlock<char> buffer;
|
||||||
|
buffer.malloc (size + 4);
|
||||||
|
|
||||||
|
const size_t numBytes = readlink (file.toUTF8(), buffer, size);
|
||||||
|
|
||||||
|
if (numBytes > 0 && numBytes <= size)
|
||||||
|
return File (file).getSiblingFile (String::fromUTF8 (buffer, (int) numBytes));
|
||||||
|
|
||||||
|
return defaultFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File File::getLinkedTarget() const
|
||||||
|
{
|
||||||
|
return beast_readlink (getFullPathName().toUTF8(), *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
|
||||||
|
{
|
||||||
|
StringArray confLines;
|
||||||
|
File ("~/.config/user-dirs.dirs").readLines (confLines);
|
||||||
|
|
||||||
|
for (int i = 0; i < confLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String line (confLines[i].trimStart());
|
||||||
|
|
||||||
|
if (line.startsWith (type))
|
||||||
|
{
|
||||||
|
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
|
||||||
|
const File f (line.replace ("$HOME", File ("~").getFullPathName())
|
||||||
|
.fromFirstOccurrenceOf ("=", false, false)
|
||||||
|
.trim().unquoted());
|
||||||
|
|
||||||
|
if (f.isDirectory())
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return File (fallbackFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const* beast_argv = nullptr;
|
||||||
|
int beast_argc = 0;
|
||||||
|
|
||||||
|
File File::getSpecialLocation (const SpecialLocationType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case userHomeDirectory:
|
||||||
|
{
|
||||||
|
const char* homeDir = getenv ("HOME");
|
||||||
|
|
||||||
|
if (homeDir == nullptr)
|
||||||
|
{
|
||||||
|
struct passwd* const pw = getpwuid (getuid());
|
||||||
|
if (pw != nullptr)
|
||||||
|
homeDir = pw->pw_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
return File (CharPointer_UTF8 (homeDir));
|
||||||
|
}
|
||||||
|
|
||||||
|
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
|
||||||
|
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~");
|
||||||
|
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~");
|
||||||
|
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~");
|
||||||
|
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
|
||||||
|
case userApplicationDataDirectory: return File ("~");
|
||||||
|
case commonApplicationDataDirectory: return File ("/var");
|
||||||
|
case globalApplicationsDirectory: return File ("/usr");
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
{
|
||||||
|
File tmp ("/var/tmp");
|
||||||
|
|
||||||
|
if (! tmp.isDirectory())
|
||||||
|
{
|
||||||
|
tmp = "/tmp";
|
||||||
|
|
||||||
|
if (! tmp.isDirectory())
|
||||||
|
tmp = File::getCurrentWorkingDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
case invokedExecutableFile:
|
||||||
|
if (beast_argv != nullptr && beast_argc > 0)
|
||||||
|
return File (CharPointer_UTF8 (beast_argv[0]));
|
||||||
|
// deliberate fall-through...
|
||||||
|
|
||||||
|
case currentExecutableFile:
|
||||||
|
case currentApplicationFile:
|
||||||
|
return beast_getExecutableFile();
|
||||||
|
|
||||||
|
case hostApplicationPath:
|
||||||
|
return beast_readlink ("/proc/self/exe", beast_getExecutableFile());
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // unknown type?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return File::nonexistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String File::getVersion() const
|
||||||
|
{
|
||||||
|
return String::empty; // xxx not yet implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::moveToTrash() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
File trashCan ("~/.Trash");
|
||||||
|
|
||||||
|
if (! trashCan.isDirectory())
|
||||||
|
trashCan = "~/.local/share/Trash/files";
|
||||||
|
|
||||||
|
if (! trashCan.isDirectory())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
|
||||||
|
getFileExtension()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class DirectoryIterator::NativeIterator::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const File& directory, const String& wildCard_)
|
||||||
|
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||||
|
wildCard (wildCard_),
|
||||||
|
dir (opendir (directory.getFullPathName().toUTF8()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
if (dir != nullptr)
|
||||||
|
closedir (dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
if (dir != nullptr)
|
||||||
|
{
|
||||||
|
const char* wildcardUTF8 = nullptr;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
struct dirent* const de = readdir (dir);
|
||||||
|
|
||||||
|
if (de == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (wildcardUTF8 == nullptr)
|
||||||
|
wildcardUTF8 = wildCard.toUTF8();
|
||||||
|
|
||||||
|
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||||
|
{
|
||||||
|
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||||
|
|
||||||
|
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
|
||||||
|
if (isHidden != nullptr)
|
||||||
|
*isHidden = filenameFound.startsWithChar ('.');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
String parentDir, wildCard;
|
||||||
|
DIR* dir;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||||
|
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static bool isFileExecutable (const String& filename)
|
||||||
|
{
|
||||||
|
beast_statStruct info;
|
||||||
|
|
||||||
|
return beast_stat (filename, info)
|
||||||
|
&& S_ISREG (info.st_mode)
|
||||||
|
&& access (filename.toUTF8(), X_OK) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||||
|
{
|
||||||
|
String cmdString (fileName.replace (" ", "\\ ",false));
|
||||||
|
cmdString << " " << parameters;
|
||||||
|
|
||||||
|
if (URL::isProbablyAWebsiteURL (fileName)
|
||||||
|
|| cmdString.startsWithIgnoreCase ("file:")
|
||||||
|
|| URL::isProbablyAnEmailAddress (fileName)
|
||||||
|
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|
||||||
|
|| ! isFileExecutable (fileName))
|
||||||
|
{
|
||||||
|
// create a command that tries to launch a bunch of likely browsers
|
||||||
|
const char* const browserNames[] = { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
|
||||||
|
"google-chrome", "chromium-browser", "opera", "konqueror" };
|
||||||
|
StringArray cmdLines;
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (browserNames); ++i)
|
||||||
|
cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
|
||||||
|
|
||||||
|
cmdString = cmdLines.joinIntoString (" || ");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
|
||||||
|
|
||||||
|
const int cpid = fork();
|
||||||
|
|
||||||
|
if (cpid == 0)
|
||||||
|
{
|
||||||
|
setsid();
|
||||||
|
|
||||||
|
// Child process
|
||||||
|
execve (argv[0], (char**) argv, environ);
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpid >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::revealToUser() const
|
||||||
|
{
|
||||||
|
if (isDirectory())
|
||||||
|
startAsProcess();
|
||||||
|
else if (getParentDirectory().exists())
|
||||||
|
getParentDirectory().startAsProcess();
|
||||||
|
}
|
||||||
457
Subtrees/beast/modules/beast_core/native/beast_linux_Network.cpp
Normal file
457
Subtrees/beast/modules/beast_core/native/beast_linux_Network.cpp
Normal file
@@ -0,0 +1,457 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
const int s = socket (AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (s != -1)
|
||||||
|
{
|
||||||
|
char buf [1024];
|
||||||
|
struct ifconf ifc;
|
||||||
|
ifc.ifc_len = sizeof (buf);
|
||||||
|
ifc.ifc_buf = buf;
|
||||||
|
ioctl (s, SIOCGIFCONF, &ifc);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
|
||||||
|
{
|
||||||
|
struct ifreq ifr;
|
||||||
|
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
|
||||||
|
|
||||||
|
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
|
||||||
|
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
|
||||||
|
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
|
||||||
|
{
|
||||||
|
result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close (s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
|
||||||
|
const String& /* emailSubject */,
|
||||||
|
const String& /* bodyText */,
|
||||||
|
const StringArray& /* filesToAttach */)
|
||||||
|
{
|
||||||
|
jassertfalse; // xxx todo
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WebInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||||
|
: socketHandle (-1), levelsOfRedirection (0),
|
||||||
|
address (address_), headers (headers_), postData (postData_), position (0),
|
||||||
|
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||||
|
{
|
||||||
|
createConnection (progressCallback, progressCallbackContext);
|
||||||
|
|
||||||
|
if (responseHeaders != nullptr && ! isError())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < headerLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String& headersEntry = headerLines[i];
|
||||||
|
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String previousValue ((*responseHeaders) [key]);
|
||||||
|
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~WebInputStream()
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isError() const { return socketHandle < 0; }
|
||||||
|
bool isExhausted() { return finished; }
|
||||||
|
int64 getPosition() { return position; }
|
||||||
|
|
||||||
|
int64 getTotalLength()
|
||||||
|
{
|
||||||
|
//xxx to do
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (void* buffer, int bytesToRead)
|
||||||
|
{
|
||||||
|
if (finished || isError())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fd_set readbits;
|
||||||
|
FD_ZERO (&readbits);
|
||||||
|
FD_SET (socketHandle, &readbits);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = bmax (1, timeOutMs / 1000);
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
|
||||||
|
return 0; // (timeout)
|
||||||
|
|
||||||
|
const int bytesRead = bmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
|
||||||
|
if (bytesRead == 0)
|
||||||
|
finished = true;
|
||||||
|
position += bytesRead;
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setPosition (int64 wantedPos)
|
||||||
|
{
|
||||||
|
if (isError())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (wantedPos != position)
|
||||||
|
{
|
||||||
|
finished = false;
|
||||||
|
|
||||||
|
if (wantedPos < position)
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
position = 0;
|
||||||
|
createConnection (0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipNextBytes (wantedPos - position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private:
|
||||||
|
int socketHandle, levelsOfRedirection;
|
||||||
|
StringArray headerLines;
|
||||||
|
String address, headers;
|
||||||
|
MemoryBlock postData;
|
||||||
|
int64 position;
|
||||||
|
bool finished;
|
||||||
|
const bool isPost;
|
||||||
|
const int timeOutMs;
|
||||||
|
|
||||||
|
void closeSocket()
|
||||||
|
{
|
||||||
|
if (socketHandle >= 0)
|
||||||
|
close (socketHandle);
|
||||||
|
|
||||||
|
socketHandle = -1;
|
||||||
|
levelsOfRedirection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
|
||||||
|
uint32 timeOutTime = Time::getMillisecondCounter();
|
||||||
|
|
||||||
|
if (timeOutMs == 0)
|
||||||
|
timeOutTime += 60000;
|
||||||
|
else if (timeOutMs < 0)
|
||||||
|
timeOutTime = 0xffffffff;
|
||||||
|
else
|
||||||
|
timeOutTime += timeOutMs;
|
||||||
|
|
||||||
|
String hostName, hostPath;
|
||||||
|
int hostPort;
|
||||||
|
if (! decomposeURL (address, hostName, hostPath, hostPort))
|
||||||
|
return;
|
||||||
|
|
||||||
|
String serverName, proxyName, proxyPath;
|
||||||
|
int proxyPort = 0;
|
||||||
|
int port = 0;
|
||||||
|
|
||||||
|
const String proxyURL (getenv ("http_proxy"));
|
||||||
|
if (proxyURL.startsWithIgnoreCase ("http://"))
|
||||||
|
{
|
||||||
|
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
|
||||||
|
return;
|
||||||
|
|
||||||
|
serverName = proxyName;
|
||||||
|
port = proxyPort;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serverName = hostName;
|
||||||
|
port = hostPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct addrinfo hints;
|
||||||
|
zerostruct (hints);
|
||||||
|
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_NUMERICSERV;
|
||||||
|
|
||||||
|
struct addrinfo* result = nullptr;
|
||||||
|
if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
socketHandle = socket (result->ai_family, result->ai_socktype, 0);
|
||||||
|
|
||||||
|
if (socketHandle == -1)
|
||||||
|
{
|
||||||
|
freeaddrinfo (result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int receiveBufferSize = 16384;
|
||||||
|
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
|
||||||
|
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
|
||||||
|
|
||||||
|
#if BEAST_MAC
|
||||||
|
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
freeaddrinfo (result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo (result);
|
||||||
|
|
||||||
|
{
|
||||||
|
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
|
||||||
|
hostPath, address, headers, postData, isPost));
|
||||||
|
|
||||||
|
if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext))
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String responseHeader (readResponse (socketHandle, timeOutTime));
|
||||||
|
|
||||||
|
if (responseHeader.isNotEmpty())
|
||||||
|
{
|
||||||
|
headerLines = StringArray::fromLines (responseHeader);
|
||||||
|
|
||||||
|
const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
|
||||||
|
.substring (0, 3).getIntValue();
|
||||||
|
|
||||||
|
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
|
||||||
|
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
|
||||||
|
|
||||||
|
String location (findHeaderItem (headerLines, "Location:"));
|
||||||
|
|
||||||
|
if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty())
|
||||||
|
{
|
||||||
|
if (! location.startsWithIgnoreCase ("http://"))
|
||||||
|
location = "http://" + location;
|
||||||
|
|
||||||
|
if (++levelsOfRedirection <= 3)
|
||||||
|
{
|
||||||
|
address = location;
|
||||||
|
createConnection (progressCallback, progressCallbackContext);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levelsOfRedirection = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static String readResponse (const int socketHandle, const uint32 timeOutTime)
|
||||||
|
{
|
||||||
|
int bytesRead = 0, numConsecutiveLFs = 0;
|
||||||
|
MemoryBlock buffer (1024, true);
|
||||||
|
|
||||||
|
while (numConsecutiveLFs < 2 && bytesRead < 32768
|
||||||
|
&& Time::getMillisecondCounter() <= timeOutTime)
|
||||||
|
{
|
||||||
|
fd_set readbits;
|
||||||
|
FD_ZERO (&readbits);
|
||||||
|
FD_SET (socketHandle, &readbits);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = bmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000);
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
|
||||||
|
return String::empty; // (timeout)
|
||||||
|
|
||||||
|
buffer.ensureSize (bytesRead + 8, true);
|
||||||
|
char* const dest = (char*) buffer.getData() + bytesRead;
|
||||||
|
|
||||||
|
if (recv (socketHandle, dest, 1, 0) == -1)
|
||||||
|
return String::empty;
|
||||||
|
|
||||||
|
const char lastByte = *dest;
|
||||||
|
++bytesRead;
|
||||||
|
|
||||||
|
if (lastByte == '\n')
|
||||||
|
++numConsecutiveLFs;
|
||||||
|
else if (lastByte != '\r')
|
||||||
|
numConsecutiveLFs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String header (CharPointer_UTF8 ((const char*) buffer.getData()));
|
||||||
|
|
||||||
|
if (header.startsWithIgnoreCase ("HTTP/"))
|
||||||
|
return header.trimEnd();
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
|
||||||
|
{
|
||||||
|
if (! headers.containsIgnoreCase (key))
|
||||||
|
dest << "\r\n" << key << ' ' << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
|
||||||
|
{
|
||||||
|
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
|
||||||
|
|
||||||
|
if (port > 0)
|
||||||
|
dest << ':' << port;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
|
||||||
|
const String& proxyName, const int proxyPort,
|
||||||
|
const String& hostPath, const String& originalURL,
|
||||||
|
const String& userHeaders, const MemoryBlock& postData,
|
||||||
|
const bool isPost)
|
||||||
|
{
|
||||||
|
MemoryOutputStream header;
|
||||||
|
|
||||||
|
if (proxyName.isEmpty())
|
||||||
|
writeHost (header, isPost, hostPath, hostName, hostPort);
|
||||||
|
else
|
||||||
|
writeHost (header, isPost, originalURL, proxyName, proxyPort);
|
||||||
|
|
||||||
|
writeValueIfNotPresent (header, userHeaders, "User-Agent:", "BEAST/" BEAST_STRINGIFY(BEAST_MAJOR_VERSION)
|
||||||
|
"." BEAST_STRINGIFY(BEAST_MINOR_VERSION)
|
||||||
|
"." BEAST_STRINGIFY(BEAST_BUILDNUMBER));
|
||||||
|
writeValueIfNotPresent (header, userHeaders, "Connection:", "Close");
|
||||||
|
|
||||||
|
if (isPost)
|
||||||
|
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
|
||||||
|
|
||||||
|
header << "\r\n" << userHeaders
|
||||||
|
<< "\r\n" << postData;
|
||||||
|
|
||||||
|
return header.getMemoryBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
size_t totalHeaderSent = 0;
|
||||||
|
|
||||||
|
while (totalHeaderSent < requestHeader.getSize())
|
||||||
|
{
|
||||||
|
if (Time::getMillisecondCounter() > timeOutTime)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int numToSend = bmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
|
||||||
|
|
||||||
|
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
totalHeaderSent += numToSend;
|
||||||
|
|
||||||
|
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decomposeURL (const String& url, String& host, String& path, int& port)
|
||||||
|
{
|
||||||
|
if (! url.startsWithIgnoreCase ("http://"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int nextSlash = url.indexOfChar (7, '/');
|
||||||
|
int nextColon = url.indexOfChar (7, ':');
|
||||||
|
if (nextColon > nextSlash && nextSlash > 0)
|
||||||
|
nextColon = -1;
|
||||||
|
|
||||||
|
if (nextColon >= 0)
|
||||||
|
{
|
||||||
|
host = url.substring (7, nextColon);
|
||||||
|
|
||||||
|
if (nextSlash >= 0)
|
||||||
|
port = url.substring (nextColon + 1, nextSlash).getIntValue();
|
||||||
|
else
|
||||||
|
port = url.substring (nextColon + 1).getIntValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port = 80;
|
||||||
|
|
||||||
|
if (nextSlash >= 0)
|
||||||
|
host = url.substring (7, nextSlash);
|
||||||
|
else
|
||||||
|
host = url.substring (7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextSlash >= 0)
|
||||||
|
path = url.substring (nextSlash);
|
||||||
|
else
|
||||||
|
path = "/";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String findHeaderItem (const StringArray& lines, const String& itemName)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < lines.size(); ++i)
|
||||||
|
if (lines[i].startsWithIgnoreCase (itemName))
|
||||||
|
return lines[i].substring (itemName.length()).trim();
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||||
|
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||||
|
{
|
||||||
|
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||||
|
progressCallback, progressCallbackContext,
|
||||||
|
headers, timeOutMs, responseHeaders));
|
||||||
|
|
||||||
|
return wi->isError() ? nullptr : wi.release();
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
void Logger::outputDebugString (const String& text)
|
||||||
|
{
|
||||||
|
std::cerr << text << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||||
|
{
|
||||||
|
return Linux;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getOperatingSystemName()
|
||||||
|
{
|
||||||
|
return "Linux";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemStats::isOperatingSystem64Bit()
|
||||||
|
{
|
||||||
|
#if BEAST_64BIT
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
//xxx not sure how to find this out?..
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace LinuxStatsHelpers
|
||||||
|
{
|
||||||
|
String getCpuInfo (const char* const key)
|
||||||
|
{
|
||||||
|
StringArray lines;
|
||||||
|
File ("/proc/cpuinfo").readLines (lines);
|
||||||
|
|
||||||
|
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
|
||||||
|
if (lines[i].startsWithIgnoreCase (key))
|
||||||
|
return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
return LinuxStatsHelpers::getCpuInfo ("vendor_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getCpuSpeedInMegaherz()
|
||||||
|
{
|
||||||
|
return roundToInt (LinuxStatsHelpers::getCpuInfo ("cpu MHz").getFloatValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getMemorySizeInMegabytes()
|
||||||
|
{
|
||||||
|
struct sysinfo sysi;
|
||||||
|
|
||||||
|
if (sysinfo (&sysi) == 0)
|
||||||
|
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getPageSize()
|
||||||
|
{
|
||||||
|
return sysconf (_SC_PAGESIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getLogonName()
|
||||||
|
{
|
||||||
|
const char* user = getenv ("USER");
|
||||||
|
|
||||||
|
if (user == nullptr)
|
||||||
|
{
|
||||||
|
struct passwd* const pw = getpwuid (getuid());
|
||||||
|
if (pw != nullptr)
|
||||||
|
user = pw->pw_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharPointer_UTF8 (user);
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getFullUserName()
|
||||||
|
{
|
||||||
|
return getLogonName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getComputerName()
|
||||||
|
{
|
||||||
|
char name [256] = { 0 };
|
||||||
|
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||||
|
return name;
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLocaleValue (nl_item key)
|
||||||
|
{
|
||||||
|
const char* oldLocale = ::setlocale (LC_ALL, "");
|
||||||
|
return String (const_cast <const char*> (nl_langinfo (key)));
|
||||||
|
::setlocale (LC_ALL, oldLocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
|
||||||
|
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
|
||||||
|
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::CPUFlags::CPUFlags()
|
||||||
|
{
|
||||||
|
const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
|
||||||
|
hasMMX = flags.contains ("mmx");
|
||||||
|
hasSSE = flags.contains ("sse");
|
||||||
|
hasSSE2 = flags.contains ("sse2");
|
||||||
|
has3DNow = flags.contains ("3dnow");
|
||||||
|
|
||||||
|
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
uint32 beast_millisecondsSinceStartup() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicks() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||||
|
{
|
||||||
|
return 1000000; // (microseconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
double Time::getMillisecondCounterHiRes() noexcept
|
||||||
|
{
|
||||||
|
return getHighResolutionTicks() * 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Time::setSystemTimeToThisTime() const
|
||||||
|
{
|
||||||
|
timeval t;
|
||||||
|
t.tv_sec = millisSinceEpoch / 1000;
|
||||||
|
t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
|
||||||
|
|
||||||
|
return settimeofday (&t, 0) == 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in beast_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void Process::setPriority (const ProcessPriority prior)
|
||||||
|
{
|
||||||
|
const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
|
||||||
|
const int minp = sched_get_priority_min (policy);
|
||||||
|
const int maxp = sched_get_priority_max (policy);
|
||||||
|
|
||||||
|
struct sched_param param;
|
||||||
|
|
||||||
|
switch (prior)
|
||||||
|
{
|
||||||
|
case LowPriority:
|
||||||
|
case NormalPriority: param.sched_priority = 0; break;
|
||||||
|
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
|
||||||
|
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
|
||||||
|
default: jassertfalse; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::terminate()
|
||||||
|
{
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
static char testResult = 0;
|
||||||
|
|
||||||
|
if (testResult == 0)
|
||||||
|
{
|
||||||
|
testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
|
||||||
|
|
||||||
|
if (testResult >= 0)
|
||||||
|
{
|
||||||
|
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
|
||||||
|
testResult = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return testResult < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_API bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return beast_isRunningUnderDebugger();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void swapUserAndEffectiveUser()
|
||||||
|
{
|
||||||
|
(void) setreuid (geteuid(), getuid());
|
||||||
|
(void) setregid (getegid(), getgid());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
|
||||||
|
void Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
|
||||||
480
Subtrees/beast/modules/beast_core/native/beast_mac_Files.mm
Normal file
480
Subtrees/beast/modules/beast_core/native/beast_mac_Files.mm
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in beast_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::copyInternal (const File& dest) const
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSFileManager* fm = [NSFileManager defaultManager];
|
||||||
|
|
||||||
|
return [fm fileExistsAtPath: beastStringToNS (fullPath)]
|
||||||
|
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||||
|
&& [fm copyItemAtPath: beastStringToNS (fullPath)
|
||||||
|
toPath: beastStringToNS (dest.getFullPathName())
|
||||||
|
error: nil];
|
||||||
|
#else
|
||||||
|
&& [fm copyPath: beastStringToNS (fullPath)
|
||||||
|
toPath: beastStringToNS (dest.getFullPathName())
|
||||||
|
handler: nil];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::findFileSystemRoots (Array<File>& destArray)
|
||||||
|
{
|
||||||
|
destArray.add (File ("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace FileHelpers
|
||||||
|
{
|
||||||
|
static bool isFileOnDriveType (const File& f, const char* const* types)
|
||||||
|
{
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
if (beast_doStatFS (f, buf))
|
||||||
|
{
|
||||||
|
const String type (buf.f_fstypename);
|
||||||
|
|
||||||
|
while (*types != 0)
|
||||||
|
if (type.equalsIgnoreCase (*types++))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isHiddenFile (const String& path)
|
||||||
|
{
|
||||||
|
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSNumber* hidden = nil;
|
||||||
|
NSError* err = nil;
|
||||||
|
|
||||||
|
return [[NSURL fileURLWithPath: beastStringToNS (path)]
|
||||||
|
getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
|
||||||
|
&& [hidden boolValue];
|
||||||
|
}
|
||||||
|
#elif BEAST_IOS
|
||||||
|
return File (path).getFileName().startsWithChar ('.');
|
||||||
|
#else
|
||||||
|
FSRef ref;
|
||||||
|
LSItemInfoRecord info;
|
||||||
|
|
||||||
|
return FSPathMakeRefWithOptions ((const UInt8*) path.toRawUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
|
||||||
|
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
|
||||||
|
&& (info.flags & kLSItemInfoIsInvisible) != 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_IOS
|
||||||
|
String getIOSSystemLocation (NSSearchPathDirectory type)
|
||||||
|
{
|
||||||
|
return nsStringToBeast ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
|
||||||
|
objectAtIndex: 0]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool launchExecutable (const String& pathAndArguments)
|
||||||
|
{
|
||||||
|
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
|
||||||
|
|
||||||
|
const int cpid = fork();
|
||||||
|
|
||||||
|
if (cpid == 0)
|
||||||
|
{
|
||||||
|
// Child process
|
||||||
|
if (execve (argv[0], (char**) argv, 0) < 0)
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cpid < 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnCDRomDrive() const
|
||||||
|
{
|
||||||
|
const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", 0 };
|
||||||
|
|
||||||
|
return FileHelpers::isFileOnDriveType (*this, cdTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnHardDisk() const
|
||||||
|
{
|
||||||
|
const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", 0 };
|
||||||
|
|
||||||
|
return ! (isOnCDRomDrive() || FileHelpers::isFileOnDriveType (*this, nonHDTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnRemovableDrive() const
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
return false; // xxx is this possible?
|
||||||
|
#else
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
BOOL removable = false;
|
||||||
|
|
||||||
|
[[NSWorkspace sharedWorkspace]
|
||||||
|
getFileSystemInfoForPath: beastStringToNS (getFullPathName())
|
||||||
|
isRemovable: &removable
|
||||||
|
isWritable: nil
|
||||||
|
isUnmountable: nil
|
||||||
|
description: nil
|
||||||
|
type: nil];
|
||||||
|
|
||||||
|
return removable;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isHidden() const
|
||||||
|
{
|
||||||
|
return FileHelpers::isHiddenFile (getFullPathName());
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
const char* const* beast_argv = nullptr;
|
||||||
|
int beast_argc = 0;
|
||||||
|
|
||||||
|
File File::getSpecialLocation (const SpecialLocationType type)
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
String resultPath;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case userHomeDirectory: resultPath = nsStringToBeast (NSHomeDirectory()); break;
|
||||||
|
|
||||||
|
#if BEAST_IOS
|
||||||
|
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
|
||||||
|
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
{
|
||||||
|
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
|
||||||
|
tmp = tmp.getChildFile (beast_getExecutableFile().getFileNameWithoutExtension());
|
||||||
|
tmp.createDirectory();
|
||||||
|
return tmp.getFullPathName();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
case userDocumentsDirectory: resultPath = "~/Documents"; break;
|
||||||
|
case userDesktopDirectory: resultPath = "~/Desktop"; break;
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
{
|
||||||
|
File tmp ("~/Library/Caches/" + beast_getExecutableFile().getFileNameWithoutExtension());
|
||||||
|
tmp.createDirectory();
|
||||||
|
return tmp.getFullPathName();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
case userMusicDirectory: resultPath = "~/Music"; break;
|
||||||
|
case userMoviesDirectory: resultPath = "~/Movies"; break;
|
||||||
|
case userPicturesDirectory: resultPath = "~/Pictures"; break;
|
||||||
|
case userApplicationDataDirectory: resultPath = "~/Library"; break;
|
||||||
|
case commonApplicationDataDirectory: resultPath = "/Library"; break;
|
||||||
|
case globalApplicationsDirectory: resultPath = "/Applications"; break;
|
||||||
|
|
||||||
|
case invokedExecutableFile:
|
||||||
|
if (beast_argv != nullptr && beast_argc > 0)
|
||||||
|
return File (CharPointer_UTF8 (beast_argv[0]));
|
||||||
|
// deliberate fall-through...
|
||||||
|
|
||||||
|
case currentExecutableFile:
|
||||||
|
return beast_getExecutableFile();
|
||||||
|
|
||||||
|
case currentApplicationFile:
|
||||||
|
{
|
||||||
|
const File exe (beast_getExecutableFile());
|
||||||
|
const File parent (exe.getParentDirectory());
|
||||||
|
|
||||||
|
#if BEAST_IOS
|
||||||
|
return parent;
|
||||||
|
#else
|
||||||
|
return parent.getFullPathName().endsWithIgnoreCase ("Contents/MacOS")
|
||||||
|
? parent.getParentDirectory().getParentDirectory()
|
||||||
|
: exe;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
case hostApplicationPath:
|
||||||
|
{
|
||||||
|
unsigned int size = 8192;
|
||||||
|
HeapBlock<char> buffer;
|
||||||
|
buffer.calloc (size + 8);
|
||||||
|
|
||||||
|
_NSGetExecutablePath (buffer.getData(), &size);
|
||||||
|
return String::fromUTF8 (buffer, (int) size);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // unknown type?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultPath.isNotEmpty())
|
||||||
|
return File (resultPath.convertToPrecomposedUnicode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return File::nonexistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String File::getVersion() const
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
if (NSBundle* bundle = [NSBundle bundleWithPath: beastStringToNS (getFullPathName())])
|
||||||
|
if (NSDictionary* info = [bundle infoDictionary])
|
||||||
|
if (NSString* name = [info valueForKey: nsStringLiteral ("CFBundleShortVersionString")])
|
||||||
|
return nsStringToBeast (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
File File::getLinkedTarget() const
|
||||||
|
{
|
||||||
|
#if BEAST_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
|
NSString* dest = [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: beastStringToNS (getFullPathName()) error: nil];
|
||||||
|
#else
|
||||||
|
// (the cast here avoids a deprecation warning)
|
||||||
|
NSString* dest = [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: beastStringToNS (getFullPathName())];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (dest != nil)
|
||||||
|
return File (nsStringToBeast (dest));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::moveToTrash() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#if BEAST_IOS
|
||||||
|
return deleteFile(); //xxx is there a trashcan on the iOS?
|
||||||
|
#else
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSString* p = beastStringToNS (getFullPathName());
|
||||||
|
|
||||||
|
return [[NSWorkspace sharedWorkspace]
|
||||||
|
performFileOperation: NSWorkspaceRecycleOperation
|
||||||
|
source: [p stringByDeletingLastPathComponent]
|
||||||
|
destination: nsEmptyString()
|
||||||
|
files: [NSArray arrayWithObject: [p lastPathComponent]]
|
||||||
|
tag: nil ];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class DirectoryIterator::NativeIterator::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const File& directory, const String& wildCard_)
|
||||||
|
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||||
|
wildCard (wildCard_),
|
||||||
|
enumerator (nil)
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: beastStringToNS (directory.getFullPathName())] retain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
[enumerator release];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
const char* wildcardUTF8 = nullptr;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
NSString* file;
|
||||||
|
if (enumerator == nil || (file = [enumerator nextObject]) == nil)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
[enumerator skipDescendents];
|
||||||
|
filenameFound = nsStringToBeast (file);
|
||||||
|
|
||||||
|
if (wildcardUTF8 == nullptr)
|
||||||
|
wildcardUTF8 = wildCard.toUTF8();
|
||||||
|
|
||||||
|
if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const String fullPath (parentDir + filenameFound);
|
||||||
|
updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
|
||||||
|
if (isHidden != nullptr)
|
||||||
|
*isHidden = FileHelpers::isHiddenFile (fullPath);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
String parentDir, wildCard;
|
||||||
|
NSDirectoryEnumerator* enumerator;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildcard)
|
||||||
|
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildcard))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
return [[UIApplication sharedApplication] openURL: [NSURL URLWithString: beastStringToNS (fileName)]];
|
||||||
|
#else
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
if (parameters.isEmpty())
|
||||||
|
{
|
||||||
|
return [[NSWorkspace sharedWorkspace] openFile: beastStringToNS (fileName)]
|
||||||
|
|| [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: beastStringToNS (fileName)]];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
const File file (fileName);
|
||||||
|
|
||||||
|
if (file.isBundle())
|
||||||
|
{
|
||||||
|
NSMutableArray* urls = [NSMutableArray array];
|
||||||
|
|
||||||
|
StringArray docs;
|
||||||
|
docs.addTokens (parameters, true);
|
||||||
|
for (int i = 0; i < docs.size(); ++i)
|
||||||
|
[urls addObject: beastStringToNS (docs[i])];
|
||||||
|
|
||||||
|
ok = [[NSWorkspace sharedWorkspace] openURLs: urls
|
||||||
|
withAppBundleIdentifier: [[NSBundle bundleWithPath: beastStringToNS (fileName)] bundleIdentifier]
|
||||||
|
options: 0
|
||||||
|
additionalEventParamDescriptor: nil
|
||||||
|
launchIdentifiers: nil];
|
||||||
|
}
|
||||||
|
else if (file.exists())
|
||||||
|
{
|
||||||
|
ok = FileHelpers::launchExecutable ("\"" + fileName + "\" " + parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::revealToUser() const
|
||||||
|
{
|
||||||
|
#if ! BEAST_IOS
|
||||||
|
if (exists())
|
||||||
|
[[NSWorkspace sharedWorkspace] selectFile: beastStringToNS (getFullPathName()) inFileViewerRootedAtPath: nsEmptyString()];
|
||||||
|
else if (getParentDirectory().exists())
|
||||||
|
getParentDirectory().revealToUser();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
OSType File::getMacOSType() const
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
#if BEAST_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
|
NSDictionary* fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath: beastStringToNS (getFullPathName()) error: nil];
|
||||||
|
#else
|
||||||
|
// (the cast here avoids a deprecation warning)
|
||||||
|
NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: beastStringToNS (getFullPathName()) traverseLink: NO];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return [fileDict fileHFSTypeCode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isBundle() const
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
return false; // xxx can't find a sensible way to do this without trying to open the bundle..
|
||||||
|
#else
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: beastStringToNS (getFullPathName())];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_MAC
|
||||||
|
void File::addToDock() const
|
||||||
|
{
|
||||||
|
// check that it's not already there...
|
||||||
|
if (! beast_getOutputFromCommand ("defaults read com.apple.dock persistent-apps").containsIgnoreCase (getFullPathName()))
|
||||||
|
{
|
||||||
|
beast_runSystemCommand ("defaults write com.apple.dock persistent-apps -array-add \"<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>"
|
||||||
|
+ getFullPathName() + "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>\"");
|
||||||
|
|
||||||
|
beast_runSystemCommand ("osascript -e \"tell application \\\"Dock\\\" to quit\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
427
Subtrees/beast/modules/beast_core/native/beast_mac_Network.mm
Normal file
427
Subtrees/beast/modules/beast_core/native/beast_mac_Network.mm
Normal file
@@ -0,0 +1,427 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
ifaddrs* addrs = nullptr;
|
||||||
|
|
||||||
|
if (getifaddrs (&addrs) == 0)
|
||||||
|
{
|
||||||
|
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
|
||||||
|
{
|
||||||
|
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
|
||||||
|
if (sto->ss_family == AF_LINK)
|
||||||
|
{
|
||||||
|
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
|
||||||
|
|
||||||
|
#ifndef IFT_ETHER
|
||||||
|
#define IFT_ETHER 6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sadd->sdl_type == IFT_ETHER)
|
||||||
|
result.addIfNotAlreadyThere (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs (addrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||||
|
const String& emailSubject,
|
||||||
|
const String& bodyText,
|
||||||
|
const StringArray& filesToAttach)
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
//xxx probably need to use MFMailComposeViewController
|
||||||
|
jassertfalse;
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
String script;
|
||||||
|
script << "tell application \"Mail\"\r\n"
|
||||||
|
"set newMessage to make new outgoing message with properties {subject:\""
|
||||||
|
<< emailSubject.replace ("\"", "\\\"")
|
||||||
|
<< "\", content:\""
|
||||||
|
<< bodyText.replace ("\"", "\\\"")
|
||||||
|
<< "\" & return & return}\r\n"
|
||||||
|
"tell newMessage\r\n"
|
||||||
|
"set visible to true\r\n"
|
||||||
|
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||||
|
"make new to recipient at end of to recipients with properties {address:\""
|
||||||
|
<< targetEmailAddress
|
||||||
|
<< "\"}\r\n";
|
||||||
|
|
||||||
|
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||||
|
{
|
||||||
|
script << "tell content\r\n"
|
||||||
|
"make new attachment with properties {file name:\""
|
||||||
|
<< filesToAttach[i].replace ("\"", "\\\"")
|
||||||
|
<< "\"} at after the last paragraph\r\n"
|
||||||
|
"end tell\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
script << "end tell\r\n"
|
||||||
|
"end tell\r\n";
|
||||||
|
|
||||||
|
NSAppleScript* s = [[NSAppleScript alloc] initWithSource: beastStringToNS (script)];
|
||||||
|
NSDictionary* error = nil;
|
||||||
|
const bool ok = [s executeAndReturnError: &error] != nil;
|
||||||
|
[s release];
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class URLConnectionState : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
URLConnectionState (NSURLRequest* req)
|
||||||
|
: Thread ("http connection"),
|
||||||
|
contentLength (-1),
|
||||||
|
delegate (nil),
|
||||||
|
request ([req retain]),
|
||||||
|
connection (nil),
|
||||||
|
data ([[NSMutableData data] retain]),
|
||||||
|
headers (nil),
|
||||||
|
initialised (false),
|
||||||
|
hasFailed (false),
|
||||||
|
hasFinished (false)
|
||||||
|
{
|
||||||
|
static DelegateClass cls;
|
||||||
|
delegate = [cls.createInstance() init];
|
||||||
|
DelegateClass::setState (delegate, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~URLConnectionState()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
[connection release];
|
||||||
|
[data release];
|
||||||
|
[request release];
|
||||||
|
[headers release];
|
||||||
|
[delegate release];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start (URL::OpenStreamProgressCallback* callback, void* context)
|
||||||
|
{
|
||||||
|
startThread();
|
||||||
|
|
||||||
|
while (isThreadRunning() && ! initialised)
|
||||||
|
{
|
||||||
|
if (callback != nullptr)
|
||||||
|
callback (context, -1, (int) [[request HTTPBody] length]);
|
||||||
|
|
||||||
|
Thread::sleep (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection != nil && ! hasFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
[connection cancel];
|
||||||
|
stopThread (10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (char* dest, int numBytes)
|
||||||
|
{
|
||||||
|
int numDone = 0;
|
||||||
|
|
||||||
|
while (numBytes > 0)
|
||||||
|
{
|
||||||
|
const int available = bmin (numBytes, (int) [data length]);
|
||||||
|
|
||||||
|
if (available > 0)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (dataLock);
|
||||||
|
[data getBytes: dest length: (NSUInteger) available];
|
||||||
|
[data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
|
||||||
|
|
||||||
|
numDone += available;
|
||||||
|
numBytes -= available;
|
||||||
|
dest += available;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (hasFailed || hasFinished)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Thread::sleep (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return numDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void didReceiveResponse (NSURLResponse* response)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const ScopedLock sl (dataLock);
|
||||||
|
[data setLength: 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
initialised = true;
|
||||||
|
contentLength = [response expectedContentLength];
|
||||||
|
|
||||||
|
[headers release];
|
||||||
|
headers = nil;
|
||||||
|
|
||||||
|
if ([response isKindOfClass: [NSHTTPURLResponse class]])
|
||||||
|
headers = [[((NSHTTPURLResponse*) response) allHeaderFields] retain];
|
||||||
|
}
|
||||||
|
|
||||||
|
void didFailWithError (NSError* error)
|
||||||
|
{
|
||||||
|
DBG (nsStringToBeast ([error description])); (void) error;
|
||||||
|
hasFailed = true;
|
||||||
|
initialised = true;
|
||||||
|
signalThreadShouldExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void didReceiveData (NSData* newData)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (dataLock);
|
||||||
|
[data appendData: newData];
|
||||||
|
initialised = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void didSendBodyData (int /*totalBytesWritten*/, int /*totalBytesExpected*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishedLoading()
|
||||||
|
{
|
||||||
|
hasFinished = true;
|
||||||
|
initialised = true;
|
||||||
|
signalThreadShouldExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||||
|
delegate: delegate];
|
||||||
|
while (! threadShouldExit())
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 contentLength;
|
||||||
|
CriticalSection dataLock;
|
||||||
|
NSObject* delegate;
|
||||||
|
NSURLRequest* request;
|
||||||
|
NSURLConnection* connection;
|
||||||
|
NSMutableData* data;
|
||||||
|
NSDictionary* headers;
|
||||||
|
bool initialised, hasFailed, hasFinished;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
struct DelegateClass : public ObjCClass <NSObject>
|
||||||
|
{
|
||||||
|
DelegateClass() : ObjCClass <NSObject> ("BEASTAppDelegate_")
|
||||||
|
{
|
||||||
|
addIvar <URLConnectionState*> ("state");
|
||||||
|
|
||||||
|
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
|
||||||
|
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
|
||||||
|
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
|
||||||
|
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:totalBytesExpectedToWrite:),
|
||||||
|
connectionDidSendBodyData, "v@:@iii");
|
||||||
|
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
|
||||||
|
|
||||||
|
registerClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); }
|
||||||
|
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
|
||||||
|
{
|
||||||
|
getState (self)->didReceiveResponse (response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
|
||||||
|
{
|
||||||
|
getState (self)->didFailWithError (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
|
||||||
|
{
|
||||||
|
getState (self)->didReceiveData (newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
|
||||||
|
{
|
||||||
|
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
|
||||||
|
{
|
||||||
|
getState (self)->finishedLoading();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WebInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||||
|
: address (address_), headers (headers_), postData (postData_), position (0),
|
||||||
|
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
createConnection (progressCallback, progressCallbackContext);
|
||||||
|
|
||||||
|
if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil)
|
||||||
|
{
|
||||||
|
NSEnumerator* enumerator = [connection->headers keyEnumerator];
|
||||||
|
NSString* key;
|
||||||
|
|
||||||
|
while ((key = [enumerator nextObject]) != nil)
|
||||||
|
responseHeaders->set (nsStringToBeast (key),
|
||||||
|
nsStringToBeast ((NSString*) [connection->headers objectForKey: key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isError() const { return connection == nullptr; }
|
||||||
|
int64 getTotalLength() { return connection == nullptr ? -1 : connection->contentLength; }
|
||||||
|
bool isExhausted() { return finished; }
|
||||||
|
int64 getPosition() { return position; }
|
||||||
|
|
||||||
|
int read (void* buffer, int bytesToRead)
|
||||||
|
{
|
||||||
|
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||||
|
|
||||||
|
if (finished || isError())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
const int bytesRead = connection->read (static_cast <char*> (buffer), bytesToRead);
|
||||||
|
position += bytesRead;
|
||||||
|
|
||||||
|
if (bytesRead == 0)
|
||||||
|
finished = true;
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setPosition (int64 wantedPos)
|
||||||
|
{
|
||||||
|
if (wantedPos != position)
|
||||||
|
{
|
||||||
|
finished = false;
|
||||||
|
|
||||||
|
if (wantedPos < position)
|
||||||
|
{
|
||||||
|
connection = nullptr;
|
||||||
|
position = 0;
|
||||||
|
createConnection (0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipNextBytes (wantedPos - position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ScopedPointer<URLConnectionState> connection;
|
||||||
|
String address, headers;
|
||||||
|
MemoryBlock postData;
|
||||||
|
int64 position;
|
||||||
|
bool finished;
|
||||||
|
const bool isPost;
|
||||||
|
const int timeOutMs;
|
||||||
|
|
||||||
|
void createConnection (URL::OpenStreamProgressCallback* progressCallback,
|
||||||
|
void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
bassert (connection == nullptr);
|
||||||
|
|
||||||
|
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: beastStringToNS (address)]
|
||||||
|
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
|
||||||
|
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
|
||||||
|
|
||||||
|
if (req != nil)
|
||||||
|
{
|
||||||
|
[req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")];
|
||||||
|
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
|
||||||
|
|
||||||
|
StringArray headerLines;
|
||||||
|
headerLines.addLines (headers);
|
||||||
|
headerLines.removeEmptyStrings (true);
|
||||||
|
|
||||||
|
for (int i = 0; i < headerLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim());
|
||||||
|
const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim());
|
||||||
|
|
||||||
|
if (key.isNotEmpty() && value.isNotEmpty())
|
||||||
|
[req addValue: beastStringToNS (value) forHTTPHeaderField: beastStringToNS (key)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPost && postData.getSize() > 0)
|
||||||
|
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
|
||||||
|
length: postData.getSize()]];
|
||||||
|
|
||||||
|
connection = new URLConnectionState (req);
|
||||||
|
|
||||||
|
if (! connection->start (progressCallback, progressCallbackContext))
|
||||||
|
connection = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||||
|
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||||
|
{
|
||||||
|
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||||
|
progressCallback, progressCallbackContext,
|
||||||
|
headers, timeOutMs, responseHeaders));
|
||||||
|
|
||||||
|
return wi->isError() ? nullptr : wi.release();
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
String String::fromCFString (CFStringRef cfString)
|
||||||
|
{
|
||||||
|
if (cfString == 0)
|
||||||
|
return String::empty;
|
||||||
|
|
||||||
|
CFRange range = { 0, CFStringGetLength (cfString) };
|
||||||
|
HeapBlock <UniChar> u ((size_t) range.length + 1);
|
||||||
|
CFStringGetCharacters (cfString, range, u);
|
||||||
|
u[range.length] = 0;
|
||||||
|
|
||||||
|
return String (CharPointer_UTF16 ((const CharPointer_UTF16::CharType*) u.getData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef String::toCFString() const
|
||||||
|
{
|
||||||
|
CharPointer_UTF16 utf16 (toUTF16());
|
||||||
|
return CFStringCreateWithCharacters (kCFAllocatorDefault, (const UniChar*) utf16.getAddress(), (CFIndex) utf16.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::convertToPrecomposedUnicode() const
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
return nsStringToBeast ([beastStringToNS (*this) precomposedStringWithCanonicalMapping]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
UnicodeMapping map;
|
||||||
|
|
||||||
|
map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||||
|
kUnicodeNoSubset,
|
||||||
|
kTextEncodingDefaultFormat);
|
||||||
|
|
||||||
|
map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||||
|
kUnicodeCanonicalCompVariant,
|
||||||
|
kTextEncodingDefaultFormat);
|
||||||
|
|
||||||
|
map.mappingVersion = kUnicodeUseLatestMapping;
|
||||||
|
|
||||||
|
UnicodeToTextInfo conversionInfo = 0;
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
|
||||||
|
{
|
||||||
|
const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (getCharPointer());
|
||||||
|
|
||||||
|
HeapBlock <char> tempOut;
|
||||||
|
tempOut.calloc (bytesNeeded + 4);
|
||||||
|
|
||||||
|
ByteCount bytesRead = 0;
|
||||||
|
ByteCount outputBufferSize = 0;
|
||||||
|
|
||||||
|
if (ConvertFromUnicodeToText (conversionInfo,
|
||||||
|
bytesNeeded, (ConstUniCharArrayPtr) toUTF16().getAddress(),
|
||||||
|
kUnicodeDefaultDirectionMask,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
bytesNeeded, &bytesRead,
|
||||||
|
&outputBufferSize, tempOut) == noErr)
|
||||||
|
{
|
||||||
|
result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DisposeUnicodeToTextInfo (&conversionInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,291 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
ScopedAutoReleasePool::ScopedAutoReleasePool()
|
||||||
|
{
|
||||||
|
pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedAutoReleasePool::~ScopedAutoReleasePool()
|
||||||
|
{
|
||||||
|
[((NSAutoreleasePool*) pool) release];
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void Logger::outputDebugString (const String& text)
|
||||||
|
{
|
||||||
|
// Would prefer to use std::cerr here, but avoiding it for
|
||||||
|
// the moment, due to clang JIT linkage problems.
|
||||||
|
fputs (text.toRawUTF8(), stderr);
|
||||||
|
fputs ("\n", stderr);
|
||||||
|
fflush (stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace SystemStatsHelpers
|
||||||
|
{
|
||||||
|
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||||
|
static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type)
|
||||||
|
{
|
||||||
|
uint32 la = a, lb = b, lc = c, ld = d;
|
||||||
|
|
||||||
|
asm ("mov %%ebx, %%esi \n\t"
|
||||||
|
"cpuid \n\t"
|
||||||
|
"xchg %%esi, %%ebx"
|
||||||
|
: "=a" (la), "=S" (lb), "=c" (lc), "=d" (ld) : "a" (type)
|
||||||
|
#if BEAST_64BIT
|
||||||
|
, "b" (lb), "c" (lc), "d" (ld)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
a = la; b = lb; c = lc; d = ld;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::CPUFlags::CPUFlags()
|
||||||
|
{
|
||||||
|
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||||
|
uint32 familyModel = 0, extFeatures = 0, features = 0, dummy = 0;
|
||||||
|
SystemStatsHelpers::doCPUID (familyModel, extFeatures, dummy, features, 1);
|
||||||
|
|
||||||
|
hasMMX = (features & (1u << 23)) != 0;
|
||||||
|
hasSSE = (features & (1u << 25)) != 0;
|
||||||
|
hasSSE2 = (features & (1u << 26)) != 0;
|
||||||
|
has3DNow = (extFeatures & (1u << 31)) != 0;
|
||||||
|
#else
|
||||||
|
hasMMX = false;
|
||||||
|
hasSSE = false;
|
||||||
|
hasSSE2 = false;
|
||||||
|
has3DNow = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BEAST_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
|
numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
|
||||||
|
#else
|
||||||
|
numCpus = (int) MPProcessors();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_MAC
|
||||||
|
struct RLimitInitialiser
|
||||||
|
{
|
||||||
|
RLimitInitialiser()
|
||||||
|
{
|
||||||
|
rlimit lim;
|
||||||
|
getrlimit (RLIMIT_NOFILE, &lim);
|
||||||
|
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
|
||||||
|
setrlimit (RLIMIT_NOFILE, &lim);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static RLimitInitialiser rLimitInitialiser;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if ! BEAST_IOS
|
||||||
|
static String getOSXVersion()
|
||||||
|
{
|
||||||
|
BEAST_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:
|
||||||
|
nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")];
|
||||||
|
|
||||||
|
return nsStringToBeast ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
return iOS;
|
||||||
|
#else
|
||||||
|
StringArray parts;
|
||||||
|
parts.addTokens (getOSXVersion(), ".", String::empty);
|
||||||
|
|
||||||
|
bassert (parts[0].getIntValue() == 10);
|
||||||
|
const int major = parts[1].getIntValue();
|
||||||
|
bassert (major > 2);
|
||||||
|
|
||||||
|
return (OperatingSystemType) (major + MacOSX_10_4 - 4);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getOperatingSystemName()
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
return "iOS " + nsStringToBeast ([[UIDevice currentDevice] systemVersion]);
|
||||||
|
#else
|
||||||
|
return "Mac OSX " + getOSXVersion();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemStats::isOperatingSystem64Bit()
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
return false;
|
||||||
|
#elif BEAST_64BIT
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return getOperatingSystemType() >= MacOSX_10_6;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getMemorySizeInMegabytes()
|
||||||
|
{
|
||||||
|
uint64 mem = 0;
|
||||||
|
size_t memSize = sizeof (mem);
|
||||||
|
int mib[] = { CTL_HW, HW_MEMSIZE };
|
||||||
|
sysctl (mib, 2, &mem, &memSize, 0, 0);
|
||||||
|
return (int) (mem / (1024 * 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
#if BEAST_INTEL && ! BEAST_NO_INLINE_ASM
|
||||||
|
uint32 dummy = 0;
|
||||||
|
uint32 vendor[4] = { 0 };
|
||||||
|
|
||||||
|
SystemStatsHelpers::doCPUID (dummy, vendor[0], vendor[2], vendor[1], 0);
|
||||||
|
|
||||||
|
return String (reinterpret_cast <const char*> (vendor), 12);
|
||||||
|
#else
|
||||||
|
return String::empty;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getCpuSpeedInMegaherz()
|
||||||
|
{
|
||||||
|
uint64 speedHz = 0;
|
||||||
|
size_t speedSize = sizeof (speedHz);
|
||||||
|
int mib[] = { CTL_HW, HW_CPU_FREQ };
|
||||||
|
sysctl (mib, 2, &speedHz, &speedSize, 0, 0);
|
||||||
|
|
||||||
|
#if BEAST_BIG_ENDIAN
|
||||||
|
if (speedSize == 4)
|
||||||
|
speedHz >>= 32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (int) (speedHz / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getLogonName()
|
||||||
|
{
|
||||||
|
return nsStringToBeast (NSUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getFullUserName()
|
||||||
|
{
|
||||||
|
return nsStringToBeast (NSFullUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getComputerName()
|
||||||
|
{
|
||||||
|
char name [256] = { 0 };
|
||||||
|
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||||
|
return String (name).upToLastOccurrenceOf (".local", false, true);
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getLocaleValue (CFStringRef key)
|
||||||
|
{
|
||||||
|
CFLocaleRef cfLocale = CFLocaleCopyCurrent();
|
||||||
|
const String result (String::fromCFString ((CFStringRef) CFLocaleGetValue (cfLocale, key)));
|
||||||
|
CFRelease (cfLocale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getUserLanguage() { return getLocaleValue (kCFLocaleLanguageCode); }
|
||||||
|
String SystemStats::getUserRegion() { return getLocaleValue (kCFLocaleCountryCode); }
|
||||||
|
|
||||||
|
String SystemStats::getDisplayLanguage()
|
||||||
|
{
|
||||||
|
CFArrayRef cfPrefLangs = CFLocaleCopyPreferredLanguages();
|
||||||
|
const String result (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (cfPrefLangs, 0)));
|
||||||
|
CFRelease (cfPrefLangs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class HiResCounterHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HiResCounterHandler()
|
||||||
|
{
|
||||||
|
mach_timebase_info_data_t timebase;
|
||||||
|
(void) mach_timebase_info (&timebase);
|
||||||
|
|
||||||
|
if (timebase.numer % 1000000 == 0)
|
||||||
|
{
|
||||||
|
numerator = timebase.numer / 1000000;
|
||||||
|
denominator = timebase.denom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
numerator = timebase.numer;
|
||||||
|
denominator = timebase.denom * (uint64) 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
highResTimerFrequency = (timebase.denom * (uint64) 1000000000) / timebase.numer;
|
||||||
|
highResTimerToMillisecRatio = numerator / (double) denominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 millisecondsSinceStartup() const noexcept
|
||||||
|
{
|
||||||
|
return (uint32) ((mach_absolute_time() * numerator) / denominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double getMillisecondCounterHiRes() const noexcept
|
||||||
|
{
|
||||||
|
return mach_absolute_time() * highResTimerToMillisecRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 highResTimerFrequency;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64 numerator, denominator;
|
||||||
|
double highResTimerToMillisecRatio;
|
||||||
|
};
|
||||||
|
|
||||||
|
static HiResCounterHandler hiResCounterHandler;
|
||||||
|
|
||||||
|
uint32 beast_millisecondsSinceStartup() noexcept { return hiResCounterHandler.millisecondsSinceStartup(); }
|
||||||
|
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
|
||||||
|
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.highResTimerFrequency; }
|
||||||
|
int64 Time::getHighResolutionTicks() noexcept { return (int64) mach_absolute_time(); }
|
||||||
|
|
||||||
|
bool Time::setSystemTimeToThisTime() const
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int SystemStats::getPageSize()
|
||||||
|
{
|
||||||
|
return (int) NSPageSize();
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in beast_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool Process::isForegroundProcess()
|
||||||
|
{
|
||||||
|
#if BEAST_MAC
|
||||||
|
return [NSApp isActive];
|
||||||
|
#else
|
||||||
|
return true; // xxx change this if more than one app is ever possible on iOS!
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::makeForegroundProcess()
|
||||||
|
{
|
||||||
|
#if BEAST_MAC
|
||||||
|
[NSApp activateIgnoringOtherApps: YES];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::raisePrivilege()
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::lowerPrivilege()
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::terminate()
|
||||||
|
{
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::setPriority (ProcessPriority)
|
||||||
|
{
|
||||||
|
// xxx
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
static char testResult = 0;
|
||||||
|
|
||||||
|
if (testResult == 0)
|
||||||
|
{
|
||||||
|
struct kinfo_proc info;
|
||||||
|
int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
|
||||||
|
size_t sz = sizeof (info);
|
||||||
|
sysctl (m, 4, &info, &sz, 0, 0);
|
||||||
|
testResult = ((info.kp_proc.p_flag & P_TRACED) != 0) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return testResult > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_API bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return beast_isRunningUnderDebugger();
|
||||||
|
}
|
||||||
153
Subtrees/beast/modules/beast_core/native/beast_osx_ObjCHelpers.h
Normal file
153
Subtrees/beast/modules/beast_core/native/beast_osx_ObjCHelpers.h
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_OSX_OBJCHELPERS_BEASTHEADER
|
||||||
|
#define BEAST_OSX_OBJCHELPERS_BEASTHEADER
|
||||||
|
|
||||||
|
|
||||||
|
/* This file contains a few helper functions that are used internally but which
|
||||||
|
need to be kept away from the public headers because they use obj-C symbols.
|
||||||
|
*/
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
//==============================================================================
|
||||||
|
static inline String nsStringToBeast (NSString* s)
|
||||||
|
{
|
||||||
|
return CharPointer_UTF8 ([s UTF8String]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline NSString* beastStringToNS (const String& s)
|
||||||
|
{
|
||||||
|
return [NSString stringWithUTF8String: s.toUTF8()];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline NSString* nsStringLiteral (const char* const s) noexcept
|
||||||
|
{
|
||||||
|
return [NSString stringWithUTF8String: s];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline NSString* nsEmptyString() noexcept
|
||||||
|
{
|
||||||
|
return [NSString string];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename ObjectType>
|
||||||
|
struct NSObjectRetainer
|
||||||
|
{
|
||||||
|
inline NSObjectRetainer (ObjectType* o) : object (o) { [object retain]; }
|
||||||
|
inline ~NSObjectRetainer() { [object release]; }
|
||||||
|
|
||||||
|
ObjectType* object;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename SuperclassType>
|
||||||
|
struct ObjCClass
|
||||||
|
{
|
||||||
|
ObjCClass (const char* nameRoot)
|
||||||
|
: cls (objc_allocateClassPair ([SuperclassType class], getRandomisedName (nameRoot).toUTF8(), 0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~ObjCClass()
|
||||||
|
{
|
||||||
|
objc_disposeClassPair (cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerClass()
|
||||||
|
{
|
||||||
|
objc_registerClassPair (cls);
|
||||||
|
}
|
||||||
|
|
||||||
|
SuperclassType* createInstance() const
|
||||||
|
{
|
||||||
|
return class_createInstance (cls, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
void addIvar (const char* name)
|
||||||
|
{
|
||||||
|
BOOL b = class_addIvar (cls, name, sizeof (Type), (uint8_t) rint (log2 (sizeof (Type))), @encode (Type));
|
||||||
|
bassert (b); (void) b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FunctionType>
|
||||||
|
void addMethod (SEL selector, FunctionType callbackFn, const char* signature)
|
||||||
|
{
|
||||||
|
BOOL b = class_addMethod (cls, selector, (IMP) callbackFn, signature);
|
||||||
|
bassert (b); (void) b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FunctionType>
|
||||||
|
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2)
|
||||||
|
{
|
||||||
|
addMethod (selector, callbackFn, (String (sig1) + sig2).toUTF8());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FunctionType>
|
||||||
|
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3)
|
||||||
|
{
|
||||||
|
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3).toUTF8());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FunctionType>
|
||||||
|
void addMethod (SEL selector, FunctionType callbackFn, const char* sig1, const char* sig2, const char* sig3, const char* sig4)
|
||||||
|
{
|
||||||
|
addMethod (selector, callbackFn, (String (sig1) + sig2 + sig3 + sig4).toUTF8());
|
||||||
|
}
|
||||||
|
|
||||||
|
void addProtocol (Protocol* protocol)
|
||||||
|
{
|
||||||
|
BOOL b = class_addProtocol (cls, protocol);
|
||||||
|
bassert (b); (void) b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static id sendSuperclassMessage (id self, SEL selector)
|
||||||
|
{
|
||||||
|
objc_super s = { self, [SuperclassType class] };
|
||||||
|
return objc_msgSendSuper (&s, selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
static Type getIvar (id self, const char* name)
|
||||||
|
{
|
||||||
|
void* v = nullptr;
|
||||||
|
object_getInstanceVariable (self, name, &v);
|
||||||
|
return static_cast <Type> (v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Class cls;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static String getRandomisedName (const char* root)
|
||||||
|
{
|
||||||
|
return root + String::toHexString (beast::Random::getSystemRandom().nextInt64());
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (ObjCClass)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // BEAST_OSX_OBJCHELPERS_BEASTHEADER
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
class NamedPipe::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const String& pipePath, bool createPipe)
|
||||||
|
: pipeInName (pipePath + "_in"),
|
||||||
|
pipeOutName (pipePath + "_out"),
|
||||||
|
pipeIn (-1), pipeOut (-1),
|
||||||
|
createdPipe (createPipe),
|
||||||
|
stopReadOperation (false)
|
||||||
|
{
|
||||||
|
signal (SIGPIPE, signalHandler);
|
||||||
|
siginterrupt (SIGPIPE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
if (pipeIn != -1) ::close (pipeIn);
|
||||||
|
if (pipeOut != -1) ::close (pipeOut);
|
||||||
|
|
||||||
|
if (createdPipe)
|
||||||
|
{
|
||||||
|
unlink (pipeInName.toUTF8());
|
||||||
|
unlink (pipeOutName.toUTF8());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (char* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||||
|
|
||||||
|
if (pipeIn == -1)
|
||||||
|
{
|
||||||
|
pipeIn = openPipe (createdPipe ? pipeInName : pipeOutName, O_RDWR | O_NONBLOCK, timeoutEnd);
|
||||||
|
|
||||||
|
if (pipeIn == -1)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytesRead = 0;
|
||||||
|
|
||||||
|
while (bytesRead < maxBytesToRead)
|
||||||
|
{
|
||||||
|
const int bytesThisTime = maxBytesToRead - bytesRead;
|
||||||
|
const int numRead = (int) ::read (pipeIn, destBuffer, (size_t) bytesThisTime);
|
||||||
|
|
||||||
|
if (numRead <= 0)
|
||||||
|
{
|
||||||
|
if (errno != EWOULDBLOCK || stopReadOperation || hasExpired (timeoutEnd))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
const int maxWaitingTime = 30;
|
||||||
|
waitForInput (pipeIn, timeoutEnd == 0 ? maxWaitingTime
|
||||||
|
: bmin (maxWaitingTime,
|
||||||
|
(int) (timeoutEnd - Time::getMillisecondCounter())));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesRead += numRead;
|
||||||
|
destBuffer += numRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write (const char* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
const uint32 timeoutEnd = getTimeoutEnd (timeOutMilliseconds);
|
||||||
|
|
||||||
|
if (pipeOut == -1)
|
||||||
|
{
|
||||||
|
pipeOut = openPipe (createdPipe ? pipeOutName : pipeInName, O_WRONLY, timeoutEnd);
|
||||||
|
|
||||||
|
if (pipeOut == -1)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytesWritten = 0;
|
||||||
|
|
||||||
|
while (bytesWritten < numBytesToWrite && ! hasExpired (timeoutEnd))
|
||||||
|
{
|
||||||
|
const int bytesThisTime = numBytesToWrite - bytesWritten;
|
||||||
|
const int numWritten = (int) ::write (pipeOut, sourceBuffer, (size_t) bytesThisTime);
|
||||||
|
|
||||||
|
if (numWritten <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
bytesWritten += numWritten;
|
||||||
|
sourceBuffer += numWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool createFifos() const
|
||||||
|
{
|
||||||
|
return (mkfifo (pipeInName .toUTF8(), 0666) == 0 || errno == EEXIST)
|
||||||
|
&& (mkfifo (pipeOutName.toUTF8(), 0666) == 0 || errno == EEXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
const String pipeInName, pipeOutName;
|
||||||
|
int pipeIn, pipeOut;
|
||||||
|
|
||||||
|
const bool createdPipe;
|
||||||
|
bool stopReadOperation;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void signalHandler (int) {}
|
||||||
|
|
||||||
|
static uint32 getTimeoutEnd (const int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
return timeOutMilliseconds >= 0 ? Time::getMillisecondCounter() + (uint32) timeOutMilliseconds : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasExpired (const uint32 timeoutEnd)
|
||||||
|
{
|
||||||
|
return timeoutEnd != 0 && Time::getMillisecondCounter() >= timeoutEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int openPipe (const String& name, int flags, const uint32 timeoutEnd)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const int p = ::open (name.toUTF8(), flags);
|
||||||
|
|
||||||
|
if (p != -1 || hasExpired (timeoutEnd) || stopReadOperation)
|
||||||
|
return p;
|
||||||
|
|
||||||
|
Thread::sleep (2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waitForInput (const int handle, const int timeoutMsecs) noexcept
|
||||||
|
{
|
||||||
|
struct timeval timeout;
|
||||||
|
timeout.tv_sec = timeoutMsecs / 1000;
|
||||||
|
timeout.tv_usec = (timeoutMsecs % 1000) * 1000;
|
||||||
|
|
||||||
|
fd_set rset;
|
||||||
|
FD_ZERO (&rset);
|
||||||
|
FD_SET (handle, &rset);
|
||||||
|
|
||||||
|
select (handle + 1, &rset, nullptr, 0, &timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
void NamedPipe::close()
|
||||||
|
{
|
||||||
|
if (pimpl != nullptr)
|
||||||
|
{
|
||||||
|
pimpl->stopReadOperation = true;
|
||||||
|
|
||||||
|
char buffer[1] = { 0 };
|
||||||
|
ssize_t done = ::write (pimpl->pipeIn, buffer, 1);
|
||||||
|
(void) done;
|
||||||
|
|
||||||
|
ScopedWriteLock sl (lock);
|
||||||
|
pimpl = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
|
||||||
|
{
|
||||||
|
#if BEAST_IOS
|
||||||
|
pimpl = new Pimpl (File::getSpecialLocation (File::tempDirectory)
|
||||||
|
.getChildFile (File::createLegalFileName (pipeName)).getFullPathName(), createPipe);
|
||||||
|
#else
|
||||||
|
pimpl = new Pimpl ("/tmp/" + File::createLegalFileName (pipeName), createPipe);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (createPipe && ! pimpl->createFifos())
|
||||||
|
{
|
||||||
|
pimpl = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
ScopedReadLock sl (lock);
|
||||||
|
return pimpl != nullptr ? pimpl->read (static_cast <char*> (destBuffer), maxBytesToRead, timeOutMilliseconds) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
ScopedReadLock sl (lock);
|
||||||
|
return pimpl != nullptr ? pimpl->write (static_cast <const char*> (sourceBuffer), numBytesToWrite, timeOutMilliseconds) : -1;
|
||||||
|
}
|
||||||
1251
Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h
Normal file
1251
Subtrees/beast/modules/beast_core/native/beast_posix_SharedCode.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef BEAST_WIN32_COMSMARTPTR_BEASTHEADER
|
||||||
|
#define BEAST_WIN32_COMSMARTPTR_BEASTHEADER
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
template<typename Type> struct UUIDGetter { static CLSID get() { jassertfalse; return CLSID(); } };
|
||||||
|
#define __uuidof(x) UUIDGetter<x>::get()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline GUID uuidFromString (const char* const s) noexcept
|
||||||
|
{
|
||||||
|
unsigned long p0;
|
||||||
|
unsigned int p1, p2, p3, p4, p5, p6, p7, p8, p9, p10;
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
sscanf
|
||||||
|
#else
|
||||||
|
sscanf_s
|
||||||
|
#endif
|
||||||
|
(s, "%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||||
|
&p0, &p1, &p2, &p3, &p4, &p5, &p6, &p7, &p8, &p9, &p10);
|
||||||
|
|
||||||
|
GUID g = { p0, (uint16) p1, (uint16) p2, { (uint8) p3, (uint8) p4, (uint8) p5, (uint8) p6,
|
||||||
|
(uint8) p7, (uint8) p8, (uint8) p9, (uint8) p10 }};
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** A simple COM smart pointer.
|
||||||
|
*/
|
||||||
|
template <class ComClass>
|
||||||
|
class ComSmartPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ComSmartPtr() throw() : p (0) {}
|
||||||
|
ComSmartPtr (ComClass* const obj) : p (obj) { if (p) p->AddRef(); }
|
||||||
|
ComSmartPtr (const ComSmartPtr<ComClass>& other) : p (other.p) { if (p) p->AddRef(); }
|
||||||
|
~ComSmartPtr() { release(); }
|
||||||
|
|
||||||
|
operator ComClass*() const throw() { return p; }
|
||||||
|
ComClass& operator*() const throw() { return *p; }
|
||||||
|
ComClass* operator->() const throw() { return p; }
|
||||||
|
|
||||||
|
ComSmartPtr& operator= (ComClass* const newP)
|
||||||
|
{
|
||||||
|
if (newP != 0) newP->AddRef();
|
||||||
|
release();
|
||||||
|
p = newP;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComSmartPtr& operator= (const ComSmartPtr<ComClass>& newP) { return operator= (newP.p); }
|
||||||
|
|
||||||
|
// Releases and nullifies this pointer and returns its address
|
||||||
|
ComClass** resetAndGetPointerAddress()
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
p = 0;
|
||||||
|
return &p;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT CoCreateInstance (REFCLSID classUUID, DWORD dwClsContext = CLSCTX_INPROC_SERVER)
|
||||||
|
{
|
||||||
|
HRESULT hr = ::CoCreateInstance (classUUID, 0, dwClsContext, __uuidof (ComClass), (void**) resetAndGetPointerAddress());
|
||||||
|
bassert (hr != CO_E_NOTINITIALIZED); // You haven't called CoInitialize for the current thread!
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class OtherComClass>
|
||||||
|
HRESULT QueryInterface (REFCLSID classUUID, ComSmartPtr<OtherComClass>& destObject) const
|
||||||
|
{
|
||||||
|
if (p == 0)
|
||||||
|
return E_POINTER;
|
||||||
|
|
||||||
|
return p->QueryInterface (classUUID, (void**) destObject.resetAndGetPointerAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class OtherComClass>
|
||||||
|
HRESULT QueryInterface (ComSmartPtr<OtherComClass>& destObject) const
|
||||||
|
{
|
||||||
|
return this->QueryInterface (__uuidof (OtherComClass), destObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ComClass* p;
|
||||||
|
|
||||||
|
void release() { if (p != 0) p->Release(); }
|
||||||
|
|
||||||
|
ComClass** operator&() throw(); // private to avoid it being used accidentally
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define BEAST_COMRESULT HRESULT __stdcall
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <class ComClass>
|
||||||
|
class ComBaseClassHelperBase : public ComClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ComBaseClassHelperBase (unsigned int initialRefCount) : refCount (initialRefCount) {}
|
||||||
|
virtual ~ComBaseClassHelperBase() {}
|
||||||
|
|
||||||
|
ULONG __stdcall AddRef() { return ++refCount; }
|
||||||
|
ULONG __stdcall Release() { const ULONG r = --refCount; if (r == 0) delete this; return r; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ULONG refCount;
|
||||||
|
|
||||||
|
BEAST_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||||
|
{
|
||||||
|
if (refId == IID_IUnknown)
|
||||||
|
return castToType <IUnknown> (result);
|
||||||
|
|
||||||
|
*result = 0;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Type>
|
||||||
|
BEAST_COMRESULT castToType (void** result)
|
||||||
|
{
|
||||||
|
this->AddRef(); *result = dynamic_cast <Type*> (this); return S_OK;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Handy base class for writing COM objects, providing ref-counting and a basic QueryInterface method.
|
||||||
|
*/
|
||||||
|
template <class ComClass>
|
||||||
|
class ComBaseClassHelper : public ComBaseClassHelperBase <ComClass>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ComBaseClassHelper (unsigned int initialRefCount = 1) : ComBaseClassHelperBase <ComClass> (initialRefCount) {}
|
||||||
|
~ComBaseClassHelper() {}
|
||||||
|
|
||||||
|
BEAST_COMRESULT QueryInterface (REFIID refId, void** result)
|
||||||
|
{
|
||||||
|
if (refId == __uuidof (ComClass))
|
||||||
|
return this->template castToType <ComClass> (result);
|
||||||
|
|
||||||
|
return ComBaseClassHelperBase <ComClass>::QueryInterface (refId, result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BEAST_WIN32_COMSMARTPTR_BEASTHEADER
|
||||||
956
Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp
Normal file
956
Subtrees/beast/modules/beast_core/native/beast_win32_Files.cpp
Normal file
@@ -0,0 +1,956 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef INVALID_FILE_ATTRIBUTES
|
||||||
|
#define INVALID_FILE_ATTRIBUTES ((DWORD) -1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace WindowsFileHelpers
|
||||||
|
{
|
||||||
|
DWORD getAtts (const String& path)
|
||||||
|
{
|
||||||
|
return GetFileAttributes (path.toWideCharPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 fileTimeToTime (const FILETIME* const ft)
|
||||||
|
{
|
||||||
|
static_bassert (sizeof (ULARGE_INTEGER) == sizeof (FILETIME)); // tell me if this fails!
|
||||||
|
|
||||||
|
return (int64) ((reinterpret_cast<const ULARGE_INTEGER*> (ft)->QuadPart - literal64bit (116444736000000000)) / 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILETIME* timeToFileTime (const int64 time, FILETIME* const ft) noexcept
|
||||||
|
{
|
||||||
|
if (time <= 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
reinterpret_cast<ULARGE_INTEGER*> (ft)->QuadPart = (ULONGLONG) (time * 10000 + literal64bit (116444736000000000));
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDriveFromPath (String path)
|
||||||
|
{
|
||||||
|
if (path.isNotEmpty() && path[1] == ':' && path[2] == 0)
|
||||||
|
path << '\\';
|
||||||
|
|
||||||
|
const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (path.getCharPointer()) + 4;
|
||||||
|
HeapBlock<WCHAR> pathCopy;
|
||||||
|
pathCopy.calloc (numBytes, 1);
|
||||||
|
path.copyToUTF16 (pathCopy, numBytes);
|
||||||
|
|
||||||
|
if (PathStripToRoot (pathCopy))
|
||||||
|
path = static_cast <const WCHAR*> (pathCopy);
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 getDiskSpaceInfo (const String& path, const bool total)
|
||||||
|
{
|
||||||
|
ULARGE_INTEGER spc, tot, totFree;
|
||||||
|
|
||||||
|
if (GetDiskFreeSpaceEx (getDriveFromPath (path).toWideCharPointer(), &spc, &tot, &totFree))
|
||||||
|
return total ? (int64) tot.QuadPart
|
||||||
|
: (int64) spc.QuadPart;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int getWindowsDriveType (const String& path)
|
||||||
|
{
|
||||||
|
return GetDriveType (getDriveFromPath (path).toWideCharPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
File getSpecialFolderPath (int type)
|
||||||
|
{
|
||||||
|
WCHAR path [MAX_PATH + 256];
|
||||||
|
|
||||||
|
if (SHGetSpecialFolderPath (0, path, type, FALSE))
|
||||||
|
return File (String (path));
|
||||||
|
|
||||||
|
return File::nonexistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
File getModuleFileName (HINSTANCE moduleHandle)
|
||||||
|
{
|
||||||
|
WCHAR dest [MAX_PATH + 256];
|
||||||
|
dest[0] = 0;
|
||||||
|
GetModuleFileName (moduleHandle, dest, (DWORD) numElementsInArray (dest));
|
||||||
|
return File (String (dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result getResultForLastError()
|
||||||
|
{
|
||||||
|
TCHAR messageBuffer [256] = { 0 };
|
||||||
|
|
||||||
|
FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
nullptr, GetLastError(), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
messageBuffer, (DWORD) numElementsInArray (messageBuffer) - 1, nullptr);
|
||||||
|
|
||||||
|
return Result::fail (String (messageBuffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
const beast_wchar File::separator = '\\';
|
||||||
|
const String File::separatorString ("\\");
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::exists() const
|
||||||
|
{
|
||||||
|
return fullPath.isNotEmpty()
|
||||||
|
&& WindowsFileHelpers::getAtts (fullPath) != INVALID_FILE_ATTRIBUTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::existsAsFile() const
|
||||||
|
{
|
||||||
|
return fullPath.isNotEmpty()
|
||||||
|
&& (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isDirectory() const
|
||||||
|
{
|
||||||
|
const DWORD attr = WindowsFileHelpers::getAtts (fullPath);
|
||||||
|
return ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) && (attr != INVALID_FILE_ATTRIBUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::hasWriteAccess() const
|
||||||
|
{
|
||||||
|
if (exists())
|
||||||
|
return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_READONLY) == 0;
|
||||||
|
|
||||||
|
// on windows, it seems that even read-only directories can still be written into,
|
||||||
|
// so checking the parent directory's permissions would return the wrong result..
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::setFileReadOnlyInternal (const bool shouldBeReadOnly) const
|
||||||
|
{
|
||||||
|
const DWORD oldAtts = WindowsFileHelpers::getAtts (fullPath);
|
||||||
|
|
||||||
|
if (oldAtts == INVALID_FILE_ATTRIBUTES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const DWORD newAtts = shouldBeReadOnly ? (oldAtts | FILE_ATTRIBUTE_READONLY)
|
||||||
|
: (oldAtts & ~FILE_ATTRIBUTE_READONLY);
|
||||||
|
return newAtts == oldAtts
|
||||||
|
|| SetFileAttributes (fullPath.toWideCharPointer(), newAtts) != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isHidden() const
|
||||||
|
{
|
||||||
|
return (WindowsFileHelpers::getAtts (fullPath) & FILE_ATTRIBUTE_HIDDEN) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::deleteFile() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return isDirectory() ? RemoveDirectory (fullPath.toWideCharPointer()) != 0
|
||||||
|
: DeleteFile (fullPath.toWideCharPointer()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::moveToTrash() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// The string we pass in must be double null terminated..
|
||||||
|
const size_t numBytes = CharPointer_UTF16::getBytesRequiredFor (fullPath.getCharPointer()) + 8;
|
||||||
|
HeapBlock<WCHAR> doubleNullTermPath;
|
||||||
|
doubleNullTermPath.calloc (numBytes, 1);
|
||||||
|
fullPath.copyToUTF16 (doubleNullTermPath, numBytes);
|
||||||
|
|
||||||
|
SHFILEOPSTRUCT fos = { 0 };
|
||||||
|
fos.wFunc = FO_DELETE;
|
||||||
|
fos.pFrom = doubleNullTermPath;
|
||||||
|
fos.fFlags = FOF_ALLOWUNDO | FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION
|
||||||
|
| FOF_NOCONFIRMMKDIR | FOF_RENAMEONCOLLISION;
|
||||||
|
|
||||||
|
return SHFileOperation (&fos) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::copyInternal (const File& dest) const
|
||||||
|
{
|
||||||
|
return CopyFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer(), false) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::moveInternal (const File& dest) const
|
||||||
|
{
|
||||||
|
return MoveFile (fullPath.toWideCharPointer(), dest.getFullPathName().toWideCharPointer()) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result File::createDirectoryInternal (const String& fileName) const
|
||||||
|
{
|
||||||
|
return CreateDirectory (fileName.toWideCharPointer(), 0) ? Result::ok()
|
||||||
|
: WindowsFileHelpers::getResultForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int64 beast_fileSetPosition (void* handle, int64 pos)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
li.QuadPart = pos;
|
||||||
|
li.LowPart = SetFilePointer ((HANDLE) handle, (LONG) li.LowPart, &li.HighPart, FILE_BEGIN); // (returns -1 if it fails)
|
||||||
|
return li.QuadPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileInputStream::openHandle()
|
||||||
|
{
|
||||||
|
HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
|
||||||
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
|
||||||
|
|
||||||
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
|
fileHandle = (void*) h;
|
||||||
|
else
|
||||||
|
status = WindowsFileHelpers::getResultForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileInputStream::closeHandle()
|
||||||
|
{
|
||||||
|
CloseHandle ((HANDLE) fileHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t FileInputStream::readInternal (void* buffer, size_t numBytes)
|
||||||
|
{
|
||||||
|
if (fileHandle != 0)
|
||||||
|
{
|
||||||
|
DWORD actualNum = 0;
|
||||||
|
if (! ReadFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
|
||||||
|
status = WindowsFileHelpers::getResultForLastError();
|
||||||
|
|
||||||
|
return (size_t) actualNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void FileOutputStream::openHandle()
|
||||||
|
{
|
||||||
|
HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
|
||||||
|
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
|
||||||
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
LARGE_INTEGER li;
|
||||||
|
li.QuadPart = 0;
|
||||||
|
li.LowPart = SetFilePointer (h, 0, &li.HighPart, FILE_END);
|
||||||
|
|
||||||
|
if (li.LowPart != INVALID_SET_FILE_POINTER)
|
||||||
|
{
|
||||||
|
fileHandle = (void*) h;
|
||||||
|
currentPosition = li.QuadPart;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status = WindowsFileHelpers::getResultForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileOutputStream::closeHandle()
|
||||||
|
{
|
||||||
|
CloseHandle ((HANDLE) fileHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t FileOutputStream::writeInternal (const void* buffer, size_t numBytes)
|
||||||
|
{
|
||||||
|
if (fileHandle != nullptr)
|
||||||
|
{
|
||||||
|
DWORD actualNum = 0;
|
||||||
|
if (! WriteFile ((HANDLE) fileHandle, buffer, (DWORD) numBytes, &actualNum, 0))
|
||||||
|
status = WindowsFileHelpers::getResultForLastError();
|
||||||
|
|
||||||
|
return (ssize_t) actualNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileOutputStream::flushInternal()
|
||||||
|
{
|
||||||
|
if (fileHandle != nullptr)
|
||||||
|
if (! FlushFileBuffers ((HANDLE) fileHandle))
|
||||||
|
status = WindowsFileHelpers::getResultForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FileOutputStream::truncate()
|
||||||
|
{
|
||||||
|
if (fileHandle == nullptr)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
flush();
|
||||||
|
return SetEndOfFile ((HANDLE) fileHandle) ? Result::ok()
|
||||||
|
: WindowsFileHelpers::getResultForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void MemoryMappedFile::openInternal (const File& file, AccessMode mode)
|
||||||
|
{
|
||||||
|
bassert (mode == readOnly || mode == readWrite);
|
||||||
|
|
||||||
|
if (range.getStart() > 0)
|
||||||
|
{
|
||||||
|
SYSTEM_INFO systemInfo;
|
||||||
|
GetNativeSystemInfo (&systemInfo);
|
||||||
|
|
||||||
|
range.setStart (range.getStart() - (range.getStart() % systemInfo.dwAllocationGranularity));
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD accessMode = GENERIC_READ, createType = OPEN_EXISTING;
|
||||||
|
DWORD protect = PAGE_READONLY, access = FILE_MAP_READ;
|
||||||
|
|
||||||
|
if (mode == readWrite)
|
||||||
|
{
|
||||||
|
accessMode = GENERIC_READ | GENERIC_WRITE;
|
||||||
|
createType = OPEN_ALWAYS;
|
||||||
|
protect = PAGE_READWRITE;
|
||||||
|
access = FILE_MAP_ALL_ACCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE h = CreateFile (file.getFullPathName().toWideCharPointer(), accessMode, FILE_SHARE_READ, 0,
|
||||||
|
createType, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 0);
|
||||||
|
|
||||||
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
fileHandle = (void*) h;
|
||||||
|
|
||||||
|
HANDLE mappingHandle = CreateFileMapping (h, 0, protect, (DWORD) (range.getEnd() >> 32), (DWORD) range.getEnd(), 0);
|
||||||
|
|
||||||
|
if (mappingHandle != 0)
|
||||||
|
{
|
||||||
|
address = MapViewOfFile (mappingHandle, access, (DWORD) (range.getStart() >> 32),
|
||||||
|
(DWORD) range.getStart(), (SIZE_T) range.getLength());
|
||||||
|
|
||||||
|
if (address == nullptr)
|
||||||
|
range = Range<int64>();
|
||||||
|
|
||||||
|
CloseHandle (mappingHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryMappedFile::~MemoryMappedFile()
|
||||||
|
{
|
||||||
|
if (address != nullptr)
|
||||||
|
UnmapViewOfFile (address);
|
||||||
|
|
||||||
|
if (fileHandle != nullptr)
|
||||||
|
CloseHandle ((HANDLE) fileHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int64 File::getSize() const
|
||||||
|
{
|
||||||
|
WIN32_FILE_ATTRIBUTE_DATA attributes;
|
||||||
|
|
||||||
|
if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
|
||||||
|
return (((int64) attributes.nFileSizeHigh) << 32) | attributes.nFileSizeLow;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::getFileTimesInternal (int64& modificationTime, int64& accessTime, int64& creationTime) const
|
||||||
|
{
|
||||||
|
using namespace WindowsFileHelpers;
|
||||||
|
WIN32_FILE_ATTRIBUTE_DATA attributes;
|
||||||
|
|
||||||
|
if (GetFileAttributesEx (fullPath.toWideCharPointer(), GetFileExInfoStandard, &attributes))
|
||||||
|
{
|
||||||
|
modificationTime = fileTimeToTime (&attributes.ftLastWriteTime);
|
||||||
|
creationTime = fileTimeToTime (&attributes.ftCreationTime);
|
||||||
|
accessTime = fileTimeToTime (&attributes.ftLastAccessTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
creationTime = accessTime = modificationTime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 creationTime) const
|
||||||
|
{
|
||||||
|
using namespace WindowsFileHelpers;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
HANDLE h = CreateFile (fullPath.toWideCharPointer(), GENERIC_WRITE, FILE_SHARE_READ, 0,
|
||||||
|
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
|
|
||||||
|
if (h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
FILETIME m, a, c;
|
||||||
|
|
||||||
|
ok = SetFileTime (h,
|
||||||
|
timeToFileTime (creationTime, &c),
|
||||||
|
timeToFileTime (accessTime, &a),
|
||||||
|
timeToFileTime (modificationTime, &m)) != 0;
|
||||||
|
|
||||||
|
CloseHandle (h);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void File::findFileSystemRoots (Array<File>& destArray)
|
||||||
|
{
|
||||||
|
TCHAR buffer [2048] = { 0 };
|
||||||
|
GetLogicalDriveStrings (2048, buffer);
|
||||||
|
|
||||||
|
const TCHAR* n = buffer;
|
||||||
|
StringArray roots;
|
||||||
|
|
||||||
|
while (*n != 0)
|
||||||
|
{
|
||||||
|
roots.add (String (n));
|
||||||
|
|
||||||
|
while (*n++ != 0)
|
||||||
|
{}
|
||||||
|
}
|
||||||
|
|
||||||
|
roots.sort (true);
|
||||||
|
|
||||||
|
for (int i = 0; i < roots.size(); ++i)
|
||||||
|
destArray.add (roots [i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String File::getVolumeLabel() const
|
||||||
|
{
|
||||||
|
TCHAR dest[64];
|
||||||
|
if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
|
||||||
|
(DWORD) numElementsInArray (dest), 0, 0, 0, 0, 0))
|
||||||
|
dest[0] = 0;
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::getVolumeSerialNumber() const
|
||||||
|
{
|
||||||
|
TCHAR dest[64];
|
||||||
|
DWORD serialNum;
|
||||||
|
|
||||||
|
if (! GetVolumeInformation (WindowsFileHelpers::getDriveFromPath (getFullPathName()).toWideCharPointer(), dest,
|
||||||
|
(DWORD) numElementsInArray (dest), &serialNum, 0, 0, 0, 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (int) serialNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 File::getBytesFreeOnVolume() const
|
||||||
|
{
|
||||||
|
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 File::getVolumeTotalSize() const
|
||||||
|
{
|
||||||
|
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::isOnCDRomDrive() const
|
||||||
|
{
|
||||||
|
return WindowsFileHelpers::getWindowsDriveType (getFullPathName()) == DRIVE_CDROM;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnHardDisk() const
|
||||||
|
{
|
||||||
|
if (fullPath.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
|
||||||
|
|
||||||
|
if (fullPath.toLowerCase()[0] <= 'b' && fullPath[1] == ':')
|
||||||
|
return n != DRIVE_REMOVABLE;
|
||||||
|
|
||||||
|
return n != DRIVE_CDROM && n != DRIVE_REMOTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnRemovableDrive() const
|
||||||
|
{
|
||||||
|
if (fullPath.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const unsigned int n = WindowsFileHelpers::getWindowsDriveType (getFullPathName());
|
||||||
|
|
||||||
|
return n == DRIVE_CDROM
|
||||||
|
|| n == DRIVE_REMOTE
|
||||||
|
|| n == DRIVE_REMOVABLE
|
||||||
|
|| n == DRIVE_RAMDISK;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
File BEAST_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
|
||||||
|
{
|
||||||
|
int csidlType = 0;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case userHomeDirectory: csidlType = CSIDL_PROFILE; break;
|
||||||
|
case userDocumentsDirectory: csidlType = CSIDL_PERSONAL; break;
|
||||||
|
case userDesktopDirectory: csidlType = CSIDL_DESKTOP; break;
|
||||||
|
case userApplicationDataDirectory: csidlType = CSIDL_APPDATA; break;
|
||||||
|
case commonApplicationDataDirectory: csidlType = CSIDL_COMMON_APPDATA; break;
|
||||||
|
case globalApplicationsDirectory: csidlType = CSIDL_PROGRAM_FILES; break;
|
||||||
|
case userMusicDirectory: csidlType = 0x0d; /*CSIDL_MYMUSIC*/ break;
|
||||||
|
case userMoviesDirectory: csidlType = 0x0e; /*CSIDL_MYVIDEO*/ break;
|
||||||
|
case userPicturesDirectory: csidlType = 0x27; /*CSIDL_MYPICTURES*/ break;
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
{
|
||||||
|
WCHAR dest [2048];
|
||||||
|
dest[0] = 0;
|
||||||
|
GetTempPath ((DWORD) numElementsInArray (dest), dest);
|
||||||
|
return File (String (dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
case invokedExecutableFile:
|
||||||
|
case currentExecutableFile:
|
||||||
|
case currentApplicationFile:
|
||||||
|
return WindowsFileHelpers::getModuleFileName ((HINSTANCE) Process::getCurrentModuleInstanceHandle());
|
||||||
|
|
||||||
|
case hostApplicationPath:
|
||||||
|
return WindowsFileHelpers::getModuleFileName (0);
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // unknown type?
|
||||||
|
return File::nonexistent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WindowsFileHelpers::getSpecialFolderPath (csidlType);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
File File::getCurrentWorkingDirectory()
|
||||||
|
{
|
||||||
|
WCHAR dest [MAX_PATH + 256];
|
||||||
|
dest[0] = 0;
|
||||||
|
GetCurrentDirectory ((DWORD) numElementsInArray (dest), dest);
|
||||||
|
return File (String (dest));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::setAsCurrentWorkingDirectory() const
|
||||||
|
{
|
||||||
|
return SetCurrentDirectory (getFullPathName().toWideCharPointer()) != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String File::getVersion() const
|
||||||
|
{
|
||||||
|
String result;
|
||||||
|
|
||||||
|
DWORD handle = 0;
|
||||||
|
DWORD bufferSize = GetFileVersionInfoSize (getFullPathName().toWideCharPointer(), &handle);
|
||||||
|
HeapBlock<char> buffer;
|
||||||
|
buffer.calloc (bufferSize);
|
||||||
|
|
||||||
|
if (GetFileVersionInfo (getFullPathName().toWideCharPointer(), 0, bufferSize, buffer))
|
||||||
|
{
|
||||||
|
VS_FIXEDFILEINFO* vffi;
|
||||||
|
UINT len = 0;
|
||||||
|
|
||||||
|
if (VerQueryValue (buffer, (LPTSTR) _T("\\"), (LPVOID*) &vffi, &len))
|
||||||
|
{
|
||||||
|
result << (int) HIWORD (vffi->dwFileVersionMS) << '.'
|
||||||
|
<< (int) LOWORD (vffi->dwFileVersionMS) << '.'
|
||||||
|
<< (int) HIWORD (vffi->dwFileVersionLS) << '.'
|
||||||
|
<< (int) LOWORD (vffi->dwFileVersionLS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
File File::getLinkedTarget() const
|
||||||
|
{
|
||||||
|
File result (*this);
|
||||||
|
String p (getFullPathName());
|
||||||
|
|
||||||
|
if (! exists())
|
||||||
|
p += ".lnk";
|
||||||
|
else if (! hasFileExtension (".lnk"))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
ComSmartPtr <IShellLink> shellLink;
|
||||||
|
ComSmartPtr <IPersistFile> persistFile;
|
||||||
|
|
||||||
|
if (SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
|
||||||
|
&& SUCCEEDED (shellLink.QueryInterface (persistFile))
|
||||||
|
&& SUCCEEDED (persistFile->Load (p.toWideCharPointer(), STGM_READ))
|
||||||
|
&& SUCCEEDED (shellLink->Resolve (0, SLR_ANY_MATCH | SLR_NO_UI)))
|
||||||
|
{
|
||||||
|
WIN32_FIND_DATA winFindData;
|
||||||
|
WCHAR resolvedPath [MAX_PATH];
|
||||||
|
|
||||||
|
if (SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH, &winFindData, SLGP_UNCPRIORITY)))
|
||||||
|
result = File (resolvedPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::createLink (const String& description, const File& linkFileToCreate) const
|
||||||
|
{
|
||||||
|
linkFileToCreate.deleteFile();
|
||||||
|
|
||||||
|
ComSmartPtr <IShellLink> shellLink;
|
||||||
|
ComSmartPtr <IPersistFile> persistFile;
|
||||||
|
|
||||||
|
return SUCCEEDED (shellLink.CoCreateInstance (CLSID_ShellLink))
|
||||||
|
&& SUCCEEDED (shellLink->SetPath (getFullPathName().toWideCharPointer()))
|
||||||
|
&& SUCCEEDED (shellLink->SetDescription (description.toWideCharPointer()))
|
||||||
|
&& SUCCEEDED (shellLink.QueryInterface (persistFile))
|
||||||
|
&& SUCCEEDED (persistFile->Save (linkFileToCreate.getFullPathName().toWideCharPointer(), TRUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class DirectoryIterator::NativeIterator::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const File& directory, const String& wildCard)
|
||||||
|
: directoryWithWildCard (File::addTrailingSeparator (directory.getFullPathName()) + wildCard),
|
||||||
|
handle (INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
if (handle != INVALID_HANDLE_VALUE)
|
||||||
|
FindClose (handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
using namespace WindowsFileHelpers;
|
||||||
|
WIN32_FIND_DATA findData;
|
||||||
|
|
||||||
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
handle = FindFirstFile (directoryWithWildCard.toWideCharPointer(), &findData);
|
||||||
|
|
||||||
|
if (handle == INVALID_HANDLE_VALUE)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (FindNextFile (handle, &findData) == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
filenameFound = findData.cFileName;
|
||||||
|
|
||||||
|
if (isDir != nullptr) *isDir = ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
|
||||||
|
if (isHidden != nullptr) *isHidden = ((findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0);
|
||||||
|
if (isReadOnly != nullptr) *isReadOnly = ((findData.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0);
|
||||||
|
if (fileSize != nullptr) *fileSize = findData.nFileSizeLow + (((int64) findData.nFileSizeHigh) << 32);
|
||||||
|
if (modTime != nullptr) *modTime = Time (fileTimeToTime (&findData.ftLastWriteTime));
|
||||||
|
if (creationTime != nullptr) *creationTime = Time (fileTimeToTime (&findData.ftCreationTime));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const String directoryWithWildCard;
|
||||||
|
HANDLE handle;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||||
|
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||||
|
{
|
||||||
|
HINSTANCE hInstance = 0;
|
||||||
|
|
||||||
|
BEAST_TRY
|
||||||
|
{
|
||||||
|
hInstance = ShellExecute (0, 0, fileName.toWideCharPointer(),
|
||||||
|
parameters.toWideCharPointer(), 0, SW_SHOWDEFAULT);
|
||||||
|
}
|
||||||
|
BEAST_CATCH_ALL
|
||||||
|
|
||||||
|
return hInstance > (HINSTANCE) 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::revealToUser() const
|
||||||
|
{
|
||||||
|
DynamicLibrary dll ("Shell32.dll");
|
||||||
|
BEAST_LOAD_WINAPI_FUNCTION (dll, ILCreateFromPathW, ilCreateFromPathW, ITEMIDLIST*, (LPCWSTR))
|
||||||
|
BEAST_LOAD_WINAPI_FUNCTION (dll, ILFree, ilFree, void, (ITEMIDLIST*))
|
||||||
|
BEAST_LOAD_WINAPI_FUNCTION (dll, SHOpenFolderAndSelectItems, shOpenFolderAndSelectItems, HRESULT, (ITEMIDLIST*, UINT, void*, DWORD))
|
||||||
|
|
||||||
|
if (ilCreateFromPathW != nullptr && shOpenFolderAndSelectItems != nullptr && ilFree != nullptr)
|
||||||
|
{
|
||||||
|
if (ITEMIDLIST* const itemIDList = ilCreateFromPathW (fullPath.toWideCharPointer()))
|
||||||
|
{
|
||||||
|
shOpenFolderAndSelectItems (itemIDList, 0, nullptr, 0);
|
||||||
|
ilFree (itemIDList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class NamedPipe::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const String& pipeName, const bool createPipe)
|
||||||
|
: filename ("\\\\.\\pipe\\" + File::createLegalFileName (pipeName)),
|
||||||
|
pipeH (INVALID_HANDLE_VALUE),
|
||||||
|
cancelEvent (CreateEvent (0, FALSE, FALSE, 0)),
|
||||||
|
connected (false), ownsPipe (createPipe), shouldStop (false)
|
||||||
|
{
|
||||||
|
if (createPipe)
|
||||||
|
pipeH = CreateNamedPipe (filename.toWideCharPointer(),
|
||||||
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 0,
|
||||||
|
PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
disconnectPipe();
|
||||||
|
|
||||||
|
if (pipeH != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle (pipeH);
|
||||||
|
|
||||||
|
CloseHandle (cancelEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connect (const int timeOutMs)
|
||||||
|
{
|
||||||
|
if (! ownsPipe)
|
||||||
|
{
|
||||||
|
if (pipeH != INVALID_HANDLE_VALUE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const Time timeOutEnd (Time::getCurrentTime() + RelativeTime::milliseconds (timeOutMs));
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const ScopedLock sl (createFileLock);
|
||||||
|
|
||||||
|
if (pipeH == INVALID_HANDLE_VALUE)
|
||||||
|
pipeH = CreateFile (filename.toWideCharPointer(),
|
||||||
|
GENERIC_READ | GENERIC_WRITE, 0, 0,
|
||||||
|
OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pipeH != INVALID_HANDLE_VALUE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (shouldStop || (timeOutMs >= 0 && Time::getCurrentTime() > timeOutEnd))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Thread::sleep (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! connected)
|
||||||
|
{
|
||||||
|
OverlappedEvent over;
|
||||||
|
|
||||||
|
if (ConnectNamedPipe (pipeH, &over.over) == 0)
|
||||||
|
{
|
||||||
|
switch (GetLastError())
|
||||||
|
{
|
||||||
|
case ERROR_PIPE_CONNECTED: connected = true; break;
|
||||||
|
case ERROR_IO_PENDING:
|
||||||
|
case ERROR_PIPE_LISTENING: connected = waitForIO (over, timeOutMs); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnectPipe()
|
||||||
|
{
|
||||||
|
if (ownsPipe && connected)
|
||||||
|
{
|
||||||
|
DisconnectNamedPipe (pipeH);
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (void* destBuffer, const int maxBytesToRead, const int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
while (connect (timeOutMilliseconds))
|
||||||
|
{
|
||||||
|
if (maxBytesToRead <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
OverlappedEvent over;
|
||||||
|
unsigned long numRead;
|
||||||
|
|
||||||
|
if (ReadFile (pipeH, destBuffer, (DWORD) maxBytesToRead, &numRead, &over.over))
|
||||||
|
return (int) numRead;
|
||||||
|
|
||||||
|
const DWORD lastError = GetLastError();
|
||||||
|
|
||||||
|
if (lastError == ERROR_IO_PENDING)
|
||||||
|
{
|
||||||
|
if (! waitForIO (over, timeOutMilliseconds))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (GetOverlappedResult (pipeH, &over.over, &numRead, FALSE))
|
||||||
|
return (int) numRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ownsPipe && (GetLastError() == ERROR_BROKEN_PIPE || GetLastError() == ERROR_PIPE_NOT_CONNECTED))
|
||||||
|
disconnectPipe();
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
if (connect (timeOutMilliseconds))
|
||||||
|
{
|
||||||
|
if (numBytesToWrite <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
OverlappedEvent over;
|
||||||
|
unsigned long numWritten;
|
||||||
|
|
||||||
|
if (WriteFile (pipeH, sourceBuffer, (DWORD) numBytesToWrite, &numWritten, &over.over))
|
||||||
|
return (int) numWritten;
|
||||||
|
|
||||||
|
if (GetLastError() == ERROR_IO_PENDING)
|
||||||
|
{
|
||||||
|
if (! waitForIO (over, timeOutMilliseconds))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (GetOverlappedResult (pipeH, &over.over, &numWritten, FALSE))
|
||||||
|
return (int) numWritten;
|
||||||
|
|
||||||
|
if (GetLastError() == ERROR_BROKEN_PIPE && ownsPipe)
|
||||||
|
disconnectPipe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String filename;
|
||||||
|
HANDLE pipeH, cancelEvent;
|
||||||
|
bool connected, ownsPipe, shouldStop;
|
||||||
|
CriticalSection createFileLock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct OverlappedEvent
|
||||||
|
{
|
||||||
|
OverlappedEvent()
|
||||||
|
{
|
||||||
|
zerostruct (over);
|
||||||
|
over.hEvent = CreateEvent (0, TRUE, FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~OverlappedEvent()
|
||||||
|
{
|
||||||
|
CloseHandle (over.hEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
OVERLAPPED over;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool waitForIO (OverlappedEvent& over, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
if (shouldStop)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
HANDLE handles[] = { over.over.hEvent, cancelEvent };
|
||||||
|
DWORD waitResult = WaitForMultipleObjects (2, handles, FALSE,
|
||||||
|
timeOutMilliseconds >= 0 ? timeOutMilliseconds
|
||||||
|
: INFINITE);
|
||||||
|
|
||||||
|
if (waitResult == WAIT_OBJECT_0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
CancelIo (pipeH);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
void NamedPipe::close()
|
||||||
|
{
|
||||||
|
if (pimpl != nullptr)
|
||||||
|
{
|
||||||
|
pimpl->shouldStop = true;
|
||||||
|
SetEvent (pimpl->cancelEvent);
|
||||||
|
|
||||||
|
ScopedWriteLock sl (lock);
|
||||||
|
pimpl = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedPipe::openInternal (const String& pipeName, const bool createPipe)
|
||||||
|
{
|
||||||
|
pimpl = new Pimpl (pipeName, createPipe);
|
||||||
|
|
||||||
|
if (createPipe && pimpl->pipeH == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
pimpl = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NamedPipe::read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
ScopedReadLock sl (lock);
|
||||||
|
return pimpl != nullptr ? pimpl->read (destBuffer, maxBytesToRead, timeOutMilliseconds) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NamedPipe::write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds)
|
||||||
|
{
|
||||||
|
ScopedReadLock sl (lock);
|
||||||
|
return pimpl != nullptr ? pimpl->write (sourceBuffer, numBytesToWrite, timeOutMilliseconds) : -1;
|
||||||
|
}
|
||||||
464
Subtrees/beast/modules/beast_core/native/beast_win32_Network.cpp
Normal file
464
Subtrees/beast/modules/beast_core/native/beast_win32_Network.cpp
Normal file
@@ -0,0 +1,464 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#ifndef INTERNET_FLAG_NEED_FILE
|
||||||
|
#define INTERNET_FLAG_NEED_FILE 0x00000010
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef INTERNET_OPTION_DISABLE_AUTODIAL
|
||||||
|
#define INTERNET_OPTION_DISABLE_AUTODIAL 70
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WebInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||||
|
: connection (0), request (0),
|
||||||
|
address (address_), headers (headers_), postData (postData_), position (0),
|
||||||
|
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||||
|
{
|
||||||
|
createConnection (progressCallback, progressCallbackContext);
|
||||||
|
|
||||||
|
if (responseHeaders != nullptr && ! isError())
|
||||||
|
{
|
||||||
|
DWORD bufferSizeBytes = 4096;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
HeapBlock<char> buffer ((size_t) bufferSizeBytes);
|
||||||
|
|
||||||
|
if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0))
|
||||||
|
{
|
||||||
|
StringArray headersArray;
|
||||||
|
headersArray.addLines (reinterpret_cast <const WCHAR*> (buffer.getData()));
|
||||||
|
|
||||||
|
for (int i = 0; i < headersArray.size(); ++i)
|
||||||
|
{
|
||||||
|
const String& header = headersArray[i];
|
||||||
|
const String key (header.upToFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String value (header.fromFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String previousValue ((*responseHeaders) [key]);
|
||||||
|
|
||||||
|
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~WebInputStream()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isError() const { return request == 0; }
|
||||||
|
bool isExhausted() { return finished; }
|
||||||
|
int64 getPosition() { return position; }
|
||||||
|
|
||||||
|
int64 getTotalLength()
|
||||||
|
{
|
||||||
|
if (! isError())
|
||||||
|
{
|
||||||
|
DWORD index = 0, result = 0, size = sizeof (result);
|
||||||
|
|
||||||
|
if (HttpQueryInfo (request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index))
|
||||||
|
return (int64) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (void* buffer, int bytesToRead)
|
||||||
|
{
|
||||||
|
bassert (buffer != nullptr && bytesToRead >= 0);
|
||||||
|
DWORD bytesRead = 0;
|
||||||
|
|
||||||
|
if (! (finished || isError()))
|
||||||
|
{
|
||||||
|
InternetReadFile (request, buffer, (DWORD) bytesToRead, &bytesRead);
|
||||||
|
position += bytesRead;
|
||||||
|
|
||||||
|
if (bytesRead == 0)
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setPosition (int64 wantedPos)
|
||||||
|
{
|
||||||
|
if (isError())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (wantedPos != position)
|
||||||
|
{
|
||||||
|
finished = false;
|
||||||
|
position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0);
|
||||||
|
|
||||||
|
if (position == wantedPos)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (wantedPos < position)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
position = 0;
|
||||||
|
createConnection (0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipNextBytes (wantedPos - position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
HINTERNET connection, request;
|
||||||
|
String address, headers;
|
||||||
|
MemoryBlock postData;
|
||||||
|
int64 position;
|
||||||
|
bool finished;
|
||||||
|
const bool isPost;
|
||||||
|
int timeOutMs;
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
if (request != 0)
|
||||||
|
{
|
||||||
|
InternetCloseHandle (request);
|
||||||
|
request = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connection != 0)
|
||||||
|
{
|
||||||
|
InternetCloseHandle (connection);
|
||||||
|
connection = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createConnection (URL::OpenStreamProgressCallback* progressCallback,
|
||||||
|
void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
static HINTERNET sessionHandle = InternetOpen (_T("beast"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0);
|
||||||
|
|
||||||
|
close();
|
||||||
|
|
||||||
|
if (sessionHandle != 0)
|
||||||
|
{
|
||||||
|
// break up the url..
|
||||||
|
const int fileNumChars = 65536;
|
||||||
|
const int serverNumChars = 2048;
|
||||||
|
const int usernameNumChars = 1024;
|
||||||
|
const int passwordNumChars = 1024;
|
||||||
|
HeapBlock<TCHAR> file (fileNumChars), server (serverNumChars),
|
||||||
|
username (usernameNumChars), password (passwordNumChars);
|
||||||
|
|
||||||
|
URL_COMPONENTS uc = { 0 };
|
||||||
|
uc.dwStructSize = sizeof (uc);
|
||||||
|
uc.lpszUrlPath = file;
|
||||||
|
uc.dwUrlPathLength = fileNumChars;
|
||||||
|
uc.lpszHostName = server;
|
||||||
|
uc.dwHostNameLength = serverNumChars;
|
||||||
|
uc.lpszUserName = username;
|
||||||
|
uc.dwUserNameLength = usernameNumChars;
|
||||||
|
uc.lpszPassword = password;
|
||||||
|
uc.dwPasswordLength = passwordNumChars;
|
||||||
|
|
||||||
|
if (InternetCrackUrl (address.toWideCharPointer(), 0, 0, &uc))
|
||||||
|
openConnection (uc, sessionHandle, progressCallback, progressCallbackContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void openConnection (URL_COMPONENTS& uc, HINTERNET sessionHandle,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback,
|
||||||
|
void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
int disable = 1;
|
||||||
|
InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable));
|
||||||
|
|
||||||
|
if (timeOutMs == 0)
|
||||||
|
timeOutMs = 30000;
|
||||||
|
else if (timeOutMs < 0)
|
||||||
|
timeOutMs = -1;
|
||||||
|
|
||||||
|
applyTimeout (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT);
|
||||||
|
applyTimeout (sessionHandle, INTERNET_OPTION_RECEIVE_TIMEOUT);
|
||||||
|
applyTimeout (sessionHandle, INTERNET_OPTION_SEND_TIMEOUT);
|
||||||
|
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT);
|
||||||
|
applyTimeout (sessionHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT);
|
||||||
|
|
||||||
|
const bool isFtp = address.startsWithIgnoreCase ("ftp:");
|
||||||
|
|
||||||
|
connection = InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort,
|
||||||
|
uc.lpszUserName, uc.lpszPassword,
|
||||||
|
isFtp ? (DWORD) INTERNET_SERVICE_FTP
|
||||||
|
: (DWORD) INTERNET_SERVICE_HTTP,
|
||||||
|
0, 0);
|
||||||
|
if (connection != 0)
|
||||||
|
{
|
||||||
|
if (isFtp)
|
||||||
|
request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ,
|
||||||
|
FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE, 0);
|
||||||
|
else
|
||||||
|
openHTTPConnection (uc, progressCallback, progressCallbackContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyTimeout (HINTERNET sessionHandle, const DWORD option)
|
||||||
|
{
|
||||||
|
InternetSetOption (sessionHandle, option, &timeOutMs, sizeof (timeOutMs));
|
||||||
|
}
|
||||||
|
|
||||||
|
void openHTTPConnection (URL_COMPONENTS& uc, URL::OpenStreamProgressCallback* progressCallback,
|
||||||
|
void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
const TCHAR* mimeTypes[] = { _T("*/*"), nullptr };
|
||||||
|
|
||||||
|
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
|
||||||
|
|
||||||
|
if (address.startsWithIgnoreCase ("https:"))
|
||||||
|
flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
|
||||||
|
// IE7 seems to automatically work out when it's https)
|
||||||
|
|
||||||
|
request = HttpOpenRequest (connection, isPost ? _T("POST") : _T("GET"),
|
||||||
|
uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0);
|
||||||
|
|
||||||
|
if (request != 0)
|
||||||
|
{
|
||||||
|
INTERNET_BUFFERS buffers = { 0 };
|
||||||
|
buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
|
||||||
|
buffers.lpcszHeader = headers.toWideCharPointer();
|
||||||
|
buffers.dwHeadersLength = (DWORD) headers.length();
|
||||||
|
buffers.dwBufferTotal = (DWORD) postData.getSize();
|
||||||
|
|
||||||
|
if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0))
|
||||||
|
{
|
||||||
|
int bytesSent = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const int bytesToDo = bmin (1024, (int) postData.getSize() - bytesSent);
|
||||||
|
DWORD bytesDone = 0;
|
||||||
|
|
||||||
|
if (bytesToDo > 0
|
||||||
|
&& ! InternetWriteFile (request,
|
||||||
|
static_cast <const char*> (postData.getData()) + bytesSent,
|
||||||
|
(DWORD) bytesToDo, &bytesDone))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytesToDo == 0 || (int) bytesDone < bytesToDo)
|
||||||
|
{
|
||||||
|
if (HttpEndRequest (request, 0, 0, 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesSent += bytesDone;
|
||||||
|
|
||||||
|
if (progressCallback != nullptr
|
||||||
|
&& ! progressCallback (progressCallbackContext, bytesSent, (int) postData.getSize()))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData,
|
||||||
|
OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers, const int timeOutMs, StringPairArray* responseHeaders)
|
||||||
|
{
|
||||||
|
ScopedPointer <WebInputStream> wi (new WebInputStream (address, isPost, postData,
|
||||||
|
progressCallback, progressCallbackContext,
|
||||||
|
headers, timeOutMs, responseHeaders));
|
||||||
|
|
||||||
|
return wi->isError() ? nullptr : wi.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
struct GetAdaptersInfoHelper
|
||||||
|
{
|
||||||
|
bool callGetAdaptersInfo()
|
||||||
|
{
|
||||||
|
DynamicLibrary dll ("iphlpapi.dll");
|
||||||
|
BEAST_LOAD_WINAPI_FUNCTION (dll, GetAdaptersInfo, getAdaptersInfo, DWORD, (PIP_ADAPTER_INFO, PULONG))
|
||||||
|
|
||||||
|
if (getAdaptersInfo == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
adapterInfo.malloc (1);
|
||||||
|
ULONG len = sizeof (IP_ADAPTER_INFO);
|
||||||
|
|
||||||
|
if (getAdaptersInfo (adapterInfo, &len) == ERROR_BUFFER_OVERFLOW)
|
||||||
|
adapterInfo.malloc (len, 1);
|
||||||
|
|
||||||
|
return getAdaptersInfo (adapterInfo, &len) == NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapBlock<IP_ADAPTER_INFO> adapterInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace MACAddressHelpers
|
||||||
|
{
|
||||||
|
void getViaGetAdaptersInfo (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
GetAdaptersInfoHelper gah;
|
||||||
|
|
||||||
|
if (gah.callGetAdaptersInfo())
|
||||||
|
{
|
||||||
|
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
|
||||||
|
if (adapter->AddressLength >= 6)
|
||||||
|
result.addIfNotAlreadyThere (MACAddress (adapter->Address));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getViaNetBios (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
DynamicLibrary dll ("netapi32.dll");
|
||||||
|
BEAST_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
|
||||||
|
|
||||||
|
if (NetbiosCall != 0)
|
||||||
|
{
|
||||||
|
LANA_ENUM enums = { 0 };
|
||||||
|
|
||||||
|
{
|
||||||
|
NCB ncb = { 0 };
|
||||||
|
ncb.ncb_command = NCBENUM;
|
||||||
|
ncb.ncb_buffer = (unsigned char*) &enums;
|
||||||
|
ncb.ncb_length = sizeof (LANA_ENUM);
|
||||||
|
NetbiosCall (&ncb);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < enums.length; ++i)
|
||||||
|
{
|
||||||
|
NCB ncb2 = { 0 };
|
||||||
|
ncb2.ncb_command = NCBRESET;
|
||||||
|
ncb2.ncb_lana_num = enums.lana[i];
|
||||||
|
|
||||||
|
if (NetbiosCall (&ncb2) == 0)
|
||||||
|
{
|
||||||
|
NCB ncb = { 0 };
|
||||||
|
memcpy (ncb.ncb_callname, "* ", NCBNAMSZ);
|
||||||
|
ncb.ncb_command = NCBASTAT;
|
||||||
|
ncb.ncb_lana_num = enums.lana[i];
|
||||||
|
|
||||||
|
struct ASTAT
|
||||||
|
{
|
||||||
|
ADAPTER_STATUS adapt;
|
||||||
|
NAME_BUFFER NameBuff [30];
|
||||||
|
};
|
||||||
|
|
||||||
|
ASTAT astat;
|
||||||
|
zerostruct (astat);
|
||||||
|
ncb.ncb_buffer = (unsigned char*) &astat;
|
||||||
|
ncb.ncb_length = sizeof (ASTAT);
|
||||||
|
|
||||||
|
if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
|
||||||
|
result.addIfNotAlreadyThere (MACAddress (astat.adapt.adapter_address));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
MACAddressHelpers::getViaGetAdaptersInfo (result);
|
||||||
|
MACAddressHelpers::getViaNetBios (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPAddress::findAllAddresses (Array<IPAddress>& result)
|
||||||
|
{
|
||||||
|
result.addIfNotAlreadyThere (IPAddress::local());
|
||||||
|
|
||||||
|
GetAdaptersInfoHelper gah;
|
||||||
|
|
||||||
|
if (gah.callGetAdaptersInfo())
|
||||||
|
{
|
||||||
|
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
|
||||||
|
{
|
||||||
|
IPAddress ip (adapter->IpAddressList.IpAddress.String);
|
||||||
|
|
||||||
|
if (ip != IPAddress::any())
|
||||||
|
result.addIfNotAlreadyThere (ip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||||
|
const String& emailSubject,
|
||||||
|
const String& bodyText,
|
||||||
|
const StringArray& filesToAttach)
|
||||||
|
{
|
||||||
|
DynamicLibrary dll ("MAPI32.dll");
|
||||||
|
BEAST_LOAD_WINAPI_FUNCTION (dll, MAPISendMail, mapiSendMail,
|
||||||
|
ULONG, (LHANDLE, ULONG, lpMapiMessage, ::FLAGS, ULONG))
|
||||||
|
|
||||||
|
if (mapiSendMail == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
MapiMessage message = { 0 };
|
||||||
|
message.lpszSubject = (LPSTR) emailSubject.toRawUTF8();
|
||||||
|
message.lpszNoteText = (LPSTR) bodyText.toRawUTF8();
|
||||||
|
|
||||||
|
MapiRecipDesc recip = { 0 };
|
||||||
|
recip.ulRecipClass = MAPI_TO;
|
||||||
|
String targetEmailAddress_ (targetEmailAddress);
|
||||||
|
if (targetEmailAddress_.isEmpty())
|
||||||
|
targetEmailAddress_ = " "; // (Windows Mail can't deal with a blank address)
|
||||||
|
recip.lpszName = (LPSTR) targetEmailAddress_.toRawUTF8();
|
||||||
|
message.nRecipCount = 1;
|
||||||
|
message.lpRecips = &recip;
|
||||||
|
|
||||||
|
HeapBlock <MapiFileDesc> files;
|
||||||
|
files.calloc ((size_t) filesToAttach.size());
|
||||||
|
|
||||||
|
message.nFileCount = (ULONG) filesToAttach.size();
|
||||||
|
message.lpFiles = files;
|
||||||
|
|
||||||
|
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||||
|
{
|
||||||
|
files[i].nPosition = (ULONG) -1;
|
||||||
|
files[i].lpszPathName = (LPSTR) filesToAttach[i].toRawUTF8();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapiSendMail (0, 0, &message, MAPI_DIALOG | MAPI_LOGON_UI, 0) == SUCCESS_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
struct RegistryKeyWrapper
|
||||||
|
{
|
||||||
|
RegistryKeyWrapper (String name, const bool createForWriting, const DWORD wow64Flags)
|
||||||
|
: key (0), wideCharValueName (nullptr)
|
||||||
|
{
|
||||||
|
HKEY rootKey = 0;
|
||||||
|
|
||||||
|
if (name.startsWithIgnoreCase ("HKEY_CURRENT_USER\\")) rootKey = HKEY_CURRENT_USER;
|
||||||
|
else if (name.startsWithIgnoreCase ("HKEY_LOCAL_MACHINE\\")) rootKey = HKEY_LOCAL_MACHINE;
|
||||||
|
else if (name.startsWithIgnoreCase ("HKEY_CLASSES_ROOT\\")) rootKey = HKEY_CLASSES_ROOT;
|
||||||
|
|
||||||
|
if (rootKey != 0)
|
||||||
|
{
|
||||||
|
name = name.substring (name.indexOfChar ('\\') + 1);
|
||||||
|
|
||||||
|
const int lastSlash = name.lastIndexOfChar ('\\');
|
||||||
|
valueName = name.substring (lastSlash + 1);
|
||||||
|
wideCharValueName = valueName.toWideCharPointer();
|
||||||
|
|
||||||
|
name = name.substring (0, lastSlash);
|
||||||
|
const wchar_t* const wideCharName = name.toWideCharPointer();
|
||||||
|
DWORD result;
|
||||||
|
|
||||||
|
if (createForWriting)
|
||||||
|
RegCreateKeyEx (rootKey, wideCharName, 0, 0, REG_OPTION_NON_VOLATILE,
|
||||||
|
KEY_WRITE | KEY_QUERY_VALUE | wow64Flags, 0, &key, &result);
|
||||||
|
else
|
||||||
|
RegOpenKeyEx (rootKey, wideCharName, 0, KEY_READ | wow64Flags, &key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~RegistryKeyWrapper()
|
||||||
|
{
|
||||||
|
if (key != 0)
|
||||||
|
RegCloseKey (key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setValue (const String& regValuePath, const DWORD type,
|
||||||
|
const void* data, size_t dataSize)
|
||||||
|
{
|
||||||
|
const RegistryKeyWrapper key (regValuePath, true, 0);
|
||||||
|
|
||||||
|
return key.key != 0
|
||||||
|
&& RegSetValueEx (key.key, key.wideCharValueName, 0, type,
|
||||||
|
reinterpret_cast <const BYTE*> (data),
|
||||||
|
(DWORD) dataSize) == ERROR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32 getBinaryValue (const String& regValuePath, MemoryBlock& result, DWORD wow64Flags)
|
||||||
|
{
|
||||||
|
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||||
|
|
||||||
|
if (key.key != 0)
|
||||||
|
{
|
||||||
|
for (unsigned long bufferSize = 1024; ; bufferSize *= 2)
|
||||||
|
{
|
||||||
|
result.setSize (bufferSize, false);
|
||||||
|
DWORD type = REG_NONE;
|
||||||
|
|
||||||
|
const LONG err = RegQueryValueEx (key.key, key.wideCharValueName, 0, &type,
|
||||||
|
(LPBYTE) result.getData(), &bufferSize);
|
||||||
|
|
||||||
|
if (err == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
result.setSize (bufferSize, false);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != ERROR_MORE_DATA)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return REG_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getValue (const String& regValuePath, const String& defaultValue, DWORD wow64Flags)
|
||||||
|
{
|
||||||
|
MemoryBlock buffer;
|
||||||
|
switch (getBinaryValue (regValuePath, buffer, wow64Flags))
|
||||||
|
{
|
||||||
|
case REG_SZ: return static_cast <const WCHAR*> (buffer.getData());
|
||||||
|
case REG_DWORD: return String ((int) *reinterpret_cast<const DWORD*> (buffer.getData()));
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool valueExists (const String& regValuePath, const DWORD wow64Flags)
|
||||||
|
{
|
||||||
|
const RegistryKeyWrapper key (regValuePath, false, wow64Flags);
|
||||||
|
|
||||||
|
if (key.key == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned char buffer [512];
|
||||||
|
unsigned long bufferSize = sizeof (buffer);
|
||||||
|
DWORD type = 0;
|
||||||
|
|
||||||
|
const LONG result = RegQueryValueEx (key.key, key.wideCharValueName,
|
||||||
|
0, &type, buffer, &bufferSize);
|
||||||
|
|
||||||
|
return result == ERROR_SUCCESS || result == ERROR_MORE_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
HKEY key;
|
||||||
|
const wchar_t* wideCharValueName;
|
||||||
|
String valueName;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (RegistryKeyWrapper)
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32 WindowsRegistry::getBinaryValue (const String& regValuePath, MemoryBlock& result)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::getBinaryValue (regValuePath, result, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
String WindowsRegistry::getValue (const String& regValuePath, const String& defaultValue)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
String WindowsRegistry::getValueWow64 (const String& regValuePath, const String& defaultValue)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::getValue (regValuePath, defaultValue, 0x100 /*KEY_WOW64_64KEY*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsRegistry::valueExistsWow64 (const String& regValuePath)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::valueExists (regValuePath, 0x100 /*KEY_WOW64_64KEY*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsRegistry::setValue (const String& regValuePath, const String& value)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::setValue (regValuePath, REG_SZ, value.toWideCharPointer(),
|
||||||
|
CharPointer_UTF16::getBytesRequiredFor (value.getCharPointer()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsRegistry::setValue (const String& regValuePath, const uint32 value)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::setValue (regValuePath, REG_DWORD, &value, sizeof (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsRegistry::setValue (const String& regValuePath, const uint64 value)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::setValue (regValuePath, REG_QWORD, &value, sizeof (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsRegistry::setValue (const String& regValuePath, const MemoryBlock& value)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::setValue (regValuePath, REG_BINARY, value.getData(), value.getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsRegistry::valueExists (const String& regValuePath)
|
||||||
|
{
|
||||||
|
return RegistryKeyWrapper::valueExists (regValuePath, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsRegistry::deleteValue (const String& regValuePath)
|
||||||
|
{
|
||||||
|
const RegistryKeyWrapper key (regValuePath, true, 0);
|
||||||
|
|
||||||
|
if (key.key != 0)
|
||||||
|
RegDeleteValue (key.key, key.wideCharValueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowsRegistry::deleteKey (const String& regKeyPath)
|
||||||
|
{
|
||||||
|
const RegistryKeyWrapper key (regKeyPath, true, 0);
|
||||||
|
|
||||||
|
if (key.key != 0)
|
||||||
|
RegDeleteKey (key.key, key.wideCharValueName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WindowsRegistry::registerFileAssociation (const String& fileExtension,
|
||||||
|
const String& symbolicDescription,
|
||||||
|
const String& fullDescription,
|
||||||
|
const File& targetExecutable,
|
||||||
|
const int iconResourceNumber,
|
||||||
|
const bool registerForCurrentUserOnly)
|
||||||
|
{
|
||||||
|
const char* const root = registerForCurrentUserOnly ? "HKEY_CURRENT_USER\\Software\\Classes\\"
|
||||||
|
: "HKEY_CLASSES_ROOT\\";
|
||||||
|
const String key (root + symbolicDescription);
|
||||||
|
|
||||||
|
return setValue (root + fileExtension + "\\", symbolicDescription)
|
||||||
|
&& setValue (key + "\\", fullDescription)
|
||||||
|
&& setValue (key + "\\shell\\open\\command\\", targetExecutable.getFullPathName() + " \"%1\"")
|
||||||
|
&& (iconResourceNumber == 0
|
||||||
|
|| setValue (key + "\\DefaultIcon\\",
|
||||||
|
targetExecutable.getFullPathName() + "," + String (-iconResourceNumber)));
|
||||||
|
}
|
||||||
@@ -0,0 +1,413 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
void Logger::outputDebugString (const String& text)
|
||||||
|
{
|
||||||
|
OutputDebugString ((text + "\n").toWideCharPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#ifdef BEAST_DLL_BUILD
|
||||||
|
BEAST_API void* beastDLL_malloc (size_t sz) { return std::malloc (sz); }
|
||||||
|
BEAST_API void beastDLL_free (void* block) { std::free (block); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if BEAST_USE_INTRINSICS
|
||||||
|
|
||||||
|
// CPU info functions using intrinsics...
|
||||||
|
|
||||||
|
#pragma intrinsic (__cpuid)
|
||||||
|
#pragma intrinsic (__rdtsc)
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
int info [4];
|
||||||
|
__cpuid (info, 0);
|
||||||
|
|
||||||
|
char v [12];
|
||||||
|
memcpy (v, info + 1, 4);
|
||||||
|
memcpy (v + 4, info + 3, 4);
|
||||||
|
memcpy (v + 8, info + 2, 4);
|
||||||
|
|
||||||
|
return String (v, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// CPU info functions using old fashioned inline asm...
|
||||||
|
|
||||||
|
static void beast_getCpuVendor (char* const v)
|
||||||
|
{
|
||||||
|
int vendor[4] = { 0 };
|
||||||
|
|
||||||
|
#if ! BEAST_MINGW
|
||||||
|
__try
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#if BEAST_GCC
|
||||||
|
unsigned int dummy = 0;
|
||||||
|
__asm__ ("cpuid" : "=a" (dummy), "=b" (vendor[0]), "=c" (vendor[2]),"=d" (vendor[1]) : "a" (0));
|
||||||
|
#else
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
mov eax, 0
|
||||||
|
cpuid
|
||||||
|
mov [vendor], ebx
|
||||||
|
mov [vendor + 4], edx
|
||||||
|
mov [vendor + 8], ecx
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if ! BEAST_MINGW
|
||||||
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memcpy (v, vendor, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
char v [16];
|
||||||
|
beast_getCpuVendor (v);
|
||||||
|
return String (v, 16);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::CPUFlags::CPUFlags()
|
||||||
|
{
|
||||||
|
hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0;
|
||||||
|
hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0;
|
||||||
|
hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0;
|
||||||
|
#ifdef PF_AMD3D_INSTRUCTIONS_AVAILABLE
|
||||||
|
has3DNow = IsProcessorFeaturePresent (PF_AMD3D_INSTRUCTIONS_AVAILABLE) != 0;
|
||||||
|
#else
|
||||||
|
has3DNow = IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SYSTEM_INFO systemInfo;
|
||||||
|
GetNativeSystemInfo (&systemInfo);
|
||||||
|
numCpus = (int) systemInfo.dwNumberOfProcessors;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_MSVC && BEAST_CHECK_MEMORY_LEAKS
|
||||||
|
struct DebugFlagsInitialiser
|
||||||
|
{
|
||||||
|
DebugFlagsInitialiser()
|
||||||
|
{
|
||||||
|
_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static DebugFlagsInitialiser debugFlagsInitialiser;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||||
|
{
|
||||||
|
OSVERSIONINFO info;
|
||||||
|
info.dwOSVersionInfoSize = sizeof (info);
|
||||||
|
GetVersionEx (&info);
|
||||||
|
|
||||||
|
if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
||||||
|
{
|
||||||
|
if (info.dwMajorVersion == 5)
|
||||||
|
return (info.dwMinorVersion == 0) ? Win2000 : WinXP;
|
||||||
|
|
||||||
|
if (info.dwMajorVersion == 6)
|
||||||
|
{
|
||||||
|
switch (info.dwMinorVersion)
|
||||||
|
{
|
||||||
|
case 0: return WinVista;
|
||||||
|
case 1: return Windows7;
|
||||||
|
case 2: return Windows8;
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // new version needs to be added here!
|
||||||
|
return Windows8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jassertfalse; // need to support whatever new version is running!
|
||||||
|
return UnknownOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getOperatingSystemName()
|
||||||
|
{
|
||||||
|
const char* name = "Unknown OS";
|
||||||
|
|
||||||
|
switch (getOperatingSystemType())
|
||||||
|
{
|
||||||
|
case Windows7: name = "Windows 7"; break;
|
||||||
|
case Windows8: name = "Windows 8"; break;
|
||||||
|
case WinVista: name = "Windows Vista"; break;
|
||||||
|
case WinXP: name = "Windows XP"; break;
|
||||||
|
case Win2000: name = "Windows 2000"; break;
|
||||||
|
default: jassertfalse; break; // !! new type of OS?
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemStats::isOperatingSystem64Bit()
|
||||||
|
{
|
||||||
|
#if BEAST_64BIT
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
typedef BOOL (WINAPI* LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
||||||
|
|
||||||
|
LPFN_ISWOW64PROCESS fnIsWow64Process
|
||||||
|
= (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandleA ("kernel32"), "IsWow64Process");
|
||||||
|
|
||||||
|
BOOL isWow64 = FALSE;
|
||||||
|
|
||||||
|
return fnIsWow64Process != nullptr
|
||||||
|
&& fnIsWow64Process (GetCurrentProcess(), &isWow64)
|
||||||
|
&& isWow64 != FALSE;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int SystemStats::getMemorySizeInMegabytes()
|
||||||
|
{
|
||||||
|
MEMORYSTATUSEX mem;
|
||||||
|
mem.dwLength = sizeof (mem);
|
||||||
|
GlobalMemoryStatusEx (&mem);
|
||||||
|
return (int) (mem.ullTotalPhys / (1024 * 1024)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getEnvironmentVariable (const String& name, const String& defaultValue)
|
||||||
|
{
|
||||||
|
DWORD len = GetEnvironmentVariableW (name.toWideCharPointer(), nullptr, 0);
|
||||||
|
if (GetLastError() == ERROR_ENVVAR_NOT_FOUND)
|
||||||
|
return String (defaultValue);
|
||||||
|
|
||||||
|
HeapBlock<WCHAR> buffer (len);
|
||||||
|
len = GetEnvironmentVariableW (name.toWideCharPointer(), buffer, len);
|
||||||
|
|
||||||
|
return String (CharPointer_wchar_t (buffer),
|
||||||
|
CharPointer_wchar_t (buffer + len));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
uint32 beast_millisecondsSinceStartup() noexcept
|
||||||
|
{
|
||||||
|
return (uint32) timeGetTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class HiResCounterHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HiResCounterHandler()
|
||||||
|
: hiResTicksOffset (0)
|
||||||
|
{
|
||||||
|
const MMRESULT res = timeBeginPeriod (1);
|
||||||
|
(void) res;
|
||||||
|
bassert (res == TIMERR_NOERROR);
|
||||||
|
|
||||||
|
LARGE_INTEGER f;
|
||||||
|
QueryPerformanceFrequency (&f);
|
||||||
|
hiResTicksPerSecond = f.QuadPart;
|
||||||
|
hiResTicksScaleFactor = 1000.0 / hiResTicksPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int64 getHighResolutionTicks() noexcept
|
||||||
|
{
|
||||||
|
LARGE_INTEGER ticks;
|
||||||
|
QueryPerformanceCounter (&ticks);
|
||||||
|
|
||||||
|
const int64 mainCounterAsHiResTicks = (beast_millisecondsSinceStartup() * hiResTicksPerSecond) / 1000;
|
||||||
|
const int64 newOffset = mainCounterAsHiResTicks - ticks.QuadPart;
|
||||||
|
|
||||||
|
// fix for a very obscure PCI hardware bug that can make the counter
|
||||||
|
// sometimes jump forwards by a few seconds..
|
||||||
|
const int64 offsetDrift = abs64 (newOffset - hiResTicksOffset);
|
||||||
|
|
||||||
|
if (offsetDrift > (hiResTicksPerSecond >> 1))
|
||||||
|
hiResTicksOffset = newOffset;
|
||||||
|
|
||||||
|
return ticks.QuadPart + hiResTicksOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double getMillisecondCounterHiRes() noexcept
|
||||||
|
{
|
||||||
|
return getHighResolutionTicks() * hiResTicksScaleFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 hiResTicksPerSecond, hiResTicksOffset;
|
||||||
|
double hiResTicksScaleFactor;
|
||||||
|
};
|
||||||
|
|
||||||
|
static HiResCounterHandler hiResCounterHandler;
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.hiResTicksPerSecond; }
|
||||||
|
int64 Time::getHighResolutionTicks() noexcept { return hiResCounterHandler.getHighResolutionTicks(); }
|
||||||
|
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static int64 beast_getClockCycleCounter() noexcept
|
||||||
|
{
|
||||||
|
#if BEAST_USE_INTRINSICS
|
||||||
|
// MS intrinsics version...
|
||||||
|
return (int64) __rdtsc();
|
||||||
|
|
||||||
|
#elif BEAST_GCC
|
||||||
|
// GNU inline asm version...
|
||||||
|
unsigned int hi = 0, lo = 0;
|
||||||
|
|
||||||
|
__asm__ __volatile__ (
|
||||||
|
"xor %%eax, %%eax \n\
|
||||||
|
xor %%edx, %%edx \n\
|
||||||
|
rdtsc \n\
|
||||||
|
movl %%eax, %[lo] \n\
|
||||||
|
movl %%edx, %[hi]"
|
||||||
|
:
|
||||||
|
: [hi] "m" (hi),
|
||||||
|
[lo] "m" (lo)
|
||||||
|
: "cc", "eax", "ebx", "ecx", "edx", "memory");
|
||||||
|
|
||||||
|
return (int64) ((((uint64) hi) << 32) | lo);
|
||||||
|
#else
|
||||||
|
// MSVC inline asm version...
|
||||||
|
unsigned int hi = 0, lo = 0;
|
||||||
|
|
||||||
|
__asm
|
||||||
|
{
|
||||||
|
xor eax, eax
|
||||||
|
xor edx, edx
|
||||||
|
rdtsc
|
||||||
|
mov lo, eax
|
||||||
|
mov hi, edx
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int64) ((((uint64) hi) << 32) | lo);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getCpuSpeedInMegaherz()
|
||||||
|
{
|
||||||
|
const int64 cycles = beast_getClockCycleCounter();
|
||||||
|
const uint32 millis = Time::getMillisecondCounter();
|
||||||
|
int lastResult = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int n = 1000000;
|
||||||
|
while (--n > 0) {}
|
||||||
|
|
||||||
|
const uint32 millisElapsed = Time::getMillisecondCounter() - millis;
|
||||||
|
const int64 cyclesNow = beast_getClockCycleCounter();
|
||||||
|
|
||||||
|
if (millisElapsed > 80)
|
||||||
|
{
|
||||||
|
const int newResult = (int) (((cyclesNow - cycles) / millisElapsed) / 1000);
|
||||||
|
|
||||||
|
if (millisElapsed > 500 || (lastResult == newResult && newResult > 100))
|
||||||
|
return newResult;
|
||||||
|
|
||||||
|
lastResult = newResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool Time::setSystemTimeToThisTime() const
|
||||||
|
{
|
||||||
|
SYSTEMTIME st;
|
||||||
|
|
||||||
|
st.wDayOfWeek = 0;
|
||||||
|
st.wYear = (WORD) getYear();
|
||||||
|
st.wMonth = (WORD) (getMonth() + 1);
|
||||||
|
st.wDay = (WORD) getDayOfMonth();
|
||||||
|
st.wHour = (WORD) getHours();
|
||||||
|
st.wMinute = (WORD) getMinutes();
|
||||||
|
st.wSecond = (WORD) getSeconds();
|
||||||
|
st.wMilliseconds = (WORD) (millisSinceEpoch % 1000);
|
||||||
|
|
||||||
|
// do this twice because of daylight saving conversion problems - the
|
||||||
|
// first one sets it up, the second one kicks it in.
|
||||||
|
return SetLocalTime (&st) != 0
|
||||||
|
&& SetLocalTime (&st) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getPageSize()
|
||||||
|
{
|
||||||
|
SYSTEM_INFO systemInfo;
|
||||||
|
GetNativeSystemInfo (&systemInfo);
|
||||||
|
|
||||||
|
return (int) systemInfo.dwPageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getLogonName()
|
||||||
|
{
|
||||||
|
TCHAR text [256] = { 0 };
|
||||||
|
DWORD len = (DWORD) numElementsInArray (text) - 1;
|
||||||
|
GetUserName (text, &len);
|
||||||
|
return String (text, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getFullUserName()
|
||||||
|
{
|
||||||
|
return getLogonName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getComputerName()
|
||||||
|
{
|
||||||
|
TCHAR text [MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
|
||||||
|
DWORD len = (DWORD) numElementsInArray (text) - 1;
|
||||||
|
GetComputerName (text, &len);
|
||||||
|
return String (text, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getLocaleValue (LCID locale, LCTYPE key, const char* defaultValue)
|
||||||
|
{
|
||||||
|
TCHAR buffer [256] = { 0 };
|
||||||
|
if (GetLocaleInfo (locale, key, buffer, 255) > 0)
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getUserLanguage() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, "en"); }
|
||||||
|
String SystemStats::getUserRegion() { return getLocaleValue (LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, "US"); }
|
||||||
|
|
||||||
|
String SystemStats::getDisplayLanguage()
|
||||||
|
{
|
||||||
|
DynamicLibrary dll ("kernel32.dll");
|
||||||
|
BEAST_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
|
||||||
|
|
||||||
|
if (getUserDefaultUILanguage != nullptr)
|
||||||
|
return getLocaleValue (MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SISO639LANGNAME, "en");
|
||||||
|
|
||||||
|
return "en";
|
||||||
|
}
|
||||||
634
Subtrees/beast/modules/beast_core/native/beast_win32_Threads.cpp
Normal file
634
Subtrees/beast/modules/beast_core/native/beast_win32_Threads.cpp
Normal file
@@ -0,0 +1,634 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||||
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||||
|
|
||||||
|
Portions of this file are from JUCE.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
Please visit http://www.juce.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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
HWND beast_messageWindowHandle = 0; // (this is used by other parts of the codebase)
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if ! BEAST_USE_INTRINSICS
|
||||||
|
// In newer compilers, the inline versions of these are used (in beast_Atomic.h), but in
|
||||||
|
// older ones we have to actually call the ops as win32 functions..
|
||||||
|
long beast_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); }
|
||||||
|
long beast_InterlockedIncrement (volatile long* a) noexcept { return InterlockedIncrement (a); }
|
||||||
|
long beast_InterlockedDecrement (volatile long* a) noexcept { return InterlockedDecrement (a); }
|
||||||
|
long beast_InterlockedExchangeAdd (volatile long* a, long b) noexcept { return InterlockedExchangeAdd (a, b); }
|
||||||
|
long beast_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept { return InterlockedCompareExchange (a, b, c); }
|
||||||
|
|
||||||
|
__int64 beast_InterlockedCompareExchange64 (volatile __int64* value, __int64 newValue, __int64 valueToCompare) noexcept
|
||||||
|
{
|
||||||
|
jassertfalse; // This operation isn't available in old MS compiler versions!
|
||||||
|
|
||||||
|
__int64 oldValue = *value;
|
||||||
|
if (oldValue == valueToCompare)
|
||||||
|
*value = newValue;
|
||||||
|
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
CriticalSection::CriticalSection() noexcept
|
||||||
|
{
|
||||||
|
// (just to check the MS haven't changed this structure and broken things...)
|
||||||
|
#if BEAST_VC7_OR_EARLIER
|
||||||
|
static_bassert (sizeof (CRITICAL_SECTION) <= 24);
|
||||||
|
#else
|
||||||
|
static_bassert (sizeof (CRITICAL_SECTION) <= sizeof (internal));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InitializeCriticalSection ((CRITICAL_SECTION*) internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
CriticalSection::~CriticalSection() noexcept
|
||||||
|
{
|
||||||
|
DeleteCriticalSection ((CRITICAL_SECTION*) internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CriticalSection::enter() const noexcept
|
||||||
|
{
|
||||||
|
EnterCriticalSection ((CRITICAL_SECTION*) internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CriticalSection::tryEnter() const noexcept
|
||||||
|
{
|
||||||
|
return TryEnterCriticalSection ((CRITICAL_SECTION*) internal) != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CriticalSection::exit() const noexcept
|
||||||
|
{
|
||||||
|
LeaveCriticalSection ((CRITICAL_SECTION*) internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
WaitableEvent::WaitableEvent (const bool manualReset) noexcept
|
||||||
|
: internal (CreateEvent (0, manualReset ? TRUE : FALSE, FALSE, 0))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitableEvent::~WaitableEvent() noexcept
|
||||||
|
{
|
||||||
|
CloseHandle (internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept
|
||||||
|
{
|
||||||
|
return WaitForSingleObject (internal, (DWORD) timeOutMillisecs) == WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitableEvent::signal() const noexcept
|
||||||
|
{
|
||||||
|
SetEvent (internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitableEvent::reset() const noexcept
|
||||||
|
{
|
||||||
|
ResetEvent (internal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void BEAST_API beast_threadEntryPoint (void*);
|
||||||
|
|
||||||
|
static unsigned int __stdcall threadEntryProc (void* userData)
|
||||||
|
{
|
||||||
|
if (beast_messageWindowHandle != 0)
|
||||||
|
AttachThreadInput (GetWindowThreadProcessId (beast_messageWindowHandle, 0),
|
||||||
|
GetCurrentThreadId(), TRUE);
|
||||||
|
|
||||||
|
beast_threadEntryPoint (userData);
|
||||||
|
|
||||||
|
_endthreadex (0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::launchThread()
|
||||||
|
{
|
||||||
|
unsigned int newThreadId;
|
||||||
|
threadHandle = (void*) _beginthreadex (0, 0, &threadEntryProc, this, 0, &newThreadId);
|
||||||
|
threadId = (ThreadID) newThreadId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::closeThreadHandle()
|
||||||
|
{
|
||||||
|
CloseHandle ((HANDLE) threadHandle);
|
||||||
|
threadId = 0;
|
||||||
|
threadHandle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::killThread()
|
||||||
|
{
|
||||||
|
if (threadHandle != 0)
|
||||||
|
{
|
||||||
|
#if BEAST_DEBUG
|
||||||
|
OutputDebugStringA ("** Warning - Forced thread termination **\n");
|
||||||
|
#endif
|
||||||
|
TerminateThread (threadHandle, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::setCurrentThreadName (const String& name)
|
||||||
|
{
|
||||||
|
#if BEAST_DEBUG && BEAST_MSVC
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
DWORD dwType;
|
||||||
|
LPCSTR szName;
|
||||||
|
DWORD dwThreadID;
|
||||||
|
DWORD dwFlags;
|
||||||
|
} info;
|
||||||
|
|
||||||
|
info.dwType = 0x1000;
|
||||||
|
info.szName = name.toUTF8();
|
||||||
|
info.dwThreadID = GetCurrentThreadId();
|
||||||
|
info.dwFlags = 0;
|
||||||
|
|
||||||
|
__try
|
||||||
|
{
|
||||||
|
RaiseException (0x406d1388 /*MS_VC_EXCEPTION*/, 0, sizeof (info) / sizeof (ULONG_PTR), (ULONG_PTR*) &info);
|
||||||
|
}
|
||||||
|
__except (EXCEPTION_CONTINUE_EXECUTION)
|
||||||
|
{}
|
||||||
|
#else
|
||||||
|
(void) name;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread::ThreadID Thread::getCurrentThreadId()
|
||||||
|
{
|
||||||
|
return (ThreadID) (pointer_sized_int) GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Thread::setThreadPriority (void* handle, int priority)
|
||||||
|
{
|
||||||
|
int pri = THREAD_PRIORITY_TIME_CRITICAL;
|
||||||
|
|
||||||
|
if (priority < 1) pri = THREAD_PRIORITY_IDLE;
|
||||||
|
else if (priority < 2) pri = THREAD_PRIORITY_LOWEST;
|
||||||
|
else if (priority < 5) pri = THREAD_PRIORITY_BELOW_NORMAL;
|
||||||
|
else if (priority < 7) pri = THREAD_PRIORITY_NORMAL;
|
||||||
|
else if (priority < 9) pri = THREAD_PRIORITY_ABOVE_NORMAL;
|
||||||
|
else if (priority < 10) pri = THREAD_PRIORITY_HIGHEST;
|
||||||
|
|
||||||
|
if (handle == 0)
|
||||||
|
handle = GetCurrentThread();
|
||||||
|
|
||||||
|
return SetThreadPriority (handle, pri) != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::setCurrentThreadAffinityMask (const uint32 affinityMask)
|
||||||
|
{
|
||||||
|
SetThreadAffinityMask (GetCurrentThread(), affinityMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
struct SleepEvent
|
||||||
|
{
|
||||||
|
SleepEvent() noexcept
|
||||||
|
: handle (CreateEvent (nullptr, FALSE, FALSE,
|
||||||
|
#if BEAST_DEBUG
|
||||||
|
_T("BEAST Sleep Event")))
|
||||||
|
#else
|
||||||
|
nullptr))
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
|
|
||||||
|
~SleepEvent() noexcept
|
||||||
|
{
|
||||||
|
CloseHandle (handle);
|
||||||
|
handle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SleepEvent sleepEvent;
|
||||||
|
|
||||||
|
void BEAST_CALLTYPE Thread::sleep (const int millisecs)
|
||||||
|
{
|
||||||
|
if (millisecs >= 10 || sleepEvent.handle == 0)
|
||||||
|
{
|
||||||
|
Sleep ((DWORD) millisecs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// unlike Sleep() this is guaranteed to return to the current thread after
|
||||||
|
// the time expires, so we'll use this for short waits, which are more likely
|
||||||
|
// to need to be accurate
|
||||||
|
WaitForSingleObject (sleepEvent.handle, (DWORD) millisecs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::yield()
|
||||||
|
{
|
||||||
|
Sleep (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static int lastProcessPriority = -1;
|
||||||
|
|
||||||
|
// called by WindowDriver because Windows does weird things to process priority
|
||||||
|
// when you swap apps, and this forces an update when the app is brought to the front.
|
||||||
|
void beast_repeatLastProcessPriority()
|
||||||
|
{
|
||||||
|
if (lastProcessPriority >= 0) // (avoid changing this if it's not been explicitly set by the app..)
|
||||||
|
{
|
||||||
|
DWORD p;
|
||||||
|
|
||||||
|
switch (lastProcessPriority)
|
||||||
|
{
|
||||||
|
case Process::LowPriority: p = IDLE_PRIORITY_CLASS; break;
|
||||||
|
case Process::NormalPriority: p = NORMAL_PRIORITY_CLASS; break;
|
||||||
|
case Process::HighPriority: p = HIGH_PRIORITY_CLASS; break;
|
||||||
|
case Process::RealtimePriority: p = REALTIME_PRIORITY_CLASS; break;
|
||||||
|
default: jassertfalse; return; // bad priority value
|
||||||
|
}
|
||||||
|
|
||||||
|
SetPriorityClass (GetCurrentProcess(), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::setPriority (ProcessPriority prior)
|
||||||
|
{
|
||||||
|
if (lastProcessPriority != (int) prior)
|
||||||
|
{
|
||||||
|
lastProcessPriority = (int) prior;
|
||||||
|
beast_repeatLastProcessPriority();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return IsDebuggerPresent() != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BEAST_CALLTYPE Process::isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return beast_isRunningUnderDebugger();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* currentModuleHandle = nullptr;
|
||||||
|
|
||||||
|
void* Process::getCurrentModuleInstanceHandle() noexcept
|
||||||
|
{
|
||||||
|
if (currentModuleHandle == nullptr)
|
||||||
|
currentModuleHandle = GetModuleHandleA (nullptr);
|
||||||
|
|
||||||
|
return currentModuleHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::setCurrentModuleInstanceHandle (void* const newHandle) noexcept
|
||||||
|
{
|
||||||
|
currentModuleHandle = newHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::raisePrivilege()
|
||||||
|
{
|
||||||
|
jassertfalse; // xxx not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::lowerPrivilege()
|
||||||
|
{
|
||||||
|
jassertfalse; // xxx not implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::terminate()
|
||||||
|
{
|
||||||
|
#if BEAST_MSVC && BEAST_CHECK_MEMORY_LEAKS
|
||||||
|
_CrtDumpMemoryLeaks();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// bullet in the head in case there's a problem shutting down..
|
||||||
|
ExitProcess (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool beast_isRunningInWine()
|
||||||
|
{
|
||||||
|
HMODULE ntdll = GetModuleHandleA ("ntdll");
|
||||||
|
return ntdll != 0 && GetProcAddress (ntdll, "wine_get_version") != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool DynamicLibrary::open (const String& name)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
|
||||||
|
BEAST_TRY
|
||||||
|
{
|
||||||
|
handle = LoadLibrary (name.toWideCharPointer());
|
||||||
|
}
|
||||||
|
BEAST_CATCH_ALL
|
||||||
|
|
||||||
|
return handle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicLibrary::close()
|
||||||
|
{
|
||||||
|
BEAST_TRY
|
||||||
|
{
|
||||||
|
if (handle != nullptr)
|
||||||
|
{
|
||||||
|
FreeLibrary ((HMODULE) handle);
|
||||||
|
handle = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BEAST_CATCH_ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
void* DynamicLibrary::getFunction (const String& functionName) noexcept
|
||||||
|
{
|
||||||
|
return handle != nullptr ? (void*) GetProcAddress ((HMODULE) handle, functionName.toUTF8()) // (void* cast is required for mingw)
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class InterProcessLock::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (String name, const int timeOutMillisecs)
|
||||||
|
: handle (0), refCount (1)
|
||||||
|
{
|
||||||
|
name = name.replaceCharacter ('\\', '/');
|
||||||
|
handle = CreateMutexW (0, TRUE, ("Global\\" + name).toWideCharPointer());
|
||||||
|
|
||||||
|
// Not 100% sure why a global mutex sometimes can't be allocated, but if it fails, fall back to
|
||||||
|
// a local one. (A local one also sometimes fails on other machines so neither type appears to be
|
||||||
|
// universally reliable)
|
||||||
|
if (handle == 0)
|
||||||
|
handle = CreateMutexW (0, TRUE, ("Local\\" + name).toWideCharPointer());
|
||||||
|
|
||||||
|
if (handle != 0 && GetLastError() == ERROR_ALREADY_EXISTS)
|
||||||
|
{
|
||||||
|
if (timeOutMillisecs == 0)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (WaitForSingleObject (handle, timeOutMillisecs < 0 ? INFINITE : timeOutMillisecs))
|
||||||
|
{
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
case WAIT_ABANDONED:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WAIT_TIMEOUT:
|
||||||
|
default:
|
||||||
|
close();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
if (handle != 0)
|
||||||
|
{
|
||||||
|
ReleaseMutex (handle);
|
||||||
|
CloseHandle (handle);
|
||||||
|
handle = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE handle;
|
||||||
|
int refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
InterProcessLock::InterProcessLock (const String& name_)
|
||||||
|
: name (name_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
InterProcessLock::~InterProcessLock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InterProcessLock::enter (const int timeOutMillisecs)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
if (pimpl == nullptr)
|
||||||
|
{
|
||||||
|
pimpl = new Pimpl (name, timeOutMillisecs);
|
||||||
|
|
||||||
|
if (pimpl->handle == 0)
|
||||||
|
pimpl = nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pimpl->refCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pimpl != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InterProcessLock::exit()
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
// Trying to release the lock too many times!
|
||||||
|
bassert (pimpl != nullptr);
|
||||||
|
|
||||||
|
if (pimpl != nullptr && --(pimpl->refCount) == 0)
|
||||||
|
pimpl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class ChildProcess::ActiveProcess
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ActiveProcess (const String& command)
|
||||||
|
: ok (false), readPipe (0), writePipe (0)
|
||||||
|
{
|
||||||
|
SECURITY_ATTRIBUTES securityAtts = { 0 };
|
||||||
|
securityAtts.nLength = sizeof (securityAtts);
|
||||||
|
securityAtts.bInheritHandle = TRUE;
|
||||||
|
|
||||||
|
if (CreatePipe (&readPipe, &writePipe, &securityAtts, 0)
|
||||||
|
&& SetHandleInformation (readPipe, HANDLE_FLAG_INHERIT, 0))
|
||||||
|
{
|
||||||
|
STARTUPINFOW startupInfo = { 0 };
|
||||||
|
startupInfo.cb = sizeof (startupInfo);
|
||||||
|
startupInfo.hStdError = writePipe;
|
||||||
|
startupInfo.hStdOutput = writePipe;
|
||||||
|
startupInfo.dwFlags = STARTF_USESTDHANDLES;
|
||||||
|
|
||||||
|
ok = CreateProcess (nullptr, const_cast <LPWSTR> (command.toWideCharPointer()),
|
||||||
|
nullptr, nullptr, TRUE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
|
||||||
|
nullptr, nullptr, &startupInfo, &processInfo) != FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ActiveProcess()
|
||||||
|
{
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
CloseHandle (processInfo.hThread);
|
||||||
|
CloseHandle (processInfo.hProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readPipe != 0)
|
||||||
|
CloseHandle (readPipe);
|
||||||
|
|
||||||
|
if (writePipe != 0)
|
||||||
|
CloseHandle (writePipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRunning() const
|
||||||
|
{
|
||||||
|
return WaitForSingleObject (processInfo.hProcess, 0) != WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (void* dest, int numNeeded) const
|
||||||
|
{
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
while (ok && numNeeded > 0)
|
||||||
|
{
|
||||||
|
DWORD available = 0;
|
||||||
|
|
||||||
|
if (! PeekNamedPipe ((HANDLE) readPipe, nullptr, 0, nullptr, &available, nullptr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
const int numToDo = bmin ((int) available, numNeeded);
|
||||||
|
|
||||||
|
if (available == 0)
|
||||||
|
{
|
||||||
|
if (! isRunning())
|
||||||
|
break;
|
||||||
|
|
||||||
|
Thread::yield();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD numRead = 0;
|
||||||
|
if (! ReadFile ((HANDLE) readPipe, dest, numToDo, &numRead, nullptr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
total += numRead;
|
||||||
|
dest = addBytesToPointer (dest, numRead);
|
||||||
|
numNeeded -= numRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool killProcess() const
|
||||||
|
{
|
||||||
|
return TerminateProcess (processInfo.hProcess, 0) != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HANDLE readPipe, writePipe;
|
||||||
|
PROCESS_INFORMATION processInfo;
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveProcess)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ChildProcess::start (const String& command)
|
||||||
|
{
|
||||||
|
activeProcess = new ActiveProcess (command);
|
||||||
|
|
||||||
|
if (! activeProcess->ok)
|
||||||
|
activeProcess = nullptr;
|
||||||
|
|
||||||
|
return activeProcess != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChildProcess::start (const StringArray& args)
|
||||||
|
{
|
||||||
|
return start (args.joinIntoString (" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChildProcess::isRunning() const
|
||||||
|
{
|
||||||
|
return activeProcess != nullptr && activeProcess->isRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChildProcess::readProcessOutput (void* dest, int numBytes)
|
||||||
|
{
|
||||||
|
return activeProcess != nullptr ? activeProcess->read (dest, numBytes) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChildProcess::kill()
|
||||||
|
{
|
||||||
|
return activeProcess == nullptr || activeProcess->killProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
struct HighResolutionTimer::Pimpl
|
||||||
|
{
|
||||||
|
Pimpl (HighResolutionTimer& t) noexcept : owner (t), periodMs (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
bassert (periodMs == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start (int newPeriod)
|
||||||
|
{
|
||||||
|
if (newPeriod != periodMs)
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
periodMs = newPeriod;
|
||||||
|
|
||||||
|
TIMECAPS tc;
|
||||||
|
if (timeGetDevCaps (&tc, sizeof (tc)) == TIMERR_NOERROR)
|
||||||
|
{
|
||||||
|
const int actualPeriod = blimit ((int) tc.wPeriodMin, (int) tc.wPeriodMax, newPeriod);
|
||||||
|
|
||||||
|
timerID = timeSetEvent (actualPeriod, tc.wPeriodMin, callbackFunction, (DWORD_PTR) this,
|
||||||
|
TIME_PERIODIC | TIME_CALLBACK_FUNCTION | 0x100 /*TIME_KILL_SYNCHRONOUS*/);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
periodMs = 0;
|
||||||
|
timeKillEvent (timerID);
|
||||||
|
}
|
||||||
|
|
||||||
|
HighResolutionTimer& owner;
|
||||||
|
int periodMs;
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int timerID;
|
||||||
|
|
||||||
|
static void __stdcall callbackFunction (UINT, UINT, DWORD_PTR userInfo, DWORD_PTR, DWORD_PTR)
|
||||||
|
{
|
||||||
|
if (Pimpl* const timer = reinterpret_cast<Pimpl*> (userInfo))
|
||||||
|
if (timer->periodMs != 0)
|
||||||
|
timer->owner.hiResTimerCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
BEAST_DECLARE_NON_COPYABLE (Pimpl)
|
||||||
|
};
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user