Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 77fbf61f19 |
@@ -1,33 +0,0 @@
|
||||
Standard: Cpp11
|
||||
UseTab: ForIndentation
|
||||
TabWidth: 1
|
||||
IndentWidth: 1
|
||||
AccessModifierOffset: -1
|
||||
PointerAlignment: Left
|
||||
NamespaceIndentation: All
|
||||
ColumnLimit: 100
|
||||
BreakBeforeBraces: Allman
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
Cpp11BracedListStyle: true
|
||||
IndentCaseLabels: false
|
||||
SortIncludes: false
|
||||
ReflowComments: true
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignTrailingComments: true
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
IndentWrappedFunctionNames: false
|
||||
|
||||
#SpaceAfterTemplateKeyword: false
|
||||
@@ -1,7 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*.{h,cpp,hpp}]
|
||||
charset = utf-8
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
@@ -38,8 +38,6 @@
|
||||
/rpcs3/Debug
|
||||
/rpcs3/Release
|
||||
/llvm_build
|
||||
/Vulkan/Vulkan-build
|
||||
/Vulkan/glslang-build
|
||||
|
||||
/wxWidgets/lib
|
||||
/bin/rpcs3.ini
|
||||
@@ -85,5 +83,3 @@ CMakeCache.txt
|
||||
# cotire
|
||||
rpcs3/cotire/*
|
||||
rpcs3/rpcs3_*_cotire.cmake
|
||||
/.vs/rpcs3/v15/ipch/AutoPCH/VKGSRENDER-1a48cf59/VKGSRENDER-717b8989/*.ipch
|
||||
/.vs/rpcs3/v15/ipch/EMUCORE-4bdb26ae/*.ipch
|
||||
|
||||
+8
-27
@@ -1,9 +1,9 @@
|
||||
[submodule "wxWidgets"]
|
||||
path = wxWidgets
|
||||
url = https://github.com/Zangetsu38/wxWidgets
|
||||
url = https://github.com/wxWidgets/wxWidgets
|
||||
ignore = dirty
|
||||
[submodule "rpcs3-ffmpeg"]
|
||||
path = 3rdparty/ffmpeg
|
||||
path = ffmpeg
|
||||
url = https://github.com/hrydgard/ppsspp-ffmpeg
|
||||
[submodule "asmjit"]
|
||||
path = asmjit
|
||||
@@ -12,32 +12,13 @@
|
||||
[submodule "llvm"]
|
||||
path = llvm
|
||||
url = https://github.com/llvm-mirror/llvm
|
||||
branch = release_39
|
||||
branch = release_36
|
||||
[submodule "minidx9"]
|
||||
path = minidx9
|
||||
url = https://github.com/hrydgard/minidx9.git
|
||||
[submodule "rsx_program_decompiler"]
|
||||
path = rsx_program_decompiler
|
||||
url = https://github.com/Zangetsu38/rsx_program_decompiler
|
||||
url = https://github.com/RPCS3/rsx_program_decompiler
|
||||
[submodule "GSL"]
|
||||
path = 3rdparty/GSL
|
||||
path = GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
[submodule "libpng"]
|
||||
path = 3rdparty/libpng
|
||||
url = https://github.com/RPCS3/libpng
|
||||
ignore = dirty
|
||||
[submodule "Vulkan/glslang"]
|
||||
path = Vulkan/glslang
|
||||
url = https://github.com/KhronosGroup/glslang.git
|
||||
[submodule "Vulkan/Vulkan-LoaderAndValidationLayers"]
|
||||
path = Vulkan/Vulkan-LoaderAndValidationLayers
|
||||
url = https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers
|
||||
[submodule "Utilities/yaml-cpp"]
|
||||
path = Utilities/yaml-cpp
|
||||
url = https://github.com/RPCS3/yaml-cpp
|
||||
[submodule "3rdparty/pugixml"]
|
||||
path = 3rdparty/pugixml
|
||||
url = https://github.com/RPCS3/pugixml
|
||||
[submodule "3rdparty/cereal"]
|
||||
path = 3rdparty/cereal
|
||||
url = https://github.com/USCiLab/cereal.git
|
||||
[submodule "rsx-debugger"]
|
||||
path = rsx-debugger
|
||||
url = https://github.com/RPCS3/rsx-debugger.git
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"userBlacklist": ["AlexAltea", "tambry", "DHrpcs3"]
|
||||
}
|
||||
"userBlacklist": ["AlexAltea"]
|
||||
}
|
||||
+18
-13
@@ -1,10 +1,8 @@
|
||||
language: cpp
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
os:
|
||||
- linux
|
||||
# - osx
|
||||
- osx
|
||||
|
||||
osx_image: xcode6.4
|
||||
|
||||
@@ -20,6 +18,10 @@ env:
|
||||
# Test mode is for testing if it's working with Coverity. Change to true if testing, to avoid reaching the quota.
|
||||
- coverity_scan_script_test_mode=false
|
||||
|
||||
branches:
|
||||
except:
|
||||
- ppu_recompiler
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
@@ -31,25 +33,28 @@ git:
|
||||
before_install:
|
||||
# shutdown services on Travis, which may have a memory impact
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo apt-get install -y libwxgtk3.0-dev;
|
||||
echo "yes" | sudo apt-add-repository 'deb http://repos.codelite.org/wx3.0/ubuntu/ precise universe';
|
||||
sudo apt-get install libwxgtk3.0-dev;
|
||||
fi;
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CXX" = "g++" ]; then
|
||||
export CXX="g++-5" CC="gcc-5" CXXFLAGS="-Wno-format-security";
|
||||
export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01';
|
||||
elif [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export CXX="clang++-3.6" CC="clang-3.6";
|
||||
fi;
|
||||
# Add coverall for C++ so coverall.io could be triggered. Even it should be --coverage and gcov.
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo pip install cpp-coveralls requests[security];
|
||||
else
|
||||
brew update; brew update;
|
||||
brew install glew wxwidgets llvm38;
|
||||
brew install glew wxwidgets llvm36;
|
||||
fi;
|
||||
|
||||
before_script:
|
||||
- git submodule update --init rsx_program_decompiler asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Utilities/yaml-cpp 3rdparty/cereal
|
||||
- git submodule update --init asmjit ffmpeg rsx_program_decompiler GSL
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm38/lib/llvm-3.8/share/llvm/cmake; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi
|
||||
|
||||
script:
|
||||
# Add a command to show all the variables. May be useful for debugging Travis.
|
||||
@@ -62,22 +67,22 @@ addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
# - llvm-toolchain-trusty-3.8 temporarily disabled
|
||||
- llvm-toolchain-precise-3.6
|
||||
- kubuntu-backports
|
||||
packages:
|
||||
- cmake
|
||||
- libopenal-dev
|
||||
- freeglut3-dev
|
||||
- libglew-dev
|
||||
- libc6-dev
|
||||
# - llvm-3.8
|
||||
# - llvm-3.8-dev
|
||||
- llvm-3.6
|
||||
- llvm-3.6-dev
|
||||
- libedit-dev
|
||||
- g++-5
|
||||
- gcc-5
|
||||
# - clang-3.6
|
||||
- libstdc++-5-dev
|
||||
- clang-3.6
|
||||
- libstdc++-4.8-dev
|
||||
- lib32stdc++6
|
||||
- zlib1g-dev
|
||||
coverity_scan:
|
||||
project:
|
||||
name: $TRAVIS_REPO_SLUG
|
||||
|
||||
Vendored
-1295
File diff suppressed because it is too large
Load Diff
Vendored
-263
@@ -1,263 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* File: audiodefs.h
|
||||
* Content: Basic constants and data types for audio work.
|
||||
*
|
||||
* Remarks: This header file defines all of the audio format constants and
|
||||
* structures required for XAudio2 and XACT work. Providing these
|
||||
* in a single location avoids certain dependency problems in the
|
||||
* legacy audio headers (mmreg.h, mmsystem.h, ksmedia.h).
|
||||
*
|
||||
* NOTE: Including the legacy headers after this one may cause a
|
||||
* compilation error, because they define some of the same types
|
||||
* defined here without preprocessor guards to avoid multiple
|
||||
* definitions. If a source file needs one of the old headers,
|
||||
* it must include it before including audiodefs.h.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __AUDIODEFS_INCLUDED__
|
||||
#define __AUDIODEFS_INCLUDED__
|
||||
|
||||
#include <windef.h> // For WORD, DWORD, etc.
|
||||
|
||||
#pragma pack(push, 1) // Pack structures to 1-byte boundaries
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* WAVEFORMATEX: Base structure for many audio formats. Format-specific
|
||||
* extensions can be defined for particular formats by using a non-zero
|
||||
* cbSize value and adding extra fields to the end of this structure.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _WAVEFORMATEX_
|
||||
|
||||
#define _WAVEFORMATEX_
|
||||
typedef struct tWAVEFORMATEX
|
||||
{
|
||||
WORD wFormatTag; // Integer identifier of the format
|
||||
WORD nChannels; // Number of audio channels
|
||||
DWORD nSamplesPerSec; // Audio sample rate
|
||||
DWORD nAvgBytesPerSec; // Bytes per second (possibly approximate)
|
||||
WORD nBlockAlign; // Size in bytes of a sample block (all channels)
|
||||
WORD wBitsPerSample; // Size in bits of a single per-channel sample
|
||||
WORD cbSize; // Bytes of extra data appended to this struct
|
||||
} WAVEFORMATEX;
|
||||
|
||||
#endif
|
||||
|
||||
// Defining pointer types outside of the #if block to make sure they are
|
||||
// defined even if mmreg.h or mmsystem.h is #included before this file
|
||||
|
||||
typedef WAVEFORMATEX *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX;
|
||||
typedef const WAVEFORMATEX *PCWAVEFORMATEX, *LPCWAVEFORMATEX;
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* WAVEFORMATEXTENSIBLE: Extended version of WAVEFORMATEX that should be
|
||||
* used as a basis for all new audio formats. The format tag is replaced
|
||||
* with a GUID, allowing new formats to be defined without registering a
|
||||
* format tag with Microsoft. There are also new fields that can be used
|
||||
* to specify the spatial positions for each channel and the bit packing
|
||||
* used for wide samples (e.g. 24-bit PCM samples in 32-bit containers).
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||
|
||||
#define _WAVEFORMATEXTENSIBLE_
|
||||
typedef struct
|
||||
{
|
||||
WAVEFORMATEX Format; // Base WAVEFORMATEX data
|
||||
union
|
||||
{
|
||||
WORD wValidBitsPerSample; // Valid bits in each sample container
|
||||
WORD wSamplesPerBlock; // Samples per block of audio data; valid
|
||||
// if wBitsPerSample=0 (but rarely used).
|
||||
WORD wReserved; // Zero if neither case above applies.
|
||||
} Samples;
|
||||
DWORD dwChannelMask; // Positions of the audio channels
|
||||
GUID SubFormat; // Format identifier GUID
|
||||
} WAVEFORMATEXTENSIBLE;
|
||||
|
||||
#endif
|
||||
|
||||
typedef WAVEFORMATEXTENSIBLE *PWAVEFORMATEXTENSIBLE, *LPWAVEFORMATEXTENSIBLE;
|
||||
typedef const WAVEFORMATEXTENSIBLE *PCWAVEFORMATEXTENSIBLE, *LPCWAVEFORMATEXTENSIBLE;
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Define the most common wave format tags used in WAVEFORMATEX formats.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef WAVE_FORMAT_PCM // Pulse Code Modulation
|
||||
|
||||
// If WAVE_FORMAT_PCM is not defined, we need to define some legacy types
|
||||
// for compatibility with the Windows mmreg.h / mmsystem.h header files.
|
||||
|
||||
// Old general format structure (information common to all formats)
|
||||
typedef struct waveformat_tag
|
||||
{
|
||||
WORD wFormatTag;
|
||||
WORD nChannels;
|
||||
DWORD nSamplesPerSec;
|
||||
DWORD nAvgBytesPerSec;
|
||||
WORD nBlockAlign;
|
||||
} WAVEFORMAT, *PWAVEFORMAT, NEAR *NPWAVEFORMAT, FAR *LPWAVEFORMAT;
|
||||
|
||||
// Specific format structure for PCM data
|
||||
typedef struct pcmwaveformat_tag
|
||||
{
|
||||
WAVEFORMAT wf;
|
||||
WORD wBitsPerSample;
|
||||
} PCMWAVEFORMAT, *PPCMWAVEFORMAT, NEAR *NPPCMWAVEFORMAT, FAR *LPPCMWAVEFORMAT;
|
||||
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_ADPCM // Microsoft Adaptive Differental PCM
|
||||
|
||||
// Replicate the Microsoft ADPCM type definitions from mmreg.h.
|
||||
|
||||
typedef struct adpcmcoef_tag
|
||||
{
|
||||
short iCoef1;
|
||||
short iCoef2;
|
||||
} ADPCMCOEFSET;
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4200) // Disable zero-sized array warnings
|
||||
|
||||
typedef struct adpcmwaveformat_tag {
|
||||
WAVEFORMATEX wfx;
|
||||
WORD wSamplesPerBlock;
|
||||
WORD wNumCoef;
|
||||
ADPCMCOEFSET aCoef[]; // Always 7 coefficient pairs for MS ADPCM
|
||||
} ADPCMWAVEFORMAT;
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#define WAVE_FORMAT_ADPCM 0x0002
|
||||
|
||||
#endif
|
||||
|
||||
// Other frequently used format tags
|
||||
|
||||
#ifndef WAVE_FORMAT_UNKNOWN
|
||||
#define WAVE_FORMAT_UNKNOWN 0x0000 // Unknown or invalid format tag
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_IEEE_FLOAT
|
||||
#define WAVE_FORMAT_IEEE_FLOAT 0x0003 // 32-bit floating-point
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_MPEGLAYER3
|
||||
#define WAVE_FORMAT_MPEGLAYER3 0x0055 // ISO/MPEG Layer3
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_DOLBY_AC3_SPDIF
|
||||
#define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 // Dolby Audio Codec 3 over S/PDIF
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_WMAUDIO2
|
||||
#define WAVE_FORMAT_WMAUDIO2 0x0161 // Windows Media Audio
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_WMAUDIO3
|
||||
#define WAVE_FORMAT_WMAUDIO3 0x0162 // Windows Media Audio Pro
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_WMASPDIF
|
||||
#define WAVE_FORMAT_WMASPDIF 0x0164 // Windows Media Audio over S/PDIF
|
||||
#endif
|
||||
|
||||
#ifndef WAVE_FORMAT_EXTENSIBLE
|
||||
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE // All WAVEFORMATEXTENSIBLE formats
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Define the most common wave format GUIDs used in WAVEFORMATEXTENSIBLE
|
||||
* formats. Note that including the Windows ksmedia.h header after this
|
||||
* one will cause build problems; this cannot be avoided, since ksmedia.h
|
||||
* defines these macros without preprocessor guards.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifdef __cplusplus // uuid() and __uuidof() are only available in C++
|
||||
|
||||
#ifndef KSDATAFORMAT_SUBTYPE_PCM
|
||||
struct __declspec(uuid("00000001-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_PCM_STRUCT;
|
||||
#define KSDATAFORMAT_SUBTYPE_PCM __uuidof(KSDATAFORMAT_SUBTYPE_PCM_STRUCT)
|
||||
#endif
|
||||
|
||||
#ifndef KSDATAFORMAT_SUBTYPE_ADPCM
|
||||
struct __declspec(uuid("00000002-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT;
|
||||
#define KSDATAFORMAT_SUBTYPE_ADPCM __uuidof(KSDATAFORMAT_SUBTYPE_ADPCM_STRUCT)
|
||||
#endif
|
||||
|
||||
#ifndef KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
|
||||
struct __declspec(uuid("00000003-0000-0010-8000-00aa00389b71")) KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT;
|
||||
#define KSDATAFORMAT_SUBTYPE_IEEE_FLOAT __uuidof(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT_STRUCT)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* Speaker positions used in the WAVEFORMATEXTENSIBLE dwChannelMask field.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef SPEAKER_FRONT_LEFT
|
||||
#define SPEAKER_FRONT_LEFT 0x00000001
|
||||
#define SPEAKER_FRONT_RIGHT 0x00000002
|
||||
#define SPEAKER_FRONT_CENTER 0x00000004
|
||||
#define SPEAKER_LOW_FREQUENCY 0x00000008
|
||||
#define SPEAKER_BACK_LEFT 0x00000010
|
||||
#define SPEAKER_BACK_RIGHT 0x00000020
|
||||
#define SPEAKER_FRONT_LEFT_OF_CENTER 0x00000040
|
||||
#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x00000080
|
||||
#define SPEAKER_BACK_CENTER 0x00000100
|
||||
#define SPEAKER_SIDE_LEFT 0x00000200
|
||||
#define SPEAKER_SIDE_RIGHT 0x00000400
|
||||
#define SPEAKER_TOP_CENTER 0x00000800
|
||||
#define SPEAKER_TOP_FRONT_LEFT 0x00001000
|
||||
#define SPEAKER_TOP_FRONT_CENTER 0x00002000
|
||||
#define SPEAKER_TOP_FRONT_RIGHT 0x00004000
|
||||
#define SPEAKER_TOP_BACK_LEFT 0x00008000
|
||||
#define SPEAKER_TOP_BACK_CENTER 0x00010000
|
||||
#define SPEAKER_TOP_BACK_RIGHT 0x00020000
|
||||
#define SPEAKER_RESERVED 0x7FFC0000
|
||||
#define SPEAKER_ALL 0x80000000
|
||||
#define _SPEAKER_POSITIONS_
|
||||
#endif
|
||||
|
||||
#ifndef SPEAKER_STEREO
|
||||
#define SPEAKER_MONO (SPEAKER_FRONT_CENTER)
|
||||
#define SPEAKER_STEREO (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT)
|
||||
#define SPEAKER_2POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY)
|
||||
#define SPEAKER_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_CENTER)
|
||||
#define SPEAKER_QUAD (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define SPEAKER_4POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define SPEAKER_5POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT)
|
||||
#define SPEAKER_7POINT1 (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_LEFT_OF_CENTER | SPEAKER_FRONT_RIGHT_OF_CENTER)
|
||||
#define SPEAKER_5POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
|
||||
#define SPEAKER_7POINT1_SURROUND (SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT)
|
||||
#endif
|
||||
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // #ifndef __AUDIODEFS_INCLUDED__
|
||||
Vendored
-65
@@ -1,65 +0,0 @@
|
||||
// comdecl.h: Macros to facilitate COM interface and GUID declarations.
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
#ifndef _COMDECL_H_
|
||||
#define _COMDECL_H_
|
||||
|
||||
#ifndef _XBOX
|
||||
#include <basetyps.h> // For standard COM interface macros
|
||||
#else
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4061)
|
||||
#include <xtl.h> // Required by xobjbase.h
|
||||
#include <xobjbase.h> // Special definitions for Xbox build
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// The DEFINE_CLSID() and DEFINE_IID() macros defined below allow COM GUIDs to
|
||||
// be declared and defined in such a way that clients can obtain the GUIDs using
|
||||
// either the __uuidof() extension or the old-style CLSID_Foo / IID_IFoo names.
|
||||
// If using the latter approach, the client can also choose whether to get the
|
||||
// GUID definitions by defining the INITGUID preprocessor constant or by linking
|
||||
// to a GUID library. This works in either C or C++.
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
#define DEFINE_UUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) __CRT_UUID_DECL(name, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) class className; DEFINE_UUID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) struct interfaceName; DEFINE_UUID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8)
|
||||
|
||||
#elif __cplusplus
|
||||
|
||||
#define DECLSPEC_UUID_WRAPPER(x) __declspec(uuid(#x))
|
||||
#ifdef INITGUID
|
||||
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY CLSID_##className = __uuidof(className)
|
||||
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \
|
||||
EXTERN_C const GUID DECLSPEC_SELECTANY IID_##interfaceName = __uuidof(interfaceName)
|
||||
|
||||
#else // INITGUID
|
||||
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
class DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) className; \
|
||||
EXTERN_C const GUID CLSID_##className
|
||||
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
interface DECLSPEC_UUID_WRAPPER(l##-##w1##-##w2##-##b1##b2##-##b3##b4##b5##b6##b7##b8) interfaceName; \
|
||||
EXTERN_C const GUID IID_##interfaceName
|
||||
|
||||
#endif // INITGUID
|
||||
|
||||
#else // __cplusplus
|
||||
|
||||
#define DEFINE_CLSID(className, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
DEFINE_GUID(CLSID_##className, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
|
||||
#define DEFINE_IID(interfaceName, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
|
||||
DEFINE_GUID(IID_##interfaceName, 0x##l, 0x##w1, 0x##w2, 0x##b1, 0x##b2, 0x##b3, 0x##b4, 0x##b5, 0x##b6, 0x##b7, 0x##b8)
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // #ifndef _COMDECL_H_
|
||||
Vendored
-18
@@ -1,18 +0,0 @@
|
||||
/*==========================================================================;
|
||||
*
|
||||
*
|
||||
* File: dxsdkver.h
|
||||
* Content: DirectX SDK Version Include File
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _DXSDKVER_H_
|
||||
#define _DXSDKVER_H_
|
||||
|
||||
#define _DXSDK_PRODUCT_MAJOR 9
|
||||
#define _DXSDK_PRODUCT_MINOR 29
|
||||
#define _DXSDK_BUILD_MAJOR 1962
|
||||
#define _DXSDK_BUILD_MINOR 0
|
||||
|
||||
#endif // _DXSDKVER_H_
|
||||
|
||||
Vendored
-718
@@ -1,718 +0,0 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
*
|
||||
* File: xma2defs.h
|
||||
* Content: Constants, data types and functions for XMA2 compressed audio.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef __XMA2DEFS_INCLUDED__
|
||||
#define __XMA2DEFS_INCLUDED__
|
||||
|
||||
#include <sal.h> // Markers for documenting API semantics
|
||||
#include <winerror.h> // For S_OK, E_FAIL
|
||||
#include <audiodefs.h> // Basic data types and constants for audio work
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Overview
|
||||
***************************************************************************/
|
||||
|
||||
// A typical XMA2 file contains these RIFF chunks:
|
||||
//
|
||||
// 'fmt' or 'XMA2' chunk (or both): A description of the XMA data's structure
|
||||
// and characteristics (length, channels, sample rate, loops, block size, etc).
|
||||
//
|
||||
// 'seek' chunk: A seek table to help navigate the XMA data.
|
||||
//
|
||||
// 'data' chunk: The encoded XMA2 data.
|
||||
//
|
||||
// The encoded XMA2 data is structured as a set of BLOCKS, which contain PACKETS,
|
||||
// which contain FRAMES, which contain SUBFRAMES (roughly speaking). The frames
|
||||
// in a file may also be divided into several subsets, called STREAMS.
|
||||
//
|
||||
// FRAME: A variable-sized segment of XMA data that decodes to exactly 512 mono
|
||||
// or stereo PCM samples. This is the smallest unit of XMA data that can
|
||||
// be decoded in isolation. Frames are an arbitrary number of bits in
|
||||
// length, and need not be byte-aligned. See "XMA frame structure" below.
|
||||
//
|
||||
// SUBFRAME: A region of bits in an XMA frame that decodes to 128 mono or stereo
|
||||
// samples. The XMA decoder cannot decode a subframe in isolation; it needs
|
||||
// a whole frame to work with. However, it can begin emitting the frame's
|
||||
// decoded samples at any one of the four subframe boundaries. Subframes
|
||||
// can be addressed for seeking and looping purposes.
|
||||
//
|
||||
// PACKET: A 2Kb region containing a 32-bit header and some XMA frames. Frames
|
||||
// can (and usually do) span packets. A packet's header includes the offset
|
||||
// in bits of the first frame that begins within that packet. All of the
|
||||
// frames that begin in a given packet belong to the same "stream" (see the
|
||||
// Multichannel Audio section below).
|
||||
//
|
||||
// STREAM: A set of packets within an XMA file that all contain data for the
|
||||
// same mono or stereo component of a PCM file with more than two channels.
|
||||
// The packets comprising a given stream may be interleaved with each other
|
||||
// more or less arbitrarily; see Multichannel Audio.
|
||||
//
|
||||
// BLOCK: An array of XMA packets; or, to break it down differently, a series of
|
||||
// consecutive XMA frames, padded at the end with reserved data. A block
|
||||
// must contain at least one 2Kb packet per stream, and it can hold up to
|
||||
// 4095 packets (8190Kb), but its size is typically in the 32Kb-128Kb range.
|
||||
// (The size chosen involves a trade-off between memory use and efficiency
|
||||
// of reading from permanent storage.)
|
||||
//
|
||||
// XMA frames do not span blocks, so a block is guaranteed to begin with a
|
||||
// set of complete frames, one per stream. Also, a block in a multi-stream
|
||||
// XMA2 file always contains the same number of samples for each stream;
|
||||
// see Multichannel Audio.
|
||||
//
|
||||
// The 'data' chunk in an XMA2 file is an array of XMA2WAVEFORMAT.BlockCount XMA
|
||||
// blocks, all the same size (as specified in XMA2WAVEFORMAT.BlockSizeInBytes)
|
||||
// except for the last one, which may be shorter.
|
||||
|
||||
|
||||
// MULTICHANNEL AUDIO: the XMA decoder can only decode raw XMA data into either
|
||||
// mono or stereo PCM data. In order to encode a 6-channel file (say), the file
|
||||
// must be deinterleaved into 3 stereo streams that are encoded independently,
|
||||
// producing 3 encoded XMA data streams. Then the packets in these 3 streams
|
||||
// are interleaved to produce a single XMA2 file, and some information is added
|
||||
// to the file so that the original 6-channel audio can be reconstructed at
|
||||
// decode time. This works using the concept of an XMA stream (see above).
|
||||
//
|
||||
// The frames for all the streams in an XMA file are interleaved in an arbitrary
|
||||
// order. To locate a frame that belongs to a given stream in a given XMA block,
|
||||
// you must examine the first few packets in the block. Here (and only here) the
|
||||
// packets are guaranteed to be presented in stream order, so that all frames
|
||||
// beginning in packet 0 belong to stream 0 (the first stereo pair), etc.
|
||||
//
|
||||
// (This means that when decoding multi-stream XMA files, only entire XMA blocks
|
||||
// should be submitted to the decoder; otherwise it cannot know which frames
|
||||
// belong to which stream.)
|
||||
//
|
||||
// Once you have one frame that belongs to a given stream, you can find the next
|
||||
// one by looking at the frame's 'NextFrameOffsetBits' value (which is stored in
|
||||
// its first 15 bits; see XMAFRAME below). The GetXmaFrameBitPosition function
|
||||
// uses this technique.
|
||||
|
||||
|
||||
// SEEKING IN XMA2 FILES: Here is some pseudocode to find the byte position and
|
||||
// subframe in an XMA2 file which will contain sample S when decoded.
|
||||
//
|
||||
// 1. Traverse the seek table to find the XMA2 block containing sample S. The
|
||||
// seek table is an array of big-endian DWORDs, one per block in the file.
|
||||
// The Nth DWORD is the total number of PCM samples that would be obtained
|
||||
// by decoding the entire XMA file up to the end of block N. Hence, the
|
||||
// block we want is the first one whose seek table entry is greater than S.
|
||||
// (See the GetXmaBlockContainingSample helper function.)
|
||||
//
|
||||
// 2. Calculate which frame F within the block found above contains sample S.
|
||||
// Since each frame decodes to 512 samples, this is straightforward. The
|
||||
// first frame in the block produces samples X to X + 512, where X is the
|
||||
// seek table entry for the prior block. So F is (S - X) / 512.
|
||||
//
|
||||
// 3. Find the bit offset within the block where frame F starts. Since frames
|
||||
// are variable-sized, this can only be done by traversing all the frames in
|
||||
// the block until we reach frame F. (See GetXmaFrameBitPosition.)
|
||||
//
|
||||
// 4. Frame F has four 128-sample subframes. To find the subframe containing S,
|
||||
// we can use the formula (S % 512) / 128.
|
||||
//
|
||||
// In the case of multi-stream XMA files, sample S is a multichannel sample with
|
||||
// parts coming from several frames, one per stream. To find all these frames,
|
||||
// steps 2-4 need to be repeated for each stream N, using the knowledge that the
|
||||
// first packets in a block are presented in stream order. The frame traversal
|
||||
// in step 3 must be started at the first frame in the Nth packet of the block,
|
||||
// which will be the first frame for stream N. (And the packet header will tell
|
||||
// you the first frame's start position within the packet.)
|
||||
//
|
||||
// Step 1 can be performed using the GetXmaBlockContainingSample function below,
|
||||
// and steps 2-4 by calling GetXmaDecodePositionForSample once for each stream.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA constants
|
||||
***************************************************************************/
|
||||
|
||||
// Size of the PCM samples produced by the XMA decoder
|
||||
#define XMA_OUTPUT_SAMPLE_BYTES 2u
|
||||
#define XMA_OUTPUT_SAMPLE_BITS (XMA_OUTPUT_SAMPLE_BYTES * 8u)
|
||||
|
||||
// Size of an XMA packet
|
||||
#define XMA_BYTES_PER_PACKET 2048u
|
||||
#define XMA_BITS_PER_PACKET (XMA_BYTES_PER_PACKET * 8u)
|
||||
|
||||
// Size of an XMA packet header
|
||||
#define XMA_PACKET_HEADER_BYTES 4u
|
||||
#define XMA_PACKET_HEADER_BITS (XMA_PACKET_HEADER_BYTES * 8u)
|
||||
|
||||
// Sample blocks in a decoded XMA frame
|
||||
#define XMA_SAMPLES_PER_FRAME 512u
|
||||
|
||||
// Sample blocks in a decoded XMA subframe
|
||||
#define XMA_SAMPLES_PER_SUBFRAME 128u
|
||||
|
||||
// Maximum encoded data that can be submitted to the XMA decoder at a time
|
||||
#define XMA_READBUFFER_MAX_PACKETS 4095u
|
||||
#define XMA_READBUFFER_MAX_BYTES (XMA_READBUFFER_MAX_PACKETS * XMA_BYTES_PER_PACKET)
|
||||
|
||||
// Maximum size allowed for the XMA decoder's output buffers
|
||||
#define XMA_WRITEBUFFER_MAX_BYTES (31u * 256u)
|
||||
|
||||
// Required byte alignment of the XMA decoder's output buffers
|
||||
#define XMA_WRITEBUFFER_BYTE_ALIGNMENT 256u
|
||||
|
||||
// Decode chunk sizes for the XMA_PLAYBACK_INIT.subframesToDecode field
|
||||
#define XMA_MIN_SUBFRAMES_TO_DECODE 1u
|
||||
#define XMA_MAX_SUBFRAMES_TO_DECODE 8u
|
||||
#define XMA_OPTIMAL_SUBFRAMES_TO_DECODE 4u
|
||||
|
||||
// LoopCount<255 means finite repetitions; LoopCount=255 means infinite looping
|
||||
#define XMA_MAX_LOOPCOUNT 254u
|
||||
#define XMA_INFINITE_LOOP 255u
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA format structures
|
||||
***************************************************************************/
|
||||
|
||||
// The currently recommended way to express format information for XMA2 files
|
||||
// is the XMA2WAVEFORMATEX structure. This structure is fully compliant with
|
||||
// the WAVEFORMATEX standard and contains all the information needed to parse
|
||||
// and manage XMA2 files in a compact way.
|
||||
|
||||
#define WAVE_FORMAT_XMA2 0x166
|
||||
|
||||
typedef struct XMA2WAVEFORMATEX
|
||||
{
|
||||
WAVEFORMATEX wfx;
|
||||
// Meaning of the WAVEFORMATEX fields here:
|
||||
// wFormatTag; // Audio format type; always WAVE_FORMAT_XMA2
|
||||
// nChannels; // Channel count of the decoded audio
|
||||
// nSamplesPerSec; // Sample rate of the decoded audio
|
||||
// nAvgBytesPerSec; // Used internally by the XMA encoder
|
||||
// nBlockAlign; // Decoded sample size; channels * wBitsPerSample / 8
|
||||
// wBitsPerSample; // Bits per decoded mono sample; always 16 for XMA
|
||||
// cbSize; // Size in bytes of the rest of this structure (34)
|
||||
|
||||
WORD NumStreams; // Number of audio streams (1 or 2 channels each)
|
||||
DWORD ChannelMask; // Spatial positions of the channels in this file,
|
||||
// stored as SPEAKER_xxx values (see audiodefs.h)
|
||||
DWORD SamplesEncoded; // Total number of PCM samples the file decodes to
|
||||
DWORD BytesPerBlock; // XMA block size (but the last one may be shorter)
|
||||
DWORD PlayBegin; // First valid sample in the decoded audio
|
||||
DWORD PlayLength; // Length of the valid part of the decoded audio
|
||||
DWORD LoopBegin; // Beginning of the loop region in decoded sample terms
|
||||
DWORD LoopLength; // Length of the loop region in decoded sample terms
|
||||
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
|
||||
BYTE EncoderVersion; // Version of XMA encoder that generated the file
|
||||
WORD BlockCount; // XMA blocks in file (and entries in its seek table)
|
||||
} XMA2WAVEFORMATEX, *PXMA2WAVEFORMATEX;
|
||||
|
||||
|
||||
// The legacy XMA format structures are described here for reference, but they
|
||||
// should not be used in new content. XMAWAVEFORMAT was the structure used in
|
||||
// XMA version 1 files. XMA2WAVEFORMAT was used in early XMA2 files; it is not
|
||||
// placed in the usual 'fmt' RIFF chunk but in its own 'XMA2' chunk.
|
||||
|
||||
#ifndef WAVE_FORMAT_XMA
|
||||
#define WAVE_FORMAT_XMA 0x0165
|
||||
|
||||
// Values used in the ChannelMask fields below. Similar to the SPEAKER_xxx
|
||||
// values defined in audiodefs.h, but modified to fit in a single byte.
|
||||
#ifndef XMA_SPEAKER_LEFT
|
||||
#define XMA_SPEAKER_LEFT 0x01
|
||||
#define XMA_SPEAKER_RIGHT 0x02
|
||||
#define XMA_SPEAKER_CENTER 0x04
|
||||
#define XMA_SPEAKER_LFE 0x08
|
||||
#define XMA_SPEAKER_LEFT_SURROUND 0x10
|
||||
#define XMA_SPEAKER_RIGHT_SURROUND 0x20
|
||||
#define XMA_SPEAKER_LEFT_BACK 0x40
|
||||
#define XMA_SPEAKER_RIGHT_BACK 0x80
|
||||
#endif
|
||||
|
||||
|
||||
// Used in XMAWAVEFORMAT for per-stream data
|
||||
typedef struct XMASTREAMFORMAT
|
||||
{
|
||||
DWORD PsuedoBytesPerSec; // Used by the XMA encoder (typo preserved for legacy reasons)
|
||||
DWORD SampleRate; // The stream's decoded sample rate (in XMA2 files,
|
||||
// this is the same for all streams in the file).
|
||||
DWORD LoopStart; // Bit offset of the frame containing the loop start
|
||||
// point, relative to the beginning of the stream.
|
||||
DWORD LoopEnd; // Bit offset of the frame containing the loop end.
|
||||
BYTE SubframeData; // Two 4-bit numbers specifying the exact location of
|
||||
// the loop points within the frames that contain them.
|
||||
// SubframeEnd: Subframe of the loop end frame where
|
||||
// the loop ends. Ranges from 0 to 3.
|
||||
// SubframeSkip: Subframes to skip in the start frame to
|
||||
// reach the loop. Ranges from 0 to 4.
|
||||
BYTE Channels; // Number of channels in the stream (1 or 2)
|
||||
WORD ChannelMask; // Spatial positions of the channels in the stream
|
||||
} XMASTREAMFORMAT;
|
||||
|
||||
// Legacy XMA1 format structure
|
||||
typedef struct XMAWAVEFORMAT
|
||||
{
|
||||
WORD FormatTag; // Audio format type (always WAVE_FORMAT_XMA)
|
||||
WORD BitsPerSample; // Bit depth (currently required to be 16)
|
||||
WORD EncodeOptions; // Options for XMA encoder/decoder
|
||||
WORD LargestSkip; // Largest skip used in interleaving streams
|
||||
WORD NumStreams; // Number of interleaved audio streams
|
||||
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
|
||||
BYTE Version; // XMA encoder version that generated the file.
|
||||
// Always 3 or higher for XMA2 files.
|
||||
XMASTREAMFORMAT XmaStreams[1]; // Per-stream format information; the actual
|
||||
// array length is in the NumStreams field.
|
||||
} XMAWAVEFORMAT;
|
||||
|
||||
|
||||
// Used in XMA2WAVEFORMAT for per-stream data
|
||||
typedef struct XMA2STREAMFORMAT
|
||||
{
|
||||
BYTE Channels; // Number of channels in the stream (1 or 2)
|
||||
BYTE RESERVED; // Reserved for future use
|
||||
WORD ChannelMask; // Spatial positions of the channels in the stream
|
||||
} XMA2STREAMFORMAT;
|
||||
|
||||
// Legacy XMA2 format structure (big-endian byte ordering)
|
||||
typedef struct XMA2WAVEFORMAT
|
||||
{
|
||||
BYTE Version; // XMA encoder version that generated the file.
|
||||
// Always 3 or higher for XMA2 files.
|
||||
BYTE NumStreams; // Number of interleaved audio streams
|
||||
BYTE RESERVED; // Reserved for future use
|
||||
BYTE LoopCount; // Number of loop repetitions; 255 = infinite
|
||||
DWORD LoopBegin; // Loop begin point, in samples
|
||||
DWORD LoopEnd; // Loop end point, in samples
|
||||
DWORD SampleRate; // The file's decoded sample rate
|
||||
DWORD EncodeOptions; // Options for the XMA encoder/decoder
|
||||
DWORD PsuedoBytesPerSec; // Used internally by the XMA encoder
|
||||
DWORD BlockSizeInBytes; // Size in bytes of this file's XMA blocks (except
|
||||
// possibly the last one). Always a multiple of
|
||||
// 2Kb, since XMA blocks are arrays of 2Kb packets.
|
||||
DWORD SamplesEncoded; // Total number of PCM samples encoded in this file
|
||||
DWORD SamplesInSource; // Actual number of PCM samples in the source
|
||||
// material used to generate this file
|
||||
DWORD BlockCount; // Number of XMA blocks in this file (and hence
|
||||
// also the number of entries in its seek table)
|
||||
XMA2STREAMFORMAT Streams[1]; // Per-stream format information; the actual
|
||||
// array length is in the NumStreams field.
|
||||
} XMA2WAVEFORMAT;
|
||||
|
||||
#endif // #ifndef WAVE_FORMAT_XMA
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA packet structure (in big-endian form)
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct XMA2PACKET
|
||||
{
|
||||
int FrameCount : 6; // Number of XMA frames that begin in this packet
|
||||
int FrameOffsetInBits : 15; // Bit of XmaData where the first complete frame begins
|
||||
int PacketMetaData : 3; // Metadata stored in the packet (always 1 for XMA2)
|
||||
int PacketSkipCount : 8; // How many packets belonging to other streams must be
|
||||
// skipped to find the next packet belonging to this one
|
||||
BYTE XmaData[XMA_BYTES_PER_PACKET - sizeof(DWORD)]; // XMA encoded data
|
||||
} XMA2PACKET;
|
||||
|
||||
// E.g. if the first DWORD of a packet is 0x30107902:
|
||||
//
|
||||
// 001100 000001000001111 001 00000010
|
||||
// | | | |____ Skip 2 packets to find the next one for this stream
|
||||
// | | |___________ XMA2 signature (always 001)
|
||||
// | |_____________________ First frame starts 527 bits into packet
|
||||
// |________________________________ Packet contains 12 frames
|
||||
|
||||
|
||||
// Helper functions to extract the fields above from an XMA packet. (Note that
|
||||
// the bitfields cannot be read directly on little-endian architectures such as
|
||||
// the Intel x86, as they are laid out in big-endian form.)
|
||||
|
||||
__inline DWORD GetXmaPacketFrameCount(__in_bcount(1) const BYTE* pPacket)
|
||||
{
|
||||
return (DWORD)(pPacket[0] >> 2);
|
||||
}
|
||||
|
||||
__inline DWORD GetXmaPacketFirstFrameOffsetInBits(__in_bcount(3) const BYTE* pPacket)
|
||||
{
|
||||
return ((DWORD)(pPacket[0] & 0x3) << 13) |
|
||||
((DWORD)(pPacket[1]) << 5) |
|
||||
((DWORD)(pPacket[2]) >> 3);
|
||||
}
|
||||
|
||||
__inline DWORD GetXmaPacketMetadata(__in_bcount(3) const BYTE* pPacket)
|
||||
{
|
||||
return (DWORD)(pPacket[2] & 0x7);
|
||||
}
|
||||
|
||||
__inline DWORD GetXmaPacketSkipCount(__in_bcount(4) const BYTE* pPacket)
|
||||
{
|
||||
return (DWORD)(pPacket[3]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA frame structure
|
||||
***************************************************************************/
|
||||
|
||||
// There is no way to represent the XMA frame as a C struct, since it is a
|
||||
// variable-sized string of bits that need not be stored at a byte-aligned
|
||||
// position in memory. This is the layout:
|
||||
//
|
||||
// XMAFRAME
|
||||
// {
|
||||
// LengthInBits: A 15-bit number representing the length of this frame.
|
||||
// XmaData: Encoded XMA data; its size in bits is (LengthInBits - 15).
|
||||
// }
|
||||
|
||||
// Size in bits of the frame's initial LengthInBits field
|
||||
#define XMA_BITS_IN_FRAME_LENGTH_FIELD 15
|
||||
|
||||
// Special LengthInBits value that marks an invalid final frame
|
||||
#define XMA_FINAL_FRAME_MARKER 0x7FFF
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* XMA helper functions
|
||||
***************************************************************************/
|
||||
|
||||
// We define a local ASSERT macro to equal the global one if it exists.
|
||||
// You can define XMA2DEFS_ASSERT in advance to override this default.
|
||||
#ifndef XMA2DEFS_ASSERT
|
||||
#ifdef ASSERT
|
||||
#define XMA2DEFS_ASSERT ASSERT
|
||||
#else
|
||||
#define XMA2DEFS_ASSERT(a) /* No-op by default */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// GetXmaBlockContainingSample: Use a given seek table to find the XMA block
|
||||
// containing a given decoded sample. Note that the seek table entries in an
|
||||
// XMA file are stored in big-endian form and may need to be converted prior
|
||||
// to calling this function.
|
||||
|
||||
__inline HRESULT GetXmaBlockContainingSample
|
||||
(
|
||||
DWORD nBlockCount, // Blocks in the file (= seek table entries)
|
||||
__in_ecount(nBlockCount) const DWORD* pSeekTable, // Pointer to the seek table data
|
||||
DWORD nDesiredSample, // Decoded sample to locate
|
||||
__out DWORD* pnBlockContainingSample, // Index of the block containing the sample
|
||||
__out DWORD* pnSampleOffsetWithinBlock // Position of the sample in this block
|
||||
)
|
||||
{
|
||||
DWORD nPreviousTotalSamples = 0;
|
||||
DWORD nBlock;
|
||||
DWORD nTotalSamplesSoFar;
|
||||
|
||||
XMA2DEFS_ASSERT(pSeekTable);
|
||||
XMA2DEFS_ASSERT(pnBlockContainingSample);
|
||||
XMA2DEFS_ASSERT(pnSampleOffsetWithinBlock);
|
||||
|
||||
for (nBlock = 0; nBlock < nBlockCount; ++nBlock)
|
||||
{
|
||||
nTotalSamplesSoFar = pSeekTable[nBlock];
|
||||
if (nTotalSamplesSoFar > nDesiredSample)
|
||||
{
|
||||
*pnBlockContainingSample = nBlock;
|
||||
*pnSampleOffsetWithinBlock = nDesiredSample - nPreviousTotalSamples;
|
||||
return S_OK;
|
||||
}
|
||||
nPreviousTotalSamples = nTotalSamplesSoFar;
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
// GetXmaFrameLengthInBits: Reads a given frame's LengthInBits field.
|
||||
|
||||
__inline DWORD GetXmaFrameLengthInBits
|
||||
(
|
||||
__in_bcount(nBitPosition / 8 + 3)
|
||||
__in const BYTE* pPacket, // Pointer to XMA packet[s] containing the frame
|
||||
DWORD nBitPosition // Bit offset of the frame within this packet
|
||||
)
|
||||
{
|
||||
DWORD nRegion;
|
||||
DWORD nBytePosition = nBitPosition / 8;
|
||||
DWORD nBitOffset = nBitPosition % 8;
|
||||
|
||||
if (nBitOffset < 2) // Only need to read 2 bytes (and might not be safe to read more)
|
||||
{
|
||||
nRegion = (DWORD)(pPacket[nBytePosition+0]) << 8 |
|
||||
(DWORD)(pPacket[nBytePosition+1]);
|
||||
return (nRegion >> (1 - nBitOffset)) & 0x7FFF; // Last 15 bits
|
||||
}
|
||||
else // Need to read 3 bytes
|
||||
{
|
||||
nRegion = (DWORD)(pPacket[nBytePosition+0]) << 16 |
|
||||
(DWORD)(pPacket[nBytePosition+1]) << 8 |
|
||||
(DWORD)(pPacket[nBytePosition+2]);
|
||||
return (nRegion >> (9 - nBitOffset)) & 0x7FFF; // Last 15 bits
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GetXmaFrameBitPosition: Calculates the bit offset of a given frame within
|
||||
// an XMA block or set of blocks. Returns 0 on failure.
|
||||
|
||||
__inline DWORD GetXmaFrameBitPosition
|
||||
(
|
||||
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
|
||||
DWORD nXmaDataBytes, // Size of pXmaData in bytes
|
||||
DWORD nStreamIndex, // Stream within which to seek
|
||||
DWORD nDesiredFrame // Frame sought
|
||||
)
|
||||
{
|
||||
const BYTE* pCurrentPacket;
|
||||
DWORD nPacketsExamined = 0;
|
||||
DWORD nFrameCountSoFar = 0;
|
||||
DWORD nFramesToSkip;
|
||||
DWORD nFrameBitOffset;
|
||||
|
||||
XMA2DEFS_ASSERT(pXmaData);
|
||||
XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
|
||||
|
||||
// Get the first XMA packet belonging to the desired stream, relying on the
|
||||
// fact that the first packets for each stream are in consecutive order at
|
||||
// the beginning of an XMA block.
|
||||
|
||||
pCurrentPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
|
||||
for (;;)
|
||||
{
|
||||
// If we have exceeded the size of the XMA data, return failure
|
||||
if (pCurrentPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If the current packet contains the frame we are looking for...
|
||||
if (nFrameCountSoFar + GetXmaPacketFrameCount(pCurrentPacket) > nDesiredFrame)
|
||||
{
|
||||
// See how many frames in this packet we need to skip to get to it
|
||||
XMA2DEFS_ASSERT(nDesiredFrame >= nFrameCountSoFar);
|
||||
nFramesToSkip = nDesiredFrame - nFrameCountSoFar;
|
||||
|
||||
// Get the bit offset of the first frame in this packet
|
||||
nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pCurrentPacket);
|
||||
|
||||
// Advance nFrameBitOffset to the frame of interest
|
||||
while (nFramesToSkip--)
|
||||
{
|
||||
nFrameBitOffset += GetXmaFrameLengthInBits(pCurrentPacket, nFrameBitOffset);
|
||||
}
|
||||
|
||||
// The bit offset to return is the number of bits from pXmaData to
|
||||
// pCurrentPacket plus the bit offset of the frame of interest
|
||||
return (DWORD)(pCurrentPacket - pXmaData) * 8 + nFrameBitOffset;
|
||||
}
|
||||
|
||||
// If we haven't found the right packet yet, advance our counters
|
||||
++nPacketsExamined;
|
||||
nFrameCountSoFar += GetXmaPacketFrameCount(pCurrentPacket);
|
||||
|
||||
// And skip to the next packet belonging to the same stream
|
||||
pCurrentPacket += XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pCurrentPacket) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GetLastXmaFrameBitPosition: Calculates the bit offset of the last complete
|
||||
// frame in an XMA block or set of blocks.
|
||||
|
||||
__inline DWORD GetLastXmaFrameBitPosition
|
||||
(
|
||||
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
|
||||
DWORD nXmaDataBytes, // Size of pXmaData in bytes
|
||||
DWORD nStreamIndex // Stream within which to seek
|
||||
)
|
||||
{
|
||||
const BYTE* pLastPacket;
|
||||
DWORD nBytesToNextPacket;
|
||||
DWORD nFrameBitOffset;
|
||||
DWORD nFramesInLastPacket;
|
||||
|
||||
XMA2DEFS_ASSERT(pXmaData);
|
||||
XMA2DEFS_ASSERT(nXmaDataBytes % XMA_BYTES_PER_PACKET == 0);
|
||||
XMA2DEFS_ASSERT(nXmaDataBytes >= XMA_BYTES_PER_PACKET * (nStreamIndex + 1));
|
||||
|
||||
// Get the first XMA packet belonging to the desired stream, relying on the
|
||||
// fact that the first packets for each stream are in consecutive order at
|
||||
// the beginning of an XMA block.
|
||||
pLastPacket = pXmaData + nStreamIndex * XMA_BYTES_PER_PACKET;
|
||||
|
||||
// Search for the last packet belonging to the desired stream
|
||||
for (;;)
|
||||
{
|
||||
nBytesToNextPacket = XMA_BYTES_PER_PACKET * (GetXmaPacketSkipCount(pLastPacket) + 1);
|
||||
XMA2DEFS_ASSERT(nBytesToNextPacket);
|
||||
if (pLastPacket + nBytesToNextPacket + XMA_BYTES_PER_PACKET > pXmaData + nXmaDataBytes)
|
||||
{
|
||||
break; // The next packet would extend beyond the end of pXmaData
|
||||
}
|
||||
pLastPacket += nBytesToNextPacket;
|
||||
}
|
||||
|
||||
// The last packet can sometimes have no seekable frames, in which case we
|
||||
// have to use the previous one
|
||||
if (GetXmaPacketFrameCount(pLastPacket) == 0)
|
||||
{
|
||||
pLastPacket -= nBytesToNextPacket;
|
||||
}
|
||||
|
||||
// Found the last packet. Get the bit offset of its first frame.
|
||||
nFrameBitOffset = XMA_PACKET_HEADER_BITS + GetXmaPacketFirstFrameOffsetInBits(pLastPacket);
|
||||
|
||||
// Traverse frames until we reach the last one
|
||||
nFramesInLastPacket = GetXmaPacketFrameCount(pLastPacket);
|
||||
while (--nFramesInLastPacket)
|
||||
{
|
||||
nFrameBitOffset += GetXmaFrameLengthInBits(pLastPacket, nFrameBitOffset);
|
||||
}
|
||||
|
||||
// The bit offset to return is the number of bits from pXmaData to
|
||||
// pLastPacket plus the offset of the last frame in this packet.
|
||||
return (DWORD)(pLastPacket - pXmaData) * 8 + nFrameBitOffset;
|
||||
}
|
||||
|
||||
|
||||
// GetXmaDecodePositionForSample: Obtains the information needed to make the
|
||||
// decoder generate audio starting at a given sample position relative to the
|
||||
// beginning of the given XMA block: the bit offset of the appropriate frame,
|
||||
// and the right subframe within that frame. This data can be passed directly
|
||||
// to the XMAPlaybackSetDecodePosition function.
|
||||
|
||||
__inline HRESULT GetXmaDecodePositionForSample
|
||||
(
|
||||
__in_bcount(nXmaDataBytes) const BYTE* pXmaData, // Pointer to XMA block[s]
|
||||
DWORD nXmaDataBytes, // Size of pXmaData in bytes
|
||||
DWORD nStreamIndex, // Stream within which to seek
|
||||
DWORD nDesiredSample, // Sample sought
|
||||
__out DWORD* pnBitOffset, // Returns the bit offset within pXmaData of
|
||||
// the frame containing the sample sought
|
||||
__out DWORD* pnSubFrame // Returns the subframe containing the sample
|
||||
)
|
||||
{
|
||||
DWORD nDesiredFrame = nDesiredSample / XMA_SAMPLES_PER_FRAME;
|
||||
DWORD nSubFrame = (nDesiredSample % XMA_SAMPLES_PER_FRAME) / XMA_SAMPLES_PER_SUBFRAME;
|
||||
DWORD nBitOffset = GetXmaFrameBitPosition(pXmaData, nXmaDataBytes, nStreamIndex, nDesiredFrame);
|
||||
|
||||
XMA2DEFS_ASSERT(pnBitOffset);
|
||||
XMA2DEFS_ASSERT(pnSubFrame);
|
||||
|
||||
if (nBitOffset)
|
||||
{
|
||||
*pnBitOffset = nBitOffset;
|
||||
*pnSubFrame = nSubFrame;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// GetXmaSampleRate: Obtains the legal XMA sample rate (24, 32, 44.1 or 48Khz)
|
||||
// corresponding to a generic sample rate.
|
||||
|
||||
__inline DWORD GetXmaSampleRate(DWORD dwGeneralRate)
|
||||
{
|
||||
DWORD dwXmaRate = 48000; // Default XMA rate for all rates above 44100Hz
|
||||
|
||||
if (dwGeneralRate <= 24000) dwXmaRate = 24000;
|
||||
else if (dwGeneralRate <= 32000) dwXmaRate = 32000;
|
||||
else if (dwGeneralRate <= 44100) dwXmaRate = 44100;
|
||||
|
||||
return dwXmaRate;
|
||||
}
|
||||
|
||||
|
||||
// Functions to convert between WAVEFORMATEXTENSIBLE channel masks (combinations
|
||||
// of the SPEAKER_xxx flags defined in audiodefs.h) and XMA channel masks (which
|
||||
// are limited to eight possible speaker positions: left, right, center, low
|
||||
// frequency, side left, side right, back left and back right).
|
||||
|
||||
__inline DWORD GetStandardChannelMaskFromXmaMask(BYTE bXmaMask)
|
||||
{
|
||||
DWORD dwStandardMask = 0;
|
||||
|
||||
if (bXmaMask & XMA_SPEAKER_LEFT) dwStandardMask |= SPEAKER_FRONT_LEFT;
|
||||
if (bXmaMask & XMA_SPEAKER_RIGHT) dwStandardMask |= SPEAKER_FRONT_RIGHT;
|
||||
if (bXmaMask & XMA_SPEAKER_CENTER) dwStandardMask |= SPEAKER_FRONT_CENTER;
|
||||
if (bXmaMask & XMA_SPEAKER_LFE) dwStandardMask |= SPEAKER_LOW_FREQUENCY;
|
||||
if (bXmaMask & XMA_SPEAKER_LEFT_SURROUND) dwStandardMask |= SPEAKER_SIDE_LEFT;
|
||||
if (bXmaMask & XMA_SPEAKER_RIGHT_SURROUND) dwStandardMask |= SPEAKER_SIDE_RIGHT;
|
||||
if (bXmaMask & XMA_SPEAKER_LEFT_BACK) dwStandardMask |= SPEAKER_BACK_LEFT;
|
||||
if (bXmaMask & XMA_SPEAKER_RIGHT_BACK) dwStandardMask |= SPEAKER_BACK_RIGHT;
|
||||
|
||||
return dwStandardMask;
|
||||
}
|
||||
|
||||
__inline BYTE GetXmaChannelMaskFromStandardMask(DWORD dwStandardMask)
|
||||
{
|
||||
BYTE bXmaMask = 0;
|
||||
|
||||
if (dwStandardMask & SPEAKER_FRONT_LEFT) bXmaMask |= XMA_SPEAKER_LEFT;
|
||||
if (dwStandardMask & SPEAKER_FRONT_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT;
|
||||
if (dwStandardMask & SPEAKER_FRONT_CENTER) bXmaMask |= XMA_SPEAKER_CENTER;
|
||||
if (dwStandardMask & SPEAKER_LOW_FREQUENCY) bXmaMask |= XMA_SPEAKER_LFE;
|
||||
if (dwStandardMask & SPEAKER_SIDE_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_SURROUND;
|
||||
if (dwStandardMask & SPEAKER_SIDE_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_SURROUND;
|
||||
if (dwStandardMask & SPEAKER_BACK_LEFT) bXmaMask |= XMA_SPEAKER_LEFT_BACK;
|
||||
if (dwStandardMask & SPEAKER_BACK_RIGHT) bXmaMask |= XMA_SPEAKER_RIGHT_BACK;
|
||||
|
||||
return bXmaMask;
|
||||
}
|
||||
|
||||
|
||||
// LocalizeXma2Format: Modifies a XMA2WAVEFORMATEX structure in place to comply
|
||||
// with the current platform's byte-ordering rules (little- or big-endian).
|
||||
|
||||
__inline HRESULT LocalizeXma2Format(__inout XMA2WAVEFORMATEX* pXma2Format)
|
||||
{
|
||||
#define XMASWAP2BYTES(n) ((WORD)(((n) >> 8) | (((n) & 0xff) << 8)))
|
||||
#define XMASWAP4BYTES(n) ((DWORD)((n) >> 24 | (n) << 24 | ((n) & 0xff00) << 8 | ((n) & 0xff0000) >> 8))
|
||||
|
||||
if (pXma2Format->wfx.wFormatTag == WAVE_FORMAT_XMA2)
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
else if (XMASWAP2BYTES(pXma2Format->wfx.wFormatTag) == WAVE_FORMAT_XMA2)
|
||||
{
|
||||
pXma2Format->wfx.wFormatTag = XMASWAP2BYTES(pXma2Format->wfx.wFormatTag);
|
||||
pXma2Format->wfx.nChannels = XMASWAP2BYTES(pXma2Format->wfx.nChannels);
|
||||
pXma2Format->wfx.nSamplesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nSamplesPerSec);
|
||||
pXma2Format->wfx.nAvgBytesPerSec = XMASWAP4BYTES(pXma2Format->wfx.nAvgBytesPerSec);
|
||||
pXma2Format->wfx.nBlockAlign = XMASWAP2BYTES(pXma2Format->wfx.nBlockAlign);
|
||||
pXma2Format->wfx.wBitsPerSample = XMASWAP2BYTES(pXma2Format->wfx.wBitsPerSample);
|
||||
pXma2Format->wfx.cbSize = XMASWAP2BYTES(pXma2Format->wfx.cbSize);
|
||||
pXma2Format->NumStreams = XMASWAP2BYTES(pXma2Format->NumStreams);
|
||||
pXma2Format->ChannelMask = XMASWAP4BYTES(pXma2Format->ChannelMask);
|
||||
pXma2Format->SamplesEncoded = XMASWAP4BYTES(pXma2Format->SamplesEncoded);
|
||||
pXma2Format->BytesPerBlock = XMASWAP4BYTES(pXma2Format->BytesPerBlock);
|
||||
pXma2Format->PlayBegin = XMASWAP4BYTES(pXma2Format->PlayBegin);
|
||||
pXma2Format->PlayLength = XMASWAP4BYTES(pXma2Format->PlayLength);
|
||||
pXma2Format->LoopBegin = XMASWAP4BYTES(pXma2Format->LoopBegin);
|
||||
pXma2Format->LoopLength = XMASWAP4BYTES(pXma2Format->LoopLength);
|
||||
pXma2Format->BlockCount = XMASWAP2BYTES(pXma2Format->BlockCount);
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_FAIL; // Not a recognizable XMA2 format
|
||||
}
|
||||
|
||||
#undef XMASWAP2BYTES
|
||||
#undef XMASWAP4BYTES
|
||||
}
|
||||
|
||||
|
||||
#endif // #ifndef __XMA2DEFS_INCLUDED__
|
||||
Vendored
-1
Submodule 3rdparty/cereal deleted from 42a45b6e15
Vendored
-1
Submodule 3rdparty/ffmpeg deleted from 2f6023d14a
Vendored
-1
Submodule 3rdparty/libpng deleted from ea77a6fd49
Vendored
-3768
File diff suppressed because it is too large
Load Diff
Vendored
-2529
File diff suppressed because it is too large
Load Diff
Vendored
-204
@@ -1,204 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This file is automatically generated. Please do not edit it directly.
|
||||
//
|
||||
// File name: D2D1_2.h
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif // #ifdef _MSC_VER
|
||||
|
||||
#ifndef _D2D1_2_H_
|
||||
#define _D2D1_2_H_
|
||||
|
||||
#ifndef _D2D1_1_H_
|
||||
#include <d2d1_1.h>
|
||||
#endif // #ifndef _D2D1_1_H_
|
||||
#ifndef _D2D1_EFFECTS_1_
|
||||
#include <d2d1effects_1.h>
|
||||
#endif // #ifndef _D2D1_EFFECTS_1_
|
||||
|
||||
#include <winapifamily.h>
|
||||
|
||||
#pragma region Application Family
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
|
||||
#ifndef D2D_USE_C_DEFINITIONS
|
||||
|
||||
interface ID2D1Device1;
|
||||
#else
|
||||
|
||||
typedef interface ID2D1Device1 ID2D1Device1;
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the extent to which D2D will throttle work sent to the GPU.
|
||||
/// </summary>
|
||||
typedef enum D2D1_RENDERING_PRIORITY
|
||||
{
|
||||
D2D1_RENDERING_PRIORITY_NORMAL = 0,
|
||||
D2D1_RENDERING_PRIORITY_LOW = 1,
|
||||
D2D1_RENDERING_PRIORITY_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_RENDERING_PRIORITY;
|
||||
|
||||
|
||||
#ifndef D2D_USE_C_DEFINITIONS
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates a device- and transform-dependent representation of a filled or
|
||||
/// stroked geometry.
|
||||
/// </summary>
|
||||
interface DX_DECLARE_INTERFACE("a16907d7-bc02-4801-99e8-8cf7f485f774") ID2D1GeometryRealization : public ID2D1Resource
|
||||
{
|
||||
}; // interface ID2D1GeometryRealization
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enables creation and drawing of geometry realization objects.
|
||||
/// </summary>
|
||||
interface DX_DECLARE_INTERFACE("d37f57e4-6908-459f-a199-e72f24f79987") ID2D1DeviceContext1 : public ID2D1DeviceContext
|
||||
{
|
||||
|
||||
STDMETHOD(CreateFilledGeometryRealization)(
|
||||
_In_ ID2D1Geometry *geometry,
|
||||
FLOAT flatteningTolerance,
|
||||
_COM_Outptr_ ID2D1GeometryRealization **geometryRealization
|
||||
) PURE;
|
||||
|
||||
STDMETHOD(CreateStrokedGeometryRealization)(
|
||||
_In_ ID2D1Geometry *geometry,
|
||||
FLOAT flatteningTolerance,
|
||||
FLOAT strokeWidth,
|
||||
_In_opt_ ID2D1StrokeStyle *strokeStyle,
|
||||
_COM_Outptr_ ID2D1GeometryRealization **geometryRealization
|
||||
) PURE;
|
||||
|
||||
STDMETHOD_(void, DrawGeometryRealization)(
|
||||
_In_ ID2D1GeometryRealization *geometryRealization,
|
||||
_In_ ID2D1Brush *brush
|
||||
) PURE;
|
||||
}; // interface ID2D1DeviceContext1
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a resource domain whose objects and device contexts can be used
|
||||
/// together.
|
||||
/// </summary>
|
||||
interface DX_DECLARE_INTERFACE("d21768e1-23a4-4823-a14b-7c3eba85d658") ID2D1Device1 : public ID2D1Device
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the rendering priority currently set on the device.
|
||||
/// </summary>
|
||||
STDMETHOD_(D2D1_RENDERING_PRIORITY, GetRenderingPriority)(
|
||||
) PURE;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rendering priority of the device.
|
||||
/// </summary>
|
||||
STDMETHOD_(void, SetRenderingPriority)(
|
||||
D2D1_RENDERING_PRIORITY renderingPriority
|
||||
) PURE;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new device context with no initially assigned target.
|
||||
/// </summary>
|
||||
STDMETHOD(CreateDeviceContext)(
|
||||
D2D1_DEVICE_CONTEXT_OPTIONS options,
|
||||
_COM_Outptr_ ID2D1DeviceContext1 **deviceContext1
|
||||
) PURE;
|
||||
|
||||
using ID2D1Device::CreateDeviceContext;
|
||||
}; // interface ID2D1Device1
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates Direct2D resources. This interface also enables the creation of
|
||||
/// ID2D1Device1 objects.
|
||||
/// </summary>
|
||||
interface DX_DECLARE_INTERFACE("94f81a73-9212-4376-9c58-b16a3a0d3992") ID2D1Factory2 : public ID2D1Factory1
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This creates a new Direct2D device from the given IDXGIDevice.
|
||||
/// </summary>
|
||||
STDMETHOD(CreateDevice)(
|
||||
_In_ IDXGIDevice *dxgiDevice,
|
||||
_COM_Outptr_ ID2D1Device1 **d2dDevice1
|
||||
) PURE;
|
||||
|
||||
using ID2D1Factory1::CreateDevice;
|
||||
}; // interface ID2D1Factory2
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This interface performs all the same functions as the existing ID2D1CommandSink
|
||||
/// interface. It also enables access to the new primitive blend modes, MIN and ADD,
|
||||
/// through its SetPrimitiveBlend1 method.
|
||||
/// </summary>
|
||||
interface DX_DECLARE_INTERFACE("9eb767fd-4269-4467-b8c2-eb30cb305743") ID2D1CommandSink1 : public ID2D1CommandSink
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This method is called if primitiveBlend value was added after Windows 8.
|
||||
/// SetPrimitiveBlend method is used for Win8 values (_SOURCE_OVER and _COPY).
|
||||
/// </summary>
|
||||
STDMETHOD(SetPrimitiveBlend1)(
|
||||
D2D1_PRIMITIVE_BLEND primitiveBlend
|
||||
) PURE;
|
||||
}; // interface ID2D1CommandSink1
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
EXTERN_C CONST IID IID_ID2D1GeometryRealization;
|
||||
EXTERN_C CONST IID IID_ID2D1DeviceContext1;
|
||||
EXTERN_C CONST IID IID_ID2D1Device1;
|
||||
EXTERN_C CONST IID IID_ID2D1Factory2;
|
||||
EXTERN_C CONST IID IID_ID2D1CommandSink1;
|
||||
|
||||
|
||||
#ifdef D2D_USE_C_DEFINITIONS
|
||||
|
||||
|
||||
typedef interface ID2D1GeometryRealization ID2D1GeometryRealization;
|
||||
|
||||
typedef interface ID2D1DeviceContext1 ID2D1DeviceContext1;
|
||||
|
||||
typedef interface ID2D1Device1 ID2D1Device1;
|
||||
|
||||
typedef interface ID2D1Factory2 ID2D1Factory2;
|
||||
|
||||
typedef interface ID2D1CommandSink1 ID2D1CommandSink1;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#if NTDDI_VERSION >= NTDDI_WINBLUE
|
||||
FLOAT WINAPI
|
||||
D2D1ComputeMaximumScaleFactor(
|
||||
_In_ CONST D2D1_MATRIX_3X2_F *matrix
|
||||
);
|
||||
#endif // #if NTDDI_VERSION >= NTDDI_WINBLUE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) */
|
||||
#pragma endregion
|
||||
#include <d2d1_2helper.h>
|
||||
#endif // #ifndef _D2D1_2_H_
|
||||
Vendored
-1535
File diff suppressed because it is too large
Load Diff
-1906
File diff suppressed because it is too large
Load Diff
-82
@@ -1,82 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This file is automatically generated. Please do not edit it directly.
|
||||
//
|
||||
// File name: D2D1Effects_1.h
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif // #ifdef _MSC_VER
|
||||
|
||||
#ifndef _D2D1_EFFECTS_1_
|
||||
#define _D2D1_EFFECTS_1_
|
||||
|
||||
#ifndef _D2D1_EFFECTS_
|
||||
#include <d2d1effects.h>
|
||||
#endif // #ifndef _D2D1_EFFECTS_
|
||||
|
||||
|
||||
#include <winapifamily.h>
|
||||
|
||||
#pragma region Application Family
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
|
||||
// Built in effect CLSIDs
|
||||
DEFINE_GUID(CLSID_D2D1YCbCr, 0x99503cc1, 0x66c7, 0x45c9, 0xa8, 0x75, 0x8a, 0xd8, 0xa7, 0x91, 0x44, 0x01);
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the YCbCr effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_YCBCR_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "ChromaSubsampling"
|
||||
/// Property Type: D2D1_YCBCR_CHROMA_SUBSAMPLING
|
||||
/// </summary>
|
||||
D2D1_YCBCR_PROP_CHROMA_SUBSAMPLING = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "TransformMatrix"
|
||||
/// Property Type: D2D1_MATRIX_3X2_F
|
||||
/// </summary>
|
||||
D2D1_YCBCR_PROP_TRANSFORM_MATRIX = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "InterpolationMode"
|
||||
/// Property Type: D2D1_YCBCR_INTERPOLATION_MODE
|
||||
/// </summary>
|
||||
D2D1_YCBCR_PROP_INTERPOLATION_MODE = 2,
|
||||
D2D1_YCBCR_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_YCBCR_PROP;
|
||||
|
||||
typedef enum D2D1_YCBCR_CHROMA_SUBSAMPLING
|
||||
{
|
||||
D2D1_YCBCR_CHROMA_SUBSAMPLING_AUTO = 0,
|
||||
D2D1_YCBCR_CHROMA_SUBSAMPLING_420 = 1,
|
||||
D2D1_YCBCR_CHROMA_SUBSAMPLING_422 = 2,
|
||||
D2D1_YCBCR_CHROMA_SUBSAMPLING_444 = 3,
|
||||
D2D1_YCBCR_CHROMA_SUBSAMPLING_440 = 4,
|
||||
D2D1_YCBCR_CHROMA_SUBSAMPLING_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_YCBCR_CHROMA_SUBSAMPLING;
|
||||
|
||||
typedef enum D2D1_YCBCR_INTERPOLATION_MODE
|
||||
{
|
||||
D2D1_YCBCR_INTERPOLATION_MODE_NEAREST_NEIGHBOR = 0,
|
||||
D2D1_YCBCR_INTERPOLATION_MODE_LINEAR = 1,
|
||||
D2D1_YCBCR_INTERPOLATION_MODE_CUBIC = 2,
|
||||
D2D1_YCBCR_INTERPOLATION_MODE_MULTI_SAMPLE_LINEAR = 3,
|
||||
D2D1_YCBCR_INTERPOLATION_MODE_ANISOTROPIC = 4,
|
||||
D2D1_YCBCR_INTERPOLATION_MODE_HIGH_QUALITY_CUBIC = 5,
|
||||
D2D1_YCBCR_INTERPOLATION_MODE_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_YCBCR_INTERPOLATION_MODE;
|
||||
|
||||
|
||||
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) */
|
||||
#pragma endregion
|
||||
|
||||
#endif // #ifndef _D2D1_EFFECTS_1_
|
||||
-535
@@ -1,535 +0,0 @@
|
||||
//---------------------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// This file is automatically generated. Please do not edit it directly.
|
||||
//
|
||||
// File name: D2D1Effects_2.h
|
||||
//---------------------------------------------------------------------------
|
||||
#ifdef _MSC_VER
|
||||
#pragma once
|
||||
#endif // #ifdef _MSC_VER
|
||||
|
||||
#ifndef _D2D1_EFFECTS_2_
|
||||
#define _D2D1_EFFECTS_2_
|
||||
|
||||
#ifndef _D2D1_EFFECTS_1_
|
||||
#include <d2d1effects_1.h>
|
||||
#endif // #ifndef _D2D1_EFFECTS_1_
|
||||
|
||||
|
||||
#include <winapifamily.h>
|
||||
|
||||
#pragma region Application Family
|
||||
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
|
||||
|
||||
// Built in effect CLSIDs
|
||||
DEFINE_GUID(CLSID_D2D1Contrast, 0xb648a78a, 0x0ed5, 0x4f80, 0xa9, 0x4a, 0x8e, 0x82, 0x5a, 0xca, 0x6b, 0x77);
|
||||
DEFINE_GUID(CLSID_D2D1RgbToHue, 0x23f3e5ec, 0x91e8, 0x4d3d, 0xad, 0x0a, 0xaf, 0xad, 0xc1, 0x00, 0x4a, 0xa1);
|
||||
DEFINE_GUID(CLSID_D2D1HueToRgb, 0x7b78a6bd, 0x0141, 0x4def, 0x8a, 0x52, 0x63, 0x56, 0xee, 0x0c, 0xbd, 0xd5);
|
||||
DEFINE_GUID(CLSID_D2D1ChromaKey, 0x74C01F5B, 0x2A0D, 0x408C, 0x88, 0xE2, 0xC7, 0xA3, 0xC7, 0x19, 0x77, 0x42);
|
||||
DEFINE_GUID(CLSID_D2D1Emboss, 0xb1c5eb2b, 0x0348, 0x43f0, 0x81, 0x07, 0x49, 0x57, 0xca, 0xcb, 0xa2, 0xae);
|
||||
DEFINE_GUID(CLSID_D2D1Exposure, 0xb56c8cfa, 0xf634, 0x41ee, 0xbe, 0xe0, 0xff, 0xa6, 0x17, 0x10, 0x60, 0x04);
|
||||
DEFINE_GUID(CLSID_D2D1Grayscale, 0x36DDE0EB, 0x3725, 0x42E0, 0x83, 0x6D, 0x52, 0xFB, 0x20, 0xAE, 0xE6, 0x44);
|
||||
DEFINE_GUID(CLSID_D2D1Invert, 0xe0c3784d, 0xcb39, 0x4e84, 0xb6, 0xfd, 0x6b, 0x72, 0xf0, 0x81, 0x02, 0x63);
|
||||
DEFINE_GUID(CLSID_D2D1Posterize, 0x2188945e, 0x33a3, 0x4366, 0xb7, 0xbc, 0x08, 0x6b, 0xd0, 0x2d, 0x08, 0x84);
|
||||
DEFINE_GUID(CLSID_D2D1Sepia, 0x3a1af410, 0x5f1d, 0x4dbe, 0x84, 0xdf, 0x91, 0x5d, 0xa7, 0x9b, 0x71, 0x53);
|
||||
DEFINE_GUID(CLSID_D2D1Sharpen, 0xC9B887CB, 0xC5FF, 0x4DC5, 0x97, 0x79, 0x27, 0x3D, 0xCF, 0x41, 0x7C, 0x7D);
|
||||
DEFINE_GUID(CLSID_D2D1Straighten, 0x4da47b12, 0x79a3, 0x4fb0, 0x82, 0x37, 0xbb, 0xc3, 0xb2, 0xa4, 0xde, 0x08);
|
||||
DEFINE_GUID(CLSID_D2D1TemperatureTint, 0x89176087, 0x8AF9, 0x4A08, 0xAE, 0xB1, 0x89, 0x5F, 0x38, 0xDB, 0x17, 0x66);
|
||||
DEFINE_GUID(CLSID_D2D1Vignette, 0xc00c40be, 0x5e67, 0x4ca3, 0x95, 0xb4, 0xf4, 0xb0, 0x2c, 0x11, 0x51, 0x35);
|
||||
DEFINE_GUID(CLSID_D2D1EdgeDetection, 0xEFF583CA, 0xCB07, 0x4AA9, 0xAC, 0x5D, 0x2C, 0xC4, 0x4C, 0x76, 0x46, 0x0F);
|
||||
DEFINE_GUID(CLSID_D2D1HighlightsShadows, 0xCADC8384, 0x323F, 0x4C7E, 0xA3, 0x61, 0x2E, 0x2B, 0x24, 0xDF, 0x6E, 0xE4);
|
||||
DEFINE_GUID(CLSID_D2D1LookupTable3D, 0x349E0EDA, 0x0088, 0x4A79, 0x9C, 0xA3, 0xC7, 0xE3, 0x00, 0x20, 0x20, 0x20);
|
||||
|
||||
#if NTDDI_VERSION >= NTDDI_WIN10_RS1
|
||||
|
||||
DEFINE_GUID(CLSID_D2D1Opacity, 0x811d79a4, 0xde28, 0x4454, 0x80, 0x94, 0xc6, 0x46, 0x85, 0xf8, 0xbd, 0x4c);
|
||||
DEFINE_GUID(CLSID_D2D1AlphaMask, 0xc80ecff0, 0x3fd5, 0x4f05, 0x83, 0x28, 0xc5, 0xd1, 0x72, 0x4b, 0x4f, 0x0a);
|
||||
DEFINE_GUID(CLSID_D2D1CrossFade, 0x12f575e8, 0x4db1, 0x485f, 0x9a, 0x84, 0x03, 0xa0, 0x7d, 0xd3, 0x82, 0x9f);
|
||||
DEFINE_GUID(CLSID_D2D1Tint, 0x36312b17, 0xf7dd, 0x4014, 0x91, 0x5d, 0xff, 0xca, 0x76, 0x8c, 0xf2, 0x11);
|
||||
|
||||
#endif // #if NTDDI_VERSION >= NTDDI_WIN10_RS1
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Contrast effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_CONTRAST_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Contrast"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_CONTRAST_PROP_CONTRAST = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "ClampInput"
|
||||
/// Property Type: BOOL
|
||||
/// </summary>
|
||||
D2D1_CONTRAST_PROP_CLAMP_INPUT = 1,
|
||||
D2D1_CONTRAST_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_CONTRAST_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the RgbToHue effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_RGBTOHUE_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "OutputColorSpace"
|
||||
/// Property Type: D2D1_RGBTOHUE_OUTPUT_COLOR_SPACE
|
||||
/// </summary>
|
||||
D2D1_RGBTOHUE_PROP_OUTPUT_COLOR_SPACE = 0,
|
||||
D2D1_RGBTOHUE_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_RGBTOHUE_PROP;
|
||||
|
||||
typedef enum D2D1_RGBTOHUE_OUTPUT_COLOR_SPACE
|
||||
{
|
||||
D2D1_RGBTOHUE_OUTPUT_COLOR_SPACE_HUE_SATURATION_VALUE = 0,
|
||||
D2D1_RGBTOHUE_OUTPUT_COLOR_SPACE_HUE_SATURATION_LIGHTNESS = 1,
|
||||
D2D1_RGBTOHUE_OUTPUT_COLOR_SPACE_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_RGBTOHUE_OUTPUT_COLOR_SPACE;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the HueToRgb effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_HUETORGB_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "InputColorSpace"
|
||||
/// Property Type: D2D1_HUETORGB_INPUT_COLOR_SPACE
|
||||
/// </summary>
|
||||
D2D1_HUETORGB_PROP_INPUT_COLOR_SPACE = 0,
|
||||
D2D1_HUETORGB_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_HUETORGB_PROP;
|
||||
|
||||
typedef enum D2D1_HUETORGB_INPUT_COLOR_SPACE
|
||||
{
|
||||
D2D1_HUETORGB_INPUT_COLOR_SPACE_HUE_SATURATION_VALUE = 0,
|
||||
D2D1_HUETORGB_INPUT_COLOR_SPACE_HUE_SATURATION_LIGHTNESS = 1,
|
||||
D2D1_HUETORGB_INPUT_COLOR_SPACE_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_HUETORGB_INPUT_COLOR_SPACE;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Chroma Key effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_CHROMAKEY_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Color"
|
||||
/// Property Type: D2D1_VECTOR_3F
|
||||
/// </summary>
|
||||
D2D1_CHROMAKEY_PROP_COLOR = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Tolerance"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_CHROMAKEY_PROP_TOLERANCE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "InvertAlpha"
|
||||
/// Property Type: BOOL
|
||||
/// </summary>
|
||||
D2D1_CHROMAKEY_PROP_INVERT_ALPHA = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Feather"
|
||||
/// Property Type: BOOL
|
||||
/// </summary>
|
||||
D2D1_CHROMAKEY_PROP_FEATHER = 3,
|
||||
D2D1_CHROMAKEY_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_CHROMAKEY_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Emboss effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_EMBOSS_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Height"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_EMBOSS_PROP_HEIGHT = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Direction"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_EMBOSS_PROP_DIRECTION = 1,
|
||||
D2D1_EMBOSS_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_EMBOSS_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Exposure effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_EXPOSURE_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "ExposureValue"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_EXPOSURE_PROP_EXPOSURE_VALUE = 0,
|
||||
D2D1_EXPOSURE_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_EXPOSURE_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Posterize effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_POSTERIZE_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "RedValueCount"
|
||||
/// Property Type: UINT32
|
||||
/// </summary>
|
||||
D2D1_POSTERIZE_PROP_RED_VALUE_COUNT = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "GreenValueCount"
|
||||
/// Property Type: UINT32
|
||||
/// </summary>
|
||||
D2D1_POSTERIZE_PROP_GREEN_VALUE_COUNT = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "BlueValueCount"
|
||||
/// Property Type: UINT32
|
||||
/// </summary>
|
||||
D2D1_POSTERIZE_PROP_BLUE_VALUE_COUNT = 2,
|
||||
D2D1_POSTERIZE_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_POSTERIZE_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Sepia effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_SEPIA_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Intensity"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_SEPIA_PROP_INTENSITY = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "AlphaMode"
|
||||
/// Property Type: D2D1_ALPHA_MODE
|
||||
/// </summary>
|
||||
D2D1_SEPIA_PROP_ALPHA_MODE = 1,
|
||||
D2D1_SEPIA_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_SEPIA_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Sharpen effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_SHARPEN_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Sharpness"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_SHARPEN_PROP_SHARPNESS = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Threshold"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_SHARPEN_PROP_THRESHOLD = 1,
|
||||
D2D1_SHARPEN_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_SHARPEN_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Straighten effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_STRAIGHTEN_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Angle"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_STRAIGHTEN_PROP_ANGLE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "MaintainSize"
|
||||
/// Property Type: BOOL
|
||||
/// </summary>
|
||||
D2D1_STRAIGHTEN_PROP_MAINTAIN_SIZE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "ScaleMode"
|
||||
/// Property Type: D2D1_STRAIGHTEN_SCALE_MODE
|
||||
/// </summary>
|
||||
D2D1_STRAIGHTEN_PROP_SCALE_MODE = 2,
|
||||
D2D1_STRAIGHTEN_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_STRAIGHTEN_PROP;
|
||||
|
||||
typedef enum D2D1_STRAIGHTEN_SCALE_MODE
|
||||
{
|
||||
D2D1_STRAIGHTEN_SCALE_MODE_NEAREST_NEIGHBOR = 0,
|
||||
D2D1_STRAIGHTEN_SCALE_MODE_LINEAR = 1,
|
||||
D2D1_STRAIGHTEN_SCALE_MODE_CUBIC = 2,
|
||||
D2D1_STRAIGHTEN_SCALE_MODE_MULTI_SAMPLE_LINEAR = 3,
|
||||
D2D1_STRAIGHTEN_SCALE_MODE_ANISOTROPIC = 4,
|
||||
D2D1_STRAIGHTEN_SCALE_MODE_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_STRAIGHTEN_SCALE_MODE;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Temperature And Tint effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_TEMPERATUREANDTINT_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Temperature"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_TEMPERATUREANDTINT_PROP_TEMPERATURE = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Tint"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_TEMPERATUREANDTINT_PROP_TINT = 1,
|
||||
D2D1_TEMPERATUREANDTINT_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_TEMPERATUREANDTINT_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Vignette effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_VIGNETTE_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Color"
|
||||
/// Property Type: D2D1_VECTOR_4F
|
||||
/// </summary>
|
||||
D2D1_VIGNETTE_PROP_COLOR = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "TransitionSize"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_VIGNETTE_PROP_TRANSITION_SIZE = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Strength"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_VIGNETTE_PROP_STRENGTH = 2,
|
||||
D2D1_VIGNETTE_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_VIGNETTE_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Edge Detection effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_EDGEDETECTION_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Strength"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_EDGEDETECTION_PROP_STRENGTH = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "BlurRadius"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_EDGEDETECTION_PROP_BLUR_RADIUS = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Mode"
|
||||
/// Property Type: D2D1_EDGEDETECTION_MODE
|
||||
/// </summary>
|
||||
D2D1_EDGEDETECTION_PROP_MODE = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "OverlayEdges"
|
||||
/// Property Type: BOOL
|
||||
/// </summary>
|
||||
D2D1_EDGEDETECTION_PROP_OVERLAY_EDGES = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "AlphaMode"
|
||||
/// Property Type: D2D1_ALPHA_MODE
|
||||
/// </summary>
|
||||
D2D1_EDGEDETECTION_PROP_ALPHA_MODE = 4,
|
||||
D2D1_EDGEDETECTION_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_EDGEDETECTION_PROP;
|
||||
|
||||
typedef enum D2D1_EDGEDETECTION_MODE
|
||||
{
|
||||
D2D1_EDGEDETECTION_MODE_SOBEL = 0,
|
||||
D2D1_EDGEDETECTION_MODE_PREWITT = 1,
|
||||
D2D1_EDGEDETECTION_MODE_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_EDGEDETECTION_MODE;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Highlights and Shadows effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_HIGHLIGHTSANDSHADOWS_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Highlights"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_PROP_HIGHLIGHTS = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Shadows"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_PROP_SHADOWS = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Clarity"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_PROP_CLARITY = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "InputGamma"
|
||||
/// Property Type: D2D1_HIGHLIGHTSANDSHADOWS_INPUT_GAMMA
|
||||
/// </summary>
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_PROP_INPUT_GAMMA = 3,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "MaskBlurRadius"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_PROP_MASK_BLUR_RADIUS = 4,
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_HIGHLIGHTSANDSHADOWS_PROP;
|
||||
|
||||
typedef enum D2D1_HIGHLIGHTSANDSHADOWS_INPUT_GAMMA
|
||||
{
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_INPUT_GAMMA_LINEAR = 0,
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_INPUT_GAMMA_SRGB = 1,
|
||||
D2D1_HIGHLIGHTSANDSHADOWS_INPUT_GAMMA_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_HIGHLIGHTSANDSHADOWS_INPUT_GAMMA;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Lookup Table 3D effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_LOOKUPTABLE3D_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Lut"
|
||||
/// Property Type: IUnknown *
|
||||
/// </summary>
|
||||
D2D1_LOOKUPTABLE3D_PROP_LUT = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "AlphaMode"
|
||||
/// Property Type: D2D1_ALPHA_MODE
|
||||
/// </summary>
|
||||
D2D1_LOOKUPTABLE3D_PROP_ALPHA_MODE = 1,
|
||||
D2D1_LOOKUPTABLE3D_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_LOOKUPTABLE3D_PROP;
|
||||
|
||||
|
||||
#if NTDDI_VERSION >= NTDDI_WIN10_RS1
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Opacity effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_OPACITY_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Opacity"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_OPACITY_PROP_OPACITY = 0,
|
||||
D2D1_OPACITY_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_OPACITY_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Cross Fade effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_CROSSFADE_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Weight"
|
||||
/// Property Type: FLOAT
|
||||
/// </summary>
|
||||
D2D1_CROSSFADE_PROP_WEIGHT = 0,
|
||||
D2D1_CROSSFADE_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_CROSSFADE_PROP;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The enumeration of the Tint effect's top level properties.
|
||||
/// </summary>
|
||||
typedef enum D2D1_TINT_PROP
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "Color"
|
||||
/// Property Type: D2D1_VECTOR_4F
|
||||
/// </summary>
|
||||
D2D1_TINT_PROP_COLOR = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Property Name: "ClampOutput"
|
||||
/// Property Type: BOOL
|
||||
/// </summary>
|
||||
D2D1_TINT_PROP_CLAMP_OUTPUT = 1,
|
||||
D2D1_TINT_PROP_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_TINT_PROP;
|
||||
|
||||
|
||||
#endif // #if NTDDI_VERSION >= NTDDI_WIN10_RS1
|
||||
|
||||
#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) */
|
||||
#pragma endregion
|
||||
|
||||
#endif // #ifndef _D2D1_EFFECTS_2_
|
||||
Vendored
-2233
File diff suppressed because it is too large
Load Diff
Vendored
-338
@@ -1,338 +0,0 @@
|
||||
//+--------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Abstract:
|
||||
// Public API definitions shared by DWrite, D2D, and DImage.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#ifndef DCOMMON_H_INCLUDED
|
||||
#define DCOMMON_H_INCLUDED
|
||||
|
||||
#include <dxgiformat.h>
|
||||
|
||||
#ifndef DX_DECLARE_INTERFACE
|
||||
#define DX_DECLARE_INTERFACE(x) DECLSPEC_UUID(x) DECLSPEC_NOVTABLE
|
||||
#endif
|
||||
|
||||
#ifndef CHECKMETHOD
|
||||
#define CHECKMETHOD(method) virtual DECLSPEC_NOTHROW _Must_inspect_result_ HRESULT STDMETHODCALLTYPE method
|
||||
#endif
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4201) // anonymous unions warning
|
||||
|
||||
//
|
||||
// Forward declarations
|
||||
//
|
||||
struct IDXGISurface;
|
||||
|
||||
/// <summary>
|
||||
/// The measuring method used for text layout.
|
||||
/// </summary>
|
||||
typedef enum DWRITE_MEASURING_MODE
|
||||
{
|
||||
/// <summary>
|
||||
/// Text is measured using glyph ideal metrics whose values are independent to the current display resolution.
|
||||
/// </summary>
|
||||
DWRITE_MEASURING_MODE_NATURAL,
|
||||
|
||||
/// <summary>
|
||||
/// Text is measured using glyph display compatible metrics whose values tuned for the current display resolution.
|
||||
/// </summary>
|
||||
DWRITE_MEASURING_MODE_GDI_CLASSIC,
|
||||
|
||||
/// <summary>
|
||||
// Text is measured using the same glyph display metrics as text measured by GDI using a font
|
||||
// created with CLEARTYPE_NATURAL_QUALITY.
|
||||
/// </summary>
|
||||
DWRITE_MEASURING_MODE_GDI_NATURAL
|
||||
|
||||
} DWRITE_MEASURING_MODE;
|
||||
|
||||
/// <summary>
|
||||
/// Qualifies how alpha is to be treated in a bitmap or render target containing
|
||||
/// alpha.
|
||||
/// </summary>
|
||||
typedef enum D2D1_ALPHA_MODE
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Alpha mode should be determined implicitly. Some target surfaces do not supply
|
||||
/// or imply this information in which case alpha must be specified.
|
||||
/// </summary>
|
||||
D2D1_ALPHA_MODE_UNKNOWN = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Treat the alpha as premultipled.
|
||||
/// </summary>
|
||||
D2D1_ALPHA_MODE_PREMULTIPLIED = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Opacity is in the 'A' component only.
|
||||
/// </summary>
|
||||
D2D1_ALPHA_MODE_STRAIGHT = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Ignore any alpha channel information.
|
||||
/// </summary>
|
||||
D2D1_ALPHA_MODE_IGNORE = 3,
|
||||
|
||||
D2D1_ALPHA_MODE_FORCE_DWORD = 0xffffffff
|
||||
|
||||
} D2D1_ALPHA_MODE;
|
||||
|
||||
/// <summary>
|
||||
/// Description of a pixel format.
|
||||
/// </summary>
|
||||
typedef struct D2D1_PIXEL_FORMAT
|
||||
{
|
||||
DXGI_FORMAT format;
|
||||
D2D1_ALPHA_MODE alphaMode;
|
||||
|
||||
} D2D1_PIXEL_FORMAT;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an x-coordinate and y-coordinate pair in two-dimensional space.
|
||||
/// </summary>
|
||||
typedef struct D2D_POINT_2U
|
||||
{
|
||||
UINT32 x;
|
||||
UINT32 y;
|
||||
|
||||
} D2D_POINT_2U;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an x-coordinate and y-coordinate pair in two-dimensional space.
|
||||
/// </summary>
|
||||
typedef struct D2D_POINT_2F
|
||||
{
|
||||
FLOAT x;
|
||||
FLOAT y;
|
||||
|
||||
} D2D_POINT_2F;
|
||||
|
||||
typedef POINT D2D_POINT_2L;
|
||||
|
||||
/// <summary>
|
||||
/// A vector of 2 FLOAT values (x, y).
|
||||
/// </summary>
|
||||
typedef struct D2D_VECTOR_2F
|
||||
{
|
||||
FLOAT x;
|
||||
FLOAT y;
|
||||
|
||||
} D2D_VECTOR_2F;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A vector of 3 FLOAT values (x, y, z).
|
||||
/// </summary>
|
||||
typedef struct D2D_VECTOR_3F
|
||||
{
|
||||
FLOAT x;
|
||||
FLOAT y;
|
||||
FLOAT z;
|
||||
|
||||
} D2D_VECTOR_3F;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A vector of 4 FLOAT values (x, y, z, w).
|
||||
/// </summary>
|
||||
typedef struct D2D_VECTOR_4F
|
||||
{
|
||||
FLOAT x;
|
||||
FLOAT y;
|
||||
FLOAT z;
|
||||
FLOAT w;
|
||||
|
||||
} D2D_VECTOR_4F;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a rectangle defined by the coordinates of the upper-left corner
|
||||
/// (left, top) and the coordinates of the lower-right corner (right, bottom).
|
||||
/// </summary>
|
||||
typedef struct D2D_RECT_F
|
||||
{
|
||||
FLOAT left;
|
||||
FLOAT top;
|
||||
FLOAT right;
|
||||
FLOAT bottom;
|
||||
|
||||
} D2D_RECT_F;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a rectangle defined by the coordinates of the upper-left corner
|
||||
/// (left, top) and the coordinates of the lower-right corner (right, bottom).
|
||||
/// </summary>
|
||||
typedef struct D2D_RECT_U
|
||||
{
|
||||
UINT32 left;
|
||||
UINT32 top;
|
||||
UINT32 right;
|
||||
UINT32 bottom;
|
||||
|
||||
} D2D_RECT_U;
|
||||
|
||||
typedef RECT D2D_RECT_L;
|
||||
|
||||
/// <summary>
|
||||
/// Stores an ordered pair of floats, typically the width and height of a rectangle.
|
||||
/// </summary>
|
||||
typedef struct D2D_SIZE_F
|
||||
{
|
||||
FLOAT width;
|
||||
FLOAT height;
|
||||
|
||||
} D2D_SIZE_F;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Stores an ordered pair of integers, typically the width and height of a
|
||||
/// rectangle.
|
||||
/// </summary>
|
||||
typedef struct D2D_SIZE_U
|
||||
{
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
|
||||
} D2D_SIZE_U;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 3-by-2 matrix.
|
||||
/// </summary>
|
||||
typedef struct D2D_MATRIX_3X2_F
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/// <summary>
|
||||
/// Horizontal scaling / cosine of rotation
|
||||
/// </summary>
|
||||
FLOAT m11;
|
||||
|
||||
/// <summary>
|
||||
/// Vertical shear / sine of rotation
|
||||
/// </summary>
|
||||
FLOAT m12;
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal shear / negative sine of rotation
|
||||
/// </summary>
|
||||
FLOAT m21;
|
||||
|
||||
/// <summary>
|
||||
/// Vertical scaling / cosine of rotation
|
||||
/// </summary>
|
||||
FLOAT m22;
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal shift (always orthogonal regardless of rotation)
|
||||
/// </summary>
|
||||
FLOAT dx;
|
||||
|
||||
/// <summary>
|
||||
/// Vertical shift (always orthogonal regardless of rotation)
|
||||
/// </summary>
|
||||
FLOAT dy;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
FLOAT _11, _12;
|
||||
FLOAT _21, _22;
|
||||
FLOAT _31, _32;
|
||||
};
|
||||
|
||||
FLOAT m[3][2];
|
||||
};
|
||||
|
||||
} D2D_MATRIX_3X2_F;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 4-by-3 matrix.
|
||||
/// </summary>
|
||||
typedef struct D2D_MATRIX_4X3_F
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT _11, _12, _13;
|
||||
FLOAT _21, _22, _23;
|
||||
FLOAT _31, _32, _33;
|
||||
FLOAT _41, _42, _43;
|
||||
};
|
||||
|
||||
FLOAT m[4][3];
|
||||
};
|
||||
|
||||
} D2D_MATRIX_4X3_F;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 4-by-4 matrix.
|
||||
/// </summary>
|
||||
typedef struct D2D_MATRIX_4X4_F
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT _11, _12, _13, _14;
|
||||
FLOAT _21, _22, _23, _24;
|
||||
FLOAT _31, _32, _33, _34;
|
||||
FLOAT _41, _42, _43, _44;
|
||||
};
|
||||
|
||||
FLOAT m[4][4];
|
||||
};
|
||||
|
||||
} D2D_MATRIX_4X4_F;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a 5-by-4 matrix.
|
||||
/// </summary>
|
||||
typedef struct D2D_MATRIX_5X4_F
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
FLOAT _11, _12, _13, _14;
|
||||
FLOAT _21, _22, _23, _24;
|
||||
FLOAT _31, _32, _33, _34;
|
||||
FLOAT _41, _42, _43, _44;
|
||||
FLOAT _51, _52, _53, _54;
|
||||
};
|
||||
|
||||
FLOAT m[5][4];
|
||||
};
|
||||
|
||||
} D2D_MATRIX_5X4_F;
|
||||
|
||||
|
||||
typedef D2D_POINT_2F D2D1_POINT_2F;
|
||||
typedef D2D_POINT_2U D2D1_POINT_2U;
|
||||
typedef D2D_POINT_2L D2D1_POINT_2L;
|
||||
typedef D2D_RECT_F D2D1_RECT_F;
|
||||
typedef D2D_RECT_U D2D1_RECT_U;
|
||||
typedef D2D_RECT_L D2D1_RECT_L;
|
||||
typedef D2D_SIZE_F D2D1_SIZE_F;
|
||||
typedef D2D_SIZE_U D2D1_SIZE_U;
|
||||
typedef D2D_MATRIX_3X2_F D2D1_MATRIX_3X2_F;
|
||||
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#endif /* DCOMMON_H_INCLUDED */
|
||||
Vendored
-1533
File diff suppressed because it is too large
Load Diff
-295
@@ -1,295 +0,0 @@
|
||||
/*
|
||||
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
Module Name:
|
||||
|
||||
sdkddkver.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Master include file for versioning windows SDK/DDK.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _INC_SDKDDKVER
|
||||
#define _INC_SDKDDKVER
|
||||
|
||||
#if (_MSC_VER >= 800)
|
||||
#if (_MSC_VER >= 1200)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4668) /* #if not_defined treated as #if 0 */
|
||||
#endif
|
||||
#pragma warning(disable:4001) /* nonstandard extension : single line comment */
|
||||
#endif
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// _WIN32_WINNT version constants
|
||||
//
|
||||
#define _WIN32_WINNT_NT4 0x0400
|
||||
#define _WIN32_WINNT_WIN2K 0x0500
|
||||
#define _WIN32_WINNT_WINXP 0x0501
|
||||
#define _WIN32_WINNT_WS03 0x0502
|
||||
#define _WIN32_WINNT_WIN6 0x0600
|
||||
#define _WIN32_WINNT_VISTA 0x0600
|
||||
#define _WIN32_WINNT_WS08 0x0600
|
||||
#define _WIN32_WINNT_LONGHORN 0x0600
|
||||
#define _WIN32_WINNT_WIN7 0x0601
|
||||
#define _WIN32_WINNT_WIN8 0x0602
|
||||
#define _WIN32_WINNT_WINBLUE 0x0603
|
||||
#define _WIN32_WINNT_WINTHRESHOLD 0x0A00 /* ABRACADABRA_THRESHOLD*/
|
||||
#define _WIN32_WINNT_WIN10 0x0A00 /* ABRACADABRA_THRESHOLD*/
|
||||
|
||||
//
|
||||
// _WIN32_IE_ version constants
|
||||
//
|
||||
#define _WIN32_IE_IE20 0x0200
|
||||
#define _WIN32_IE_IE30 0x0300
|
||||
#define _WIN32_IE_IE302 0x0302
|
||||
#define _WIN32_IE_IE40 0x0400
|
||||
#define _WIN32_IE_IE401 0x0401
|
||||
#define _WIN32_IE_IE50 0x0500
|
||||
#define _WIN32_IE_IE501 0x0501
|
||||
#define _WIN32_IE_IE55 0x0550
|
||||
#define _WIN32_IE_IE60 0x0600
|
||||
#define _WIN32_IE_IE60SP1 0x0601
|
||||
#define _WIN32_IE_IE60SP2 0x0603
|
||||
#define _WIN32_IE_IE70 0x0700
|
||||
#define _WIN32_IE_IE80 0x0800
|
||||
#define _WIN32_IE_IE90 0x0900
|
||||
#define _WIN32_IE_IE100 0x0A00
|
||||
#define _WIN32_IE_IE110 0x0A00 /* ABRACADABRA_THRESHOLD */
|
||||
|
||||
//
|
||||
// IE <-> OS version mapping
|
||||
//
|
||||
// NT4 supports IE versions 2.0 -> 6.0 SP1
|
||||
#define _WIN32_IE_NT4 _WIN32_IE_IE20
|
||||
#define _WIN32_IE_NT4SP1 _WIN32_IE_IE20
|
||||
#define _WIN32_IE_NT4SP2 _WIN32_IE_IE20
|
||||
#define _WIN32_IE_NT4SP3 _WIN32_IE_IE302
|
||||
#define _WIN32_IE_NT4SP4 _WIN32_IE_IE401
|
||||
#define _WIN32_IE_NT4SP5 _WIN32_IE_IE401
|
||||
#define _WIN32_IE_NT4SP6 _WIN32_IE_IE50
|
||||
// Win98 supports IE versions 4.01 -> 6.0 SP1
|
||||
#define _WIN32_IE_WIN98 _WIN32_IE_IE401
|
||||
// Win98SE supports IE versions 5.0 -> 6.0 SP1
|
||||
#define _WIN32_IE_WIN98SE _WIN32_IE_IE50
|
||||
// WinME supports IE versions 5.5 -> 6.0 SP1
|
||||
#define _WIN32_IE_WINME _WIN32_IE_IE55
|
||||
// Win2k supports IE versions 5.01 -> 6.0 SP1
|
||||
#define _WIN32_IE_WIN2K _WIN32_IE_IE501
|
||||
#define _WIN32_IE_WIN2KSP1 _WIN32_IE_IE501
|
||||
#define _WIN32_IE_WIN2KSP2 _WIN32_IE_IE501
|
||||
#define _WIN32_IE_WIN2KSP3 _WIN32_IE_IE501
|
||||
#define _WIN32_IE_WIN2KSP4 _WIN32_IE_IE501
|
||||
#define _WIN32_IE_XP _WIN32_IE_IE60
|
||||
#define _WIN32_IE_XPSP1 _WIN32_IE_IE60SP1
|
||||
#define _WIN32_IE_XPSP2 _WIN32_IE_IE60SP2
|
||||
#define _WIN32_IE_WS03 0x0602
|
||||
#define _WIN32_IE_WS03SP1 _WIN32_IE_IE60SP2
|
||||
#define _WIN32_IE_WIN6 _WIN32_IE_IE70
|
||||
#define _WIN32_IE_LONGHORN _WIN32_IE_IE70
|
||||
#define _WIN32_IE_WIN7 _WIN32_IE_IE80
|
||||
#define _WIN32_IE_WIN8 _WIN32_IE_IE100
|
||||
#define _WIN32_IE_WINBLUE _WIN32_IE_IE100
|
||||
#define _WIN32_IE_WINTHRESHOLD _WIN32_IE_IE110 /* ABRACADABRA_THRESHOLD */
|
||||
#define _WIN32_IE_WIN10 _WIN32_IE_IE110 /* ABRACADABRA_THRESHOLD */
|
||||
|
||||
|
||||
//
|
||||
// NTDDI version constants
|
||||
//
|
||||
#define NTDDI_WIN2K 0x05000000
|
||||
#define NTDDI_WIN2KSP1 0x05000100
|
||||
#define NTDDI_WIN2KSP2 0x05000200
|
||||
#define NTDDI_WIN2KSP3 0x05000300
|
||||
#define NTDDI_WIN2KSP4 0x05000400
|
||||
|
||||
#define NTDDI_WINXP 0x05010000
|
||||
#define NTDDI_WINXPSP1 0x05010100
|
||||
#define NTDDI_WINXPSP2 0x05010200
|
||||
#define NTDDI_WINXPSP3 0x05010300
|
||||
#define NTDDI_WINXPSP4 0x05010400
|
||||
|
||||
#define NTDDI_WS03 0x05020000
|
||||
#define NTDDI_WS03SP1 0x05020100
|
||||
#define NTDDI_WS03SP2 0x05020200
|
||||
#define NTDDI_WS03SP3 0x05020300
|
||||
#define NTDDI_WS03SP4 0x05020400
|
||||
|
||||
#define NTDDI_WIN6 0x06000000
|
||||
#define NTDDI_WIN6SP1 0x06000100
|
||||
#define NTDDI_WIN6SP2 0x06000200
|
||||
#define NTDDI_WIN6SP3 0x06000300
|
||||
#define NTDDI_WIN6SP4 0x06000400
|
||||
|
||||
#define NTDDI_VISTA NTDDI_WIN6
|
||||
#define NTDDI_VISTASP1 NTDDI_WIN6SP1
|
||||
#define NTDDI_VISTASP2 NTDDI_WIN6SP2
|
||||
#define NTDDI_VISTASP3 NTDDI_WIN6SP3
|
||||
#define NTDDI_VISTASP4 NTDDI_WIN6SP4
|
||||
|
||||
#define NTDDI_LONGHORN NTDDI_VISTA
|
||||
|
||||
#define NTDDI_WS08 NTDDI_WIN6SP1
|
||||
#define NTDDI_WS08SP2 NTDDI_WIN6SP2
|
||||
#define NTDDI_WS08SP3 NTDDI_WIN6SP3
|
||||
#define NTDDI_WS08SP4 NTDDI_WIN6SP4
|
||||
|
||||
#define NTDDI_WIN7 0x06010000
|
||||
#define NTDDI_WIN8 0x06020000
|
||||
#define NTDDI_WINBLUE 0x06030000
|
||||
#define NTDDI_WINTHRESHOLD 0x0A000000 /* ABRACADABRA_THRESHOLD */
|
||||
#define NTDDI_WIN10 0x0A000000 /* ABRACADABRA_THRESHOLD */
|
||||
#define NTDDI_WIN10_TH2 0x0A000001 /* ABRACADABRA_WIN10_TH2 */
|
||||
#define NTDDI_WIN10_RS1 0x0A000002 /* ABRACADABRA_WIN10_RS1 */
|
||||
|
||||
//
|
||||
// masks for version macros
|
||||
//
|
||||
#define OSVERSION_MASK 0xFFFF0000
|
||||
#define SPVERSION_MASK 0x0000FF00
|
||||
#define SUBVERSION_MASK 0x000000FF
|
||||
|
||||
|
||||
//
|
||||
// macros to extract various version fields from the NTDDI version
|
||||
//
|
||||
#define OSVER(Version) ((Version) & OSVERSION_MASK)
|
||||
#define SPVER(Version) (((Version) & SPVERSION_MASK) >> 8)
|
||||
#define SUBVER(Version) (((Version) & SUBVERSION_MASK) )
|
||||
|
||||
|
||||
#if defined(DECLSPEC_DEPRECATED_DDK)
|
||||
|
||||
// deprecate in 2k or later
|
||||
#if (NTDDI_VERSION >= NTDDI_WIN2K)
|
||||
#define DECLSPEC_DEPRECATED_DDK_WIN2K DECLSPEC_DEPRECATED_DDK
|
||||
#else
|
||||
#define DECLSPEC_DEPRECATED_DDK_WIN2K
|
||||
#endif
|
||||
|
||||
// deprecate in XP or later
|
||||
#if (NTDDI_VERSION >= NTDDI_WINXP)
|
||||
#define DECLSPEC_DEPRECATED_DDK_WINXP DECLSPEC_DEPRECATED_DDK
|
||||
#else
|
||||
#define DECLSPEC_DEPRECATED_DDK_WINXP
|
||||
#endif
|
||||
|
||||
// deprecate in WS03 or later
|
||||
#if (NTDDI_VERSION >= NTDDI_WS03)
|
||||
#define DECLSPEC_DEPRECATED_DDK_WIN2003 DECLSPEC_DEPRECATED_DDK
|
||||
#else
|
||||
#define DECLSPEC_DEPRECATED_DDK_WIN2003
|
||||
#endif
|
||||
|
||||
// deprecate in WIN6 or later
|
||||
#if (NTDDI_VERSION >= NTDDI_WIN6)
|
||||
#define DECLSPEC_DEPRECATED_DDK_WIN6 DECLSPEC_DEPRECATED_DDK
|
||||
#else
|
||||
#define DECLSPEC_DEPRECATED_DDK_WIN6
|
||||
#endif
|
||||
|
||||
#define DECLSPEC_DEPRECATED_DDK_LONGHORN DECLSPEC_DEPRECATED_DDK_WIN6
|
||||
|
||||
#endif // defined(DECLSPEC_DEPRECATED_DDK)
|
||||
|
||||
|
||||
//
|
||||
// if versions aren't already defined, default to most current
|
||||
//
|
||||
|
||||
#define NTDDI_VERSION_FROM_WIN32_WINNT2(ver) ver##0000
|
||||
#define NTDDI_VERSION_FROM_WIN32_WINNT(ver) NTDDI_VERSION_FROM_WIN32_WINNT2(ver)
|
||||
|
||||
#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_)
|
||||
#define _WIN32_WINNT 0x0A00
|
||||
#endif
|
||||
|
||||
#ifndef NTDDI_VERSION
|
||||
#ifdef _WIN32_WINNT
|
||||
// set NTDDI_VERSION based on _WIN32_WINNT
|
||||
#define NTDDI_VERSION NTDDI_VERSION_FROM_WIN32_WINNT(_WIN32_WINNT)
|
||||
#else
|
||||
#define NTDDI_VERSION 0x0A000002
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef WINVER
|
||||
#ifdef _WIN32_WINNT
|
||||
// set WINVER based on _WIN32_WINNT
|
||||
#define WINVER _WIN32_WINNT
|
||||
#else
|
||||
#define WINVER 0x0A00
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32_IE
|
||||
#ifdef _WIN32_WINNT
|
||||
// set _WIN32_IE based on _WIN32_WINNT
|
||||
#if (_WIN32_WINNT <= _WIN32_WINNT_NT4)
|
||||
#define _WIN32_IE _WIN32_IE_IE50
|
||||
#elif (_WIN32_WINNT <= _WIN32_WINNT_WIN2K)
|
||||
#define _WIN32_IE _WIN32_IE_IE501
|
||||
#elif (_WIN32_WINNT <= _WIN32_WINNT_WINXP)
|
||||
#define _WIN32_IE _WIN32_IE_IE60
|
||||
#elif (_WIN32_WINNT <= _WIN32_WINNT_WS03)
|
||||
#define _WIN32_IE _WIN32_IE_WS03
|
||||
#elif (_WIN32_WINNT <= _WIN32_WINNT_VISTA)
|
||||
#define _WIN32_IE _WIN32_IE_LONGHORN
|
||||
#elif (_WIN32_WINNT <= _WIN32_WINNT_WIN7)
|
||||
#define _WIN32_IE _WIN32_IE_WIN7
|
||||
#elif (_WIN32_WINNT <= _WIN32_WINNT_WIN8)
|
||||
#define _WIN32_IE _WIN32_IE_WIN8
|
||||
#else
|
||||
#define _WIN32_IE 0x0A00
|
||||
#endif
|
||||
#else
|
||||
#define _WIN32_IE 0x0A00
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// Sanity check for compatible versions
|
||||
//
|
||||
#if defined(_WIN32_WINNT) && !defined(MIDL_PASS) && !defined(RC_INVOKED)
|
||||
|
||||
#if (defined(WINVER) && (WINVER < 0x0400) && (_WIN32_WINNT > 0x0400))
|
||||
#error WINVER setting conflicts with _WIN32_WINNT setting
|
||||
#endif
|
||||
|
||||
#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_WIN2K) && (_WIN32_WINNT != _WIN32_WINNT_WIN2K))
|
||||
#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting
|
||||
#endif
|
||||
|
||||
#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_WINXP) && (_WIN32_WINNT != _WIN32_WINNT_WINXP))
|
||||
#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting
|
||||
#endif
|
||||
|
||||
#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_WS03) && (_WIN32_WINNT != _WIN32_WINNT_WS03))
|
||||
#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting
|
||||
#endif
|
||||
|
||||
#if (((OSVERSION_MASK & NTDDI_VERSION) == NTDDI_VISTA) && (_WIN32_WINNT != _WIN32_WINNT_VISTA))
|
||||
#error NTDDI_VERSION setting conflicts with _WIN32_WINNT setting
|
||||
#endif
|
||||
|
||||
#if ((_WIN32_WINNT < _WIN32_WINNT_WIN2K) && (_WIN32_IE > _WIN32_IE_IE60SP1))
|
||||
#error _WIN32_WINNT settings conflicts with _WIN32_IE setting
|
||||
#endif
|
||||
|
||||
#endif // defined(_WIN32_WINNT) && !defined(MIDL_PASS) && !defined(_WINRESRC_)
|
||||
|
||||
#if (_MSC_VER >= 800)
|
||||
#if (_MSC_VER >= 1200)
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma warning(default:4001) /* nonstandard extension : single line comment */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* !_INC_SDKDDKVER */
|
||||
|
||||
Vendored
-1158
File diff suppressed because it is too large
Load Diff
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
-1
Submodule 3rdparty/pugixml deleted from f205aaf6e1
Vendored
-6698
File diff suppressed because it is too large
Load Diff
Vendored
-3301
File diff suppressed because it is too large
Load Diff
+1
-23
@@ -11,30 +11,8 @@ if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
|
||||
endif()
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
|
||||
message( FATAL_ERROR "RPCS3 requires at least gcc-5.1." )
|
||||
endif()
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 6.1)
|
||||
message( FATAL_ERROR "RPCS3 can't be compiled with gcc-6.1, see #1691." )
|
||||
endif()
|
||||
|
||||
add_definitions(-DCMAKE_BUILD)
|
||||
|
||||
# We use libpng's static library and don't need to build the shared library and run the tests
|
||||
set(PNG_SHARED OFF CACHE BOOL "Build shared lib." FORCE)
|
||||
set(PNG_TESTS OFF CACHE BOOL "Build tests." FORCE)
|
||||
|
||||
# Select the version of libpng to use, default is builtin
|
||||
if (NOT USE_SYSTEM_LIBPNG)
|
||||
add_subdirectory( 3rdparty/libpng )
|
||||
endif()
|
||||
|
||||
option(VULKAN_PREBUILT "" OFF)
|
||||
|
||||
add_subdirectory( asmjit )
|
||||
# TODO: do real installation, including copying directory structure
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin")
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin")
|
||||
add_subdirectory( Vulkan )
|
||||
add_subdirectory( rpcs3 )
|
||||
add_subdirectory( rsx_program_decompiler )
|
||||
|
||||
@@ -6,7 +6,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Copyright (c) 2013-2016 The Khronos Group Inc.
|
||||
** Copyright (c) 2013-2014 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
@@ -33,7 +33,7 @@ extern "C" {
|
||||
** used to make the header, and the header can be found at
|
||||
** http://www.opengl.org/registry/
|
||||
**
|
||||
** Khronos $Revision: 33248 $ on $Date: 2016-10-24 01:22:03 -0400 (Mon, 24 Oct 2016) $
|
||||
** Khronos $Revision: 31191 $ on $Date: 2015-05-14 06:31:39 -0400 (Thu, 14 May 2015) $
|
||||
*/
|
||||
|
||||
#if defined(_WIN32) && !defined(APIENTRY) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__)
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
#define GLAPI extern
|
||||
#endif
|
||||
|
||||
#define GL_GLEXT_VERSION 20161024
|
||||
#define GL_GLEXT_VERSION 20150514
|
||||
|
||||
/* Generated C header for:
|
||||
* API: gl
|
||||
@@ -2654,7 +2654,7 @@ typedef void (APIENTRYP PFNGLINVALIDATENAMEDFRAMEBUFFERSUBDATAPROC) (GLuint fram
|
||||
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);
|
||||
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERUIVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);
|
||||
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFVPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);
|
||||
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
typedef void (APIENTRYP PFNGLCLEARNAMEDFRAMEBUFFERFIPROC) (GLuint framebuffer, GLenum buffer, const GLfloat depth, GLint stencil);
|
||||
typedef void (APIENTRYP PFNGLBLITNAMEDFRAMEBUFFERPROC) (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
typedef GLenum (APIENTRYP PFNGLCHECKNAMEDFRAMEBUFFERSTATUSPROC) (GLuint framebuffer, GLenum target);
|
||||
typedef void (APIENTRYP PFNGLGETNAMEDFRAMEBUFFERPARAMETERIVPROC) (GLuint framebuffer, GLenum pname, GLint *param);
|
||||
@@ -2777,7 +2777,7 @@ GLAPI void APIENTRY glInvalidateNamedFramebufferSubData (GLuint framebuffer, GLs
|
||||
GLAPI void APIENTRY glClearNamedFramebufferiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLint *value);
|
||||
GLAPI void APIENTRY glClearNamedFramebufferuiv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLuint *value);
|
||||
GLAPI void APIENTRY glClearNamedFramebufferfv (GLuint framebuffer, GLenum buffer, GLint drawbuffer, const GLfloat *value);
|
||||
GLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
|
||||
GLAPI void APIENTRY glClearNamedFramebufferfi (GLuint framebuffer, GLenum buffer, const GLfloat depth, GLint stencil);
|
||||
GLAPI void APIENTRY glBlitNamedFramebuffer (GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
|
||||
GLAPI GLenum APIENTRY glCheckNamedFramebufferStatus (GLuint framebuffer, GLenum target);
|
||||
GLAPI void APIENTRY glGetNamedFramebufferParameteriv (GLuint framebuffer, GLenum pname, GLint *param);
|
||||
@@ -2875,17 +2875,6 @@ GLAPI void APIENTRY glTextureBarrier (void);
|
||||
#define GL_ARB_ES3_1_compatibility 1
|
||||
#endif /* GL_ARB_ES3_1_compatibility */
|
||||
|
||||
#ifndef GL_ARB_ES3_2_compatibility
|
||||
#define GL_ARB_ES3_2_compatibility 1
|
||||
#define GL_PRIMITIVE_BOUNDING_BOX_ARB 0x92BE
|
||||
#define GL_MULTISAMPLE_LINE_WIDTH_RANGE_ARB 0x9381
|
||||
#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY_ARB 0x9382
|
||||
typedef void (APIENTRYP PFNGLPRIMITIVEBOUNDINGBOXARBPROC) (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glPrimitiveBoundingBoxARB (GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
|
||||
#endif
|
||||
#endif /* GL_ARB_ES3_2_compatibility */
|
||||
|
||||
#ifndef GL_ARB_ES3_compatibility
|
||||
#define GL_ARB_ES3_compatibility 1
|
||||
#endif /* GL_ARB_ES3_compatibility */
|
||||
@@ -3299,10 +3288,6 @@ GLAPI GLboolean APIENTRY glIsProgramARB (GLuint program);
|
||||
#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_ARB 0x8B8B
|
||||
#endif /* GL_ARB_fragment_shader */
|
||||
|
||||
#ifndef GL_ARB_fragment_shader_interlock
|
||||
#define GL_ARB_fragment_shader_interlock 1
|
||||
#endif /* GL_ARB_fragment_shader_interlock */
|
||||
|
||||
#ifndef GL_ARB_framebuffer_no_attachments
|
||||
#define GL_ARB_framebuffer_no_attachments 1
|
||||
#endif /* GL_ARB_framebuffer_no_attachments */
|
||||
@@ -3363,91 +3348,6 @@ GLAPI void APIENTRY glFramebufferTextureFaceARB (GLenum target, GLenum attachmen
|
||||
#define GL_ARB_gpu_shader_fp64 1
|
||||
#endif /* GL_ARB_gpu_shader_fp64 */
|
||||
|
||||
#ifndef GL_ARB_gpu_shader_int64
|
||||
#define GL_ARB_gpu_shader_int64 1
|
||||
#define GL_INT64_ARB 0x140E
|
||||
#define GL_INT64_VEC2_ARB 0x8FE9
|
||||
#define GL_INT64_VEC3_ARB 0x8FEA
|
||||
#define GL_INT64_VEC4_ARB 0x8FEB
|
||||
#define GL_UNSIGNED_INT64_VEC2_ARB 0x8FF5
|
||||
#define GL_UNSIGNED_INT64_VEC3_ARB 0x8FF6
|
||||
#define GL_UNSIGNED_INT64_VEC4_ARB 0x8FF7
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1I64ARBPROC) (GLint location, GLint64 x);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM2I64ARBPROC) (GLint location, GLint64 x, GLint64 y);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM3I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM4I64ARBPROC) (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM2I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM3I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM4I64VARBPROC) (GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1UI64ARBPROC) (GLint location, GLuint64 x);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM2UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM3UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM4UI64ARBPROC) (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM2UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM3UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM4UI64VARBPROC) (GLint location, GLsizei count, const GLuint64 *value);
|
||||
typedef void (APIENTRYP PFNGLGETUNIFORMI64VARBPROC) (GLuint program, GLint location, GLint64 *params);
|
||||
typedef void (APIENTRYP PFNGLGETUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLuint64 *params);
|
||||
typedef void (APIENTRYP PFNGLGETNUNIFORMI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLint64 *params);
|
||||
typedef void (APIENTRYP PFNGLGETNUNIFORMUI64VARBPROC) (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64ARBPROC) (GLuint program, GLint location, GLint64 x);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64ARBPROC) (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4I64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64ARBPROC) (GLuint program, GLint location, GLuint64 x);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64ARBPROC) (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM1UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM2UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM3UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
typedef void (APIENTRYP PFNGLPROGRAMUNIFORM4UI64VARBPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glUniform1i64ARB (GLint location, GLint64 x);
|
||||
GLAPI void APIENTRY glUniform2i64ARB (GLint location, GLint64 x, GLint64 y);
|
||||
GLAPI void APIENTRY glUniform3i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z);
|
||||
GLAPI void APIENTRY glUniform4i64ARB (GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
|
||||
GLAPI void APIENTRY glUniform1i64vARB (GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glUniform2i64vARB (GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glUniform3i64vARB (GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glUniform4i64vARB (GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glUniform1ui64ARB (GLint location, GLuint64 x);
|
||||
GLAPI void APIENTRY glUniform2ui64ARB (GLint location, GLuint64 x, GLuint64 y);
|
||||
GLAPI void APIENTRY glUniform3ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
|
||||
GLAPI void APIENTRY glUniform4ui64ARB (GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
|
||||
GLAPI void APIENTRY glUniform1ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI void APIENTRY glUniform2ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI void APIENTRY glUniform3ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI void APIENTRY glUniform4ui64vARB (GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI void APIENTRY glGetUniformi64vARB (GLuint program, GLint location, GLint64 *params);
|
||||
GLAPI void APIENTRY glGetUniformui64vARB (GLuint program, GLint location, GLuint64 *params);
|
||||
GLAPI void APIENTRY glGetnUniformi64vARB (GLuint program, GLint location, GLsizei bufSize, GLint64 *params);
|
||||
GLAPI void APIENTRY glGetnUniformui64vARB (GLuint program, GLint location, GLsizei bufSize, GLuint64 *params);
|
||||
GLAPI void APIENTRY glProgramUniform1i64ARB (GLuint program, GLint location, GLint64 x);
|
||||
GLAPI void APIENTRY glProgramUniform2i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y);
|
||||
GLAPI void APIENTRY glProgramUniform3i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z);
|
||||
GLAPI void APIENTRY glProgramUniform4i64ARB (GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w);
|
||||
GLAPI void APIENTRY glProgramUniform1i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glProgramUniform2i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glProgramUniform3i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glProgramUniform4i64vARB (GLuint program, GLint location, GLsizei count, const GLint64 *value);
|
||||
GLAPI void APIENTRY glProgramUniform1ui64ARB (GLuint program, GLint location, GLuint64 x);
|
||||
GLAPI void APIENTRY glProgramUniform2ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y);
|
||||
GLAPI void APIENTRY glProgramUniform3ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z);
|
||||
GLAPI void APIENTRY glProgramUniform4ui64ARB (GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w);
|
||||
GLAPI void APIENTRY glProgramUniform1ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI void APIENTRY glProgramUniform2ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI void APIENTRY glProgramUniform3ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
GLAPI void APIENTRY glProgramUniform4ui64vARB (GLuint program, GLint location, GLsizei count, const GLuint64 *value);
|
||||
#endif
|
||||
#endif /* GL_ARB_gpu_shader_int64 */
|
||||
|
||||
#ifndef GL_ARB_half_float_pixel
|
||||
#define GL_ARB_half_float_pixel 1
|
||||
typedef unsigned short GLhalfARB;
|
||||
@@ -3827,16 +3727,6 @@ GLAPI void APIENTRY glGetQueryObjectuivARB (GLuint id, GLenum pname, GLuint *par
|
||||
#define GL_ARB_occlusion_query2 1
|
||||
#endif /* GL_ARB_occlusion_query2 */
|
||||
|
||||
#ifndef GL_ARB_parallel_shader_compile
|
||||
#define GL_ARB_parallel_shader_compile 1
|
||||
#define GL_MAX_SHADER_COMPILER_THREADS_ARB 0x91B0
|
||||
#define GL_COMPLETION_STATUS_ARB 0x91B1
|
||||
typedef void (APIENTRYP PFNGLMAXSHADERCOMPILERTHREADSARBPROC) (GLuint count);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glMaxShaderCompilerThreadsARB (GLuint count);
|
||||
#endif
|
||||
#endif /* GL_ARB_parallel_shader_compile */
|
||||
|
||||
#ifndef GL_ARB_pipeline_statistics_query
|
||||
#define GL_ARB_pipeline_statistics_query 1
|
||||
#define GL_VERTICES_SUBMITTED_ARB 0x82EE
|
||||
@@ -3879,10 +3769,6 @@ GLAPI void APIENTRY glPointParameterfvARB (GLenum pname, const GLfloat *params);
|
||||
#define GL_COORD_REPLACE_ARB 0x8862
|
||||
#endif /* GL_ARB_point_sprite */
|
||||
|
||||
#ifndef GL_ARB_post_depth_coverage
|
||||
#define GL_ARB_post_depth_coverage 1
|
||||
#endif /* GL_ARB_post_depth_coverage */
|
||||
|
||||
#ifndef GL_ARB_program_interface_query
|
||||
#define GL_ARB_program_interface_query 1
|
||||
#endif /* GL_ARB_program_interface_query */
|
||||
@@ -3956,26 +3842,6 @@ GLAPI void APIENTRY glGetnMinmaxARB (GLenum target, GLboolean reset, GLenum form
|
||||
#define GL_ARB_robustness_isolation 1
|
||||
#endif /* GL_ARB_robustness_isolation */
|
||||
|
||||
#ifndef GL_ARB_sample_locations
|
||||
#define GL_ARB_sample_locations 1
|
||||
#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_ARB 0x933D
|
||||
#define GL_SAMPLE_LOCATION_PIXEL_GRID_WIDTH_ARB 0x933E
|
||||
#define GL_SAMPLE_LOCATION_PIXEL_GRID_HEIGHT_ARB 0x933F
|
||||
#define GL_PROGRAMMABLE_SAMPLE_LOCATION_TABLE_SIZE_ARB 0x9340
|
||||
#define GL_SAMPLE_LOCATION_ARB 0x8E50
|
||||
#define GL_PROGRAMMABLE_SAMPLE_LOCATION_ARB 0x9341
|
||||
#define GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB 0x9342
|
||||
#define GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB 0x9343
|
||||
typedef void (APIENTRYP PFNGLFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLenum target, GLuint start, GLsizei count, const GLfloat *v);
|
||||
typedef void (APIENTRYP PFNGLNAMEDFRAMEBUFFERSAMPLELOCATIONSFVARBPROC) (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
|
||||
typedef void (APIENTRYP PFNGLEVALUATEDEPTHVALUESARBPROC) (void);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glFramebufferSampleLocationsfvARB (GLenum target, GLuint start, GLsizei count, const GLfloat *v);
|
||||
GLAPI void APIENTRY glNamedFramebufferSampleLocationsfvARB (GLuint framebuffer, GLuint start, GLsizei count, const GLfloat *v);
|
||||
GLAPI void APIENTRY glEvaluateDepthValuesARB (void);
|
||||
#endif
|
||||
#endif /* GL_ARB_sample_locations */
|
||||
|
||||
#ifndef GL_ARB_sample_shading
|
||||
#define GL_ARB_sample_shading 1
|
||||
#define GL_SAMPLE_SHADING_ARB 0x8C36
|
||||
@@ -4002,26 +3868,14 @@ GLAPI void APIENTRY glMinSampleShadingARB (GLfloat value);
|
||||
#define GL_ARB_separate_shader_objects 1
|
||||
#endif /* GL_ARB_separate_shader_objects */
|
||||
|
||||
#ifndef GL_ARB_shader_atomic_counter_ops
|
||||
#define GL_ARB_shader_atomic_counter_ops 1
|
||||
#endif /* GL_ARB_shader_atomic_counter_ops */
|
||||
|
||||
#ifndef GL_ARB_shader_atomic_counters
|
||||
#define GL_ARB_shader_atomic_counters 1
|
||||
#endif /* GL_ARB_shader_atomic_counters */
|
||||
|
||||
#ifndef GL_ARB_shader_ballot
|
||||
#define GL_ARB_shader_ballot 1
|
||||
#endif /* GL_ARB_shader_ballot */
|
||||
|
||||
#ifndef GL_ARB_shader_bit_encoding
|
||||
#define GL_ARB_shader_bit_encoding 1
|
||||
#endif /* GL_ARB_shader_bit_encoding */
|
||||
|
||||
#ifndef GL_ARB_shader_clock
|
||||
#define GL_ARB_shader_clock 1
|
||||
#endif /* GL_ARB_shader_clock */
|
||||
|
||||
#ifndef GL_ARB_shader_draw_parameters
|
||||
#define GL_ARB_shader_draw_parameters 1
|
||||
#endif /* GL_ARB_shader_draw_parameters */
|
||||
@@ -4186,10 +4040,6 @@ GLAPI void APIENTRY glGetShaderSourceARB (GLhandleARB obj, GLsizei maxLength, GL
|
||||
#define GL_ARB_shader_texture_lod 1
|
||||
#endif /* GL_ARB_shader_texture_lod */
|
||||
|
||||
#ifndef GL_ARB_shader_viewport_layer_array
|
||||
#define GL_ARB_shader_viewport_layer_array 1
|
||||
#endif /* GL_ARB_shader_viewport_layer_array */
|
||||
|
||||
#ifndef GL_ARB_shading_language_100
|
||||
#define GL_ARB_shading_language_100 1
|
||||
#define GL_SHADING_LANGUAGE_VERSION_ARB 0x8B8C
|
||||
@@ -4269,14 +4119,6 @@ GLAPI void APIENTRY glTexPageCommitmentARB (GLenum target, GLint level, GLint xo
|
||||
#endif
|
||||
#endif /* GL_ARB_sparse_texture */
|
||||
|
||||
#ifndef GL_ARB_sparse_texture2
|
||||
#define GL_ARB_sparse_texture2 1
|
||||
#endif /* GL_ARB_sparse_texture2 */
|
||||
|
||||
#ifndef GL_ARB_sparse_texture_clamp
|
||||
#define GL_ARB_sparse_texture_clamp 1
|
||||
#endif /* GL_ARB_sparse_texture_clamp */
|
||||
|
||||
#ifndef GL_ARB_stencil_texturing
|
||||
#define GL_ARB_stencil_texturing 1
|
||||
#endif /* GL_ARB_stencil_texturing */
|
||||
@@ -4429,12 +4271,6 @@ GLAPI void APIENTRY glGetCompressedTexImageARB (GLenum target, GLint level, void
|
||||
#define GL_DOT3_RGBA_ARB 0x86AF
|
||||
#endif /* GL_ARB_texture_env_dot3 */
|
||||
|
||||
#ifndef GL_ARB_texture_filter_minmax
|
||||
#define GL_ARB_texture_filter_minmax 1
|
||||
#define GL_TEXTURE_REDUCTION_MODE_ARB 0x9366
|
||||
#define GL_WEIGHTED_AVERAGE_ARB 0x9367
|
||||
#endif /* GL_ARB_texture_filter_minmax */
|
||||
|
||||
#ifndef GL_ARB_texture_float
|
||||
#define GL_ARB_texture_float 1
|
||||
#define GL_TEXTURE_RED_TYPE_ARB 0x8C10
|
||||
@@ -4979,10 +4815,6 @@ GLAPI void APIENTRY glBlendBarrierKHR (void);
|
||||
#define GL_KHR_texture_compression_astc_ldr 1
|
||||
#endif /* GL_KHR_texture_compression_astc_ldr */
|
||||
|
||||
#ifndef GL_KHR_texture_compression_astc_sliced_3d
|
||||
#define GL_KHR_texture_compression_astc_sliced_3d 1
|
||||
#endif /* GL_KHR_texture_compression_astc_sliced_3d */
|
||||
|
||||
#ifndef GL_OES_byte_coordinates
|
||||
#define GL_OES_byte_coordinates 1
|
||||
typedef void (APIENTRYP PFNGLMULTITEXCOORD1BOESPROC) (GLenum texture, GLbyte s);
|
||||
@@ -5378,23 +5210,6 @@ GLAPI void APIENTRY glBlendEquationSeparateIndexedAMD (GLuint buf, GLenum modeRG
|
||||
#define GL_AMD_gcn_shader 1
|
||||
#endif /* GL_AMD_gcn_shader */
|
||||
|
||||
#ifndef GL_AMD_gpu_shader_half_float
|
||||
#define GL_AMD_gpu_shader_half_float 1
|
||||
#define GL_FLOAT16_NV 0x8FF8
|
||||
#define GL_FLOAT16_VEC2_NV 0x8FF9
|
||||
#define GL_FLOAT16_VEC3_NV 0x8FFA
|
||||
#define GL_FLOAT16_VEC4_NV 0x8FFB
|
||||
#define GL_FLOAT16_MAT2_AMD 0x91C5
|
||||
#define GL_FLOAT16_MAT3_AMD 0x91C6
|
||||
#define GL_FLOAT16_MAT4_AMD 0x91C7
|
||||
#define GL_FLOAT16_MAT2x3_AMD 0x91C8
|
||||
#define GL_FLOAT16_MAT2x4_AMD 0x91C9
|
||||
#define GL_FLOAT16_MAT3x2_AMD 0x91CA
|
||||
#define GL_FLOAT16_MAT3x4_AMD 0x91CB
|
||||
#define GL_FLOAT16_MAT4x2_AMD 0x91CC
|
||||
#define GL_FLOAT16_MAT4x3_AMD 0x91CD
|
||||
#endif /* GL_AMD_gpu_shader_half_float */
|
||||
|
||||
#ifndef GL_AMD_gpu_shader_int64
|
||||
#define GL_AMD_gpu_shader_int64 1
|
||||
typedef int64_t GLint64EXT;
|
||||
@@ -5422,6 +5237,10 @@ typedef int64_t GLint64EXT;
|
||||
#define GL_UNSIGNED_INT64_VEC2_NV 0x8FF5
|
||||
#define GL_UNSIGNED_INT64_VEC3_NV 0x8FF6
|
||||
#define GL_UNSIGNED_INT64_VEC4_NV 0x8FF7
|
||||
#define GL_FLOAT16_NV 0x8FF8
|
||||
#define GL_FLOAT16_VEC2_NV 0x8FF9
|
||||
#define GL_FLOAT16_VEC3_NV 0x8FFA
|
||||
#define GL_FLOAT16_VEC4_NV 0x8FFB
|
||||
typedef void (APIENTRYP PFNGLUNIFORM1I64NVPROC) (GLint location, GLint64EXT x);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM2I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y);
|
||||
typedef void (APIENTRYP PFNGLUNIFORM3I64NVPROC) (GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z);
|
||||
@@ -5609,14 +5428,6 @@ GLAPI void APIENTRY glSetMultisamplefvAMD (GLenum pname, GLuint index, const GLf
|
||||
#define GL_AMD_shader_atomic_counter_ops 1
|
||||
#endif /* GL_AMD_shader_atomic_counter_ops */
|
||||
|
||||
#ifndef GL_AMD_shader_ballot
|
||||
#define GL_AMD_shader_ballot 1
|
||||
#endif /* GL_AMD_shader_ballot */
|
||||
|
||||
#ifndef GL_AMD_shader_explicit_vertex_parameter
|
||||
#define GL_AMD_shader_explicit_vertex_parameter 1
|
||||
#endif /* GL_AMD_shader_explicit_vertex_parameter */
|
||||
|
||||
#ifndef GL_AMD_shader_stencil_export
|
||||
#define GL_AMD_shader_stencil_export 1
|
||||
#endif /* GL_AMD_shader_stencil_export */
|
||||
@@ -8657,20 +8468,6 @@ GLAPI void APIENTRY glVertexWeightPointerEXT (GLint size, GLenum type, GLsizei s
|
||||
#endif
|
||||
#endif /* GL_EXT_vertex_weighting */
|
||||
|
||||
#ifndef GL_EXT_window_rectangles
|
||||
#define GL_EXT_window_rectangles 1
|
||||
#define GL_INCLUSIVE_EXT 0x8F10
|
||||
#define GL_EXCLUSIVE_EXT 0x8F11
|
||||
#define GL_WINDOW_RECTANGLE_EXT 0x8F12
|
||||
#define GL_WINDOW_RECTANGLE_MODE_EXT 0x8F13
|
||||
#define GL_MAX_WINDOW_RECTANGLES_EXT 0x8F14
|
||||
#define GL_NUM_WINDOW_RECTANGLES_EXT 0x8F15
|
||||
typedef void (APIENTRYP PFNGLWINDOWRECTANGLESEXTPROC) (GLenum mode, GLsizei count, const GLint *box);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glWindowRectanglesEXT (GLenum mode, GLsizei count, const GLint *box);
|
||||
#endif
|
||||
#endif /* GL_EXT_window_rectangles */
|
||||
|
||||
#ifndef GL_EXT_x11_sync_object
|
||||
#define GL_EXT_x11_sync_object 1
|
||||
#define GL_SYNC_X11_FENCE_EXT 0x90E1
|
||||
@@ -8848,23 +8645,10 @@ GLAPI void APIENTRY glBlendFuncSeparateINGR (GLenum sfactorRGB, GLenum dfactorRG
|
||||
#define GL_INTERLACE_READ_INGR 0x8568
|
||||
#endif /* GL_INGR_interlace_read */
|
||||
|
||||
#ifndef GL_INTEL_conservative_rasterization
|
||||
#define GL_INTEL_conservative_rasterization 1
|
||||
#define GL_CONSERVATIVE_RASTERIZATION_INTEL 0x83FE
|
||||
#endif /* GL_INTEL_conservative_rasterization */
|
||||
|
||||
#ifndef GL_INTEL_fragment_shader_ordering
|
||||
#define GL_INTEL_fragment_shader_ordering 1
|
||||
#endif /* GL_INTEL_fragment_shader_ordering */
|
||||
|
||||
#ifndef GL_INTEL_framebuffer_CMAA
|
||||
#define GL_INTEL_framebuffer_CMAA 1
|
||||
typedef void (APIENTRYP PFNGLAPPLYFRAMEBUFFERATTACHMENTCMAAINTELPROC) (void);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glApplyFramebufferAttachmentCMAAINTEL (void);
|
||||
#endif
|
||||
#endif /* GL_INTEL_framebuffer_CMAA */
|
||||
|
||||
#ifndef GL_INTEL_map_texture
|
||||
#define GL_INTEL_map_texture 1
|
||||
#define GL_TEXTURE_MEMORY_LAYOUT_INTEL 0x83FF
|
||||
@@ -9169,17 +8953,6 @@ GLAPI void APIENTRY glBlendBarrierNV (void);
|
||||
#define GL_NV_blend_square 1
|
||||
#endif /* GL_NV_blend_square */
|
||||
|
||||
#ifndef GL_NV_clip_space_w_scaling
|
||||
#define GL_NV_clip_space_w_scaling 1
|
||||
#define GL_VIEWPORT_POSITION_W_SCALE_NV 0x937C
|
||||
#define GL_VIEWPORT_POSITION_W_SCALE_X_COEFF_NV 0x937D
|
||||
#define GL_VIEWPORT_POSITION_W_SCALE_Y_COEFF_NV 0x937E
|
||||
typedef void (APIENTRYP PFNGLVIEWPORTPOSITIONWSCALENVPROC) (GLuint index, GLfloat xcoeff, GLfloat ycoeff);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glViewportPositionWScaleNV (GLuint index, GLfloat xcoeff, GLfloat ycoeff);
|
||||
#endif
|
||||
#endif /* GL_NV_clip_space_w_scaling */
|
||||
|
||||
#ifndef GL_NV_command_list
|
||||
#define GL_NV_command_list 1
|
||||
#define GL_TERMINATE_SEQUENCE_COMMAND_NV 0x0000
|
||||
@@ -9271,28 +9044,6 @@ GLAPI void APIENTRY glSubpixelPrecisionBiasNV (GLuint xbits, GLuint ybits);
|
||||
#endif
|
||||
#endif /* GL_NV_conservative_raster */
|
||||
|
||||
#ifndef GL_NV_conservative_raster_dilate
|
||||
#define GL_NV_conservative_raster_dilate 1
|
||||
#define GL_CONSERVATIVE_RASTER_DILATE_NV 0x9379
|
||||
#define GL_CONSERVATIVE_RASTER_DILATE_RANGE_NV 0x937A
|
||||
#define GL_CONSERVATIVE_RASTER_DILATE_GRANULARITY_NV 0x937B
|
||||
typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERFNVPROC) (GLenum pname, GLfloat value);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glConservativeRasterParameterfNV (GLenum pname, GLfloat value);
|
||||
#endif
|
||||
#endif /* GL_NV_conservative_raster_dilate */
|
||||
|
||||
#ifndef GL_NV_conservative_raster_pre_snap_triangles
|
||||
#define GL_NV_conservative_raster_pre_snap_triangles 1
|
||||
#define GL_CONSERVATIVE_RASTER_MODE_NV 0x954D
|
||||
#define GL_CONSERVATIVE_RASTER_MODE_POST_SNAP_NV 0x954E
|
||||
#define GL_CONSERVATIVE_RASTER_MODE_PRE_SNAP_TRIANGLES_NV 0x954F
|
||||
typedef void (APIENTRYP PFNGLCONSERVATIVERASTERPARAMETERINVPROC) (GLenum pname, GLint param);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glConservativeRasterParameteriNV (GLenum pname, GLint param);
|
||||
#endif
|
||||
#endif /* GL_NV_conservative_raster_pre_snap_triangles */
|
||||
|
||||
#ifndef GL_NV_copy_depth_to_color
|
||||
#define GL_NV_copy_depth_to_color 1
|
||||
#define GL_DEPTH_STENCIL_TO_RGBA_NV 0x886E
|
||||
@@ -10285,11 +10036,6 @@ GLAPI void APIENTRY glGetCombinerStageParameterfvNV (GLenum stage, GLenum pname,
|
||||
#endif
|
||||
#endif /* GL_NV_register_combiners2 */
|
||||
|
||||
#ifndef GL_NV_robustness_video_memory_purge
|
||||
#define GL_NV_robustness_video_memory_purge 1
|
||||
#define GL_PURGED_CONTEXT_RESET_NV 0x92BB
|
||||
#endif /* GL_NV_robustness_video_memory_purge */
|
||||
|
||||
#ifndef GL_NV_sample_locations
|
||||
#define GL_NV_sample_locations 1
|
||||
#define GL_SAMPLE_LOCATION_SUBPIXEL_BITS_NV 0x933D
|
||||
@@ -10322,10 +10068,6 @@ GLAPI void APIENTRY glResolveDepthValuesNV (void);
|
||||
#define GL_NV_shader_atomic_float 1
|
||||
#endif /* GL_NV_shader_atomic_float */
|
||||
|
||||
#ifndef GL_NV_shader_atomic_float64
|
||||
#define GL_NV_shader_atomic_float64 1
|
||||
#endif /* GL_NV_shader_atomic_float64 */
|
||||
|
||||
#ifndef GL_NV_shader_atomic_fp16_vector
|
||||
#define GL_NV_shader_atomic_fp16_vector 1
|
||||
#endif /* GL_NV_shader_atomic_fp16_vector */
|
||||
@@ -10389,10 +10131,6 @@ GLAPI void APIENTRY glProgramUniformui64vNV (GLuint program, GLint location, GLs
|
||||
#define GL_NV_shader_thread_shuffle 1
|
||||
#endif /* GL_NV_shader_thread_shuffle */
|
||||
|
||||
#ifndef GL_NV_stereo_view_rendering
|
||||
#define GL_NV_stereo_view_rendering 1
|
||||
#endif /* GL_NV_stereo_view_rendering */
|
||||
|
||||
#ifndef GL_NV_tessellation_program5
|
||||
#define GL_NV_tessellation_program5 1
|
||||
#define GL_MAX_PROGRAM_PATCH_ATTRIBS_NV 0x86D8
|
||||
@@ -11163,26 +10901,6 @@ GLAPI void APIENTRY glVideoCaptureStreamParameterdvNV (GLuint video_capture_slot
|
||||
#define GL_NV_viewport_array2 1
|
||||
#endif /* GL_NV_viewport_array2 */
|
||||
|
||||
#ifndef GL_NV_viewport_swizzle
|
||||
#define GL_NV_viewport_swizzle 1
|
||||
#define GL_VIEWPORT_SWIZZLE_POSITIVE_X_NV 0x9350
|
||||
#define GL_VIEWPORT_SWIZZLE_NEGATIVE_X_NV 0x9351
|
||||
#define GL_VIEWPORT_SWIZZLE_POSITIVE_Y_NV 0x9352
|
||||
#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Y_NV 0x9353
|
||||
#define GL_VIEWPORT_SWIZZLE_POSITIVE_Z_NV 0x9354
|
||||
#define GL_VIEWPORT_SWIZZLE_NEGATIVE_Z_NV 0x9355
|
||||
#define GL_VIEWPORT_SWIZZLE_POSITIVE_W_NV 0x9356
|
||||
#define GL_VIEWPORT_SWIZZLE_NEGATIVE_W_NV 0x9357
|
||||
#define GL_VIEWPORT_SWIZZLE_X_NV 0x9358
|
||||
#define GL_VIEWPORT_SWIZZLE_Y_NV 0x9359
|
||||
#define GL_VIEWPORT_SWIZZLE_Z_NV 0x935A
|
||||
#define GL_VIEWPORT_SWIZZLE_W_NV 0x935B
|
||||
typedef void (APIENTRYP PFNGLVIEWPORTSWIZZLENVPROC) (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum swizzley, GLenum swizzlez, GLenum swizzlew);
|
||||
#endif
|
||||
#endif /* GL_NV_viewport_swizzle */
|
||||
|
||||
#ifndef GL_OML_interlace
|
||||
#define GL_OML_interlace 1
|
||||
#define GL_INTERLACE_OML 0x8980
|
||||
@@ -11210,7 +10928,6 @@ GLAPI void APIENTRY glViewportSwizzleNV (GLuint index, GLenum swizzlex, GLenum s
|
||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR 0x9630
|
||||
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR 0x9632
|
||||
#define GL_MAX_VIEWS_OVR 0x9631
|
||||
#define GL_FRAMEBUFFER_INCOMPLETE_VIEW_TARGETS_OVR 0x9633
|
||||
typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC) (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
#ifdef GL_GLEXT_PROTOTYPES
|
||||
GLAPI void APIENTRY glFramebufferTextureMultiviewOVR (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint baseViewIndex, GLsizei numViews);
|
||||
@@ -10,13 +10,10 @@ An open-source PlayStation 3 emulator/debugger written in C++.
|
||||
|
||||
You can find some basic information in the [FAQ](https://github.com/RPCS3/rpcs3/wiki/FAQ). For discussion about this emulator and PS3 emulation please visit the [official forums](http://www.emunewz.net/forum/forumdisplay.php?fid=162).
|
||||
|
||||
Official Discord server: https://discord.me/RPCS3
|
||||
|
||||
Support Nekotekina on Patreon: https://www.patreon.com/Nekotekina
|
||||
|
||||
### Development
|
||||
|
||||
If you want to contribute please take a look at the [Coding Style](https://github.com/RPCS3/rpcs3/wiki/Coding-Style), [Roadmap](https://github.com/RPCS3/rpcs3/wiki/Roadmap) and [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information) pages. You should as well contact any of the developers in the forum in order to know about the current situation of the emulator.
|
||||
If you want to contribute please take a took at the [Coding Style](https://github.com/RPCS3/rpcs3/wiki/Coding-Style), [Roadmap](https://github.com/RPCS3/rpcs3/wiki/Roadmap) and [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information) pages. You should as well contact any of the developers in the forum in order to know about the current situation of the emulator.
|
||||
|
||||
|
||||
### Dependencies
|
||||
@@ -24,47 +21,30 @@ If you want to contribute please take a look at the [Coding Style](https://githu
|
||||
__Windows__
|
||||
* [Visual Studio 2015](https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx)
|
||||
* [Visual C++ Redistributable Packages for Visual Studio 2015](http://www.microsoft.com/en-us/download/details.aspx?id=48145)
|
||||
* [Cmake 3.1.0+](http://www.cmake.org/download/) (required; add to PATH)
|
||||
* [Python 3.3+](https://www.python.org/downloads/) (required; add to PATH)
|
||||
* [Cmake 3.1.0+](http://www.cmake.org/download/) (optional, required only for LLVM build; add to PATH)
|
||||
* [Python](https://www.python.org/downloads/) (optional, required only for LLVM build; add to PATH)
|
||||
|
||||
__Linux__
|
||||
* GCC 5.1+ or Clang 3.5.0+ ([not GCC 6.1](https://github.com/RPCS3/rpcs3/issues/1691))
|
||||
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libopenal-dev libwxgtk3.0-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev git`
|
||||
* GCC 5.1+ or Clang 3.5.0+
|
||||
* Debian & Ubuntu: `sudo apt-get install libopenal-dev libwxgtk3.0-dev build-essential libglew-dev`
|
||||
* Arch: `sudo pacman -S glew openal wxgtk cmake llvm`
|
||||
|
||||
__Mac OSX__
|
||||
Mac OSX is not supported at this moment because it doesn't meet system requirements (OpenGL 4.3)
|
||||
* Xcode 6+ (tested with Xcode 6.4)
|
||||
* Install with Homebrew: `brew install glew wxwidgets`
|
||||
* Install with Homebrew: `brew install glew wxwidgets` (add `llvm36` to that list if you want to build with ppu jit)
|
||||
* Remove '-framework QuickTime' from '_ldflags' in /usr/local/bin/wx-config
|
||||
|
||||
|
||||
### Building
|
||||
|
||||
- __Windows__: </br>
|
||||
1) To initialize the repository don't forget to execute `git submodule update --init` to pull the submodules. </br>
|
||||
2) Open the *.SLN* file. </br>
|
||||
3) Build the projects in *__BUILD_BEFORE* folder: right-click on every project > *Build*. </br>
|
||||
4) Press *BUILD* > *Build Solution* or *Rebuild Solution*. </br>
|
||||
|
||||
- __Linux & Mac OSX__: </br>
|
||||
1) `git clone https://github.com/RPCS3/rpcs3.git` </br>
|
||||
2) `cd rpcs3/` </br>
|
||||
3) `git submodule update --init` </br>
|
||||
4) `cmake CMakeLists.txt && make GitVersion && make` </br>
|
||||
5) Run RPCS3 with `./bin/rpcs3` </br>
|
||||
|
||||
If you are on OSX and want to build with llvm don't forget to add `-DLLVM_DIR=...` (or wherever llvm brew was installed) to cmake invocation.
|
||||
|
||||
To initialize the repository don't forget to execute `git submodule update --init` to pull the wxWidgets source.
|
||||
* __Windows__:
|
||||
Open the *.SLN* file, and press *Build* > *Clean Solution*, then *Build Solution*. *Rebuild* may not work correctly.
|
||||
* __Linux & Mac OSX__:
|
||||
If you want to build with LLVM, then LLVM 3.6.2 is required.
|
||||
`cd rpcs3 && cmake CMakeLists.txt && make && cd ../` then run with `cd bin && ./rpcs3`.
|
||||
If you are on OSX and want to build with llvm don't forget to add `-DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake` (or wherever llvm brew was installed) to cmake invocation.
|
||||
When using GDB, configure it to ignore SIGSEGV signal (`handle SIGSEGV nostop noprint`).
|
||||
|
||||
##### CMake Build Options (Linux & Mac OSX)
|
||||
|
||||
- ```-DUSE_SYSTEM_LIBPNG=ON/OFF``` (default = *OFF*) </br>
|
||||
Build against the shared libpng instead of using the builtin one. libpng 1.6+ highly recommended. Try this option if you get version conflict errors or only see black game icons.
|
||||
|
||||
- ```-DUSE_SYSTEM_FFMPEG=ON/OFF``` (default = *OFF*) </br>
|
||||
Build against the shared ffmpeg libraries instead of using the builtin patched version. Try this if the builtin version breaks the OpenGL renderer for you.
|
||||
|
||||
### License
|
||||
|
||||
Most files are licensed under the terms of GNU GPLv2 License, see LICENSE file for details. Some files may be licensed differently, check appropriate file headers for details.
|
||||
### Support
|
||||
* [Donate by PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MPJ3S9XQXCE3G)
|
||||
|
||||
+603
-955
File diff suppressed because it is too large
Load Diff
@@ -1,150 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Atomic.h"
|
||||
#include <memory>
|
||||
|
||||
// Unfinished. Only std::default_delete will work as expected.
|
||||
template<typename T, typename D>
|
||||
class atomic_ptr_base : D
|
||||
{
|
||||
protected:
|
||||
atomic_t<T*> m_ptr;
|
||||
|
||||
constexpr atomic_ptr_base(T* ptr)
|
||||
: m_ptr(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
~atomic_ptr_base()
|
||||
{
|
||||
if (m_ptr)
|
||||
{
|
||||
(*this)(m_ptr.load());
|
||||
}
|
||||
}
|
||||
|
||||
D& get_deleter()
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
const D& get_deleter() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// Simple atomic pointer with unique ownership. Draft, unfinished.
|
||||
template<typename T, typename D = std::default_delete<T>>
|
||||
class atomic_ptr final : atomic_ptr_base<T, D>
|
||||
{
|
||||
using base = atomic_ptr_base<T, D>;
|
||||
|
||||
static_assert(sizeof(T*) == sizeof(base), "atomic_ptr<> error: invalid deleter (empty class expected)");
|
||||
|
||||
public:
|
||||
constexpr atomic_ptr()
|
||||
: base(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
constexpr atomic_ptr(std::nullptr_t)
|
||||
: base(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
explicit atomic_ptr(T* ptr)
|
||||
: base(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T2, typename = std::enable_if_t<std::is_convertible<T2, T>::value>>
|
||||
atomic_ptr(std::unique_ptr<T2, D>&& ptr)
|
||||
: base(ptr.release())
|
||||
{
|
||||
}
|
||||
|
||||
atomic_ptr& operator =(std::nullptr_t)
|
||||
{
|
||||
if (T* old = base::m_ptr.exchange(nullptr))
|
||||
{
|
||||
this->get_deleter()(old);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T2, typename = std::enable_if_t<std::is_convertible<T2, T>::value>>
|
||||
atomic_ptr& operator =(std::unique_ptr<T2, D>&& ptr)
|
||||
{
|
||||
if (T* old = base::m_ptr.exchange(ptr.release()))
|
||||
{
|
||||
this->get_deleter()(old);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(std::unique_ptr<T, D>& ptr)
|
||||
{
|
||||
ptr.reset(base::m_ptr.exchange(ptr.release()));
|
||||
}
|
||||
|
||||
std::add_lvalue_reference_t<T> operator *() const
|
||||
{
|
||||
return *base::m_ptr;
|
||||
}
|
||||
|
||||
T* operator ->() const
|
||||
{
|
||||
return base::m_ptr;
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return base::m_ptr;
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return base::m_ptr != nullptr;
|
||||
}
|
||||
|
||||
T* release() const
|
||||
{
|
||||
return base::m_ptr.exchange(0);
|
||||
}
|
||||
|
||||
void reset(T* ptr = nullptr)
|
||||
{
|
||||
if (T* old = base::m_ptr.exchange(ptr))
|
||||
{
|
||||
this->get_deleter()(old);
|
||||
}
|
||||
}
|
||||
|
||||
// Steal the pointer from `ptr`, convert old value to unique_ptr
|
||||
std::unique_ptr<T, D> exchange(std::unique_ptr<T, D>&& ptr)
|
||||
{
|
||||
return std::unique_ptr<T, D>(base::m_ptr.exchange(ptr.release()));
|
||||
}
|
||||
|
||||
// If pointer is null, steal it from `ptr`
|
||||
bool test_and_swap(std::unique_ptr<T, D>&& ptr)
|
||||
{
|
||||
if (base::m_ptr.compare_and_swap_test(nullptr, ptr.get()))
|
||||
{
|
||||
ptr.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename D>
|
||||
class atomic_ptr<T[], D> final : atomic_ptr_base<T[], D>
|
||||
{
|
||||
// TODO
|
||||
};
|
||||
+93
-43
@@ -1,29 +1,57 @@
|
||||
#include "stdafx.h"
|
||||
#include "Config.h"
|
||||
#include "Emu/System.h"
|
||||
#include "AutoPause.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/File.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/state.h"
|
||||
|
||||
cfg::bool_entry g_cfg_debug_autopause_syscall(cfg::root.misc, "Automatically pause at system call");
|
||||
cfg::bool_entry g_cfg_debug_autopause_func_call(cfg::root.misc, "Automatically pause at function call");
|
||||
using namespace Debug;
|
||||
|
||||
debug::autopause& debug::autopause::get_instance()
|
||||
std::unique_ptr<AutoPause> g_autopause;
|
||||
|
||||
AutoPause& AutoPause::getInstance(void)
|
||||
{
|
||||
// Use magic static
|
||||
static autopause instance;
|
||||
return instance;
|
||||
if (!g_autopause)
|
||||
{
|
||||
g_autopause.reset(new AutoPause);
|
||||
}
|
||||
|
||||
return *g_autopause;
|
||||
}
|
||||
|
||||
// Load Auto Pause Configuration from file "pause.bin"
|
||||
void debug::autopause::reload(void)
|
||||
//Still use binary format. Default Setting should be "disable all auto pause".
|
||||
AutoPause::AutoPause(void)
|
||||
{
|
||||
auto& instance = get_instance();
|
||||
m_pause_function.reserve(16);
|
||||
m_pause_syscall.reserve(16);
|
||||
initialized = false;
|
||||
//Reload(false, false);
|
||||
Reload();
|
||||
}
|
||||
|
||||
instance.m_pause_function.clear();
|
||||
instance.m_pause_syscall.clear();
|
||||
//Notice: I would not allow to write the binary to file in this command.
|
||||
AutoPause::~AutoPause(void)
|
||||
{
|
||||
initialized = false;
|
||||
m_pause_function.clear();
|
||||
m_pause_syscall.clear();
|
||||
m_pause_function_enable = false;
|
||||
m_pause_syscall_enable = false;
|
||||
}
|
||||
|
||||
// TODO: better format, possibly a config entry
|
||||
if (fs::file list{ fs::get_config_dir() + "pause.bin" })
|
||||
//Load Auto Pause Configuration from file "pause.bin"
|
||||
//This would be able to create in a GUI window.
|
||||
void AutoPause::Reload(void)
|
||||
{
|
||||
if (fs::is_file(fs::get_config_dir() + "pause.bin"))
|
||||
{
|
||||
m_pause_function.clear();
|
||||
m_pause_function.reserve(16);
|
||||
m_pause_syscall.clear();
|
||||
m_pause_syscall.reserve(16);
|
||||
|
||||
fs::file list(fs::get_config_dir() + "pause.bin");
|
||||
//System calls ID and Function calls ID are all u32 iirc.
|
||||
u32 num;
|
||||
size_t fmax = list.size();
|
||||
size_t fcur = 0;
|
||||
@@ -36,38 +64,60 @@ void debug::autopause::reload(void)
|
||||
|
||||
if (num < 1024)
|
||||
{
|
||||
instance.m_pause_syscall.emplace(num);
|
||||
LOG_WARNING(HLE, "Set autopause at syscall %lld", num);
|
||||
//Less than 1024 - be regarded as a system call.
|
||||
//emplace_back may not cause reductant move/copy operation.
|
||||
m_pause_syscall.emplace_back(num);
|
||||
LOG_WARNING(HLE, "Auto Pause: Find System Call ID 0x%x", num);
|
||||
}
|
||||
else
|
||||
{
|
||||
instance.m_pause_function.emplace(num);
|
||||
LOG_WARNING(HLE, "Set autopause at function 0x%08x", num);
|
||||
m_pause_function.emplace_back(num);
|
||||
LOG_WARNING(HLE, "Auto Pause: Find Function Call ID 0x%x", num);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_pause_syscall_enable = rpcs3::config.misc.debug.auto_pause_syscall.value();
|
||||
m_pause_function_enable = rpcs3::config.misc.debug.auto_pause_func_call.value();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void AutoPause::TryPause(u32 code)
|
||||
{
|
||||
if (code < 1024)
|
||||
{
|
||||
//Would first check Enable setting. Then the list length.
|
||||
if ((!m_pause_syscall_enable)
|
||||
|| (m_pause_syscall.size() <= 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m_pause_syscall.size(); ++i)
|
||||
{
|
||||
if (code == m_pause_syscall[i])
|
||||
{
|
||||
Emu.Pause();
|
||||
LOG_ERROR(HLE, "Auto Pause Triggered: System call 0x%x", code); // Used Error
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Well similiar.. Seperate the list caused by possible setting difference.
|
||||
if ((!m_pause_function_enable)
|
||||
|| (m_pause_function.size() <= 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m_pause_function.size(); ++i)
|
||||
{
|
||||
if (code == m_pause_function[i])
|
||||
{
|
||||
Emu.Pause();
|
||||
LOG_ERROR(HLE, "Auto Pause Triggered: Function call 0x%x", code); // Used Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool debug::autopause::pause_syscall(u64 code)
|
||||
{
|
||||
if (g_cfg_debug_autopause_syscall && get_instance().m_pause_syscall.count(code) != 0)
|
||||
{
|
||||
Emu.Pause();
|
||||
LOG_SUCCESS(HLE, "Autopause triggered at syscall %lld", code);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool debug::autopause::pause_function(u32 code)
|
||||
{
|
||||
if (g_cfg_debug_autopause_func_call && get_instance().m_pause_function.count(code) != 0)
|
||||
{
|
||||
Emu.Pause();
|
||||
LOG_SUCCESS(HLE, "Autopause triggered at function 0x%08x", code);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
+17
-15
@@ -1,22 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
// Regarded as a Debugger Enchantment
|
||||
namespace debug
|
||||
{
|
||||
// To store the pause function/call id, and let those pause there.
|
||||
// Would be with a GUI to configure those.
|
||||
class autopause
|
||||
//Regarded as a Debugger Enchantment
|
||||
namespace Debug {
|
||||
//To store the pause function/call id, and let those pause there.
|
||||
//Would be with a GUI to configure those.
|
||||
struct AutoPause
|
||||
{
|
||||
std::unordered_set<u64> m_pause_syscall;
|
||||
std::unordered_set<u32> m_pause_function;
|
||||
std::vector<u32> m_pause_syscall;
|
||||
std::vector<u32> m_pause_function;
|
||||
bool initialized;
|
||||
bool m_pause_syscall_enable;
|
||||
bool m_pause_function_enable;
|
||||
|
||||
static autopause& get_instance();
|
||||
AutoPause();
|
||||
~AutoPause();
|
||||
public:
|
||||
static AutoPause& getInstance(void);
|
||||
|
||||
static void reload();
|
||||
static bool pause_syscall(u64 code);
|
||||
static bool pause_function(u32 code);
|
||||
void Reload(void);
|
||||
|
||||
void TryPause(u32 code);
|
||||
};
|
||||
}
|
||||
}
|
||||
+425
-284
File diff suppressed because it is too large
Load Diff
+50
-187
@@ -1,106 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
template<typename T, uint N>
|
||||
struct bf_base
|
||||
// BitField access helper class (N bits from I position), intended to be put in union
|
||||
template<typename T, u32 I, u32 N> class bf_t
|
||||
{
|
||||
using type = T;
|
||||
using vtype = simple_t<type>;
|
||||
// Checks
|
||||
static_assert(I < sizeof(T) * 8, "bf_t<> error: I out of bounds");
|
||||
static_assert(N < sizeof(T) * 8, "bf_t<> error: N out of bounds");
|
||||
static_assert(I + N <= sizeof(T) * 8, "bf_t<> error: values out of bounds");
|
||||
|
||||
// Datatype bitsize
|
||||
static constexpr uint bitmax = sizeof(T) * 8; static_assert(N - 1 < bitmax, "bf_base<> error: N out of bounds");
|
||||
|
||||
// Field bitsize
|
||||
static constexpr uint bitsize = N;
|
||||
// Underlying data type
|
||||
using type = typename std::remove_cv<T>::type;
|
||||
|
||||
// Value mask
|
||||
static constexpr vtype vmask = static_cast<vtype>(~std::make_unsigned_t<vtype>{} >> (bitmax - bitsize));
|
||||
// Underlying value type (native endianness)
|
||||
using vtype = typename to_ne<type>::type;
|
||||
|
||||
protected:
|
||||
// Mask of size N
|
||||
constexpr static vtype s_mask = (static_cast<vtype>(1) << N) - 1;
|
||||
|
||||
// Underlying data member
|
||||
type m_data;
|
||||
};
|
||||
|
||||
// Bitfield accessor (N bits from I position, 0 is LSB)
|
||||
template<typename T, uint I, uint N>
|
||||
struct bf_t : bf_base<T, N>
|
||||
{
|
||||
using type = typename bf_t::type;
|
||||
using vtype = typename bf_t::vtype;
|
||||
// Conversion operator helper (uses SFINAE)
|
||||
template<typename T2, typename = void> struct converter {};
|
||||
|
||||
// Field offset
|
||||
static constexpr uint bitpos = I; static_assert(bitpos + N <= bf_t::bitmax, "bf_t<> error: I out of bounds");
|
||||
|
||||
// Get bitmask of size N, at I pos
|
||||
static constexpr vtype data_mask()
|
||||
{
|
||||
return bf_t::vmask << bitpos;
|
||||
}
|
||||
|
||||
// Bitfield extraction helper
|
||||
template<typename T2, typename = void>
|
||||
struct extract_impl
|
||||
{
|
||||
static_assert(!sizeof(T2), "bf_t<> error: Invalid type");
|
||||
};
|
||||
|
||||
template<typename T2>
|
||||
struct extract_impl<T2, std::enable_if_t<std::is_unsigned<T2>::value>>
|
||||
template<typename T2> struct converter<T2, std::enable_if_t<std::is_unsigned<T2>::value>>
|
||||
{
|
||||
// Load unsigned value
|
||||
static constexpr T2 extract(const T& data)
|
||||
static inline T2 convert(const type& data)
|
||||
{
|
||||
return (data >> bitpos) & bf_t::vmask;
|
||||
return (data >> I) & s_mask;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T2>
|
||||
struct extract_impl<T2, std::enable_if_t<std::is_signed<T2>::value>>
|
||||
template<typename T2> struct converter<T2, std::enable_if_t<std::is_signed<T2>::value>>
|
||||
{
|
||||
// Load signed value (sign-extended)
|
||||
static constexpr T2 extract(const T& data)
|
||||
static inline T2 convert(const type& data)
|
||||
{
|
||||
return data << (bf_t::bitmax - bitpos - N) >> (bf_t::bitmax - N);
|
||||
return data << (sizeof(T) * 8 - I - N) >> (sizeof(T) * 8 - N);
|
||||
}
|
||||
};
|
||||
|
||||
// Bitfield extraction
|
||||
static constexpr vtype extract(const T& data)
|
||||
public:
|
||||
// Assignment operator (store bitfield value)
|
||||
bf_t& operator =(vtype value)
|
||||
{
|
||||
return extract_impl<vtype>::extract(data);
|
||||
m_data = (m_data & ~(s_mask << I)) | (value & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Bitfield insertion
|
||||
static constexpr vtype insert(vtype value)
|
||||
// Conversion operator (load bitfield value)
|
||||
operator vtype() const
|
||||
{
|
||||
return (value & bf_t::vmask) << bitpos;
|
||||
return converter<vtype>::convert(m_data);
|
||||
}
|
||||
|
||||
// Load bitfield value
|
||||
constexpr operator vtype() const
|
||||
// Get raw data with mask applied
|
||||
type unshifted() const
|
||||
{
|
||||
return extract(this->m_data);
|
||||
return (m_data & (s_mask << I));
|
||||
}
|
||||
|
||||
// Load raw data with mask applied
|
||||
constexpr T unshifted() const
|
||||
{
|
||||
return this->m_data & data_mask();
|
||||
}
|
||||
|
||||
// Optimized bool conversion (must be removed if inappropriate)
|
||||
explicit constexpr operator bool() const
|
||||
// Optimized bool conversion
|
||||
explicit operator bool() const
|
||||
{
|
||||
return unshifted() != 0;
|
||||
}
|
||||
|
||||
// Store bitfield value
|
||||
bf_t& operator =(vtype value)
|
||||
{
|
||||
this->m_data = (this->m_data & ~data_mask()) | insert(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Postfix increment operator
|
||||
vtype operator ++(int)
|
||||
{
|
||||
vtype result = *this;
|
||||
@@ -108,11 +75,13 @@ struct bf_t : bf_base<T, N>
|
||||
return result;
|
||||
}
|
||||
|
||||
// Prefix increment operator
|
||||
bf_t& operator ++()
|
||||
{
|
||||
return *this = *this + 1;
|
||||
}
|
||||
|
||||
// Postfix decrement operator
|
||||
vtype operator --(int)
|
||||
{
|
||||
vtype result = *this;
|
||||
@@ -120,158 +89,52 @@ struct bf_t : bf_base<T, N>
|
||||
return result;
|
||||
}
|
||||
|
||||
// Prefix decrement operator
|
||||
bf_t& operator --()
|
||||
{
|
||||
return *this = *this - 1;
|
||||
}
|
||||
|
||||
// Addition assignment operator
|
||||
bf_t& operator +=(vtype right)
|
||||
{
|
||||
return *this = *this + right;
|
||||
}
|
||||
|
||||
// Subtraction assignment operator
|
||||
bf_t& operator -=(vtype right)
|
||||
{
|
||||
return *this = *this - right;
|
||||
}
|
||||
|
||||
// Multiplication assignment operator
|
||||
bf_t& operator *=(vtype right)
|
||||
{
|
||||
return *this = *this * right;
|
||||
}
|
||||
|
||||
// Bitwise AND assignment operator
|
||||
bf_t& operator &=(vtype right)
|
||||
{
|
||||
this->m_data &= (right & bf_t::vmask) << bitpos;
|
||||
m_data &= (right & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Bitwise OR assignment operator
|
||||
bf_t& operator |=(vtype right)
|
||||
{
|
||||
this->m_data |= (right & bf_t::vmask) << bitpos;
|
||||
m_data |= (right & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Bitwise XOR assignment operator
|
||||
bf_t& operator ^=(vtype right)
|
||||
{
|
||||
this->m_data ^= (right & bf_t::vmask) << bitpos;
|
||||
m_data ^= (right & s_mask) << I;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// Field pack (concatenated from left to right)
|
||||
template<typename F = void, typename... Fields>
|
||||
struct cf_t : bf_base<typename F::type, F::bitsize + cf_t<Fields...>::bitsize>
|
||||
{
|
||||
using type = typename cf_t::type;
|
||||
using vtype = typename cf_t::vtype;
|
||||
template<typename T, u32 I, u32 N> using bf_be_t = bf_t<be_t<T>, I, N>;
|
||||
|
||||
// Get disjunction of all "data" masks of concatenated values
|
||||
static constexpr vtype data_mask()
|
||||
{
|
||||
return F::data_mask() | cf_t<Fields...>::data_mask();
|
||||
}
|
||||
|
||||
// Extract all bitfields and concatenate
|
||||
static constexpr vtype extract(const type& data)
|
||||
{
|
||||
return F::extract(data) << cf_t<Fields...>::bitsize | cf_t<Fields...>::extract(data);
|
||||
}
|
||||
|
||||
// Split bitfields and insert them
|
||||
static constexpr vtype insert(vtype value)
|
||||
{
|
||||
return F::insert(value >> cf_t<Fields...>::bitsize) | cf_t<Fields...>::insert(value);
|
||||
}
|
||||
|
||||
// Load value
|
||||
constexpr operator vtype() const
|
||||
{
|
||||
return extract(this->m_data);
|
||||
}
|
||||
|
||||
// Store value
|
||||
cf_t& operator =(vtype value)
|
||||
{
|
||||
this->m_data = (this->m_data & ~data_mask()) | insert(value);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// Empty field pack (recursion terminator)
|
||||
template<>
|
||||
struct cf_t<void>
|
||||
{
|
||||
static constexpr uint bitsize = 0;
|
||||
|
||||
static constexpr uint data_mask()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr auto extract(const T& data) -> decltype(+T())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static constexpr T insert(T value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Fixed field (provides constant values in field pack)
|
||||
template<typename T, T V, uint N>
|
||||
struct ff_t : bf_base<T, N>
|
||||
{
|
||||
using type = typename ff_t::type;
|
||||
using vtype = typename ff_t::vtype;
|
||||
|
||||
// Return constant value
|
||||
static constexpr vtype extract(const type& data)
|
||||
{
|
||||
static_assert((V & ff_t::vmask) == V, "ff_t<> error: V out of bounds");
|
||||
return V;
|
||||
}
|
||||
|
||||
// Get value
|
||||
operator vtype() const
|
||||
{
|
||||
return V;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, uint I, uint N>
|
||||
struct fmt_unveil<bf_t<T, I, N>, void>
|
||||
{
|
||||
using type = typename fmt_unveil<simple_t<T>>::type;
|
||||
|
||||
static inline auto get(const bf_t<T, I, N>& bf)
|
||||
{
|
||||
return fmt_unveil<type>::get(bf);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F, typename... Fields>
|
||||
struct fmt_unveil<cf_t<F, Fields...>, void>
|
||||
{
|
||||
using type = typename fmt_unveil<simple_t<typename F::type>>::type;
|
||||
|
||||
static inline auto get(const cf_t<F, Fields...>& cf)
|
||||
{
|
||||
return fmt_unveil<type>::get(cf);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, T V, uint N>
|
||||
struct fmt_unveil<ff_t<T, V, N>, void>
|
||||
{
|
||||
using type = typename fmt_unveil<simple_t<T>>::type;
|
||||
|
||||
static inline auto get(const ff_t<T, V, N>& ff)
|
||||
{
|
||||
return fmt_unveil<type>::get(ff);
|
||||
}
|
||||
};
|
||||
template<typename T, u32 I, u32 N> using bf_le_t = bf_t<le_t<T>, I, N>;
|
||||
|
||||
@@ -1,269 +0,0 @@
|
||||
#include "stdafx.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include "yaml-cpp/yaml.h"
|
||||
|
||||
namespace cfg
|
||||
{
|
||||
logs::channel cfg("CFG", logs::level::notice);
|
||||
|
||||
entry_base::entry_base(type _type)
|
||||
: m_type(_type)
|
||||
{
|
||||
if (_type != type::node)
|
||||
{
|
||||
fmt::throw_exception<std::logic_error>("Invalid root node" HERE);
|
||||
}
|
||||
}
|
||||
|
||||
entry_base::entry_base(type _type, node& owner, const std::string& name)
|
||||
: m_type(_type)
|
||||
{
|
||||
if (!owner.m_nodes.emplace(name, this).second)
|
||||
{
|
||||
fmt::throw_exception<std::logic_error>("Node already exists: %s" HERE, name);
|
||||
}
|
||||
}
|
||||
|
||||
entry_base& entry_base::operator[](const std::string& name) const
|
||||
{
|
||||
if (m_type == type::node)
|
||||
{
|
||||
return *static_cast<const node&>(*this).m_nodes.at(name);
|
||||
}
|
||||
|
||||
fmt::throw_exception<std::logic_error>("Invalid node type" HERE);
|
||||
}
|
||||
|
||||
entry_base& entry_base::operator[](const char* name) const
|
||||
{
|
||||
if (m_type == type::node)
|
||||
{
|
||||
return *static_cast<const node&>(*this).m_nodes.at(name);
|
||||
}
|
||||
|
||||
fmt::throw_exception<std::logic_error>("Invalid node type" HERE);
|
||||
}
|
||||
|
||||
bool entry_base::from_string(const std::string&)
|
||||
{
|
||||
fmt::throw_exception<std::logic_error>("from_string() purecall" HERE);
|
||||
}
|
||||
|
||||
bool entry_base::from_list(std::vector<std::string>&&)
|
||||
{
|
||||
fmt::throw_exception<std::logic_error>("from_list() purecall" HERE);
|
||||
}
|
||||
|
||||
// Emit YAML
|
||||
static void encode(YAML::Emitter& out, const class entry_base& rhs);
|
||||
|
||||
// Incrementally load config entries from YAML::Node.
|
||||
// The config value is preserved if the corresponding YAML node doesn't exist.
|
||||
static void decode(const YAML::Node& data, class entry_base& rhs);
|
||||
}
|
||||
|
||||
bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
|
||||
{
|
||||
// TODO: this could be rewritten without exceptions (but it should be as safe as possible and provide logs)
|
||||
s64 result;
|
||||
std::size_t pos;
|
||||
|
||||
try
|
||||
{
|
||||
result = std::stoll(value, &pos, 0 /* Auto-detect numeric base */);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
if (out) cfg.error("cfg::try_to_int('%s'): exception: %s", value, e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pos != value.size())
|
||||
{
|
||||
if (out) cfg.error("cfg::try_to_int('%s'): unexpected characters (pos=%zu)", value, pos);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (result < min || result > max)
|
||||
{
|
||||
if (out) cfg.error("cfg::try_to_int('%s'): out of bounds (%lld..%lld)", value, min, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out) *out = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string& value)
|
||||
{
|
||||
for (u64 i = 0;; i++)
|
||||
{
|
||||
std::string var;
|
||||
func(var, i);
|
||||
|
||||
if (var == value)
|
||||
{
|
||||
if (out) *out = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string hex;
|
||||
fmt_class_string<u64>::format(hex, i);
|
||||
if (var == hex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const auto val = std::stoull(value, nullptr, 0);
|
||||
|
||||
if (out) *out = val;
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> cfg::try_to_enum_list(decltype(&fmt_class_string<int>::format) func)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
for (u64 i = 0;; i++)
|
||||
{
|
||||
std::string var;
|
||||
func(var, i);
|
||||
|
||||
std::string hex;
|
||||
fmt_class_string<u64>::format(hex, i);
|
||||
if (var == hex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
result.emplace_back(std::move(var));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void cfg::encode(YAML::Emitter& out, const cfg::entry_base& rhs)
|
||||
{
|
||||
switch (rhs.get_type())
|
||||
{
|
||||
case type::node:
|
||||
{
|
||||
out << YAML::BeginMap;
|
||||
for (const auto& np : static_cast<const node&>(rhs).get_nodes())
|
||||
{
|
||||
out << YAML::Key << np.first;
|
||||
out << YAML::Value; encode(out, *np.second);
|
||||
}
|
||||
|
||||
out << YAML::EndMap;
|
||||
return;
|
||||
}
|
||||
case type::set:
|
||||
{
|
||||
out << YAML::BeginSeq;
|
||||
for (const auto& str : static_cast<const set_entry&>(rhs).get_set())
|
||||
{
|
||||
out << str;
|
||||
}
|
||||
|
||||
out << YAML::EndSeq;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
out << rhs.to_string();
|
||||
}
|
||||
|
||||
void cfg::decode(const YAML::Node& data, cfg::entry_base& rhs)
|
||||
{
|
||||
switch (rhs.get_type())
|
||||
{
|
||||
case type::node:
|
||||
{
|
||||
if (data.IsScalar() || data.IsSequence())
|
||||
{
|
||||
return; // ???
|
||||
}
|
||||
|
||||
for (const auto& pair : data)
|
||||
{
|
||||
if (!pair.first.IsScalar()) continue;
|
||||
|
||||
// Find the key among existing nodes
|
||||
const auto name = pair.first.Scalar();
|
||||
const auto found = static_cast<node&>(rhs).get_nodes().find(name);
|
||||
|
||||
if (found != static_cast<node&>(rhs).get_nodes().cend())
|
||||
{
|
||||
decode(pair.second, *found->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ???
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case type::set:
|
||||
{
|
||||
std::vector<std::string> values;
|
||||
|
||||
if (YAML::convert<decltype(values)>::decode(data, values))
|
||||
{
|
||||
rhs.from_list(std::move(values));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
std::string value;
|
||||
|
||||
if (YAML::convert<std::string>::decode(data, value))
|
||||
{
|
||||
rhs.from_string(value);
|
||||
}
|
||||
|
||||
break; // ???
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string cfg::node::to_string() const
|
||||
{
|
||||
YAML::Emitter out;
|
||||
cfg::encode(out, *this);
|
||||
|
||||
return{ out.c_str(), out.size() };
|
||||
}
|
||||
|
||||
bool cfg::node::from_string(const std::string& value)
|
||||
{
|
||||
cfg::decode(YAML::Load(value), *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cfg::node::from_default()
|
||||
{
|
||||
for (auto& node : m_nodes)
|
||||
{
|
||||
node.second->from_default();
|
||||
}
|
||||
}
|
||||
|
||||
cfg::root_node& cfg::get_root()
|
||||
{
|
||||
// Magic static
|
||||
static root_node root;
|
||||
return root;
|
||||
}
|
||||
@@ -1,520 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Utilities/types.h"
|
||||
#include "Utilities/Atomic.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
|
||||
#include <initializer_list>
|
||||
#include <exception>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
namespace cfg
|
||||
{
|
||||
// Convert string to signed integer
|
||||
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max);
|
||||
|
||||
// Internal hack
|
||||
bool try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string&);
|
||||
|
||||
// Internal hack
|
||||
std::vector<std::string> try_to_enum_list(decltype(&fmt_class_string<int>::format) func);
|
||||
|
||||
// Config tree entry type.
|
||||
enum class type : uint
|
||||
{
|
||||
node = 0, // cfg::node type
|
||||
boolean, // cfg::bool_entry type
|
||||
fixed_map, // cfg::map_entry type
|
||||
enumeration, // cfg::enum_entry type
|
||||
integer, // cfg::int_entry type
|
||||
string, // cfg::string_entry type
|
||||
set, // cfg::set_entry type
|
||||
};
|
||||
|
||||
// Config tree entry abstract base class
|
||||
class entry_base
|
||||
{
|
||||
const type m_type;
|
||||
|
||||
protected:
|
||||
// Ownerless entry constructor
|
||||
entry_base(type _type);
|
||||
|
||||
// Owned entry constructor
|
||||
entry_base(type _type, class node& owner, const std::string& name);
|
||||
|
||||
public:
|
||||
// Disallow copy/move constructors and assignments
|
||||
entry_base(const entry_base&) = delete;
|
||||
|
||||
// Get type
|
||||
type get_type() const { return m_type; }
|
||||
|
||||
// Access child node (must exist)
|
||||
entry_base& operator [](const std::string& name) const; entry_base& operator [](const char* name) const;
|
||||
|
||||
// Reset defaults
|
||||
virtual void from_default() = 0;
|
||||
|
||||
// Convert to string (optional)
|
||||
virtual std::string to_string() const
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
// Try to convert from string (optional)
|
||||
virtual bool from_string(const std::string&);
|
||||
|
||||
// Get string list (optional)
|
||||
virtual std::vector<std::string> to_list() const
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
// Set multiple values. Implementation-specific, optional.
|
||||
virtual bool from_list(std::vector<std::string>&&);
|
||||
};
|
||||
|
||||
// Config tree node which contains another nodes
|
||||
class node : public entry_base
|
||||
{
|
||||
std::map<std::string, entry_base*> m_nodes;
|
||||
|
||||
friend class entry_base;
|
||||
|
||||
public:
|
||||
// Root node constructor
|
||||
node()
|
||||
: entry_base(type::node)
|
||||
{
|
||||
}
|
||||
|
||||
// Registered node constructor
|
||||
node(node& owner, const std::string& name)
|
||||
: entry_base(type::node, owner, name)
|
||||
{
|
||||
}
|
||||
|
||||
// Get child nodes
|
||||
const std::map<std::string, entry_base*>& get_nodes() const
|
||||
{
|
||||
return m_nodes;
|
||||
}
|
||||
|
||||
// Serialize node
|
||||
std::string to_string() const override;
|
||||
|
||||
// Deserialize node
|
||||
bool from_string(const std::string& value) override;
|
||||
|
||||
// Set default values
|
||||
void from_default() override;
|
||||
};
|
||||
|
||||
struct bool_entry final : public entry_base
|
||||
{
|
||||
atomic_t<bool> value;
|
||||
|
||||
const bool def;
|
||||
|
||||
bool_entry(node& owner, const std::string& name, bool def = false)
|
||||
: entry_base(type::boolean, owner, name)
|
||||
, value(def)
|
||||
, def(def)
|
||||
{
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return value.load();
|
||||
}
|
||||
|
||||
bool_entry& operator =(bool value)
|
||||
{
|
||||
value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
value = def;
|
||||
}
|
||||
|
||||
std::string to_string() const override
|
||||
{
|
||||
return value.load() ? "true" : "false";
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value) override
|
||||
{
|
||||
if (value == "false")
|
||||
this->value = false;
|
||||
else if (value == "true")
|
||||
this->value = true;
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Value node with fixed set of possible values, each maps to a value of type T.
|
||||
template<typename T>
|
||||
struct map_entry final : public entry_base
|
||||
{
|
||||
using init_type = std::initializer_list<std::pair<std::string, T>>;
|
||||
using map_type = std::unordered_map<std::string, T>;
|
||||
using list_type = std::vector<std::string>;
|
||||
using value_type = typename map_type::value_type;
|
||||
|
||||
static map_type make_map(init_type init)
|
||||
{
|
||||
map_type map(init.size());
|
||||
|
||||
for (const auto& v : init)
|
||||
{
|
||||
// Ensure elements are unique
|
||||
verify(HERE), map.emplace(v.first, v.second).second;
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static list_type make_list(init_type init)
|
||||
{
|
||||
list_type list; list.reserve(init.size());
|
||||
|
||||
for (const auto& v : init)
|
||||
{
|
||||
list.emplace_back(v.first);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public:
|
||||
const map_type map;
|
||||
const list_type list; // Element list sorted in original order
|
||||
const value_type& def; // Pointer to the default value
|
||||
|
||||
private:
|
||||
atomic_t<const value_type*> m_value;
|
||||
|
||||
public:
|
||||
map_entry(node& owner, const std::string& name, const std::string& def, init_type init)
|
||||
: entry_base(type::fixed_map, owner, name)
|
||||
, map(make_map(init))
|
||||
, list(make_list(init))
|
||||
, def(*map.find(def))
|
||||
, m_value(&this->def)
|
||||
{
|
||||
}
|
||||
|
||||
map_entry(node& owner, const std::string& name, std::size_t def_index, init_type init)
|
||||
: map_entry(owner, name, (init.begin() + (def_index < init.size() ? def_index : 0))->first, init)
|
||||
{
|
||||
}
|
||||
|
||||
map_entry(node& owner, const std::string& name, init_type init)
|
||||
: map_entry(owner, name, 0, init)
|
||||
{
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
{
|
||||
return m_value.load()->second;
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
m_value = &def;
|
||||
}
|
||||
|
||||
std::string to_string() const override
|
||||
{
|
||||
return m_value.load()->first;
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value) override
|
||||
{
|
||||
const auto found = map.find(value);
|
||||
|
||||
if (found == map.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_value = &*found;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> to_list() const override
|
||||
{
|
||||
return list;
|
||||
}
|
||||
};
|
||||
|
||||
// Value node with fixed set of possible values, each maps to an enum value of type T.
|
||||
template<typename T, bool External = false>
|
||||
class enum_entry final : public entry_base
|
||||
{
|
||||
// Value or reference
|
||||
std::conditional_t<External, atomic_t<T>&, atomic_t<T>> m_value;
|
||||
|
||||
public:
|
||||
const T def;
|
||||
|
||||
enum_entry(node& owner, const std::string& name, std::conditional_t<External, atomic_t<T>&, T> value)
|
||||
: entry_base(type::enumeration, owner, name)
|
||||
, m_value(value)
|
||||
, def(value)
|
||||
{
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return m_value.load();
|
||||
}
|
||||
|
||||
enum_entry& operator =(T value)
|
||||
{
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
m_value = def;
|
||||
}
|
||||
|
||||
std::string to_string() const override
|
||||
{
|
||||
std::string result;
|
||||
fmt_class_string<T>::format(result, fmt_unveil<T>::get(m_value));
|
||||
return result; // TODO: ???
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value) override
|
||||
{
|
||||
u64 result;
|
||||
|
||||
if (try_to_enum_value(&result, &fmt_class_string<T>::format, value))
|
||||
{
|
||||
// No narrowing check, it's hard to do right there
|
||||
m_value = static_cast<T>(static_cast<std::underlying_type_t<T>>(result));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> to_list() const override
|
||||
{
|
||||
return try_to_enum_list(&fmt_class_string<T>::format);
|
||||
}
|
||||
};
|
||||
|
||||
// Signed 32/64-bit integer entry with custom Min/Max range.
|
||||
template<s64 Min, s64 Max>
|
||||
class int_entry final : public entry_base
|
||||
{
|
||||
static_assert(Min < Max, "Invalid cfg::int_entry range");
|
||||
|
||||
// Prefer 32 bit type if possible
|
||||
using int_type = std::conditional_t<Min >= INT32_MIN && Max <= INT32_MAX, s32, s64>;
|
||||
|
||||
atomic_t<int_type> m_value;
|
||||
|
||||
public:
|
||||
const int_type def;
|
||||
|
||||
int_entry(node& owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)))
|
||||
: entry_base(type::integer, owner, name)
|
||||
, m_value(def)
|
||||
, def(def)
|
||||
{
|
||||
}
|
||||
|
||||
operator int_type() const
|
||||
{
|
||||
return m_value.load();
|
||||
}
|
||||
|
||||
int_entry& operator =(int_type value)
|
||||
{
|
||||
if (value < Min || value > Max)
|
||||
{
|
||||
fmt::throw_exception("Value out of the valid range: %lld" HERE, s64{ value });
|
||||
}
|
||||
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
m_value = def;
|
||||
}
|
||||
|
||||
std::string to_string() const override
|
||||
{
|
||||
return std::to_string(m_value.load());
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value) override
|
||||
{
|
||||
s64 result;
|
||||
if (try_to_int64(&result, value, Min, Max))
|
||||
{
|
||||
m_value = static_cast<int_type>(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Alias for 32 bit int
|
||||
using int32_entry = int_entry<INT32_MIN, INT32_MAX>;
|
||||
|
||||
// Alias for 64 bit int
|
||||
using int64_entry = int_entry<INT64_MIN, INT64_MAX>;
|
||||
|
||||
// Simple string entry with mutex
|
||||
class string_entry final : public entry_base
|
||||
{
|
||||
mutable std::mutex m_mutex;
|
||||
std::string m_value;
|
||||
|
||||
public:
|
||||
const std::string def;
|
||||
|
||||
string_entry(node& owner, const std::string& name, const std::string& def = {})
|
||||
: entry_base(type::string, owner, name)
|
||||
, m_value(def)
|
||||
, def(def)
|
||||
{
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::string get() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
string_entry& operator =(const std::string& value)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_value.size();
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
*this = def;
|
||||
}
|
||||
|
||||
std::string to_string() const override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool from_string(const std::string& value) override
|
||||
{
|
||||
*this = value;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Simple set entry with mutex (TODO: template for various types)
|
||||
class set_entry final : public entry_base
|
||||
{
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
std::set<std::string> m_set;
|
||||
|
||||
public:
|
||||
// Default value is empty list in current implementation
|
||||
set_entry(node& owner, const std::string& name)
|
||||
: entry_base(type::set, owner, name)
|
||||
{
|
||||
}
|
||||
|
||||
std::set<std::string> get_set() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
return m_set;
|
||||
}
|
||||
|
||||
void set_set(std::set<std::string>&& set)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_set = std::move(set);
|
||||
}
|
||||
|
||||
void from_default() override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_set = {};
|
||||
}
|
||||
|
||||
std::vector<std::string> to_list() const override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
return{ m_set.begin(), m_set.end() };
|
||||
}
|
||||
|
||||
bool from_list(std::vector<std::string>&& list) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) };
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Root type with some predefined nodes. Don't change it, this is not mandatory for adding nodes.
|
||||
struct root_node : node
|
||||
{
|
||||
node core { *this, "Core" };
|
||||
node vfs { *this, "VFS" };
|
||||
node log { *this, "Log" };
|
||||
node video { *this, "Video" };
|
||||
node audio { *this, "Audio" };
|
||||
node io { *this, "Input/Output" };
|
||||
node sys { *this, "System" };
|
||||
node net { *this, "Net" };
|
||||
node misc { *this, "Miscellaneous" };
|
||||
};
|
||||
|
||||
// Get global configuration root instance
|
||||
extern root_node& get_root();
|
||||
|
||||
// Global configuration root instance (cached reference)
|
||||
static root_node& root = get_root();
|
||||
}
|
||||
|
||||
// Registered log channel
|
||||
#define LOG_CHANNEL(name) extern logs::channel name; namespace logs { static cfg::enum_entry<logs::level, true> name(cfg::root.log, #name, ::name.enabled); }
|
||||
+568
-800
File diff suppressed because it is too large
Load Diff
+194
-239
@@ -1,49 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "bit_set.h"
|
||||
namespace fom // file open mode
|
||||
{
|
||||
enum open_mode : u32
|
||||
{
|
||||
read = 1 << 0, // enable reading
|
||||
write = 1 << 1, // enable writing
|
||||
append = 1 << 2, // enable appending (always write to the end of file)
|
||||
create = 1 << 3, // create file if it doesn't exist
|
||||
trunc = 1 << 4, // clear opened file if it's not empty
|
||||
excl = 1 << 5, // failure if the file already exists (used with `create`)
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
rewrite = write | create | trunc,
|
||||
};
|
||||
};
|
||||
|
||||
namespace fs
|
||||
{
|
||||
// File open mode flags
|
||||
enum class open_mode : u32
|
||||
{
|
||||
read,
|
||||
write,
|
||||
append,
|
||||
create,
|
||||
trunc,
|
||||
excl,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
|
||||
constexpr auto read = +open_mode::read; // Enable reading
|
||||
constexpr auto write = +open_mode::write; // Enable writing
|
||||
constexpr auto append = +open_mode::append; // Always append to the end of the file
|
||||
constexpr auto create = +open_mode::create; // Create file if it doesn't exist
|
||||
constexpr auto trunc = +open_mode::trunc; // Clear opened file if it's not empty
|
||||
constexpr auto excl = +open_mode::excl; // Failure if the file already exists (used with `create`)
|
||||
|
||||
constexpr auto rewrite = open_mode::write + open_mode::create + open_mode::trunc;
|
||||
|
||||
// File seek mode
|
||||
enum class seek_mode : u32
|
||||
enum seek_mode : u32 // file seek mode
|
||||
{
|
||||
seek_set,
|
||||
seek_cur,
|
||||
seek_end,
|
||||
};
|
||||
|
||||
constexpr auto seek_set = seek_mode::seek_set; // From beginning
|
||||
constexpr auto seek_cur = seek_mode::seek_cur; // From current position
|
||||
constexpr auto seek_end = seek_mode::seek_end; // From end
|
||||
|
||||
// File attributes (TODO)
|
||||
struct stat_t
|
||||
{
|
||||
bool is_directory;
|
||||
@@ -54,57 +34,7 @@ namespace fs
|
||||
s64 ctime;
|
||||
};
|
||||
|
||||
// File handle base
|
||||
struct file_base
|
||||
{
|
||||
virtual ~file_base() = default;
|
||||
|
||||
virtual stat_t stat() = 0;
|
||||
virtual bool trunc(u64 length) = 0;
|
||||
virtual u64 read(void* buffer, u64 size) = 0;
|
||||
virtual u64 write(const void* buffer, u64 size) = 0;
|
||||
virtual u64 seek(s64 offset, seek_mode whence) = 0;
|
||||
virtual u64 size() = 0;
|
||||
};
|
||||
|
||||
// Directory entry (TODO)
|
||||
struct dir_entry : stat_t
|
||||
{
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// Directory handle base
|
||||
struct dir_base
|
||||
{
|
||||
virtual ~dir_base() = default;
|
||||
|
||||
virtual bool read(dir_entry&) = 0;
|
||||
virtual void rewind() = 0;
|
||||
};
|
||||
|
||||
// Virtual device
|
||||
struct device_base
|
||||
{
|
||||
virtual ~device_base() = default;
|
||||
|
||||
virtual bool stat(const std::string& path, stat_t& info) = 0;
|
||||
virtual bool remove_dir(const std::string& path) = 0;
|
||||
virtual bool create_dir(const std::string& path) = 0;
|
||||
virtual bool rename(const std::string& from, const std::string& to) = 0;
|
||||
virtual bool remove(const std::string& path) = 0;
|
||||
virtual bool trunc(const std::string& path, u64 length) = 0;
|
||||
|
||||
virtual std::unique_ptr<file_base> open(const std::string& path, bs_t<open_mode> mode) = 0;
|
||||
virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
|
||||
};
|
||||
|
||||
// Get virtual device for specified path (nullptr for real path)
|
||||
std::shared_ptr<device_base> get_virtual_device(const std::string& path);
|
||||
|
||||
// Set virtual device with specified name (nullptr for deletion)
|
||||
std::shared_ptr<device_base> set_virtual_device(const std::string& root_name, const std::shared_ptr<device_base>&);
|
||||
|
||||
// Try to get parent directory (returns empty string on failure)
|
||||
// Get parent directory for the path (returns empty string on failure)
|
||||
std::string get_parent_dir(const std::string& path);
|
||||
|
||||
// Get file information
|
||||
@@ -142,102 +72,77 @@ namespace fs
|
||||
|
||||
class file final
|
||||
{
|
||||
std::unique_ptr<file_base> m_file;
|
||||
using handle_type = std::intptr_t;
|
||||
|
||||
[[noreturn]] void xnull() const;
|
||||
[[noreturn]] void xfail() const;
|
||||
constexpr static handle_type null = -1;
|
||||
|
||||
handle_type m_fd = null;
|
||||
|
||||
friend class file_read_map;
|
||||
friend class file_write_map;
|
||||
|
||||
public:
|
||||
// Default constructor
|
||||
file() = default;
|
||||
|
||||
// Open file with specified mode
|
||||
explicit file(const std::string& path, bs_t<open_mode> mode = ::fs::read)
|
||||
explicit file(const std::string& path, u32 mode = fom::read)
|
||||
{
|
||||
open(path, mode);
|
||||
}
|
||||
|
||||
// Open file with specified mode
|
||||
bool open(const std::string& path, bs_t<open_mode> mode = ::fs::read);
|
||||
file(file&& other)
|
||||
: m_fd(other.m_fd)
|
||||
{
|
||||
other.m_fd = null;
|
||||
}
|
||||
|
||||
// Open memory for read
|
||||
explicit file(const void* ptr, std::size_t size);
|
||||
file& operator =(file&& right)
|
||||
{
|
||||
std::swap(m_fd, right.m_fd);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~file();
|
||||
|
||||
// Check whether the handle is valid (opened file)
|
||||
bool is_opened() const
|
||||
{
|
||||
return m_fd != null;
|
||||
}
|
||||
|
||||
// Check whether the handle is valid (opened file)
|
||||
explicit operator bool() const
|
||||
{
|
||||
return m_file.operator bool();
|
||||
return is_opened();
|
||||
}
|
||||
|
||||
// Close the file explicitly
|
||||
void close()
|
||||
{
|
||||
m_file.reset();
|
||||
}
|
||||
|
||||
void reset(std::unique_ptr<file_base>&& ptr)
|
||||
{
|
||||
m_file = std::move(ptr);
|
||||
}
|
||||
|
||||
std::unique_ptr<file_base> release()
|
||||
{
|
||||
return std::move(m_file);
|
||||
}
|
||||
// Open specified file with specified mode
|
||||
bool open(const std::string& path, u32 mode = fom::read);
|
||||
|
||||
// Change file size (possibly appending zero bytes)
|
||||
bool trunc(u64 length) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
return m_file->trunc(length);
|
||||
}
|
||||
bool trunc(u64 size) const;
|
||||
|
||||
// Get file information
|
||||
stat_t stat() const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
return m_file->stat();
|
||||
}
|
||||
bool stat(stat_t& info) const;
|
||||
|
||||
// Close the file explicitly (destructor automatically closes the file)
|
||||
void close();
|
||||
|
||||
// Read the data from the file and return the amount of data written in buffer
|
||||
u64 read(void* buffer, u64 count) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
return m_file->read(buffer, count);
|
||||
}
|
||||
u64 read(void* buffer, u64 count) const;
|
||||
|
||||
// Write the data to the file and return the amount of data actually written
|
||||
u64 write(const void* buffer, u64 count) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
return m_file->write(buffer, count);
|
||||
}
|
||||
u64 write(const void* buffer, u64 count) const;
|
||||
|
||||
// Change current position, returns resulting position
|
||||
u64 seek(s64 offset, seek_mode whence = seek_set) const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
return m_file->seek(offset, whence);
|
||||
}
|
||||
// Move file pointer
|
||||
u64 seek(s64 offset, seek_mode whence = seek_set) const;
|
||||
|
||||
// Get file size
|
||||
u64 size() const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
return m_file->size();
|
||||
}
|
||||
|
||||
// Get current position
|
||||
u64 pos() const
|
||||
{
|
||||
if (!m_file) xnull();
|
||||
return m_file->seek(0, seek_cur);
|
||||
}
|
||||
u64 size() const;
|
||||
|
||||
// Write std::string unconditionally
|
||||
const file& write(const std::string& str) const
|
||||
{
|
||||
if (write(str.data(), str.size()) != str.size()) xfail();
|
||||
CHECK_ASSERTION(write(str.data(), str.size()) == str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -245,7 +150,7 @@ namespace fs
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const
|
||||
{
|
||||
if (write(std::addressof(data), sizeof(T)) != sizeof(T)) xfail();
|
||||
CHECK_ASSERTION(write(std::addressof(data), sizeof(T)) == sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -253,7 +158,7 @@ namespace fs
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const std::vector<T>& vec) const
|
||||
{
|
||||
if (write(vec.data(), vec.size() * sizeof(T)) != vec.size() * sizeof(T)) xfail();
|
||||
CHECK_ASSERTION(write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -263,13 +168,6 @@ namespace fs
|
||||
return read(&str[0], str.size()) == str.size();
|
||||
}
|
||||
|
||||
// Read std::string
|
||||
bool read(std::string& str, std::size_t size) const
|
||||
{
|
||||
str.resize(size);
|
||||
return read(&str[0], size) == size;
|
||||
}
|
||||
|
||||
// Read POD, sizeof(T) is used
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(T& data) const
|
||||
@@ -284,20 +182,12 @@ namespace fs
|
||||
return read(vec.data(), sizeof(T) * vec.size()) == sizeof(T) * vec.size();
|
||||
}
|
||||
|
||||
// Read POD std::vector
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(std::vector<T>& vec, std::size_t size) const
|
||||
{
|
||||
vec.resize(size);
|
||||
return read(vec.data(), sizeof(T) * size) == sizeof(T) * size;
|
||||
}
|
||||
|
||||
// Read POD (experimental)
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const
|
||||
{
|
||||
T result;
|
||||
if (!read(result)) xfail();
|
||||
CHECK_ASSERTION(read(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -306,79 +196,164 @@ namespace fs
|
||||
{
|
||||
std::string result;
|
||||
result.resize(size());
|
||||
if (seek(0), !read(result)) xfail();
|
||||
CHECK_ASSERTION(seek(0) != -1 && read(result));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Read full file to std::vector
|
||||
template<typename T>
|
||||
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, std::vector<T>> to_vector() const
|
||||
// TODO
|
||||
class file_read_map final
|
||||
{
|
||||
char* m_ptr = nullptr;
|
||||
u64 m_size;
|
||||
|
||||
public:
|
||||
file_read_map() = default;
|
||||
|
||||
file_read_map(file_read_map&& right)
|
||||
: m_ptr(right.m_ptr)
|
||||
, m_size(right.m_size)
|
||||
{
|
||||
std::vector<T> result;
|
||||
result.resize(size() / sizeof(T));
|
||||
if (seek(0), !read(result)) xfail();
|
||||
return result;
|
||||
right.m_ptr = 0;
|
||||
}
|
||||
|
||||
file_read_map& operator =(file_read_map&& right)
|
||||
{
|
||||
std::swap(m_ptr, right.m_ptr);
|
||||
std::swap(m_size, right.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_read_map(const file& f)
|
||||
{
|
||||
reset(f);
|
||||
}
|
||||
|
||||
~file_read_map()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Open file mapping
|
||||
void reset(const file& f);
|
||||
|
||||
// Close file mapping
|
||||
void reset();
|
||||
|
||||
// Get pointer
|
||||
operator const char*() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO
|
||||
class file_write_map final
|
||||
{
|
||||
char* m_ptr = nullptr;
|
||||
u64 m_size;
|
||||
|
||||
public:
|
||||
file_write_map() = default;
|
||||
|
||||
file_write_map(file_write_map&& right)
|
||||
: m_ptr(right.m_ptr)
|
||||
, m_size(right.m_size)
|
||||
{
|
||||
right.m_ptr = 0;
|
||||
}
|
||||
|
||||
file_write_map& operator =(file_write_map&& right)
|
||||
{
|
||||
std::swap(m_ptr, right.m_ptr);
|
||||
std::swap(m_size, right.m_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
file_write_map(const file& f)
|
||||
{
|
||||
reset(f);
|
||||
}
|
||||
|
||||
~file_write_map()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// Open file mapping
|
||||
void reset(const file& f);
|
||||
|
||||
// Close file mapping
|
||||
void reset();
|
||||
|
||||
// Get pointer
|
||||
operator char*() const
|
||||
{
|
||||
return m_ptr;
|
||||
}
|
||||
};
|
||||
|
||||
class dir final
|
||||
{
|
||||
std::unique_ptr<dir_base> m_dir;
|
||||
|
||||
[[noreturn]] void xnull() const;
|
||||
std::unique_ptr<char[]> m_path;
|
||||
std::intptr_t m_dd; // handle (aux)
|
||||
|
||||
public:
|
||||
dir() = default;
|
||||
|
||||
// Open dir handle
|
||||
explicit dir(const std::string& path)
|
||||
explicit dir(const std::string& dirname)
|
||||
{
|
||||
open(path);
|
||||
open(dirname);
|
||||
}
|
||||
|
||||
// Open specified directory
|
||||
bool open(const std::string& path);
|
||||
dir(dir&& other)
|
||||
: m_dd(other.m_dd)
|
||||
, m_path(std::move(other.m_path))
|
||||
{
|
||||
}
|
||||
|
||||
dir& operator =(dir&& right)
|
||||
{
|
||||
std::swap(m_dd, right.m_dd);
|
||||
std::swap(m_path, right.m_path);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~dir();
|
||||
|
||||
// Check whether the handle is valid (opened directory)
|
||||
bool is_opened() const
|
||||
{
|
||||
return m_path.operator bool();
|
||||
}
|
||||
|
||||
// Check whether the handle is valid (opened directory)
|
||||
explicit operator bool() const
|
||||
{
|
||||
return m_dir.operator bool();
|
||||
return is_opened();
|
||||
}
|
||||
|
||||
// Close the directory explicitly
|
||||
void close()
|
||||
{
|
||||
m_dir.reset();
|
||||
}
|
||||
|
||||
void reset(std::unique_ptr<dir_base>&& ptr)
|
||||
{
|
||||
m_dir = std::move(ptr);
|
||||
}
|
||||
// Open specified directory
|
||||
bool open(const std::string& dirname);
|
||||
|
||||
std::unique_ptr<dir_base> release()
|
||||
{
|
||||
return std::move(m_dir);
|
||||
}
|
||||
// Close the directory explicitly (destructor automatically closes the directory)
|
||||
void close();
|
||||
|
||||
// Get next directory entry
|
||||
bool read(dir_entry& out) const
|
||||
{
|
||||
if (!m_dir) xnull();
|
||||
return m_dir->read(out);
|
||||
}
|
||||
// Get next directory entry (UTF-8 name and file stat)
|
||||
bool read(std::string& name, stat_t& info);
|
||||
|
||||
// Reset to the beginning
|
||||
void rewind() const
|
||||
bool first(std::string& name, stat_t& info);
|
||||
|
||||
struct entry
|
||||
{
|
||||
if (!m_dir) xnull();
|
||||
return m_dir->rewind();
|
||||
}
|
||||
std::string name;
|
||||
stat_t info;
|
||||
};
|
||||
|
||||
class iterator
|
||||
{
|
||||
entry m_entry;
|
||||
dir* m_parent;
|
||||
dir_entry m_entry;
|
||||
|
||||
public:
|
||||
enum class mode
|
||||
@@ -397,16 +372,20 @@ namespace fs
|
||||
|
||||
if (mode_ == mode::from_first)
|
||||
{
|
||||
m_parent->rewind();
|
||||
m_parent->first(m_entry.name, m_entry.info);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_parent->read(m_entry.name, m_entry.info);
|
||||
}
|
||||
|
||||
if (!m_parent->read(m_entry))
|
||||
if (m_entry.name.empty())
|
||||
{
|
||||
m_parent = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
dir_entry& operator *()
|
||||
entry& operator *()
|
||||
{
|
||||
return m_entry;
|
||||
}
|
||||
@@ -425,7 +404,7 @@ namespace fs
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return{ m_dir ? this : nullptr };
|
||||
return{ this };
|
||||
}
|
||||
|
||||
iterator end()
|
||||
@@ -439,28 +418,4 @@ namespace fs
|
||||
|
||||
// Get executable directory
|
||||
const std::string& get_executable_dir();
|
||||
|
||||
// Get data/cache directory for specified prefix and suffix
|
||||
std::string get_data_dir(const std::string& prefix, const std::string& location, const std::string& suffix);
|
||||
|
||||
// Get data/cache directory for specified prefix and path (suffix will be filename)
|
||||
std::string get_data_dir(const std::string& prefix, const std::string& path);
|
||||
|
||||
// Delete directory and all its contents recursively
|
||||
void remove_all(const std::string& path, bool remove_root = true);
|
||||
|
||||
// Get size of all files recursively
|
||||
u64 get_dir_size(const std::string& path);
|
||||
|
||||
enum class error : uint
|
||||
{
|
||||
ok = 0,
|
||||
|
||||
inval,
|
||||
noent,
|
||||
exist,
|
||||
};
|
||||
|
||||
// Error code returned
|
||||
extern thread_local error g_tls_error;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "GNU.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sys/types.h>
|
||||
#include <sys/_types/_timespec.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/clock.h>
|
||||
#include <mach/mach_time.h>
|
||||
#undef CPU_STATE_MAX
|
||||
|
||||
#define MT_NANO (+1.0E-9)
|
||||
#define MT_GIGA UINT64_C(1000000000)
|
||||
|
||||
// TODO create a list of timers,
|
||||
static double mt_timebase = 0.0;
|
||||
static uint64_t mt_timestart = 0;
|
||||
|
||||
// TODO be more careful in a multithreaded environement
|
||||
int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||
{
|
||||
kern_return_t retval = KERN_SUCCESS;
|
||||
if( clk_id == TIMER_ABSTIME)
|
||||
{
|
||||
if (!mt_timestart) { // only one timer, initilized on the first call to the TIMER
|
||||
mach_timebase_info_data_t tb = { 0 };
|
||||
mach_timebase_info(&tb);
|
||||
mt_timebase = tb.numer;
|
||||
mt_timebase /= tb.denom;
|
||||
mt_timestart = mach_absolute_time();
|
||||
}
|
||||
|
||||
double diff = (mach_absolute_time() - mt_timestart) * mt_timebase;
|
||||
tp->tv_sec = diff * MT_NANO;
|
||||
tp->tv_nsec = diff - (tp->tv_sec * MT_GIGA);
|
||||
}
|
||||
else // other clk_ids are mapped to the coresponding mach clock_service
|
||||
{
|
||||
clock_serv_t cclock;
|
||||
mach_timespec_t mts;
|
||||
|
||||
host_get_clock_service(mach_host_self(), clk_id, &cclock);
|
||||
retval = clock_get_time(cclock, &mts);
|
||||
mach_port_deallocate(mach_task_self(), cclock);
|
||||
|
||||
tp->tv_sec = mts.tv_sec;
|
||||
tp->tv_nsec = mts.tv_nsec;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
#pragma once
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
#define thread_local __declspec(thread)
|
||||
#elif __APPLE__
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define never_inline __declspec(noinline)
|
||||
#else
|
||||
#define never_inline __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define safe_buffers __declspec(safebuffers)
|
||||
#else
|
||||
#define safe_buffers
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define force_inline __forceinline
|
||||
#else
|
||||
#define force_inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
#define alignas(x) _CRT_ALIGN(x)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUG__)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <cstdint>
|
||||
|
||||
#define _fpclass(x) std::fpclassify(x)
|
||||
#define INFINITE 0xFFFFFFFF
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
// XXX only supports a single timer
|
||||
#define TIMER_ABSTIME -1
|
||||
/* The opengroup spec isn't clear on the mapping from REALTIME to CALENDAR
|
||||
being appropriate or not.
|
||||
http://pubs.opengroup.org/onlinepubs/009695299/basedefs/time.h.html */
|
||||
#define CLOCK_REALTIME 1 // #define CALENDAR_CLOCK 1 from mach/clock_types.h
|
||||
#define CLOCK_MONOTONIC 0 // #define SYSTEM_CLOCK 0
|
||||
|
||||
typedef int clockid_t;
|
||||
|
||||
/* the mach kernel uses struct mach_timespec, so struct timespec
|
||||
is loaded from <sys/_types/_timespec.h> for compatability */
|
||||
// struct timespec { time_t tv_sec; long tv_nsec; };
|
||||
|
||||
int clock_gettime(clockid_t clk_id, struct timespec *tp);
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
#endif /* __GNUG__ */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
// Unsigned 128-bit integer implementation
|
||||
struct alignas(16) u128
|
||||
{
|
||||
std::uint64_t lo, hi;
|
||||
|
||||
u128() = default;
|
||||
|
||||
u128(const u128&) = default;
|
||||
|
||||
u128(std::uint64_t l)
|
||||
: lo(l)
|
||||
, hi(0)
|
||||
{
|
||||
}
|
||||
|
||||
u128 operator +(const u128& r) const
|
||||
{
|
||||
u128 value;
|
||||
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
friend u128 operator +(const u128& l, std::uint64_t r)
|
||||
{
|
||||
u128 value;
|
||||
_addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
friend u128 operator +(std::uint64_t l, const u128& r)
|
||||
{
|
||||
u128 value;
|
||||
_addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator -(const u128& r) const
|
||||
{
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
friend u128 operator -(const u128& l, std::uint64_t r)
|
||||
{
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
friend u128 operator -(std::uint64_t l, const u128& r)
|
||||
{
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator +() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
u128 operator -() const
|
||||
{
|
||||
u128 value;
|
||||
_subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
u128& operator ++()
|
||||
{
|
||||
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
u128 operator ++(int)
|
||||
{
|
||||
u128 value = *this;
|
||||
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
u128& operator --()
|
||||
{
|
||||
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
u128 operator --(int)
|
||||
{
|
||||
u128 value = *this;
|
||||
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator ~() const
|
||||
{
|
||||
u128 value;
|
||||
value.lo = ~lo;
|
||||
value.hi = ~hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator &(const u128& r) const
|
||||
{
|
||||
u128 value;
|
||||
value.lo = lo & r.lo;
|
||||
value.hi = hi & r.hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator |(const u128& r) const
|
||||
{
|
||||
u128 value;
|
||||
value.lo = lo | r.lo;
|
||||
value.hi = hi | r.hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
u128 operator ^(const u128& r) const
|
||||
{
|
||||
u128 value;
|
||||
value.lo = lo ^ r.lo;
|
||||
value.hi = hi ^ r.hi;
|
||||
return value;
|
||||
}
|
||||
|
||||
u128& operator +=(const u128& r)
|
||||
{
|
||||
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
u128& operator +=(uint64_t r)
|
||||
{
|
||||
_addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi);
|
||||
return *this;
|
||||
}
|
||||
|
||||
u128& operator &=(const u128& r)
|
||||
{
|
||||
lo &= r.lo;
|
||||
hi &= r.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
u128& operator |=(const u128& r)
|
||||
{
|
||||
lo |= r.lo;
|
||||
hi |= r.hi;
|
||||
return *this;
|
||||
}
|
||||
|
||||
u128& operator ^=(const u128& r)
|
||||
{
|
||||
lo ^= r.lo;
|
||||
hi ^= r.hi;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
inline std::uint32_t cntlz32(std::uint32_t arg)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
unsigned long res;
|
||||
return _BitScanReverse(&res, arg) ? res ^ 31 : 32;
|
||||
#else
|
||||
return arg ? __builtin_clzll(arg) - 32 : 32;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::uint64_t cntlz64(std::uint64_t arg)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
unsigned long res;
|
||||
return _BitScanReverse64(&res, arg) ? res ^ 63 : 64;
|
||||
#else
|
||||
return arg ? __builtin_clzll(arg) : 64;
|
||||
#endif
|
||||
}
|
||||
|
||||
// compare 16 packed unsigned bytes (greater than)
|
||||
inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B)
|
||||
{
|
||||
// (A xor 0x80) > (B xor 0x80)
|
||||
const auto sign = _mm_set1_epi32(0x80808080);
|
||||
return _mm_cmpgt_epi8(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
|
||||
}
|
||||
|
||||
inline __m128i sse_cmpgt_epu16(__m128i A, __m128i B)
|
||||
{
|
||||
const auto sign = _mm_set1_epi32(0x80008000);
|
||||
return _mm_cmpgt_epi16(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
|
||||
}
|
||||
|
||||
inline __m128i sse_cmpgt_epu32(__m128i A, __m128i B)
|
||||
{
|
||||
const auto sign = _mm_set1_epi32(0x80000000);
|
||||
return _mm_cmpgt_epi32(_mm_xor_si128(A, sign), _mm_xor_si128(B, sign));
|
||||
}
|
||||
|
||||
inline __m128 sse_exp2_ps(__m128 A)
|
||||
{
|
||||
const auto x0 = _mm_max_ps(_mm_min_ps(A, _mm_set1_ps(127.4999961f)), _mm_set1_ps(-127.4999961f));
|
||||
const auto x1 = _mm_add_ps(x0, _mm_set1_ps(0.5f));
|
||||
const auto x2 = _mm_sub_epi32(_mm_cvtps_epi32(x1), _mm_and_si128(_mm_castps_si128(_mm_cmpnlt_ps(_mm_setzero_ps(), x1)), _mm_set1_epi32(1)));
|
||||
const auto x3 = _mm_sub_ps(x0, _mm_cvtepi32_ps(x2));
|
||||
const auto x4 = _mm_mul_ps(x3, x3);
|
||||
const auto x5 = _mm_mul_ps(x3, _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(x4, _mm_set1_ps(0.023093347705f)), _mm_set1_ps(20.20206567f)), x4), _mm_set1_ps(1513.906801f)));
|
||||
const auto x6 = _mm_mul_ps(x5, _mm_rcp_ps(_mm_sub_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(233.1842117f), x4), _mm_set1_ps(4368.211667f)), x5)));
|
||||
return _mm_mul_ps(_mm_add_ps(_mm_add_ps(x6, x6), _mm_set1_ps(1.0f)), _mm_castsi128_ps(_mm_slli_epi32(_mm_add_epi32(x2, _mm_set1_epi32(127)), 23)));
|
||||
}
|
||||
|
||||
inline __m128 sse_log2_ps(__m128 A)
|
||||
{
|
||||
const auto _1 = _mm_set1_ps(1.0f);
|
||||
const auto _c = _mm_set1_ps(1.442695040f);
|
||||
const auto x0 = _mm_max_ps(A, _mm_castsi128_ps(_mm_set1_epi32(0x00800000)));
|
||||
const auto x1 = _mm_or_ps(_mm_and_ps(x0, _mm_castsi128_ps(_mm_set1_epi32(0x807fffff))), _1);
|
||||
const auto x2 = _mm_rcp_ps(_mm_add_ps(x1, _1));
|
||||
const auto x3 = _mm_mul_ps(_mm_sub_ps(x1, _1), x2);
|
||||
const auto x4 = _mm_add_ps(x3, x3);
|
||||
const auto x5 = _mm_mul_ps(x4, x4);
|
||||
const auto x6 = _mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-0.7895802789f), x5), _mm_set1_ps(16.38666457f)), x5), _mm_set1_ps(-64.1409953f));
|
||||
const auto x7 = _mm_rcp_ps(_mm_add_ps(_mm_mul_ps(_mm_add_ps(_mm_mul_ps(_mm_set1_ps(-35.67227983f), x5), _mm_set1_ps(312.0937664f)), x5), _mm_set1_ps(-769.6919436f)));
|
||||
const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127)));
|
||||
return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8));
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#define GSL_THROW_ON_CONTRACT_VIOLATION
|
||||
|
||||
#pragma push_macro("new")
|
||||
#undef new
|
||||
#include <gsl.h>
|
||||
#pragma pop_macro("new")
|
||||
#undef Expects
|
||||
#undef Ensures
|
||||
@@ -1,345 +0,0 @@
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <unordered_set>
|
||||
#include <set>
|
||||
#include <array>
|
||||
|
||||
#include "types.h"
|
||||
#include "StrFmt.h"
|
||||
#include "File.h"
|
||||
#include "Log.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/FormattedStream.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/ExecutionEngine/RTDyldMemoryManager.h"
|
||||
#include "llvm/ExecutionEngine/JITEventListener.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "JIT.h"
|
||||
|
||||
// Global LLVM context (thread-unsafe)
|
||||
llvm::LLVMContext g_llvm_ctx;
|
||||
|
||||
// Size of virtual memory area reserved: 512 MB
|
||||
static const u64 s_memory_size = 0x20000000;
|
||||
|
||||
// Try to reserve a portion of virtual memory in the first 2 GB address space beforehand, if possible.
|
||||
static void* const s_memory = []() -> void*
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for (u64 addr = 0x10000000; addr <= 0x60000000; addr += 0x1000000)
|
||||
{
|
||||
if (VirtualAlloc((void*)addr, s_memory_size, MEM_RESERVE, PAGE_NOACCESS))
|
||||
{
|
||||
return (void*)addr;
|
||||
}
|
||||
}
|
||||
|
||||
return VirtualAlloc(NULL, s_memory_size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
#else
|
||||
return ::mmap((void*)0x10000000, s_memory_size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
#endif
|
||||
}();
|
||||
|
||||
// Code section
|
||||
static u8* s_code_addr;
|
||||
static u64 s_code_size;
|
||||
|
||||
// EH frames
|
||||
static u8* s_unwind_info;
|
||||
static u64 s_unwind_size;
|
||||
|
||||
#ifdef _WIN32
|
||||
static std::vector<RUNTIME_FUNCTION> s_unwind; // Custom .pdata section replacement
|
||||
#endif
|
||||
|
||||
// Helper class
|
||||
struct MemoryManager final : llvm::RTDyldMemoryManager
|
||||
{
|
||||
std::unordered_map<std::string, std::uintptr_t> table;
|
||||
|
||||
MemoryManager(std::unordered_map<std::string, std::uintptr_t>&& table)
|
||||
: table(std::move(table))
|
||||
{
|
||||
}
|
||||
|
||||
[[noreturn]] static void null()
|
||||
{
|
||||
fmt::throw_exception("Null function" HERE);
|
||||
}
|
||||
|
||||
virtual u64 getSymbolAddress(const std::string& name) override
|
||||
{
|
||||
if (u64 addr = RTDyldMemoryManager::getSymbolAddress(name))
|
||||
{
|
||||
// This may be bad if LLVM requests some built-in functions like fma.
|
||||
LOG_ERROR(GENERAL, "LLVM: Symbol requested %s -> 0x%016llx", name, addr);
|
||||
return addr;
|
||||
}
|
||||
|
||||
const auto found = table.find(name);
|
||||
|
||||
if (found != table.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
|
||||
// It's fine if some function is never called, for example.
|
||||
LOG_ERROR(GENERAL, "LLVM: Linkage failed for %s", name);
|
||||
return (u64)null;
|
||||
}
|
||||
|
||||
virtual u8* allocateCodeSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name) override
|
||||
{
|
||||
// Simple allocation
|
||||
const u64 next = ::align((u64)m_next + size, 4096);
|
||||
|
||||
if (next > (u64)s_memory + s_memory_size)
|
||||
{
|
||||
LOG_FATAL(GENERAL, "LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!VirtualAlloc(m_next, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
|
||||
#else
|
||||
if (::mprotect(m_next, size, PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
#endif
|
||||
{
|
||||
LOG_FATAL(GENERAL, "LLVM: Failed to allocate memory at %p", m_next);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
s_code_addr = (u8*)m_next;
|
||||
s_code_size = size;
|
||||
|
||||
LOG_SUCCESS(GENERAL, "LLVM: Code section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x)", sec_id, sec_name.data(), m_next, size, align);
|
||||
return (u8*)std::exchange(m_next, (void*)next);
|
||||
}
|
||||
|
||||
virtual u8* allocateDataSection(std::uintptr_t size, uint align, uint sec_id, llvm::StringRef sec_name, bool is_ro) override
|
||||
{
|
||||
// Simple allocation
|
||||
const u64 next = ::align((u64)m_next + size, 4096);
|
||||
|
||||
if (next > (u64)s_memory + s_memory_size)
|
||||
{
|
||||
LOG_FATAL(GENERAL, "LLVM: Out of memory (size=0x%llx, aligned 0x%x)", size, align);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!is_ro)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "LLVM: Writeable data section not supported!");
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!VirtualAlloc(m_next, size, MEM_COMMIT, PAGE_READWRITE))
|
||||
#else
|
||||
if (::mprotect(m_next, size, PROT_READ | PROT_WRITE))
|
||||
#endif
|
||||
{
|
||||
LOG_FATAL(GENERAL, "LLVM: Failed to allocate memory at %p", m_next);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LOG_SUCCESS(GENERAL, "LLVM: Data section %u '%s' allocated -> %p (size=0x%llx, aligned 0x%x, %s)", sec_id, sec_name.data(), m_next, size, align, is_ro ? "ro" : "rw");
|
||||
return (u8*)std::exchange(m_next, (void*)next);
|
||||
}
|
||||
|
||||
virtual bool finalizeMemory(std::string* = nullptr) override
|
||||
{
|
||||
// TODO: make only read-only sections read-only
|
||||
#ifdef _WIN32
|
||||
DWORD op;
|
||||
VirtualProtect(s_memory, (u64)m_next - (u64)s_memory, PAGE_READONLY, &op);
|
||||
VirtualProtect(s_code_addr, s_code_size, PAGE_EXECUTE_READ, &op);
|
||||
#else
|
||||
::mprotect(s_memory, (u64)m_next - (u64)s_memory, PROT_READ);
|
||||
::mprotect(s_code_addr, s_code_size, PROT_READ | PROT_EXEC);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void registerEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
s_unwind_info = addr;
|
||||
s_unwind_size = size;
|
||||
|
||||
return RTDyldMemoryManager::registerEHFrames(addr, load_addr, size);
|
||||
}
|
||||
|
||||
virtual void deregisterEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
LOG_ERROR(GENERAL, "deregisterEHFrames() called"); // Not expected
|
||||
|
||||
return RTDyldMemoryManager::deregisterEHFrames(addr, load_addr, size);
|
||||
}
|
||||
|
||||
~MemoryManager()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!RtlDeleteFunctionTable(s_unwind.data()))
|
||||
{
|
||||
LOG_FATAL(GENERAL, "RtlDeleteFunctionTable(%p) failed! Error %u", s_unwind_info, GetLastError());
|
||||
}
|
||||
|
||||
if (!VirtualFree(s_memory, 0, MEM_DECOMMIT))
|
||||
{
|
||||
LOG_FATAL(GENERAL, "VirtualFree(%p) failed! Error %u", s_memory, GetLastError());
|
||||
}
|
||||
#else
|
||||
if (::mprotect(s_memory, s_memory_size, PROT_NONE))
|
||||
{
|
||||
LOG_FATAL(GENERAL, "mprotect(%p) failed! Error %d", s_memory, errno);
|
||||
}
|
||||
|
||||
// TODO: unregister EH frames if necessary
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
void* m_next = s_memory;
|
||||
};
|
||||
|
||||
// Helper class
|
||||
struct EventListener final : llvm::JITEventListener
|
||||
{
|
||||
virtual void NotifyObjectEmitted(const llvm::object::ObjectFile& obj, const llvm::RuntimeDyld::LoadedObjectInfo& inf) override
|
||||
{
|
||||
const llvm::StringRef elf = obj.getData();
|
||||
fs::file(fs::get_config_dir() + "LLVM.obj", fs::rewrite)
|
||||
.write(elf.data(), elf.size());
|
||||
}
|
||||
};
|
||||
|
||||
static EventListener s_listener;
|
||||
|
||||
jit_compiler::jit_compiler(std::unique_ptr<llvm::Module>&& _module, std::unordered_map<std::string, std::uintptr_t>&& table)
|
||||
{
|
||||
verify(HERE), s_memory;
|
||||
|
||||
std::string result;
|
||||
|
||||
const auto module_ptr = _module.get();
|
||||
|
||||
// Initialization
|
||||
llvm::InitializeNativeTarget();
|
||||
llvm::InitializeNativeTargetAsmPrinter();
|
||||
LLVMLinkInMCJIT();
|
||||
const auto _cpu = llvm::sys::getHostCPUName();
|
||||
|
||||
m_engine.reset(llvm::EngineBuilder(std::move(_module))
|
||||
.setErrorStr(&result)
|
||||
.setMCJITMemoryManager(std::make_unique<MemoryManager>(std::move(table)))
|
||||
.setOptLevel(llvm::CodeGenOpt::Aggressive)
|
||||
.setCodeModel((u64)s_memory <= 0x60000000 ? llvm::CodeModel::Small : llvm::CodeModel::Large) // TODO
|
||||
.setMCPU(_cpu == "skylake" ? "haswell" : _cpu)
|
||||
.create());
|
||||
|
||||
if (!m_engine)
|
||||
{
|
||||
fmt::throw_exception("LLVM: Failed to create ExecutionEngine: %s", result);
|
||||
}
|
||||
|
||||
m_engine->setProcessAllSections(true); // ???
|
||||
m_engine->RegisterJITEventListener(&s_listener);
|
||||
m_engine->finalizeObject();
|
||||
|
||||
for (auto& func : module_ptr->functions())
|
||||
{
|
||||
if (!func.empty())
|
||||
{
|
||||
const std::string& name = func.getName();
|
||||
|
||||
// Register compiled function
|
||||
m_map[name] = m_engine->getFunctionAddress(name);
|
||||
}
|
||||
|
||||
// Delete IR to lower memory consumption
|
||||
func.deleteBody();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Register .xdata UNWIND_INFO (.pdata section is empty for some reason)
|
||||
std::set<u64> func_set;
|
||||
|
||||
for (const auto& pair : m_map)
|
||||
{
|
||||
func_set.emplace(pair.second);
|
||||
}
|
||||
|
||||
const u64 base = (u64)s_memory;
|
||||
const u8* bits = s_unwind_info;
|
||||
|
||||
s_unwind.clear();
|
||||
s_unwind.reserve(m_map.size());
|
||||
|
||||
for (const u64 addr : func_set)
|
||||
{
|
||||
// Find next function address
|
||||
const auto _next = func_set.upper_bound(addr);
|
||||
const u64 next = _next != func_set.end() ? *_next : (u64)s_code_addr + s_code_size;
|
||||
|
||||
// Generate RUNTIME_FUNCTION record
|
||||
RUNTIME_FUNCTION uw;
|
||||
uw.BeginAddress = static_cast<u32>(addr - base);
|
||||
uw.EndAddress = static_cast<u32>(next - base);
|
||||
uw.UnwindData = static_cast<u32>((u64)bits - base);
|
||||
s_unwind.emplace_back(uw);
|
||||
|
||||
// Parse .xdata UNWIND_INFO record
|
||||
const u8 flags = *bits++; // Version and flags
|
||||
const u8 prolog = *bits++; // Size of prolog
|
||||
const u8 count = *bits++; // Count of unwind codes
|
||||
const u8 frame = *bits++; // Frame Reg + Off
|
||||
bits += ::align(std::max<u8>(1, count), 2) * sizeof(u16); // UNWIND_CODE array
|
||||
|
||||
if (flags != 1)
|
||||
{
|
||||
// Can't happen for trivial code
|
||||
LOG_ERROR(GENERAL, "LLVM: unsupported UNWIND_INFO version/flags (0x%02x)", flags);
|
||||
break;
|
||||
}
|
||||
|
||||
LOG_TRACE(GENERAL, "LLVM: .xdata at 0x%llx: function 0x%x..0x%x: p0x%02x, c0x%02x, f0x%02x", uw.UnwindData + base, uw.BeginAddress + base, uw.EndAddress + base, prolog, count, frame);
|
||||
}
|
||||
|
||||
if (s_unwind_info + s_unwind_size != bits)
|
||||
{
|
||||
LOG_ERROR(GENERAL, "LLVM: .xdata analysis failed! (%p != %p)", s_unwind_info + s_unwind_size, bits);
|
||||
}
|
||||
else if (!RtlAddFunctionTable(s_unwind.data(), (DWORD)s_unwind.size(), base))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "RtlAddFunctionTable(%p) failed! Error %u", s_unwind_info, GetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_SUCCESS(GENERAL, "LLVM: UNWIND_INFO registered (%p, size=0x%llx)", s_unwind_info, s_unwind_size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
jit_compiler::~jit_compiler()
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef LLVM_AVAILABLE
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
extern llvm::LLVMContext g_llvm_ctx;
|
||||
|
||||
// Temporary compiler interface
|
||||
class jit_compiler final
|
||||
{
|
||||
// Execution instance
|
||||
std::unique_ptr<llvm::ExecutionEngine> m_engine;
|
||||
|
||||
// Compiled functions
|
||||
std::unordered_map<std::string, std::uintptr_t> m_map;
|
||||
|
||||
public:
|
||||
jit_compiler(std::unique_ptr<llvm::Module>&&, std::unordered_map<std::string, std::uintptr_t>&&);
|
||||
~jit_compiler();
|
||||
|
||||
// Get compiled function address
|
||||
std::uintptr_t get(const std::string& name) const
|
||||
{
|
||||
const auto found = m_map.find(name);
|
||||
|
||||
if (found != m_map.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,23 +0,0 @@
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
+100
-119
@@ -1,72 +1,26 @@
|
||||
#include "Log.h"
|
||||
#include "stdafx.h"
|
||||
#include "Thread.h"
|
||||
#include "File.h"
|
||||
#include "StrFmt.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include "rpcs3_version.h"
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
// Thread-specific log prefix provider
|
||||
thread_local std::string(*g_tls_log_prefix)() = nullptr;
|
||||
|
||||
template<>
|
||||
void fmt_class_string<logs::level>::format(std::string& out, u64 arg)
|
||||
namespace _log
|
||||
{
|
||||
format_enum(out, arg, [](auto lev)
|
||||
logger& get_logger()
|
||||
{
|
||||
switch (lev)
|
||||
{
|
||||
case logs::level::always: return "Nothing";
|
||||
case logs::level::fatal: return "Fatal";
|
||||
case logs::level::error: return "Error";
|
||||
case logs::level::todo: return "TODO";
|
||||
case logs::level::success: return "Success";
|
||||
case logs::level::warning: return "Warning";
|
||||
case logs::level::notice: return "Notice";
|
||||
case logs::level::trace: return "Trace";
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
namespace logs
|
||||
{
|
||||
class file_writer
|
||||
{
|
||||
// Could be memory-mapped file
|
||||
fs::file m_file;
|
||||
|
||||
public:
|
||||
file_writer(const std::string& name);
|
||||
|
||||
virtual ~file_writer() = default;
|
||||
|
||||
// Append raw data
|
||||
void log(const char* text, std::size_t size);
|
||||
};
|
||||
|
||||
struct file_listener : public file_writer, public listener
|
||||
{
|
||||
file_listener(const std::string& name)
|
||||
: file_writer(name)
|
||||
, listener()
|
||||
{
|
||||
const std::string& start = fmt::format("\xEF\xBB\xBF" "RPCS3 v%s\n", rpcs3::version.to_string());
|
||||
file_writer::log(start.data(), start.size());
|
||||
}
|
||||
|
||||
// Encode level, current thread name, channel name and write log message
|
||||
virtual void log(const message& msg, const std::string& prefix, const std::string& text) override;
|
||||
};
|
||||
|
||||
static file_listener* get_logger()
|
||||
{
|
||||
// Use magic static
|
||||
static file_listener logger("RPCS3.log");
|
||||
return &logger;
|
||||
// Use magic static for global logger instance
|
||||
static logger instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
channel GENERAL(nullptr, level::notice);
|
||||
file_listener g_log_file(_PRGNAME_ ".log");
|
||||
|
||||
file_writer g_tty_file("TTY.log");
|
||||
|
||||
channel GENERAL("", level::notice);
|
||||
channel LOADER("LDR", level::notice);
|
||||
channel MEMORY("MEM", level::notice);
|
||||
channel RSX("RSX", level::notice);
|
||||
@@ -76,94 +30,121 @@ namespace logs
|
||||
channel ARMv7("ARMv7");
|
||||
}
|
||||
|
||||
void logs::listener::add(logs::listener* _new)
|
||||
_log::listener::listener()
|
||||
{
|
||||
// Get first (main) listener
|
||||
listener* lis = get_logger();
|
||||
// Register self
|
||||
get_logger().add_listener(this);
|
||||
}
|
||||
|
||||
// Install new listener at the end of linked list
|
||||
while (lis->m_next || !lis->m_next.compare_and_swap_test(nullptr, _new))
|
||||
_log::listener::~listener()
|
||||
{
|
||||
// Unregister self
|
||||
get_logger().remove_listener(this);
|
||||
}
|
||||
|
||||
_log::channel::channel(const std::string& name, _log::level init_level)
|
||||
: name{ name }
|
||||
, enabled{ init_level }
|
||||
{
|
||||
// TODO: register config property "name" associated with "enabled" member
|
||||
}
|
||||
|
||||
void _log::logger::add_listener(_log::listener* listener)
|
||||
{
|
||||
std::lock_guard<shared_mutex> lock(m_mutex);
|
||||
|
||||
m_listeners.emplace(listener);
|
||||
}
|
||||
|
||||
void _log::logger::remove_listener(_log::listener* listener)
|
||||
{
|
||||
std::lock_guard<shared_mutex> lock(m_mutex);
|
||||
|
||||
m_listeners.erase(listener);
|
||||
}
|
||||
|
||||
void _log::logger::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) const
|
||||
{
|
||||
reader_lock lock(m_mutex);
|
||||
|
||||
for (auto listener : m_listeners)
|
||||
{
|
||||
lis = lis->m_next;
|
||||
listener->log(ch, sev, text);
|
||||
}
|
||||
}
|
||||
|
||||
void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||
void _log::broadcast(const _log::channel& ch, _log::level sev, const std::string& text)
|
||||
{
|
||||
std::string text; fmt::raw_append(text, fmt, sup, args);
|
||||
std::string prefix(g_tls_log_prefix ? g_tls_log_prefix() : "");
|
||||
|
||||
// Get first (main) listener
|
||||
listener* lis = get_logger();
|
||||
|
||||
// Send message to all listeners
|
||||
while (lis)
|
||||
{
|
||||
lis->log(*this, prefix, text);
|
||||
lis = lis->m_next;
|
||||
}
|
||||
get_logger().broadcast(ch, sev, text);
|
||||
}
|
||||
|
||||
[[noreturn]] extern void catch_all_exceptions();
|
||||
|
||||
logs::file_writer::file_writer(const std::string& name)
|
||||
_log::file_writer::file_writer(const std::string& name)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
|
||||
if (!m_file.open(fs::get_config_dir() + name, fom::rewrite | fom::append))
|
||||
{
|
||||
fmt::throw_exception("Can't create log file %s (error %s)", name, fs::g_tls_error);
|
||||
throw EXCEPTION("Can't create log file %s (error %d)", name, errno);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
catch (const fmt::exception& e)
|
||||
{
|
||||
catch_all_exceptions();
|
||||
#ifdef _WIN32
|
||||
MessageBoxA(0, e.what(), "_log::file_writer() failed", MB_ICONERROR);
|
||||
#else
|
||||
std::printf("_log::file_writer() failed: %s\n", e.what());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void logs::file_writer::log(const char* text, std::size_t size)
|
||||
void _log::file_writer::log(const std::string& text)
|
||||
{
|
||||
m_file.write(text, size);
|
||||
m_file.write(text);
|
||||
}
|
||||
|
||||
void logs::file_listener::log(const logs::message& msg, const std::string& prefix, const std::string& _text)
|
||||
std::size_t _log::file_writer::size() const
|
||||
{
|
||||
std::string text; text.reserve(prefix.size() + _text.size() + 200);
|
||||
return m_file.seek(0, fs::seek_cur);
|
||||
}
|
||||
|
||||
void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text)
|
||||
{
|
||||
std::string msg; msg.reserve(text.size() + 200);
|
||||
|
||||
// Used character: U+00B7 (Middle Dot)
|
||||
switch (msg.sev)
|
||||
switch (sev)
|
||||
{
|
||||
case level::always: text = u8"·A "; break;
|
||||
case level::fatal: text = u8"·F "; break;
|
||||
case level::error: text = u8"·E "; break;
|
||||
case level::todo: text = u8"·U "; break;
|
||||
case level::success: text = u8"·S "; break;
|
||||
case level::warning: text = u8"·W "; break;
|
||||
case level::notice: text = u8"·! "; break;
|
||||
case level::trace: text = u8"·T "; break;
|
||||
case level::always: msg = u8"·A "; break;
|
||||
case level::fatal: msg = u8"·F "; break;
|
||||
case level::error: msg = u8"·E "; break;
|
||||
case level::todo: msg = u8"·U "; break;
|
||||
case level::success: msg = u8"·S "; break;
|
||||
case level::warning: msg = u8"·W "; break;
|
||||
case level::notice: msg = u8"·! "; break;
|
||||
case level::trace: msg = u8"·T "; break;
|
||||
}
|
||||
|
||||
// TODO: print time?
|
||||
|
||||
if (prefix.size() > 0)
|
||||
if (auto t = thread_ctrl::get_current())
|
||||
{
|
||||
text += "{";
|
||||
text += prefix;
|
||||
text += "} ";
|
||||
msg += '{';
|
||||
msg += t->get_name();
|
||||
msg += "} ";
|
||||
}
|
||||
|
||||
if (msg.ch->name)
|
||||
{
|
||||
text += msg.ch->name;
|
||||
text += msg.sev == level::todo ? " TODO: " : ": ";
|
||||
}
|
||||
else if (msg.sev == level::todo)
|
||||
{
|
||||
text += "TODO: ";
|
||||
}
|
||||
|
||||
text += _text;
|
||||
text += '\n';
|
||||
|
||||
file_writer::log(text.data(), text.size());
|
||||
if (ch.name.size())
|
||||
{
|
||||
msg += ch.name;
|
||||
msg += sev == level::todo ? " TODO: " : ": ";
|
||||
}
|
||||
else if (sev == level::todo)
|
||||
{
|
||||
msg += "TODO: ";
|
||||
}
|
||||
|
||||
msg += text;
|
||||
msg += '\n';
|
||||
|
||||
file_writer::log(msg);
|
||||
}
|
||||
|
||||
+87
-47
@@ -1,10 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "Atomic.h"
|
||||
#include "StrFmt.h"
|
||||
#include "SharedMutex.h"
|
||||
|
||||
namespace logs
|
||||
namespace _log
|
||||
{
|
||||
enum class level : uint
|
||||
{
|
||||
@@ -19,64 +17,61 @@ namespace logs
|
||||
};
|
||||
|
||||
struct channel;
|
||||
struct listener;
|
||||
|
||||
// Message information (temporary data)
|
||||
struct message
|
||||
// Log manager
|
||||
class logger final
|
||||
{
|
||||
const channel* ch;
|
||||
level sev;
|
||||
mutable shared_mutex m_mutex;
|
||||
|
||||
// Send log message to global logger instance
|
||||
void broadcast(const char*, const fmt_type_info*, const u64*);
|
||||
};
|
||||
|
||||
class listener
|
||||
{
|
||||
// Next listener (linked list)
|
||||
atomic_t<listener*> m_next{};
|
||||
|
||||
friend struct message;
|
||||
std::set<listener*> m_listeners;
|
||||
|
||||
public:
|
||||
constexpr listener() = default;
|
||||
// Register listener
|
||||
void add_listener(listener* listener);
|
||||
|
||||
virtual ~listener() = default;
|
||||
// Unregister listener
|
||||
void remove_listener(listener* listener);
|
||||
|
||||
// Process log message
|
||||
virtual void log(const message& msg, const std::string& prefix, const std::string& text) = 0;
|
||||
|
||||
// Add new listener
|
||||
static void add(listener*);
|
||||
// Send log message to all listeners
|
||||
void broadcast(const channel& ch, level sev, const std::string& text) const;
|
||||
};
|
||||
|
||||
// Send log message to global logger instance
|
||||
void broadcast(const channel& ch, level sev, const std::string& text);
|
||||
|
||||
// Log channel (source)
|
||||
struct channel
|
||||
{
|
||||
// Channel prefix (added to every log message)
|
||||
const char* const name;
|
||||
// Channel prefix (also used for identification)
|
||||
const std::string name;
|
||||
|
||||
// The lowest logging level enabled for this channel (used for early filtering)
|
||||
atomic_t<level> enabled;
|
||||
std::atomic<level> enabled;
|
||||
|
||||
// Constant initialization: name and initial log level
|
||||
constexpr channel(const char* name, level enabled = level::trace)
|
||||
: name(name)
|
||||
, enabled(enabled)
|
||||
// Initialization (max level enabled by default)
|
||||
channel(const std::string& name, level = level::trace);
|
||||
|
||||
virtual ~channel() = default;
|
||||
|
||||
// Log without formatting
|
||||
force_inline void log(level sev, const std::string& text) const
|
||||
{
|
||||
if (sev <= enabled)
|
||||
broadcast(*this, sev, text);
|
||||
}
|
||||
|
||||
// Formatting function
|
||||
// Log with formatting
|
||||
template<typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE void format(level sev, const char* fmt, const Args&... args) const
|
||||
force_inline safe_buffers void format(level sev, const char* fmt, const Args&... args) const
|
||||
{
|
||||
if (UNLIKELY(sev <= enabled))
|
||||
{
|
||||
message{this, sev}.broadcast(fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||
}
|
||||
if (sev <= enabled)
|
||||
broadcast(*this, sev, fmt::format(fmt, fmt::do_unveil(args)...));
|
||||
}
|
||||
|
||||
#define GEN_LOG_METHOD(_sev)\
|
||||
template<typename... Args>\
|
||||
SAFE_BUFFERS void _sev(const char* fmt, const Args&... args) const\
|
||||
force_inline void _sev(const char* fmt, const Args&... args)\
|
||||
{\
|
||||
return format<Args...>(level::_sev, fmt, args...);\
|
||||
}
|
||||
@@ -92,7 +87,52 @@ namespace logs
|
||||
#undef GEN_LOG_METHOD
|
||||
};
|
||||
|
||||
/* Small set of predefined channels */
|
||||
// Log listener (destination)
|
||||
struct listener
|
||||
{
|
||||
listener();
|
||||
|
||||
virtual ~listener();
|
||||
|
||||
virtual void log(const channel& ch, level sev, const std::string& text) = 0;
|
||||
};
|
||||
|
||||
class file_writer
|
||||
{
|
||||
// Could be memory-mapped file
|
||||
fs::file m_file;
|
||||
|
||||
public:
|
||||
file_writer(const std::string& name);
|
||||
|
||||
virtual ~file_writer() = default;
|
||||
|
||||
// Append raw data
|
||||
void log(const std::string& text);
|
||||
|
||||
// Get current file size (may be used by secondary readers)
|
||||
std::size_t size() const;
|
||||
};
|
||||
|
||||
struct file_listener : public file_writer, public listener
|
||||
{
|
||||
file_listener(const std::string& name)
|
||||
: file_writer(name)
|
||||
, listener()
|
||||
{
|
||||
}
|
||||
|
||||
// Encode level, current thread name, channel name and write log message
|
||||
virtual void log(const channel& ch, level sev, const std::string& text) override;
|
||||
};
|
||||
|
||||
// Global variable for RPCS3.log
|
||||
extern file_listener g_log_file;
|
||||
|
||||
// Global variable for TTY.log
|
||||
extern file_writer g_tty_file;
|
||||
|
||||
// Small set of predefined channels:
|
||||
|
||||
extern channel GENERAL;
|
||||
extern channel LOADER;
|
||||
@@ -106,10 +146,10 @@ namespace logs
|
||||
|
||||
// Legacy:
|
||||
|
||||
#define LOG_SUCCESS(ch, fmt, ...) logs::ch.success("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_NOTICE(ch, fmt, ...) logs::ch.notice ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_WARNING(ch, fmt, ...) logs::ch.warning("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_ERROR(ch, fmt, ...) logs::ch.error ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_TODO(ch, fmt, ...) logs::ch.todo ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_TRACE(ch, fmt, ...) logs::ch.trace ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_FATAL(ch, fmt, ...) logs::ch.fatal ("" fmt, ##__VA_ARGS__)
|
||||
#define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__)
|
||||
#define LOG_NOTICE(ch, fmt, ...) _log::ch.notice (fmt, ##__VA_ARGS__)
|
||||
#define LOG_WARNING(ch, fmt, ...) _log::ch.warning(fmt, ##__VA_ARGS__)
|
||||
#define LOG_ERROR(ch, fmt, ...) _log::ch.error (fmt, ##__VA_ARGS__)
|
||||
#define LOG_TODO(ch, fmt, ...) _log::ch.todo (fmt, ##__VA_ARGS__)
|
||||
#define LOG_TRACE(ch, fmt, ...) _log::ch.trace (fmt, ##__VA_ARGS__)
|
||||
#define LOG_FATAL(ch, fmt, ...) _log::ch.fatal (fmt, ##__VA_ARGS__)
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
Show();
|
||||
}
|
||||
|
||||
void Update(const u8 thread_id, const u64 value, const wxString& msg)
|
||||
force_inline void Update(const u8 thread_id, const u64 value, const wxString& msg)
|
||||
{
|
||||
if(thread_id > m_cores) return;
|
||||
|
||||
|
||||
+106
-76
@@ -1,90 +1,120 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/Semaphore.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
struct benaphore::internal
|
||||
bool semaphore_t::try_wait()
|
||||
{
|
||||
std::mutex mutex;
|
||||
|
||||
std::size_t acq_order{};
|
||||
std::size_t rel_order{};
|
||||
|
||||
std::condition_variable cond;
|
||||
};
|
||||
|
||||
void benaphore::wait_hard()
|
||||
{
|
||||
initialize_once();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
|
||||
// Notify non-zero waiter queue size
|
||||
if (m_value.exchange(-1) == 1)
|
||||
// check m_value without interlocked op
|
||||
if (m_var.load().value == 0)
|
||||
{
|
||||
// Return immediately (acquired)
|
||||
m_value = 0;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remember the order
|
||||
const std::size_t order = ++m_data->acq_order;
|
||||
|
||||
// Wait for the appropriate rel_order (TODO)
|
||||
while (m_data->rel_order < order)
|
||||
// try to decrement m_value atomically
|
||||
const auto old = m_var.atomic_op([](sync_var_t& var)
|
||||
{
|
||||
m_data->cond.wait(lock);
|
||||
}
|
||||
|
||||
if (order == m_data->acq_order && m_data->acq_order == m_data->rel_order)
|
||||
{
|
||||
// Cleaup
|
||||
m_data->acq_order = 0;
|
||||
m_data->rel_order = 0;
|
||||
m_value.compare_and_swap(-1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void benaphore::post_hard()
|
||||
{
|
||||
initialize_once();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
|
||||
if (m_value.compare_and_swap(0, 1) != -1)
|
||||
{
|
||||
// Do nothing (released)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_data->acq_order == m_data->rel_order)
|
||||
{
|
||||
m_value = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
// Awake one thread
|
||||
m_data->rel_order += 1;
|
||||
|
||||
// Unlock and notify
|
||||
lock.unlock();
|
||||
m_data->cond.notify_one();
|
||||
}
|
||||
|
||||
void benaphore::initialize_once()
|
||||
{
|
||||
if (UNLIKELY(!m_data))
|
||||
{
|
||||
auto ptr = new benaphore::internal;
|
||||
|
||||
if (!m_data.compare_and_swap_test(nullptr, ptr))
|
||||
if (var.value)
|
||||
{
|
||||
delete ptr;
|
||||
var.value--;
|
||||
}
|
||||
});
|
||||
|
||||
// recheck atomic result
|
||||
if (old.value == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool semaphore_t::try_post()
|
||||
{
|
||||
// check m_value without interlocked op
|
||||
if (m_var.load().value >= max_value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// try to increment m_value atomically
|
||||
const auto old = m_var.atomic_op([&](sync_var_t& var)
|
||||
{
|
||||
if (var.value < max_value)
|
||||
{
|
||||
var.value++;
|
||||
}
|
||||
});
|
||||
|
||||
// recheck atomic result
|
||||
if (old.value >= max_value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (old.waiters)
|
||||
{
|
||||
// notify waiting thread
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void semaphore_t::wait()
|
||||
{
|
||||
if (m_var.atomic_op([](sync_var_t& var) -> bool
|
||||
{
|
||||
if (var.value)
|
||||
{
|
||||
var.value--;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//var.waiters++;
|
||||
|
||||
return false;
|
||||
}
|
||||
}))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
m_var.atomic_op([](sync_var_t& var)
|
||||
{
|
||||
var.waiters++;
|
||||
});
|
||||
|
||||
while (!m_var.atomic_op([](sync_var_t& var) -> bool
|
||||
{
|
||||
if (var.value)
|
||||
{
|
||||
var.value--;
|
||||
var.waiters--;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}))
|
||||
{
|
||||
m_cv.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
benaphore::~benaphore()
|
||||
bool semaphore_t::post_and_wait()
|
||||
{
|
||||
delete m_data;
|
||||
// TODO: merge these functions? Probably has a race condition.
|
||||
if (try_wait()) return false;
|
||||
|
||||
try_post();
|
||||
wait();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+24
-34
@@ -1,47 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
// Binary semaphore
|
||||
class benaphore
|
||||
class semaphore_t
|
||||
{
|
||||
struct internal;
|
||||
// semaphore mutex
|
||||
std::mutex m_mutex;
|
||||
|
||||
// Reserved value (-1) enforces *_hard() calls
|
||||
atomic_t<u32> m_value{};
|
||||
// semaphore condition variable
|
||||
std::condition_variable m_cv;
|
||||
|
||||
atomic_t<internal*> m_data{};
|
||||
struct sync_var_t
|
||||
{
|
||||
u32 value; // current semaphore value
|
||||
u32 waiters; // current amount of waiters
|
||||
};
|
||||
|
||||
void wait_hard();
|
||||
void post_hard();
|
||||
// current semaphore value
|
||||
atomic_t<sync_var_t> m_var;
|
||||
|
||||
public:
|
||||
constexpr benaphore() = default;
|
||||
// max semaphore value
|
||||
const u32 max_value;
|
||||
|
||||
~benaphore();
|
||||
|
||||
// Initialize internal data
|
||||
void initialize_once();
|
||||
|
||||
void wait()
|
||||
semaphore_t(u32 max_value = 1, u32 value = 0)
|
||||
: m_var(sync_var_t{ value, 0 })
|
||||
, max_value(max_value)
|
||||
{
|
||||
if (UNLIKELY(!m_value.compare_and_swap_test(1, 0)))
|
||||
{
|
||||
wait_hard();
|
||||
}
|
||||
}
|
||||
|
||||
bool try_wait()
|
||||
{
|
||||
return m_value.compare_and_swap_test(1, 0);
|
||||
}
|
||||
bool try_wait();
|
||||
|
||||
void post()
|
||||
{
|
||||
if (UNLIKELY(!m_value.compare_and_swap_test(0, 1)))
|
||||
{
|
||||
post_hard();
|
||||
}
|
||||
}
|
||||
};
|
||||
bool try_post();
|
||||
|
||||
void wait();
|
||||
|
||||
bool post_and_wait();
|
||||
};
|
||||
+51
-135
@@ -1,187 +1,103 @@
|
||||
#include "stdafx.h"
|
||||
#include "SharedMutex.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
struct shared_mutex::internal
|
||||
void shared_mutex::impl_lock_shared(u32 old_value)
|
||||
{
|
||||
std::mutex mutex;
|
||||
// Throw if reader count breaks the "second" limit (it should be impossible)
|
||||
CHECK_ASSERTION((old_value & SM_READER_COUNT) != SM_READER_COUNT);
|
||||
|
||||
std::size_t rq_size{}; // Reader queue size (threads waiting on m_rcv)
|
||||
std::size_t wq_size{}; // Writer queue size (threads waiting on m_wcv and m_ocv)
|
||||
|
||||
std::condition_variable rcv; // Reader queue
|
||||
std::condition_variable wcv; // Writer queue
|
||||
std::condition_variable ocv; // For current exclusive owner
|
||||
};
|
||||
|
||||
void shared_mutex::lock_shared_hard()
|
||||
{
|
||||
initialize_once();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
|
||||
// Validate
|
||||
if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock_shared(): Invalid bit");
|
||||
if ((m_ctrl & SM_READER_MASK) == 0) throw std::runtime_error("shared_mutex::lock_shared(): No readers");
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
// Notify non-zero reader queue size
|
||||
m_ctrl |= SM_WAITERS_BIT, m_data->rq_size++;
|
||||
m_ctrl |= SM_READER_QUEUE;
|
||||
|
||||
// Fix excess reader count
|
||||
if ((--m_ctrl & SM_READER_MASK) == 0 && m_data->wq_size)
|
||||
// Compensate incorrectly increased reader count
|
||||
if ((--m_ctrl & SM_READER_COUNT) == 0 && m_wq_size)
|
||||
{
|
||||
// Notify exclusive owner
|
||||
m_data->ocv.notify_one();
|
||||
// Notify current exclusive owner (condition passed)
|
||||
m_ocv.notify_one();
|
||||
}
|
||||
|
||||
CHECK_ASSERTION(++m_rq_size);
|
||||
|
||||
// Obtain the reader lock
|
||||
while (true)
|
||||
while (!atomic_op(m_ctrl, op_lock_shared))
|
||||
{
|
||||
const auto ctrl = m_ctrl.load();
|
||||
|
||||
// Check writers and reader limit
|
||||
if (m_data->wq_size || (ctrl & ~SM_WAITERS_BIT) >= SM_READER_MAX)
|
||||
{
|
||||
m_data->rcv.wait(lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_ctrl.compare_and_swap_test(ctrl, ctrl + 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_rcv.wait(lock);
|
||||
}
|
||||
|
||||
if (!--m_data->rq_size && !m_data->wq_size)
|
||||
CHECK_ASSERTION(m_rq_size--);
|
||||
|
||||
if (m_rq_size == 0)
|
||||
{
|
||||
m_ctrl &= ~SM_WAITERS_BIT;
|
||||
m_ctrl &= ~SM_READER_QUEUE;
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::unlock_shared_notify()
|
||||
void shared_mutex::impl_unlock_shared(u32 new_value)
|
||||
{
|
||||
initialize_once();
|
||||
// Throw if reader count was zero
|
||||
CHECK_ASSERTION((new_value & SM_READER_COUNT) != SM_READER_COUNT);
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
// Mutex cannot be unlocked before notification because m_ctrl has been changed outside
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if ((m_ctrl & SM_READER_MASK) == 0 && m_data->wq_size)
|
||||
if (m_wq_size && (new_value & SM_READER_COUNT) == 0)
|
||||
{
|
||||
// Notify exclusive owner
|
||||
lock.unlock();
|
||||
m_data->ocv.notify_one();
|
||||
// Notify current exclusive owner that the latest reader is gone
|
||||
m_ocv.notify_one();
|
||||
}
|
||||
else if (m_data->rq_size)
|
||||
else if (m_rq_size)
|
||||
{
|
||||
// Notify other readers
|
||||
lock.unlock();
|
||||
m_data->rcv.notify_one();
|
||||
m_rcv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::lock_hard()
|
||||
void shared_mutex::impl_lock_excl(u32 value)
|
||||
{
|
||||
initialize_once();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
|
||||
// Validate
|
||||
if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock(): Invalid bit");
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
// Notify non-zero writer queue size
|
||||
m_ctrl |= SM_WAITERS_BIT, m_data->wq_size++;
|
||||
m_ctrl |= SM_WRITER_QUEUE;
|
||||
|
||||
CHECK_ASSERTION(++m_wq_size);
|
||||
|
||||
// Obtain the writer lock
|
||||
while (true)
|
||||
while (!atomic_op(m_ctrl, op_lock_excl))
|
||||
{
|
||||
const auto ctrl = m_ctrl.load();
|
||||
|
||||
if (ctrl & SM_WRITER_LOCK)
|
||||
{
|
||||
m_data->wcv.wait(lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_ctrl.compare_and_swap_test(ctrl, ctrl | SM_WRITER_LOCK))
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_wcv.wait(lock);
|
||||
}
|
||||
|
||||
// Wait for remaining readers
|
||||
while ((m_ctrl & SM_READER_MASK) != 0)
|
||||
while ((m_ctrl & SM_READER_COUNT) != 0)
|
||||
{
|
||||
m_data->ocv.wait(lock);
|
||||
m_ocv.wait(lock);
|
||||
}
|
||||
|
||||
if (!--m_data->wq_size && !m_data->rq_size)
|
||||
CHECK_ASSERTION(m_wq_size--);
|
||||
|
||||
if (m_wq_size == 0)
|
||||
{
|
||||
m_ctrl &= ~SM_WAITERS_BIT;
|
||||
m_ctrl &= ~SM_WRITER_QUEUE;
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::unlock_notify()
|
||||
void shared_mutex::impl_unlock_excl(u32 value)
|
||||
{
|
||||
initialize_once();
|
||||
// Throw if was not locked exclusively
|
||||
CHECK_ASSERTION(value & SM_WRITER_LOCK);
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
|
||||
if (m_data->wq_size)
|
||||
// Mutex cannot be unlocked before notification because m_ctrl has been changed outside
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_wq_size)
|
||||
{
|
||||
// Notify next exclusive owner
|
||||
lock.unlock();
|
||||
m_data->wcv.notify_one();
|
||||
m_wcv.notify_one();
|
||||
}
|
||||
else if (m_data->rq_size)
|
||||
else if (m_rq_size)
|
||||
{
|
||||
// Notify all readers
|
||||
lock.unlock();
|
||||
m_data->rcv.notify_all();
|
||||
m_rcv.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::lock_upgrade_hard()
|
||||
{
|
||||
unlock_shared();
|
||||
lock();
|
||||
}
|
||||
|
||||
void shared_mutex::lock_degrade_hard()
|
||||
{
|
||||
initialize_once();
|
||||
|
||||
std::unique_lock<std::mutex> lock(m_data->mutex);
|
||||
|
||||
m_ctrl -= SM_WRITER_LOCK - 1;
|
||||
|
||||
if (m_data->rq_size)
|
||||
{
|
||||
// Notify all readers
|
||||
lock.unlock();
|
||||
m_data->rcv.notify_all();
|
||||
}
|
||||
else if (m_data->wq_size)
|
||||
{
|
||||
// Notify next exclusive owner
|
||||
lock.unlock();
|
||||
m_data->wcv.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void shared_mutex::initialize_once()
|
||||
{
|
||||
if (UNLIKELY(!m_data))
|
||||
{
|
||||
auto ptr = new shared_mutex::internal;
|
||||
|
||||
if (!m_data.compare_and_swap_test(nullptr, ptr))
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shared_mutex::~shared_mutex()
|
||||
{
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
+71
-114
@@ -1,122 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
//! An attempt to create effective implementation of "shared mutex", lock-free in optimistic case.
|
||||
//! All locking and unlocking may be done by a single LOCK XADD or LOCK CMPXCHG instruction.
|
||||
//! All locking and unlocking may be done by single LOCK XADD or LOCK CMPXCHG instructions.
|
||||
//! MSVC implementation of std::shared_timed_mutex seems suboptimal.
|
||||
//! std::shared_mutex is not available until C++17.
|
||||
class shared_mutex final
|
||||
{
|
||||
enum : u32
|
||||
{
|
||||
SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB
|
||||
SM_WAITERS_BIT = 1u << 30, // Flag set if m_wq_size or m_rq_size is non-zero
|
||||
SM_INVALID_BIT = 1u << 29, // Unreachable reader count bit (may be set by incorrect unlock_shared() call)
|
||||
SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB
|
||||
SM_WRITER_QUEUE = 1u << 30, // Flag set if m_wq_size != 0
|
||||
SM_READER_QUEUE = 1u << 29, // Flag set if m_rq_size != 0
|
||||
|
||||
SM_READER_MASK = SM_WAITERS_BIT - 1, // Valid reader count bit mask
|
||||
SM_READER_MAX = 1u << 24, // Max reader count
|
||||
SM_READER_COUNT = SM_READER_QUEUE - 1, // Valid reader count bit mask
|
||||
SM_READER_MAX = 1u << 24, // Max reader count
|
||||
};
|
||||
|
||||
atomic_t<u32> m_ctrl{}; // Control variable: reader count | SM_* flags
|
||||
std::atomic<u32> m_ctrl{}; // Control atomic variable: reader count | SM_* flags
|
||||
std::thread::id m_owner{}; // Current exclusive owner (TODO: implement only for debug mode?)
|
||||
|
||||
struct internal;
|
||||
std::mutex m_mutex;
|
||||
|
||||
atomic_t<internal*> m_data{}; // Internal data
|
||||
u32 m_rq_size{}; // Reader queue size (threads waiting on m_rcv)
|
||||
u32 m_wq_size{}; // Writer queue size (threads waiting on m_wcv+m_ocv)
|
||||
|
||||
std::condition_variable m_rcv; // Reader queue
|
||||
std::condition_variable m_wcv; // Writer queue
|
||||
std::condition_variable m_ocv; // For current exclusive owner
|
||||
|
||||
void lock_shared_hard();
|
||||
void unlock_shared_notify();
|
||||
static bool op_lock_shared(u32& ctrl)
|
||||
{
|
||||
// Check writer flags and reader limit
|
||||
return (ctrl & ~SM_READER_QUEUE) < SM_READER_MAX ? ctrl++, true : false;
|
||||
}
|
||||
|
||||
void lock_hard();
|
||||
void unlock_notify();
|
||||
static bool op_lock_excl(u32& ctrl)
|
||||
{
|
||||
// Test and set writer lock
|
||||
return (ctrl & SM_WRITER_LOCK) == 0 ? ctrl |= SM_WRITER_LOCK, true : false;
|
||||
}
|
||||
|
||||
void lock_upgrade_hard();
|
||||
void lock_degrade_hard();
|
||||
void impl_lock_shared(u32 old_ctrl);
|
||||
void impl_unlock_shared(u32 new_ctrl);
|
||||
void impl_lock_excl(u32 ctrl);
|
||||
void impl_unlock_excl(u32 ctrl);
|
||||
|
||||
public:
|
||||
constexpr shared_mutex() = default;
|
||||
|
||||
// Initialize internal data
|
||||
void initialize_once();
|
||||
|
||||
~shared_mutex();
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
const u32 ctrl = m_ctrl.load();
|
||||
|
||||
return ctrl < SM_READER_MAX && m_ctrl.compare_and_swap_test(ctrl, ctrl + 1);
|
||||
}
|
||||
shared_mutex() = default;
|
||||
|
||||
// Lock in shared mode
|
||||
void lock_shared()
|
||||
{
|
||||
// Optimization: unconditional increment, compensated later
|
||||
if (UNLIKELY(m_ctrl++ >= SM_READER_MAX))
|
||||
const u32 old_ctrl = m_ctrl++;
|
||||
|
||||
// Check flags and reader limit
|
||||
if (old_ctrl >= SM_READER_MAX)
|
||||
{
|
||||
lock_shared_hard();
|
||||
impl_lock_shared(old_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to lock in shared mode
|
||||
bool try_lock_shared()
|
||||
{
|
||||
return atomic_op(m_ctrl, [](u32& ctrl)
|
||||
{
|
||||
// Check flags and reader limit
|
||||
return ctrl < SM_READER_MAX ? ctrl++, true : false;
|
||||
});
|
||||
}
|
||||
|
||||
// Unlock in shared mode
|
||||
void unlock_shared()
|
||||
{
|
||||
if (UNLIKELY(m_ctrl-- >= SM_READER_MAX))
|
||||
const u32 new_ctrl = --m_ctrl;
|
||||
|
||||
// Check if notification required
|
||||
if (new_ctrl >= SM_READER_MAX)
|
||||
{
|
||||
unlock_shared_notify();
|
||||
impl_unlock_shared(new_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return !m_ctrl && m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK);
|
||||
}
|
||||
|
||||
// Lock exclusively
|
||||
void lock()
|
||||
{
|
||||
if (UNLIKELY(!m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK)))
|
||||
u32 value = 0;
|
||||
|
||||
if (!m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK))
|
||||
{
|
||||
lock_hard();
|
||||
impl_lock_excl(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to lock exclusively
|
||||
bool try_lock()
|
||||
{
|
||||
u32 value = 0;
|
||||
|
||||
return m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK);
|
||||
}
|
||||
|
||||
// Unlock exclusively
|
||||
void unlock()
|
||||
{
|
||||
m_ctrl &= ~SM_WRITER_LOCK;
|
||||
const u32 value = m_ctrl.fetch_add(SM_WRITER_LOCK);
|
||||
|
||||
if (UNLIKELY(m_ctrl))
|
||||
// Check if notification required
|
||||
if (value != SM_WRITER_LOCK)
|
||||
{
|
||||
unlock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
return m_ctrl == 1 && m_ctrl.compare_and_swap_test(1, SM_WRITER_LOCK);
|
||||
}
|
||||
|
||||
bool try_lock_degrade()
|
||||
{
|
||||
return m_ctrl == SM_WRITER_LOCK && m_ctrl.compare_and_swap_test(SM_WRITER_LOCK, 1);
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
if (UNLIKELY(!m_ctrl.compare_and_swap_test(1, SM_WRITER_LOCK)))
|
||||
{
|
||||
lock_upgrade_hard();
|
||||
}
|
||||
}
|
||||
|
||||
void lock_degrade()
|
||||
{
|
||||
if (UNLIKELY(!m_ctrl.compare_and_swap_test(SM_WRITER_LOCK, 1)))
|
||||
{
|
||||
lock_degrade_hard();
|
||||
impl_unlock_excl(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//! Simplified shared (reader) lock implementation.
|
||||
//! Simplified shared (reader) lock implementation, similar to std::lock_guard.
|
||||
//! std::shared_lock may be used instead if necessary.
|
||||
class reader_lock final
|
||||
{
|
||||
@@ -136,44 +134,3 @@ public:
|
||||
m_mutex.unlock_shared();
|
||||
}
|
||||
};
|
||||
|
||||
//! Simplified exclusive (writer) lock implementation.
|
||||
//! std::lock_guard may or std::unique_lock be used instead if necessary.
|
||||
class writer_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
writer_lock(const writer_lock&) = delete;
|
||||
|
||||
writer_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock();
|
||||
}
|
||||
|
||||
~writer_lock()
|
||||
{
|
||||
m_mutex.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
// Exclusive (writer) lock in the scope of shared (reader) lock.
|
||||
class upgraded_lock final
|
||||
{
|
||||
shared_mutex& m_mutex;
|
||||
|
||||
public:
|
||||
upgraded_lock(const writer_lock&) = delete;
|
||||
|
||||
upgraded_lock(shared_mutex& mutex)
|
||||
: m_mutex(mutex)
|
||||
{
|
||||
m_mutex.lock_upgrade();
|
||||
}
|
||||
|
||||
~upgraded_lock()
|
||||
{
|
||||
m_mutex.lock_degrade();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/CPU/CPUThread.h"
|
||||
|
||||
#include "SleepQueue.h"
|
||||
|
||||
void sleep_queue_entry_t::add_entry()
|
||||
{
|
||||
m_queue.emplace_back(std::static_pointer_cast<CPUThread>(m_thread.shared_from_this()));
|
||||
}
|
||||
|
||||
void sleep_queue_entry_t::remove_entry()
|
||||
{
|
||||
for (auto it = m_queue.begin(); it != m_queue.end(); it++)
|
||||
{
|
||||
if (it->get() == &m_thread)
|
||||
{
|
||||
m_queue.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool sleep_queue_entry_t::find() const
|
||||
{
|
||||
for (auto it = m_queue.begin(); it != m_queue.end(); it++)
|
||||
{
|
||||
if (it->get() == &m_thread)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue)
|
||||
: m_thread(cpu)
|
||||
, m_queue(queue)
|
||||
{
|
||||
add_entry();
|
||||
cpu.sleep();
|
||||
}
|
||||
|
||||
sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue, const defer_sleep_t&)
|
||||
: m_thread(cpu)
|
||||
, m_queue(queue)
|
||||
{
|
||||
cpu.sleep();
|
||||
}
|
||||
|
||||
sleep_queue_entry_t::~sleep_queue_entry_t()
|
||||
{
|
||||
remove_entry();
|
||||
m_thread.awake();
|
||||
}
|
||||
+23
-59
@@ -1,81 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
using sleep_entry_t = class CPUThread;
|
||||
using sleep_queue_t = std::deque<std::shared_ptr<sleep_entry_t>>;
|
||||
|
||||
// Tag used in sleep_entry<> constructor
|
||||
static struct defer_sleep_tag {} constexpr defer_sleep{};
|
||||
static struct defer_sleep_t {} const defer_sleep{};
|
||||
|
||||
// Define sleep queue as std::deque with T* pointers, T - thread type
|
||||
template<typename T> using sleep_queue = std::deque<T*>;
|
||||
|
||||
// Automatic object handling a thread pointer (T*) in the sleep queue
|
||||
// Sleep queue is actually std::deque with pointers, be careful about the lifetime
|
||||
template<typename T>
|
||||
class sleep_entry final
|
||||
// automatic object handling a thread entry in the sleep queue
|
||||
class sleep_queue_entry_t final
|
||||
{
|
||||
sleep_queue<T>& m_queue;
|
||||
T& m_thread;
|
||||
sleep_entry_t& m_thread;
|
||||
sleep_queue_t& m_queue;
|
||||
|
||||
void add_entry();
|
||||
void remove_entry();
|
||||
bool find() const;
|
||||
|
||||
public:
|
||||
// Constructor; enter() not called
|
||||
sleep_entry(sleep_queue<T>& queue, T& entry, const defer_sleep_tag&)
|
||||
: m_queue(queue)
|
||||
, m_thread(entry)
|
||||
{
|
||||
}
|
||||
// add specified thread to the sleep queue
|
||||
sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue);
|
||||
|
||||
// Constructor; calls enter()
|
||||
sleep_entry(sleep_queue<T>& queue, T& entry)
|
||||
: sleep_entry(queue, entry, defer_sleep)
|
||||
{
|
||||
enter();
|
||||
}
|
||||
// don't add specified thread to the sleep queue
|
||||
sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue, const defer_sleep_t&);
|
||||
|
||||
// Destructor; calls leave()
|
||||
~sleep_entry()
|
||||
{
|
||||
leave();
|
||||
}
|
||||
// removes specified thread from the sleep queue if added
|
||||
~sleep_queue_entry_t();
|
||||
|
||||
// Add thread to the sleep queue
|
||||
// add thread to the sleep queue
|
||||
void enter()
|
||||
{
|
||||
for (auto t : m_queue)
|
||||
{
|
||||
if (t == &m_thread)
|
||||
{
|
||||
// Already exists, is it an error?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_queue.emplace_back(&m_thread);
|
||||
add_entry();
|
||||
}
|
||||
|
||||
// Remove thread from the sleep queue
|
||||
// remove thread from the sleep queue
|
||||
void leave()
|
||||
{
|
||||
for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++)
|
||||
{
|
||||
if (*it == &m_thread)
|
||||
{
|
||||
m_queue.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
remove_entry();
|
||||
}
|
||||
|
||||
// Check whether the thread exists in the sleep queue
|
||||
// check whether the thread exists in the sleep queue
|
||||
explicit operator bool() const
|
||||
{
|
||||
for (auto it = m_queue.begin(), end = m_queue.end(); it != end; it++)
|
||||
{
|
||||
if (*it == &m_thread)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return find();
|
||||
}
|
||||
};
|
||||
|
||||
+179
-273
@@ -1,286 +1,85 @@
|
||||
#include "StrFmt.h"
|
||||
#include "BEType.h"
|
||||
#include "StrUtil.h"
|
||||
#include "cfmt.h"
|
||||
#include "stdafx.h"
|
||||
#pragma warning(push)
|
||||
#pragma message("TODO: remove wx dependency: <wx/string.h>")
|
||||
#pragma warning(disable : 4996)
|
||||
#include <wx/string.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
void fmt_class_string<const void*>::format(std::string& out, u64 arg)
|
||||
std::string v128::to_hex() const
|
||||
{
|
||||
if (arg)
|
||||
return fmt::format("%016llx%016llx", _u64[1], _u64[0]);
|
||||
}
|
||||
|
||||
std::string v128::to_xyzw() const
|
||||
{
|
||||
return fmt::format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]);
|
||||
}
|
||||
|
||||
std::string fmt::to_hex(u64 value, u64 count)
|
||||
{
|
||||
if (count - 1 >= 16)
|
||||
{
|
||||
fmt::append(out, "%p", reinterpret_cast<const void*>(static_cast<std::uintptr_t>(arg)));
|
||||
}
|
||||
else
|
||||
{
|
||||
out += "(NULL)";
|
||||
}
|
||||
}
|
||||
|
||||
void fmt_class_string<const char*>::format(std::string& out, u64 arg)
|
||||
{
|
||||
if (arg)
|
||||
{
|
||||
out += reinterpret_cast<const char*>(static_cast<std::uintptr_t>(arg));
|
||||
}
|
||||
else
|
||||
{
|
||||
out += "(NULL)";
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<std::string>::format(std::string& out, u64 arg)
|
||||
{
|
||||
out += get_object(arg).c_str(); // TODO?
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<std::vector<char>>::format(std::string& out, u64 arg)
|
||||
{
|
||||
const std::vector<char>& obj = get_object(arg);
|
||||
out.append(obj.cbegin(), obj.cend());
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<char>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#hhx", static_cast<char>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<uchar>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#hhx", static_cast<uchar>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<schar>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#hhx", static_cast<schar>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<short>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#hx", static_cast<short>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<ushort>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#hx", static_cast<ushort>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<int>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#x", static_cast<int>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<uint>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#x", static_cast<uint>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<long>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#lx", static_cast<long>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<ulong>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#lx", static_cast<ulong>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<llong>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#llx", static_cast<llong>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<ullong>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%#llx", static_cast<ullong>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<float>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%gf", static_cast<float>(reinterpret_cast<f64&>(arg)));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<double>::format(std::string& out, u64 arg)
|
||||
{
|
||||
fmt::append(out, "%g", reinterpret_cast<f64&>(arg));
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<bool>::format(std::string& out, u64 arg)
|
||||
{
|
||||
out += arg ? "true" : "false";
|
||||
}
|
||||
|
||||
template <>
|
||||
void fmt_class_string<v128>::format(std::string& out, u64 arg)
|
||||
{
|
||||
const v128& vec = get_object(arg);
|
||||
fmt::append(out, "0x%016llx%016llx", vec._u64[1], vec._u64[0]);
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
void raw_error(const char* msg)
|
||||
{
|
||||
throw std::runtime_error{msg};
|
||||
throw EXCEPTION("Invalid count: 0x%llx", count);
|
||||
}
|
||||
|
||||
void raw_verify_error(const char* msg, const fmt_type_info* sup, u64 arg)
|
||||
count = std::max<u64>(count, 16 - cntlz64(value) / 4);
|
||||
|
||||
char res[16] = {};
|
||||
|
||||
for (size_t i = count - 1; ~i; i--, value /= 16)
|
||||
{
|
||||
std::string out{"Verification failed"};
|
||||
|
||||
// Print error code (may be irrelevant)
|
||||
#ifdef _WIN32
|
||||
if (DWORD error = GetLastError())
|
||||
{
|
||||
fmt::append(out, " (e%#x)", error);
|
||||
}
|
||||
#else
|
||||
if (int error = errno)
|
||||
{
|
||||
fmt::append(out, " (e%d)", error);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sup)
|
||||
{
|
||||
out += " (";
|
||||
sup->fmt_string(out, arg); // Print value
|
||||
out += ")";
|
||||
}
|
||||
|
||||
if (msg)
|
||||
{
|
||||
out += ": ";
|
||||
out += msg;
|
||||
}
|
||||
|
||||
throw std::runtime_error{out};
|
||||
res[i] = "0123456789abcdef"[value % 16];
|
||||
}
|
||||
|
||||
void raw_narrow_error(const char* msg, const fmt_type_info* sup, u64 arg)
|
||||
{
|
||||
std::string out{"Narrow error"};
|
||||
|
||||
if (sup)
|
||||
{
|
||||
out += " (";
|
||||
sup->fmt_string(out, arg); // Print value
|
||||
out += ")";
|
||||
}
|
||||
|
||||
if (msg)
|
||||
{
|
||||
out += ": ";
|
||||
out += msg;
|
||||
}
|
||||
|
||||
throw std::range_error{out};
|
||||
}
|
||||
|
||||
// Hidden template
|
||||
template <typename T>
|
||||
void raw_throw_exception(const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||
{
|
||||
std::string out;
|
||||
raw_append(out, fmt, sup, args);
|
||||
throw T{out};
|
||||
}
|
||||
|
||||
// Explicit instantiations (not exhaustive)
|
||||
template void raw_throw_exception<std::runtime_error>(const char*, const fmt_type_info*, const u64*);
|
||||
template void raw_throw_exception<std::logic_error>(const char*, const fmt_type_info*, const u64*);
|
||||
template void raw_throw_exception<std::domain_error>(const char*, const fmt_type_info*, const u64*);
|
||||
template void raw_throw_exception<std::invalid_argument>(const char*, const fmt_type_info*, const u64*);
|
||||
template void raw_throw_exception<std::out_of_range>(const char*, const fmt_type_info*, const u64*);
|
||||
template void raw_throw_exception<std::range_error>(const char*, const fmt_type_info*, const u64*);
|
||||
template void raw_throw_exception<std::overflow_error>(const char*, const fmt_type_info*, const u64*);
|
||||
template void raw_throw_exception<std::underflow_error>(const char*, const fmt_type_info*, const u64*);
|
||||
|
||||
struct cfmt_src;
|
||||
return std::string(res, count);
|
||||
}
|
||||
|
||||
// Temporary implementation
|
||||
struct fmt::cfmt_src
|
||||
std::string fmt::to_udec(u64 value)
|
||||
{
|
||||
const fmt_type_info* sup;
|
||||
const u64* args;
|
||||
char res[20] = {};
|
||||
size_t first = sizeof(res);
|
||||
|
||||
bool test(std::size_t index) const
|
||||
if (!value)
|
||||
{
|
||||
if (!sup[index].fmt_string)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
res[--first] = '0';
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T get(std::size_t index) const
|
||||
for (; value; value /= 10)
|
||||
{
|
||||
return reinterpret_cast<const T&>(args[index]);
|
||||
res[--first] = '0' + (value % 10);
|
||||
}
|
||||
|
||||
void skip(std::size_t extra)
|
||||
{
|
||||
++sup += extra;
|
||||
++args += extra;
|
||||
}
|
||||
|
||||
std::size_t fmt_string(std::string& out, std::size_t extra) const
|
||||
{
|
||||
const std::size_t start = out.size();
|
||||
sup[extra].fmt_string(out, args[extra]);
|
||||
return out.size() - start;
|
||||
}
|
||||
|
||||
// Returns type size (0 if unknown, pointer, unsigned, assumed max)
|
||||
std::size_t type(std::size_t extra) const
|
||||
{
|
||||
// Hack: use known function pointers to determine type
|
||||
#define TYPE(type) \
|
||||
if (sup[extra].fmt_string == &fmt_class_string<type>::format) return sizeof(type);
|
||||
|
||||
TYPE(int);
|
||||
TYPE(llong);
|
||||
TYPE(schar);
|
||||
TYPE(short);
|
||||
if (std::is_signed<char>::value) TYPE(char);
|
||||
TYPE(long);
|
||||
|
||||
#undef TYPE
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
void fmt::raw_append(std::string& out, const char* fmt, const fmt_type_info* sup, const u64* args) noexcept
|
||||
{
|
||||
cfmt_append(out, fmt, cfmt_src{sup, args});
|
||||
return std::string(&res[first], sizeof(res) - first);
|
||||
}
|
||||
|
||||
std::string fmt::to_sdec(s64 svalue)
|
||||
{
|
||||
const bool sign = svalue < 0;
|
||||
u64 value = sign ? -svalue : svalue;
|
||||
|
||||
char res[20] = {};
|
||||
size_t first = sizeof(res);
|
||||
|
||||
if (!value)
|
||||
{
|
||||
res[--first] = '0';
|
||||
}
|
||||
|
||||
for (; value; value /= 10)
|
||||
{
|
||||
res[--first] = '0' + (value % 10);
|
||||
}
|
||||
|
||||
if (sign)
|
||||
{
|
||||
res[--first] = '-';
|
||||
}
|
||||
|
||||
return std::string(&res[first], sizeof(res) - first);
|
||||
}
|
||||
|
||||
//extern const std::string fmt::placeholder = "???";
|
||||
|
||||
std::string fmt::replace_first(const std::string& src, const std::string& from, const std::string& to)
|
||||
{
|
||||
auto pos = src.find(from);
|
||||
@@ -293,7 +92,7 @@ std::string fmt::replace_first(const std::string& src, const std::string& from,
|
||||
return (pos ? src.substr(0, pos) + to : to) + std::string(src.c_str() + pos + from.length());
|
||||
}
|
||||
|
||||
std::string fmt::replace_all(const std::string& src, const std::string& from, const std::string& to)
|
||||
std::string fmt::replace_all(const std::string &src, const std::string& from, const std::string& to)
|
||||
{
|
||||
std::string target = src;
|
||||
for (auto pos = target.find(from); pos != std::string::npos; pos = target.find(from, pos + 1))
|
||||
@@ -305,6 +104,83 @@ std::string fmt::replace_all(const std::string& src, const std::string& from, co
|
||||
return target;
|
||||
}
|
||||
|
||||
//TODO: move this wx Stuff somewhere else
|
||||
//convert a wxString to a std::string encoded in utf8
|
||||
//CAUTION, only use this to interface with wxWidgets classes
|
||||
std::string fmt::ToUTF8(const wxString& right)
|
||||
{
|
||||
auto ret = std::string(((const char *)right.utf8_str()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
//convert a std::string encoded in utf8 to a wxString
|
||||
//CAUTION, only use this to interface with wxWidgets classes
|
||||
wxString fmt::FromUTF8(const std::string& right)
|
||||
{
|
||||
auto ret = wxString::FromUTF8(right.c_str());
|
||||
return ret;
|
||||
}
|
||||
|
||||
//TODO: remove this after every snippet that uses it is gone
|
||||
//WARNING: not fully compatible with CmpNoCase from wxString
|
||||
int fmt::CmpNoCase(const std::string& a, const std::string& b)
|
||||
{
|
||||
if (a.length() != b.length())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::equal(a.begin(),
|
||||
a.end(),
|
||||
b.begin(),
|
||||
[](const char& a, const char& b){return ::tolower(a) == ::tolower(b); })
|
||||
? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: remove this after every snippet that uses it is gone
|
||||
//WARNING: not fully compatible with CmpNoCase from wxString
|
||||
void fmt::Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm)
|
||||
{
|
||||
size_t cursor = 0;
|
||||
do
|
||||
{
|
||||
cursor = str.find(searchterm, cursor);
|
||||
if (cursor != std::string::npos)
|
||||
{
|
||||
str.replace(cursor, searchterm.size(), replaceterm);
|
||||
cursor += replaceterm.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
std::vector<std::string> fmt::rSplit(const std::string& source, const std::string& delim)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
size_t cursor = 0;
|
||||
do
|
||||
{
|
||||
size_t prevcurs = cursor;
|
||||
cursor = source.find(delim, cursor);
|
||||
if (cursor != std::string::npos)
|
||||
{
|
||||
ret.push_back(source.substr(prevcurs,cursor-prevcurs));
|
||||
cursor += delim.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back(source.substr(prevcurs));
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<std::string> fmt::split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
@@ -313,7 +189,7 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
|
||||
|
||||
for (size_t cursor_end = 0; cursor_end < source.length(); ++cursor_end)
|
||||
{
|
||||
for (auto& separator : separators)
|
||||
for (auto &separator : separators)
|
||||
{
|
||||
if (strncmp(source.c_str() + cursor_end, separator.c_str(), separator.length()) == 0)
|
||||
{
|
||||
@@ -322,7 +198,7 @@ std::vector<std::string> fmt::split(const std::string& source, std::initializer_
|
||||
result.push_back(candidate);
|
||||
|
||||
cursor_begin = cursor_end + separator.length();
|
||||
cursor_end = cursor_begin - 1;
|
||||
cursor_end = cursor_begin - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -341,20 +217,50 @@ std::string fmt::trim(const std::string& source, const std::string& values)
|
||||
std::size_t begin = source.find_first_not_of(values);
|
||||
|
||||
if (begin == source.npos)
|
||||
return {};
|
||||
return{};
|
||||
|
||||
return source.substr(begin, source.find_last_not_of(values) + 1);
|
||||
}
|
||||
|
||||
std::string fmt::to_upper(const std::string& string)
|
||||
std::string fmt::tolower(std::string source)
|
||||
{
|
||||
std::string result;
|
||||
result.resize(string.size());
|
||||
std::transform(string.begin(), string.end(), result.begin(), ::toupper);
|
||||
return result;
|
||||
std::transform(source.begin(), source.end(), source.begin(), ::tolower);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
bool fmt::match(const std::string& source, const std::string& mask)
|
||||
std::string fmt::toupper(std::string source)
|
||||
{
|
||||
std::transform(source.begin(), source.end(), source.begin(), ::toupper);
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
std::string fmt::escape(std::string source)
|
||||
{
|
||||
const std::pair<std::string, std::string> escape_list[] =
|
||||
{
|
||||
{ "\\", "\\\\" },
|
||||
{ "\a", "\\a" },
|
||||
{ "\b", "\\b" },
|
||||
{ "\f", "\\f" },
|
||||
{ "\n", "\\n\n" },
|
||||
{ "\r", "\\r" },
|
||||
{ "\t", "\\t" },
|
||||
{ "\v", "\\v" },
|
||||
};
|
||||
|
||||
source = fmt::replace_all(source, escape_list);
|
||||
|
||||
for (char c = 0; c < 32; c++)
|
||||
{
|
||||
if (c != '\n') source = fmt::replace_all(source, std::string(1, c), fmt::format("\\x%02X", c));
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
bool fmt::match(const std::string &source, const std::string &mask)
|
||||
{
|
||||
std::size_t source_position = 0, mask_position = 0;
|
||||
|
||||
|
||||
+318
-219
@@ -1,260 +1,359 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
class wxString;
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <typename... Args>
|
||||
static std::string format(const char*, const Args&...);
|
||||
}
|
||||
//struct empty_t{};
|
||||
|
||||
template <typename T, typename>
|
||||
struct fmt_unveil
|
||||
{
|
||||
static_assert(sizeof(T) > 0, "fmt_unveil<>: cannot pass forward-declared object");
|
||||
//extern const std::string placeholder;
|
||||
|
||||
using type = T;
|
||||
|
||||
static inline u64 get(const T& arg)
|
||||
template <typename T>
|
||||
std::string AfterLast(const std::string& source, T searchstr)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(&arg);
|
||||
size_t search_pos = source.rfind(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(search_pos);
|
||||
}
|
||||
|
||||
// Temporary value container (can possibly be created by other fmt_unveil<> specializations)
|
||||
struct u64_wrapper
|
||||
template <typename T>
|
||||
std::string BeforeLast(const std::string& source, T searchstr)
|
||||
{
|
||||
T arg;
|
||||
size_t search_pos = source.rfind(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(0, search_pos);
|
||||
}
|
||||
|
||||
// Allow implicit conversion
|
||||
operator u64() const
|
||||
template <typename T>
|
||||
std::string AfterFirst(const std::string& source, T searchstr)
|
||||
{
|
||||
size_t search_pos = source.find(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(search_pos);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string BeforeFirst(const std::string& source, T searchstr)
|
||||
{
|
||||
size_t search_pos = source.find(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(0, search_pos);
|
||||
}
|
||||
|
||||
// write `fmt` from `pos` to the first occurence of `fmt::placeholder` to
|
||||
// the stream `os`. Then write `arg` to to the stream. If there's no
|
||||
// `fmt::placeholder` after `pos` everything in `fmt` after pos is written
|
||||
// to `os`. Then `arg` is written to `os` after appending a space character
|
||||
//template<typename T>
|
||||
//empty_t write(const std::string &fmt, std::ostream &os, std::string::size_type &pos, T &&arg)
|
||||
//{
|
||||
// std::string::size_type ins = fmt.find(placeholder, pos);
|
||||
|
||||
// if (ins == std::string::npos)
|
||||
// {
|
||||
// os.write(fmt.data() + pos, fmt.size() - pos);
|
||||
// os << ' ' << arg;
|
||||
|
||||
// pos = fmt.size();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// os.write(fmt.data() + pos, ins - pos);
|
||||
// os << arg;
|
||||
|
||||
// pos = ins + placeholder.size();
|
||||
// }
|
||||
// return{};
|
||||
//}
|
||||
|
||||
// typesafe version of a sprintf-like function. Returns the printed to
|
||||
// string. To mark positions where the arguments are supposed to be
|
||||
// inserted use `fmt::placeholder`. If there's not enough placeholders
|
||||
// the rest of the arguments are appended at the end, seperated by spaces
|
||||
//template<typename ... Args>
|
||||
//std::string SFormat(const std::string &fmt, Args&& ... parameters)
|
||||
//{
|
||||
// std::ostringstream os;
|
||||
// std::string::size_type pos = 0;
|
||||
// std::initializer_list<empty_t> { write(fmt, os, pos, parameters)... };
|
||||
|
||||
// if (!fmt.empty())
|
||||
// {
|
||||
// os.write(fmt.data() + pos, fmt.size() - pos);
|
||||
// }
|
||||
|
||||
// std::string result = os.str();
|
||||
// return result;
|
||||
//}
|
||||
|
||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
||||
std::string replace_all(const std::string &src, const std::string& from, const std::string& to);
|
||||
|
||||
template<size_t list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::string>(&list)[list_size])
|
||||
{
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(&arg);
|
||||
}
|
||||
};
|
||||
|
||||
// This overload resolution takes the precedence
|
||||
static inline u64_wrapper get(T&& arg)
|
||||
{
|
||||
return u64_wrapper{std::move(arg)};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_integral<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||
{
|
||||
using type = T;
|
||||
|
||||
static inline u64 get(T arg)
|
||||
{
|
||||
return static_cast<T>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_floating_point<T>::value && sizeof(T) <= 8 && alignof(T) <= 8>>
|
||||
{
|
||||
using type = T;
|
||||
|
||||
// Convert FP to f64 and reinterpret (TODO?)
|
||||
static inline u64 get(f64 arg)
|
||||
{
|
||||
return reinterpret_cast<u64&>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T, std::enable_if_t<std::is_enum<T>::value>>
|
||||
{
|
||||
using type = T;
|
||||
|
||||
static inline u64 get(T arg)
|
||||
{
|
||||
return static_cast<std::underlying_type_t<T>>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_unveil<T*, void>
|
||||
{
|
||||
using type = const T*;
|
||||
|
||||
static inline u64 get(const T* arg)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct fmt_unveil<T[N], void>
|
||||
{
|
||||
using type = const T*;
|
||||
|
||||
static inline u64 get(const T* arg)
|
||||
{
|
||||
return reinterpret_cast<std::uintptr_t>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt_unveil<b8, void>
|
||||
{
|
||||
using type = bool;
|
||||
|
||||
static inline u64 get(const b8& value)
|
||||
{
|
||||
return fmt_unveil<bool>::get(value);
|
||||
}
|
||||
};
|
||||
|
||||
// String type format provider, also type classifier (format() called if an argument is formatted as "%s")
|
||||
template <typename T, typename = void>
|
||||
struct fmt_class_string
|
||||
{
|
||||
// Formatting function (must be explicitly specialized)
|
||||
static void format(std::string& out, u64 arg);
|
||||
|
||||
// Helper typedef (visible in format())
|
||||
using type = T;
|
||||
|
||||
// Helper function (converts arg to object reference)
|
||||
static SAFE_BUFFERS FORCE_INLINE const T& get_object(u64 arg)
|
||||
{
|
||||
return *reinterpret_cast<const T*>(static_cast<std::uintptr_t>(arg));
|
||||
}
|
||||
|
||||
// Helper function (safely converts arg to enum value)
|
||||
static SAFE_BUFFERS FORCE_INLINE void format_enum(std::string& out, u64 arg, const char* (*get)(T value))
|
||||
{
|
||||
const auto value = static_cast<std::underlying_type_t<T>>(arg);
|
||||
|
||||
// Check narrowing
|
||||
if (static_cast<u64>(value) == arg)
|
||||
{
|
||||
if (const char* str = get(static_cast<T>(value)))
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
{
|
||||
out += str;
|
||||
return;
|
||||
}
|
||||
}
|
||||
const size_t comp_length = list[i].first.length();
|
||||
|
||||
// Fallback to underlying type formatting
|
||||
fmt_class_string<std::underlying_type_t<T>>::format(out, static_cast<u64>(value));
|
||||
}
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
|
||||
// Helper function (bitset formatting)
|
||||
static SAFE_BUFFERS FORCE_INLINE void format_bitset(std::string& out, u64 arg, const char* prefix, const char* delim, const char* suffix, void (*fmt)(std::string&, u64))
|
||||
{
|
||||
// Start from raw value
|
||||
fmt_class_string<u64>::format(out, arg);
|
||||
|
||||
out += prefix;
|
||||
|
||||
for (u64 i = 0; i < 64; i++)
|
||||
{
|
||||
const u64 mask = 1ull << i;
|
||||
|
||||
if (arg & mask)
|
||||
{
|
||||
fmt(out, i);
|
||||
|
||||
if (arg > mask)
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
out += delim;
|
||||
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length);
|
||||
pos += list[i].second.length() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out += suffix;
|
||||
return src;
|
||||
}
|
||||
|
||||
// Helper constant (may be used in format_enum as lambda return value)
|
||||
static constexpr const char* unknown = nullptr;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt_class_string<const void*, void>
|
||||
{
|
||||
static void format(std::string& out, u64 arg);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct fmt_class_string<T*, void> : fmt_class_string<const void*, void>
|
||||
{
|
||||
// Classify all pointers as const void*
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt_class_string<const char*, void>
|
||||
{
|
||||
static void format(std::string& out, u64 arg);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmt_class_string<char*, void> : fmt_class_string<const char*>
|
||||
{
|
||||
// Classify char* as const char*
|
||||
};
|
||||
|
||||
struct fmt_type_info
|
||||
{
|
||||
decltype(&fmt_class_string<int>::format) fmt_string;
|
||||
|
||||
template <typename T>
|
||||
static constexpr fmt_type_info make()
|
||||
template<size_t list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>>(&list)[list_size])
|
||||
{
|
||||
return fmt_type_info
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
&fmt_class_string<T>::format,
|
||||
};
|
||||
}
|
||||
};
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
{
|
||||
const size_t comp_length = list[i].first.length();
|
||||
|
||||
// Argument array type (each element generated via fmt_unveil<>)
|
||||
template <typename... Args>
|
||||
using fmt_args_t = const u64(&&)[sizeof...(Args) + 1];
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
template <typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE const fmt_type_info* get_type_info()
|
||||
{
|
||||
// Constantly initialized null-terminated list of type-specific information
|
||||
static constexpr fmt_type_info result[sizeof...(Args) + 1]{fmt_type_info::make<Args>()...};
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length);
|
||||
pos += list[i].second().length() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return src;
|
||||
}
|
||||
|
||||
// Internal formatting function
|
||||
void raw_append(std::string& out, const char*, const fmt_type_info*, const u64*) noexcept;
|
||||
std::string to_hex(u64 value, u64 count = 1);
|
||||
std::string to_udec(u64 value);
|
||||
std::string to_sdec(s64 value);
|
||||
|
||||
// Formatting function
|
||||
template <typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE void append(std::string& out, const char* fmt, const Args&... args)
|
||||
template<typename T, bool is_enum = std::is_enum<T>::value> struct unveil
|
||||
{
|
||||
raw_append(out, fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||
using result_type = T;
|
||||
|
||||
force_inline static result_type get_value(const T& arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct unveil<const char*, false>
|
||||
{
|
||||
using result_type = const char* const;
|
||||
|
||||
force_inline static result_type get_value(const char* const& arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
template<std::size_t N> struct unveil<char[N], false>
|
||||
{
|
||||
using result_type = const char* const;
|
||||
|
||||
force_inline static result_type get_value(const char(&arg)[N])
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct unveil<std::string, false>
|
||||
{
|
||||
using result_type = const char*;
|
||||
|
||||
force_inline static result_type get_value(const std::string& arg)
|
||||
{
|
||||
return arg.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct unveil<T, true>
|
||||
{
|
||||
using result_type = std::underlying_type_t<T>;
|
||||
|
||||
force_inline static result_type get_value(const T& arg)
|
||||
{
|
||||
return static_cast<result_type>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, bool Se> struct unveil<se_t<T, Se>, false>
|
||||
{
|
||||
using result_type = typename unveil<T>::result_type;
|
||||
|
||||
force_inline static result_type get_value(const se_t<T, Se>& arg)
|
||||
{
|
||||
return unveil<T>::get_value(arg);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
force_inline typename unveil<T>::result_type do_unveil(const T& arg)
|
||||
{
|
||||
return unveil<T>::get_value(arg);
|
||||
}
|
||||
|
||||
// Formatting function
|
||||
template <typename... Args>
|
||||
SAFE_BUFFERS FORCE_INLINE std::string format(const char* fmt, const Args&... args)
|
||||
// Formatting function with special functionality:
|
||||
//
|
||||
// std::string is forced to .c_str()
|
||||
// be_t<> is forced to .value() (fmt::do_unveil reverts byte order automatically)
|
||||
//
|
||||
// External specializations for fmt::do_unveil (can be found in another headers):
|
||||
// vm::ptr, vm::bptr, ... (fmt::do_unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided)
|
||||
// vm::ref, vm::bref, ... (fmt::do_unveil) (vm_ref.h)
|
||||
//
|
||||
template<typename... Args>
|
||||
safe_buffers std::string format(const char* fmt, const Args&... args)
|
||||
{
|
||||
// fixed stack buffer for the first attempt
|
||||
std::array<char, 4096> fixed_buf;
|
||||
|
||||
// possibly dynamically allocated buffer for the second attempt
|
||||
std::unique_ptr<char[]> buf;
|
||||
|
||||
// pointer to the current buffer
|
||||
char* buf_addr = fixed_buf.data();
|
||||
|
||||
for (std::size_t buf_size = fixed_buf.size();;)
|
||||
{
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-security"
|
||||
#endif
|
||||
const std::size_t len = std::snprintf(buf_addr, buf_size, fmt, do_unveil(args)...);
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
if (len > INT_MAX)
|
||||
{
|
||||
throw std::runtime_error("std::snprintf() failed");
|
||||
}
|
||||
|
||||
if (len < buf_size)
|
||||
{
|
||||
return{ buf_addr, len };
|
||||
}
|
||||
|
||||
buf.reset(buf_addr = new char[buf_size = len + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
struct exception : public std::exception
|
||||
{
|
||||
std::unique_ptr<char[]> message;
|
||||
|
||||
template<typename... Args> never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) noexcept
|
||||
{
|
||||
const std::string data = format(text, args...) + format("\n(in file %s:%d, in function %s)", file, line, func);
|
||||
|
||||
message.reset(new char[data.size() + 1]);
|
||||
|
||||
std::memcpy(message.get(), data.c_str(), data.size() + 1);
|
||||
}
|
||||
|
||||
exception(const exception& other) noexcept
|
||||
{
|
||||
const std::size_t size = std::strlen(other.message.get());
|
||||
|
||||
message.reset(new char[size + 1]);
|
||||
|
||||
std::memcpy(message.get(), other.message.get(), size + 1);
|
||||
}
|
||||
|
||||
virtual const char* what() const noexcept override
|
||||
{
|
||||
return message.get();
|
||||
}
|
||||
};
|
||||
|
||||
//convert a wxString to a std::string encoded in utf8
|
||||
//CAUTION, only use this to interface with wxWidgets classes
|
||||
std::string ToUTF8(const wxString& right);
|
||||
|
||||
//convert a std::string encoded in utf8 to a wxString
|
||||
//CAUTION, only use this to interface with wxWidgets classes
|
||||
wxString FromUTF8(const std::string& right);
|
||||
|
||||
//TODO: remove this after every snippet that uses it is gone
|
||||
//WARNING: not fully compatible with CmpNoCase from wxString
|
||||
int CmpNoCase(const std::string& a, const std::string& b);
|
||||
|
||||
//TODO: remove this after every snippet that uses it is gone
|
||||
//WARNING: not fully compatible with Replace from wxString
|
||||
void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm);
|
||||
|
||||
std::vector<std::string> rSplit(const std::string& source, const std::string& delim);
|
||||
|
||||
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
|
||||
std::string trim(const std::string& source, const std::string& values = " \t");
|
||||
|
||||
template<typename T>
|
||||
std::string merge(const T& source, const std::string& separator)
|
||||
{
|
||||
if (!source.size())
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
std::string result;
|
||||
append<Args...>(result, fmt, args...);
|
||||
|
||||
auto it = source.begin();
|
||||
auto end = source.end();
|
||||
for (--end; it != end; ++it)
|
||||
{
|
||||
result += *it + separator;
|
||||
}
|
||||
|
||||
return result + source.back();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::string merge(std::initializer_list<T> sources, const std::string& separator)
|
||||
{
|
||||
if (!sources.size())
|
||||
{
|
||||
return{};
|
||||
}
|
||||
|
||||
std::string result;
|
||||
bool first = true;
|
||||
|
||||
for (auto &v : sources)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
result = fmt::merge(v, separator);
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += separator + fmt::merge(v, separator);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Internal exception message formatting template, must be explicitly specialized or instantiated in cpp to minimize code bloat
|
||||
template <typename T>
|
||||
[[noreturn]] void raw_throw_exception(const char*, const fmt_type_info*, const u64*);
|
||||
|
||||
// Throw exception with formatting
|
||||
template <typename T = std::runtime_error, typename... Args>
|
||||
[[noreturn]] SAFE_BUFFERS FORCE_INLINE void throw_exception(const char* fmt, const Args&... args)
|
||||
{
|
||||
raw_throw_exception<T>(fmt, fmt::get_type_info<fmt_unveil_t<Args>...>(), fmt_args_t<Args...>{fmt_unveil<Args>::get(args)...});
|
||||
}
|
||||
std::string tolower(std::string source);
|
||||
std::string toupper(std::string source);
|
||||
std::string escape(std::string source);
|
||||
bool match(const std::string &source, const std::string &mask);
|
||||
}
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
// Copy null-terminated string from std::string to char array with truncation
|
||||
template <std::size_t N>
|
||||
inline void strcpy_trunc(char (&dst)[N], const std::string& src)
|
||||
{
|
||||
const std::size_t count = src.size() >= N ? N - 1 : src.size();
|
||||
std::memcpy(dst, src.c_str(), count);
|
||||
dst[count] = '\0';
|
||||
}
|
||||
|
||||
// Copy null-terminated string from char array to another char array with truncation
|
||||
template <std::size_t N, std::size_t N2>
|
||||
inline void strcpy_trunc(char (&dst)[N], const char (&src)[N2])
|
||||
{
|
||||
const std::size_t count = N2 >= N ? N - 1 : N2;
|
||||
std::memcpy(dst, src, count);
|
||||
dst[count] = '\0';
|
||||
}
|
||||
|
||||
namespace fmt
|
||||
{
|
||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
||||
std::string replace_all(const std::string& src, const std::string& from, const std::string& to);
|
||||
|
||||
template <size_t list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::string> (&list)[list_size])
|
||||
{
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
{
|
||||
const size_t comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + src.substr(pos + comp_length);
|
||||
pos += list[i].second.length() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
template <size_t list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>> (&list)[list_size])
|
||||
{
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
{
|
||||
const size_t comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + src.substr(pos + comp_length);
|
||||
pos += list[i].second().length() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
|
||||
std::string trim(const std::string& source, const std::string& values = " \t");
|
||||
|
||||
template <typename T>
|
||||
std::string merge(const T& source, const std::string& separator)
|
||||
{
|
||||
if (!source.size())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string result;
|
||||
|
||||
auto it = source.begin();
|
||||
auto end = source.end();
|
||||
for (--end; it != end; ++it)
|
||||
{
|
||||
result += *it + separator;
|
||||
}
|
||||
|
||||
return result + source.back();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string merge(std::initializer_list<T> sources, const std::string& separator)
|
||||
{
|
||||
if (!sources.size())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string result;
|
||||
bool first = true;
|
||||
|
||||
for (auto& v : sources)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
result = fmt::merge(v, separator);
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += separator + fmt::merge(v, separator);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_upper(const std::string& string);
|
||||
|
||||
bool match(const std::string& source, const std::string& mask);
|
||||
}
|
||||
+188
-1135
File diff suppressed because it is too large
Load Diff
+417
-412
@@ -1,505 +1,510 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
// Will report exception and call std::abort() if put in catch(...)
|
||||
[[noreturn]] void catch_all_exceptions();
|
||||
|
||||
// Simple list of void() functors
|
||||
class task_stack
|
||||
{
|
||||
struct task_base
|
||||
{
|
||||
std::unique_ptr<task_base> next;
|
||||
|
||||
virtual ~task_base() = default;
|
||||
|
||||
virtual void exec()
|
||||
{
|
||||
if (next)
|
||||
{
|
||||
next->exec();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct task_type : task_base
|
||||
{
|
||||
std::remove_reference_t<F> func;
|
||||
|
||||
task_type(F&& func)
|
||||
: func(std::forward<F>(func))
|
||||
{
|
||||
}
|
||||
|
||||
void exec() override
|
||||
{
|
||||
func();
|
||||
task_base::exec();
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<task_base> m_stack;
|
||||
|
||||
public:
|
||||
task_stack() = default;
|
||||
|
||||
template<typename F>
|
||||
task_stack(F&& func)
|
||||
: m_stack(new task_type<F>(std::forward<F>(func)))
|
||||
{
|
||||
}
|
||||
|
||||
void push(task_stack stack)
|
||||
{
|
||||
auto _top = stack.m_stack.release();
|
||||
auto _next = m_stack.release();
|
||||
m_stack.reset(_top);
|
||||
while (UNLIKELY(_top->next)) _top = _top->next.get();
|
||||
_top->next.reset(_next);
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
m_stack.reset();
|
||||
}
|
||||
|
||||
void exec() const
|
||||
{
|
||||
if (m_stack)
|
||||
{
|
||||
m_stack->exec();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Thread control class
|
||||
class thread_ctrl final
|
||||
{
|
||||
public: // TODO
|
||||
struct internal;
|
||||
|
||||
private:
|
||||
static thread_local thread_ctrl* g_tls_this_thread;
|
||||
|
||||
// Thread handle storage
|
||||
std::aligned_storage_t<16> m_thread;
|
||||
// Name getter
|
||||
std::function<std::string()> m_name;
|
||||
|
||||
// Thread join contention counter
|
||||
atomic_t<u32> m_joining{};
|
||||
// Thread handle (be careful)
|
||||
std::thread m_thread;
|
||||
|
||||
// Thread interrupt guard counter
|
||||
volatile u32 m_guard = 0x80000000;
|
||||
// Thread result
|
||||
std::future<void> m_future;
|
||||
|
||||
// Thread internals
|
||||
atomic_t<internal*> m_data{};
|
||||
|
||||
// Fixed name
|
||||
std::string m_name;
|
||||
|
||||
// Start thread
|
||||
static void start(const std::shared_ptr<thread_ctrl>&, task_stack);
|
||||
// Functions scheduled at thread exit
|
||||
std::deque<std::function<void()>> m_atexit;
|
||||
|
||||
// Called at the thread start
|
||||
void initialize();
|
||||
static void initialize();
|
||||
|
||||
// Called at the thread end
|
||||
void finalize() noexcept;
|
||||
|
||||
// Get atexit function
|
||||
void push_atexit(task_stack);
|
||||
|
||||
// Start waiting
|
||||
void wait_start(u64 timeout);
|
||||
|
||||
// Proceed waiting
|
||||
bool wait_wait(u64 timeout);
|
||||
|
||||
// Check exception
|
||||
void test();
|
||||
static void finalize() noexcept;
|
||||
|
||||
public:
|
||||
thread_ctrl(std::string&& name);
|
||||
template<typename T>
|
||||
thread_ctrl(T&& name)
|
||||
: m_name(std::forward<T>(name))
|
||||
{
|
||||
}
|
||||
|
||||
// Disable copy/move constructors and operators
|
||||
thread_ctrl(const thread_ctrl&) = delete;
|
||||
|
||||
~thread_ctrl();
|
||||
|
||||
// Get thread name
|
||||
const std::string& get_name() const
|
||||
std::string get_name() const;
|
||||
|
||||
// Get future result (may throw)
|
||||
void join()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
// Initialize internal data
|
||||
void initialize_once();
|
||||
|
||||
// Get thread result (may throw, simultaneous joining allowed)
|
||||
void join();
|
||||
|
||||
// Lock thread mutex
|
||||
void lock();
|
||||
|
||||
// Lock conditionally (double-checked)
|
||||
template<typename F>
|
||||
bool lock_if(F&& pred)
|
||||
{
|
||||
if (pred())
|
||||
{
|
||||
lock();
|
||||
|
||||
try
|
||||
{
|
||||
if (LIKELY(pred()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
unlock();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Unlock thread mutex (internal data must be initialized)
|
||||
void unlock();
|
||||
|
||||
// Lock, unlock, notify the thread (required if the condition changed locklessly)
|
||||
void lock_notify();
|
||||
|
||||
// Notify the thread (internal data must be initialized)
|
||||
void notify();
|
||||
|
||||
// Set exception (internal data must be initialized, thread mutex must be locked)
|
||||
void set_exception(std::exception_ptr);
|
||||
|
||||
// Internal
|
||||
static void handle_interrupt();
|
||||
|
||||
// Interrupt thread with specified handler call (thread mutex must be locked)
|
||||
void interrupt(void(*handler)());
|
||||
|
||||
// Interrupt guard recursive enter
|
||||
void guard_enter()
|
||||
{
|
||||
m_guard++;
|
||||
}
|
||||
|
||||
// Interrupt guard recursive leave
|
||||
void guard_leave()
|
||||
{
|
||||
if (UNLIKELY(--m_guard & 0x40000000))
|
||||
{
|
||||
test_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
// Allow interrupts
|
||||
void interrupt_enable()
|
||||
{
|
||||
m_guard &= ~0x80000000;
|
||||
}
|
||||
|
||||
// Disable and discard any interrupt
|
||||
void interrupt_disable()
|
||||
{
|
||||
m_guard |= 0x80000000;
|
||||
}
|
||||
|
||||
// Check interrupt if delayed by guard scope
|
||||
void test_interrupt();
|
||||
|
||||
// Current thread sleeps for specified amount of microseconds.
|
||||
// Wrapper for std::this_thread::sleep, doesn't require valid thread_ctrl.
|
||||
[[deprecated]] static void sleep(u64 useconds);
|
||||
|
||||
// Wait until pred(). Abortable, may throw. Thread must be locked.
|
||||
// Timeout in microseconds (zero means infinite).
|
||||
template<typename F>
|
||||
static inline auto wait_for(u64 useconds, F&& pred)
|
||||
{
|
||||
if (useconds)
|
||||
{
|
||||
g_tls_this_thread->wait_start(useconds);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
g_tls_this_thread->test();
|
||||
|
||||
if (auto&& result = pred())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
else if (!g_tls_this_thread->wait_wait(useconds) && useconds)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait once. Abortable, may throw. Thread must be locked.
|
||||
// Timeout in microseconds (zero means infinite).
|
||||
static inline bool wait_for(u64 useconds = 0)
|
||||
{
|
||||
if (useconds)
|
||||
{
|
||||
g_tls_this_thread->wait_start(useconds);
|
||||
}
|
||||
|
||||
g_tls_this_thread->test();
|
||||
|
||||
if (!g_tls_this_thread->wait_wait(useconds) && useconds)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
g_tls_this_thread->test();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wait until pred(). Abortable, may throw. Thread must be locked.
|
||||
template<typename F>
|
||||
static inline auto wait(F&& pred)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
g_tls_this_thread->test();
|
||||
|
||||
if (auto&& result = pred())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
g_tls_this_thread->wait_wait(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait once. Abortable, may throw. Thread must be locked.
|
||||
static inline void wait()
|
||||
{
|
||||
g_tls_this_thread->test();
|
||||
g_tls_this_thread->wait_wait(0);
|
||||
g_tls_this_thread->test();
|
||||
}
|
||||
|
||||
// Wait eternally. Abortable, may throw. Thread must be locked.
|
||||
[[noreturn]] static inline void eternalize()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
g_tls_this_thread->test();
|
||||
g_tls_this_thread->wait_wait(0);
|
||||
}
|
||||
return m_future.get();
|
||||
}
|
||||
|
||||
// Get current thread (may be nullptr)
|
||||
static thread_ctrl* get_current()
|
||||
static const thread_ctrl* get_current()
|
||||
{
|
||||
return g_tls_this_thread;
|
||||
}
|
||||
|
||||
// Register function at thread exit (for the current thread)
|
||||
template<typename F>
|
||||
static inline void atexit(F&& func)
|
||||
template<typename T>
|
||||
static inline void at_exit(T&& func)
|
||||
{
|
||||
return g_tls_this_thread->push_atexit(std::forward<F>(func));
|
||||
CHECK_ASSERTION(g_tls_this_thread);
|
||||
|
||||
g_tls_this_thread->m_atexit.emplace_front(std::forward<T>(func));
|
||||
}
|
||||
|
||||
// Named thread factory
|
||||
template<typename N, typename F>
|
||||
static inline void spawn(N&& name, F&& func)
|
||||
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func)
|
||||
{
|
||||
auto&& out = std::make_shared<thread_ctrl>(std::forward<N>(name));
|
||||
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
|
||||
|
||||
thread_ctrl::start(out, std::forward<F>(func));
|
||||
}
|
||||
std::promise<void> promise;
|
||||
|
||||
// Named thread factory
|
||||
template<typename N, typename F>
|
||||
static inline void spawn(std::shared_ptr<thread_ctrl>& out, N&& name, F&& func)
|
||||
{
|
||||
out = std::make_shared<thread_ctrl>(std::forward<N>(name));
|
||||
ctrl->m_future = promise.get_future();
|
||||
|
||||
thread_ctrl::start(out, std::forward<F>(func));
|
||||
ctrl->m_thread = std::thread([ctrl, task = std::forward<F>(func)](std::promise<void> promise)
|
||||
{
|
||||
g_tls_this_thread = ctrl.get();
|
||||
|
||||
try
|
||||
{
|
||||
initialize();
|
||||
task();
|
||||
finalize();
|
||||
promise.set_value();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
finalize();
|
||||
promise.set_exception(std::current_exception());
|
||||
}
|
||||
|
||||
}, std::move(promise));
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
};
|
||||
|
||||
class named_thread
|
||||
class named_thread_t : public std::enable_shared_from_this<named_thread_t>
|
||||
{
|
||||
// Pointer to managed resource (shared with actual thread)
|
||||
std::shared_ptr<thread_ctrl> m_thread;
|
||||
|
||||
public:
|
||||
named_thread();
|
||||
// Thread condition variable for external use (this thread waits on it, other threads may notify)
|
||||
std::condition_variable cv;
|
||||
|
||||
virtual ~named_thread();
|
||||
|
||||
// Deleted copy/move constructors + copy/move operators
|
||||
named_thread(const named_thread&) = delete;
|
||||
|
||||
// Get thread name
|
||||
virtual std::string get_name() const;
|
||||
// Thread mutex for external use (can be used with `cv`)
|
||||
std::mutex mutex;
|
||||
|
||||
protected:
|
||||
// Start thread (cannot be called from the constructor: should throw in such case)
|
||||
void start_thread(const std::shared_ptr<void>& _this);
|
||||
|
||||
// Thread task (called in the thread)
|
||||
virtual void on_task() = 0;
|
||||
|
||||
// Thread finalization (called after on_task)
|
||||
virtual void on_exit() {}
|
||||
|
||||
public:
|
||||
// ID initialization
|
||||
virtual void on_init(const std::shared_ptr<void>& _this)
|
||||
{
|
||||
return start_thread(_this);
|
||||
}
|
||||
// ID initialization (called through id_aux_initialize)
|
||||
virtual void on_id_aux_initialize() { start(); }
|
||||
|
||||
// ID finalization
|
||||
virtual void on_stop()
|
||||
{
|
||||
m_thread->join();
|
||||
}
|
||||
|
||||
// Access thread_ctrl
|
||||
thread_ctrl* operator->() const
|
||||
{
|
||||
return m_thread.get();
|
||||
}
|
||||
|
||||
void join() const
|
||||
{
|
||||
return m_thread->join();
|
||||
}
|
||||
|
||||
void lock() const
|
||||
{
|
||||
return m_thread->lock();
|
||||
}
|
||||
|
||||
void unlock() const
|
||||
{
|
||||
return m_thread->unlock();
|
||||
}
|
||||
|
||||
void lock_notify() const
|
||||
{
|
||||
return m_thread->lock_notify();
|
||||
}
|
||||
|
||||
void notify() const
|
||||
{
|
||||
return m_thread->notify();
|
||||
}
|
||||
};
|
||||
|
||||
// Simple thread mutex locker
|
||||
class thread_lock final
|
||||
{
|
||||
thread_ctrl* m_thread;
|
||||
// ID finalization (called through id_aux_finalize)
|
||||
virtual void on_id_aux_finalize() { join(); }
|
||||
|
||||
public:
|
||||
thread_lock(const thread_lock&) = delete;
|
||||
named_thread_t() = default;
|
||||
|
||||
// Lock specified thread
|
||||
thread_lock(thread_ctrl* thread)
|
||||
: m_thread(thread)
|
||||
{
|
||||
m_thread->lock();
|
||||
}
|
||||
virtual ~named_thread_t() = default;
|
||||
|
||||
// Lock specified named_thread
|
||||
thread_lock(named_thread& thread)
|
||||
: thread_lock(thread.operator->())
|
||||
{
|
||||
}
|
||||
// Deleted copy/move constructors + copy/move operators
|
||||
named_thread_t(const named_thread_t&) = delete;
|
||||
|
||||
// Lock current thread
|
||||
thread_lock()
|
||||
: thread_lock(thread_ctrl::get_current())
|
||||
{
|
||||
}
|
||||
// Get thread name
|
||||
virtual std::string get_name() const;
|
||||
|
||||
~thread_lock()
|
||||
{
|
||||
m_thread->unlock();
|
||||
}
|
||||
};
|
||||
// Start thread (cannot be called from the constructor: should throw bad_weak_ptr in such case)
|
||||
void start();
|
||||
|
||||
// Interrupt guard scope
|
||||
class thread_guard final
|
||||
{
|
||||
thread_ctrl* m_thread;
|
||||
// Join thread (get future result)
|
||||
void join();
|
||||
|
||||
public:
|
||||
thread_guard(const thread_guard&) = delete;
|
||||
// Check whether the thread is not in "empty state"
|
||||
bool is_started() const { return m_thread.operator bool(); }
|
||||
|
||||
thread_guard(thread_ctrl* thread)
|
||||
: m_thread(thread)
|
||||
{
|
||||
m_thread->guard_enter();
|
||||
}
|
||||
// Compare with the current thread
|
||||
bool is_current() const { CHECK_ASSERTION(m_thread); return thread_ctrl::get_current() == m_thread.get(); }
|
||||
|
||||
thread_guard(named_thread& thread)
|
||||
: thread_guard(thread.operator->())
|
||||
{
|
||||
}
|
||||
// Get thread_ctrl
|
||||
const thread_ctrl* get_thread_ctrl() const { return m_thread.get(); }
|
||||
|
||||
thread_guard()
|
||||
: thread_guard(thread_ctrl::get_current())
|
||||
{
|
||||
}
|
||||
|
||||
~thread_guard() noexcept(false)
|
||||
{
|
||||
m_thread->guard_leave();
|
||||
}
|
||||
friend void id_aux_initialize(named_thread_t* ptr) { ptr->on_id_aux_initialize(); }
|
||||
friend void id_aux_finalize(named_thread_t* ptr) { ptr->on_id_aux_finalize(); }
|
||||
};
|
||||
|
||||
// Wrapper for named thread, joins automatically in the destructor, can only be used in function scope
|
||||
class scope_thread final
|
||||
class scope_thread_t final
|
||||
{
|
||||
std::shared_ptr<thread_ctrl> m_thread;
|
||||
|
||||
public:
|
||||
template<typename N, typename F>
|
||||
scope_thread(N&& name, F&& func)
|
||||
scope_thread_t(N&& name, F&& func)
|
||||
: m_thread(thread_ctrl::spawn(std::forward<N>(name), std::forward<F>(func)))
|
||||
{
|
||||
thread_ctrl::spawn(m_thread, std::forward<N>(name), std::forward<F>(func));
|
||||
}
|
||||
|
||||
// Deleted copy/move constructors + copy/move operators
|
||||
scope_thread(const scope_thread&) = delete;
|
||||
scope_thread_t(const scope_thread_t&) = delete;
|
||||
|
||||
// Destructor with exceptions allowed
|
||||
~scope_thread() noexcept(false)
|
||||
~scope_thread_t() noexcept(false)
|
||||
{
|
||||
m_thread->join();
|
||||
}
|
||||
};
|
||||
|
||||
// Access thread_ctrl
|
||||
thread_ctrl* operator->() const
|
||||
extern const std::function<bool()> SQUEUE_ALWAYS_EXIT;
|
||||
extern const std::function<bool()> SQUEUE_NEVER_EXIT;
|
||||
|
||||
bool squeue_test_exit();
|
||||
|
||||
template<typename T, u32 sq_size = 256>
|
||||
class squeue_t
|
||||
{
|
||||
struct squeue_sync_var_t
|
||||
{
|
||||
return m_thread.get();
|
||||
struct
|
||||
{
|
||||
u32 position : 31;
|
||||
u32 pop_lock : 1;
|
||||
};
|
||||
struct
|
||||
{
|
||||
u32 count : 31;
|
||||
u32 push_lock : 1;
|
||||
};
|
||||
};
|
||||
|
||||
atomic_t<squeue_sync_var_t> m_sync;
|
||||
|
||||
mutable std::mutex m_rcv_mutex;
|
||||
mutable std::mutex m_wcv_mutex;
|
||||
mutable std::condition_variable m_rcv;
|
||||
mutable std::condition_variable m_wcv;
|
||||
|
||||
T m_data[sq_size];
|
||||
|
||||
enum squeue_sync_var_result : u32
|
||||
{
|
||||
SQSVR_OK = 0,
|
||||
SQSVR_LOCKED = 1,
|
||||
SQSVR_FAILED = 2,
|
||||
};
|
||||
|
||||
public:
|
||||
squeue_t()
|
||||
: m_sync(squeue_sync_var_t{})
|
||||
{
|
||||
}
|
||||
|
||||
u32 get_max_size() const
|
||||
{
|
||||
return sq_size;
|
||||
}
|
||||
|
||||
bool is_full() const
|
||||
{
|
||||
return m_sync.load().count == sq_size;
|
||||
}
|
||||
|
||||
bool push(const T& data, const std::function<bool()>& test_exit)
|
||||
{
|
||||
u32 pos = 0;
|
||||
|
||||
while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.push_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
if (sync.count == sq_size)
|
||||
{
|
||||
return SQSVR_FAILED;
|
||||
}
|
||||
|
||||
sync.push_lock = 1;
|
||||
pos = sync.position + sync.count;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> wcv_lock(m_wcv_mutex);
|
||||
m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
m_data[pos >= sq_size ? pos - sq_size : pos] = data;
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.push_lock);
|
||||
sync.push_lock = 0;
|
||||
sync.count++;
|
||||
});
|
||||
|
||||
m_rcv.notify_one();
|
||||
m_wcv.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool push(const T& data, const volatile bool* do_exit)
|
||||
{
|
||||
return push(data, [do_exit](){ return do_exit && *do_exit; });
|
||||
}
|
||||
|
||||
force_inline bool push(const T& data)
|
||||
{
|
||||
return push(data, SQUEUE_NEVER_EXIT);
|
||||
}
|
||||
|
||||
force_inline bool try_push(const T& data)
|
||||
{
|
||||
return push(data, SQUEUE_ALWAYS_EXIT);
|
||||
}
|
||||
|
||||
bool pop(T& data, const std::function<bool()>& test_exit)
|
||||
{
|
||||
u32 pos = 0;
|
||||
|
||||
while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (!sync.count)
|
||||
{
|
||||
return SQSVR_FAILED;
|
||||
}
|
||||
if (sync.pop_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
sync.pop_lock = 1;
|
||||
pos = sync.position;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
data = m_data[pos];
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.pop_lock);
|
||||
sync.pop_lock = 0;
|
||||
sync.position++;
|
||||
sync.count--;
|
||||
if (sync.position == sq_size)
|
||||
{
|
||||
sync.position = 0;
|
||||
}
|
||||
});
|
||||
|
||||
m_rcv.notify_one();
|
||||
m_wcv.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pop(T& data, const volatile bool* do_exit)
|
||||
{
|
||||
return pop(data, [do_exit](){ return do_exit && *do_exit; });
|
||||
}
|
||||
|
||||
force_inline bool pop(T& data)
|
||||
{
|
||||
return pop(data, SQUEUE_NEVER_EXIT);
|
||||
}
|
||||
|
||||
force_inline bool try_pop(T& data)
|
||||
{
|
||||
return pop(data, SQUEUE_ALWAYS_EXIT);
|
||||
}
|
||||
|
||||
bool peek(T& data, u32 start_pos, const std::function<bool()>& test_exit)
|
||||
{
|
||||
assert(start_pos < sq_size);
|
||||
u32 pos = 0;
|
||||
|
||||
while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.count <= start_pos)
|
||||
{
|
||||
return SQSVR_FAILED;
|
||||
}
|
||||
if (sync.pop_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
sync.pop_lock = 1;
|
||||
pos = sync.position + start_pos;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
data = m_data[pos >= sq_size ? pos - sq_size : pos];
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.pop_lock);
|
||||
sync.pop_lock = 0;
|
||||
});
|
||||
|
||||
m_rcv.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peek(T& data, u32 start_pos, const volatile bool* do_exit)
|
||||
{
|
||||
return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; });
|
||||
}
|
||||
|
||||
force_inline bool peek(T& data, u32 start_pos = 0)
|
||||
{
|
||||
return peek(data, start_pos, SQUEUE_NEVER_EXIT);
|
||||
}
|
||||
|
||||
force_inline bool try_peek(T& data, u32 start_pos = 0)
|
||||
{
|
||||
return peek(data, start_pos, SQUEUE_ALWAYS_EXIT);
|
||||
}
|
||||
|
||||
class squeue_data_t
|
||||
{
|
||||
T* const m_data;
|
||||
const u32 m_pos;
|
||||
const u32 m_count;
|
||||
|
||||
squeue_data_t(T* data, u32 pos, u32 count)
|
||||
: m_data(data)
|
||||
, m_pos(pos)
|
||||
, m_count(count)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
T& operator [] (u32 index)
|
||||
{
|
||||
assert(index < m_count);
|
||||
index += m_pos;
|
||||
index = index < sq_size ? index : index - sq_size;
|
||||
return m_data[index];
|
||||
}
|
||||
};
|
||||
|
||||
void process(void(*proc)(squeue_data_t data))
|
||||
{
|
||||
u32 pos, count;
|
||||
|
||||
while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.pop_lock || sync.push_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
pos = sync.position;
|
||||
count = sync.count;
|
||||
sync.pop_lock = 1;
|
||||
sync.push_lock = 1;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
proc(squeue_data_t(m_data, pos, count));
|
||||
|
||||
m_sync.atomic_op([](squeue_sync_var_t& sync)
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
assert(sync.pop_lock && sync.push_lock);
|
||||
sync.pop_lock = 0;
|
||||
sync.push_lock = 0;
|
||||
});
|
||||
|
||||
m_wcv.notify_one();
|
||||
m_rcv.notify_one();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32
|
||||
{
|
||||
assert(sync.count <= sq_size);
|
||||
assert(sync.position < sq_size);
|
||||
|
||||
if (sync.pop_lock || sync.push_lock)
|
||||
{
|
||||
return SQSVR_LOCKED;
|
||||
}
|
||||
|
||||
sync.pop_lock = 1;
|
||||
sync.push_lock = 1;
|
||||
return SQSVR_OK;
|
||||
}))
|
||||
{
|
||||
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
|
||||
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
m_sync.exchange({});
|
||||
m_wcv.notify_one();
|
||||
m_rcv.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,27 +16,30 @@ namespace memory_helper
|
||||
void* reserve_memory(size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return verify("reserve_memory" HERE, VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS));
|
||||
void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
|
||||
CHECK_ASSERTION(ret != NULL);
|
||||
#else
|
||||
return verify("reserve_memory" HERE, ::mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0));
|
||||
void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
CHECK_ASSERTION(ret != 0);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void commit_page_memory(void* pointer, size_t size)
|
||||
void commit_page_memory(void* pointer, size_t page_size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
verify(HERE), VirtualAlloc(pointer, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
CHECK_ASSERTION(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL);
|
||||
#else
|
||||
verify(HERE), ::mprotect((void*)((u64)pointer & -4096), size, PROT_READ | PROT_WRITE) != -1;
|
||||
CHECK_ASSERTION(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void free_reserved_memory(void* pointer, size_t size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
verify(HERE), VirtualFree(pointer, 0, MEM_DECOMMIT);
|
||||
CHECK_ASSERTION(VirtualFree(pointer, 0, MEM_RELEASE) != 0);
|
||||
#else
|
||||
verify(HERE), ::mprotect(pointer, size, PROT_NONE) != -1;
|
||||
CHECK_ASSERTION(munmap(pointer, size) == 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,20 @@
|
||||
namespace memory_helper
|
||||
{
|
||||
/**
|
||||
* Reserve `size` bytes of virtual memory and returns it.
|
||||
* Reserve size bytes of virtual memory and returns it.
|
||||
* The memory should be commited before usage.
|
||||
*/
|
||||
void* reserve_memory(std::size_t size);
|
||||
void* reserve_memory(size_t size);
|
||||
|
||||
/**
|
||||
* Commit `size` bytes of virtual memory starting at pointer.
|
||||
* Commit page_size bytes of virtual memory starting at pointer.
|
||||
* That is, bake reserved memory with physical memory.
|
||||
* pointer should belong to a range of reserved memory.
|
||||
*/
|
||||
void commit_page_memory(void* pointer, std::size_t size);
|
||||
void commit_page_memory(void* pointer, size_t page_size);
|
||||
|
||||
/**
|
||||
* Decommit all memory committed via commit_page_memory.
|
||||
* Free memory alloced via reserve_memory.
|
||||
*/
|
||||
void free_reserved_memory(void* pointer, std::size_t size);
|
||||
}
|
||||
void free_reserved_memory(void* pointer, size_t size);
|
||||
}
|
||||
@@ -1,732 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
This header helps to extend scoped enum types (enum class) in two possible ways:
|
||||
1) Enabling bitwise operators for enums
|
||||
2) Advanced bs_t<> template (this converts enum type to another "bitset" enum type)
|
||||
|
||||
To enable bitwise operators, enum scope must contain `__bitwise_ops` entry.
|
||||
|
||||
enum class flags
|
||||
{
|
||||
__bitwise_ops, // Not essential, but recommended to put it first
|
||||
|
||||
flag1 = 1 << 0,
|
||||
flag2 = 1 << 1,
|
||||
};
|
||||
|
||||
Examples:
|
||||
`flags::flag1 | flags::flag2` - bitwise OR
|
||||
`flags::flag1 & flags::flag2` - bitwise AND
|
||||
`flags::flag1 ^ flags::flag2` - bitwise XOR
|
||||
`~flags::flag1` - bitwise NEG
|
||||
|
||||
To enable bs_t<> template, enum scope must contain `__bitset_enum_max` entry.
|
||||
|
||||
enum class flagzz : u32
|
||||
{
|
||||
flag1, // Bit indices start from zero
|
||||
flag2,
|
||||
|
||||
__bitset_enum_max // It must be the last value
|
||||
};
|
||||
|
||||
Now some operators are enabled for two enum types: `flagzz` and `bs_t<flagzz>`.
|
||||
These are very different from previously described bitwise operators.
|
||||
|
||||
Examples:
|
||||
`+flagzz::flag1` - unary `+` operator convert flagzz value to bs_t<flagzz>
|
||||
`flagzz::flag1 + flagzz::flag2` - bitset union
|
||||
`flagzz::flag1 - flagzz::flag2` - bitset difference
|
||||
Intersection (&) and symmetric difference (^) is also available.
|
||||
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
|
||||
// Helper template
|
||||
template<typename T>
|
||||
struct bs_base
|
||||
{
|
||||
// Underlying type
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
// Actual bitset type
|
||||
enum class type : under
|
||||
{
|
||||
null = 0, // Empty bitset
|
||||
|
||||
__bitset_set_type = 0 // SFINAE marker
|
||||
};
|
||||
|
||||
static constexpr std::size_t bitmax = sizeof(T) * 8;
|
||||
static constexpr std::size_t bitsize = static_cast<under>(T::__bitset_enum_max);
|
||||
|
||||
static_assert(std::is_enum<T>::value, "bs_t<> error: invalid type (must be enum)");
|
||||
static_assert(!bitsize || bitsize <= bitmax, "bs_t<> error: invalid __bitset_enum_max");
|
||||
|
||||
// Helper function
|
||||
static constexpr under shift(T value)
|
||||
{
|
||||
return static_cast<under>(1) << static_cast<under>(value);
|
||||
}
|
||||
|
||||
friend type& operator +=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) |= static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator -=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= ~static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator &=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator ^=(type& lhs, type rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) ^= static_cast<under>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator +=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) |= shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator -=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= ~shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator &=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) &= shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend type& operator ^=(type& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<under&>(lhs) ^= shift(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
friend constexpr type operator +(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) | static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator -(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) & ~static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator &(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) & static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator ^(type lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) ^ static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator &(type lhs, T rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) & shift(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator ^(type lhs, T rhs)
|
||||
{
|
||||
return static_cast<type>(static_cast<under>(lhs) ^ shift(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator &(T lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(shift(lhs) & static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr type operator ^(T lhs, type rhs)
|
||||
{
|
||||
return static_cast<type>(shift(lhs) ^ static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend constexpr bool operator ==(T lhs, type rhs)
|
||||
{
|
||||
return shift(lhs) == rhs;
|
||||
}
|
||||
|
||||
friend constexpr bool operator ==(type lhs, T rhs)
|
||||
{
|
||||
return lhs == shift(rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool operator !=(T lhs, type rhs)
|
||||
{
|
||||
return shift(lhs) != rhs;
|
||||
}
|
||||
|
||||
friend constexpr bool operator !=(type lhs, T rhs)
|
||||
{
|
||||
return lhs != shift(rhs);
|
||||
}
|
||||
|
||||
friend constexpr bool test(type value)
|
||||
{
|
||||
return static_cast<under>(value) != 0;
|
||||
}
|
||||
|
||||
friend constexpr bool test(type lhs, type rhs)
|
||||
{
|
||||
return (static_cast<under>(lhs) & static_cast<under>(rhs)) != 0;
|
||||
}
|
||||
|
||||
friend constexpr bool test(type lhs, T rhs)
|
||||
{
|
||||
return (static_cast<under>(lhs) & shift(rhs)) != 0;
|
||||
}
|
||||
|
||||
friend constexpr bool test(T lhs, type rhs)
|
||||
{
|
||||
return (shift(lhs) & static_cast<under>(rhs)) != 0;
|
||||
}
|
||||
|
||||
friend bool test_and_set(type& lhs, type rhs)
|
||||
{
|
||||
return test_and_set(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend bool test_and_set(type& lhs, T rhs)
|
||||
{
|
||||
return test_and_set(reinterpret_cast<under&>(lhs), shift(rhs));
|
||||
}
|
||||
|
||||
friend bool test_and_reset(type& lhs, type rhs)
|
||||
{
|
||||
return test_and_reset(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend bool test_and_reset(type& lhs, T rhs)
|
||||
{
|
||||
return test_and_reset(reinterpret_cast<under&>(lhs), shift(rhs));
|
||||
}
|
||||
|
||||
friend bool test_and_complement(type& lhs, type rhs)
|
||||
{
|
||||
return test_and_complement(reinterpret_cast<under&>(lhs), static_cast<under>(rhs));
|
||||
}
|
||||
|
||||
friend bool test_and_complement(type& lhs, T rhs)
|
||||
{
|
||||
return test_and_complement(reinterpret_cast<under&>(lhs), shift(rhs));
|
||||
}
|
||||
};
|
||||
|
||||
// Bitset type for enum class with available bits [0, T::__bitset_enum_max)
|
||||
template<typename T>
|
||||
using bs_t = typename bs_base<T>::type;
|
||||
|
||||
// Unary '+' operator: promote plain enum value to bitset value
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(T value)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(value));
|
||||
}
|
||||
|
||||
// Binary '+' operator: bitset union
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) | bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '+' operator: bitset union
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(typename bs_base<T>::type lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(static_cast<typename bs_base<T>::under>(lhs) | bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '+' operator: bitset union
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator +(T lhs, typename bs_base<T>::type rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) | static_cast<typename bs_base<T>::under>(rhs));
|
||||
}
|
||||
|
||||
// Binary '-' operator: bitset difference
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator -(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) & ~bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '-' operator: bitset difference
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator -(typename bs_base<T>::type lhs, T rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(static_cast<typename bs_base<T>::under>(lhs) & ~bs_base<T>::shift(rhs));
|
||||
}
|
||||
|
||||
// Binary '-' operator: bitset difference
|
||||
template<typename T, typename = decltype(T::__bitset_enum_max)>
|
||||
constexpr bs_t<T> operator -(T lhs, typename bs_base<T>::type rhs)
|
||||
{
|
||||
return static_cast<bs_t<T>>(bs_base<T>::shift(lhs) & ~static_cast<typename bs_base<T>::under>(rhs));
|
||||
}
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_add<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_sub<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_and<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_xor<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bs_t<T> op1(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline bs_t<T> op2(bs_t<T>& left, T right)
|
||||
{
|
||||
return static_cast<bs_t<T>>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), bs_base<T>::shift(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_add<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_sub<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_and<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_xor<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_test_and_set<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bool _op(bs_t<T>& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_test_and_reset<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bool _op(bs_t<T>& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename BS, typename T>
|
||||
struct atomic_test_and_complement<BS, T, void_t<decltype(T::__bitset_enum_max), std::enable_if_t<std::is_same<BS, bs_t<T>>::value>>>
|
||||
{
|
||||
using under = typename bs_base<T>::under;
|
||||
|
||||
static inline bool _op(bs_t<T>& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(static_cast<under>(value)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_set<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline bool _op(T& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::test_and_set(reinterpret_cast<under&>(left), static_cast<under>(value));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_reset<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline bool _op(T& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::test_and_reset(reinterpret_cast<under&>(left), static_cast<under>(value));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_complement<T, T, void_t<decltype(T::__bitset_set_type)>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline bool _op(T& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::test_and_complement(reinterpret_cast<under&>(left), static_cast<under>(value));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
// Binary '|' operator: bitwise OR
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator |(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<T>(std::underlying_type_t<T>(lhs) | std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
// Binary '&' operator: bitwise AND
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator &(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<T>(std::underlying_type_t<T>(lhs) & std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
// Binary '^' operator: bitwise XOR
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator ^(T lhs, T rhs)
|
||||
{
|
||||
return static_cast<T>(std::underlying_type_t<T>(lhs) ^ std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
// Unary '~' operator: bitwise NEG
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr T operator ~(T value)
|
||||
{
|
||||
return static_cast<T>(~std::underlying_type_t<T>(value));
|
||||
}
|
||||
|
||||
// Bitwise OR assignment
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline T& operator |=(T& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<std::underlying_type_t<T>&>(lhs) |= std::underlying_type_t<T>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// Bitwise AND assignment
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline T& operator &=(T& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<std::underlying_type_t<T>&>(lhs) &= std::underlying_type_t<T>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// Bitwise XOR assignment
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline T& operator ^=(T& lhs, T rhs)
|
||||
{
|
||||
reinterpret_cast<std::underlying_type_t<T>&>(lhs) ^= std::underlying_type_t<T>(rhs);
|
||||
return lhs;
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr bool test(T value)
|
||||
{
|
||||
return std::underlying_type_t<T>(value) != 0;
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
constexpr bool test(T lhs, T rhs)
|
||||
{
|
||||
return (std::underlying_type_t<T>(lhs) & std::underlying_type_t<T>(rhs)) != 0;
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline bool test_and_set(T& lhs, T rhs)
|
||||
{
|
||||
return test_and_set(reinterpret_cast<std::underlying_type_t<T>&>(lhs), std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline bool test_and_reset(T& lhs, T rhs)
|
||||
{
|
||||
return test_and_reset(reinterpret_cast<std::underlying_type_t<T>&>(lhs), std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
template<typename T, typename = decltype(T::__bitwise_ops)>
|
||||
inline bool test_and_complement(T& lhs, T rhs)
|
||||
{
|
||||
return test_and_complement(reinterpret_cast<std::underlying_type_t<T>&>(lhs), std::underlying_type_t<T>(rhs));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct atomic_or<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_and<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_xor<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline T op1(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op1;
|
||||
|
||||
static inline T op2(T& left, T right)
|
||||
{
|
||||
return static_cast<T>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), static_cast<under>(right)));
|
||||
}
|
||||
|
||||
static constexpr auto op_fetch = &op2;
|
||||
static constexpr auto atomic_op = &op2;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_set<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline bool _op(T& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::test_and_set(reinterpret_cast<under&>(left), static_cast<under>(value));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_reset<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline bool _op(T& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::test_and_reset(reinterpret_cast<under&>(left), static_cast<under>(value));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct atomic_test_and_complement<T, T, void_t<decltype(T::__bitwise_ops), std::enable_if_t<std::is_enum<T>::value>>>
|
||||
{
|
||||
using under = std::underlying_type_t<T>;
|
||||
|
||||
static inline bool _op(T& left, T value)
|
||||
{
|
||||
return atomic_storage<under>::test_and_complement(reinterpret_cast<under&>(left), static_cast<under>(value));
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &_op;
|
||||
static constexpr auto op_fetch = &_op;
|
||||
static constexpr auto atomic_op = &_op;
|
||||
};
|
||||
@@ -1,614 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <climits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
/*
|
||||
C-style format parser. Appends formatted string to `out`, returns number of characters written.
|
||||
`out`: mutable reference to std::string, std::vector<char> or other compatible container
|
||||
`fmt`: null-terminated string of `Char` type (char or constructible from char)
|
||||
`src`: rvalue reference to argument provider.
|
||||
*/
|
||||
template<typename Dst, typename Char, typename Src>
|
||||
std::size_t cfmt_append(Dst& out, const Char* fmt, Src&& src)
|
||||
{
|
||||
const std::size_t start_pos = out.size();
|
||||
|
||||
struct cfmt_context
|
||||
{
|
||||
std::size_t size; // Size of current format sequence
|
||||
|
||||
u8 args; // Number of extra args used
|
||||
u8 type; // Integral type bytesize
|
||||
bool dot; // Precision enabled
|
||||
bool left;
|
||||
bool sign;
|
||||
bool space;
|
||||
bool alter;
|
||||
bool zeros;
|
||||
|
||||
uint width;
|
||||
uint prec;
|
||||
};
|
||||
|
||||
cfmt_context ctx{0};
|
||||
|
||||
// Error handling: print untouched sequence, stop further formatting
|
||||
const auto drop_sequence = [&]
|
||||
{
|
||||
out.insert(out.end(), fmt - ctx.size, fmt);
|
||||
ctx.size = -1;
|
||||
};
|
||||
|
||||
const auto read_decimal = [&](uint result) -> uint
|
||||
{
|
||||
while (fmt[0] >= '0' && fmt[0] <= '9' && result <= (UINT_MAX / 10))
|
||||
{
|
||||
result = result * 10 + (fmt[0] - '0');
|
||||
fmt++, ctx.size++;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const auto write_octal = [&](u64 value, u64 min_num)
|
||||
{
|
||||
out.resize(out.size() + std::max<u64>(min_num, 66 / 3 - (cntlz64(value | 1, true) + 2) / 3), '0');
|
||||
|
||||
// Write in reversed order
|
||||
for (auto i = out.rbegin(); value; i++, value /= 8)
|
||||
{
|
||||
*i = value % 8 + '0';
|
||||
}
|
||||
};
|
||||
|
||||
const auto write_hex = [&](u64 value, bool upper, u64 min_num)
|
||||
{
|
||||
out.resize(out.size() + std::max<u64>(min_num, 64 / 4 - cntlz64(value | 1, true) / 4), '0');
|
||||
|
||||
// Write in reversed order
|
||||
for (auto i = out.rbegin(); value; i++, value /= 16)
|
||||
{
|
||||
*i = (upper ? "0123456789ABCDEF" : "0123456789abcdef")[value % 16];
|
||||
}
|
||||
};
|
||||
|
||||
const auto write_decimal = [&](u64 value, s64 min_size)
|
||||
{
|
||||
const std::size_t start = out.size();
|
||||
|
||||
do
|
||||
{
|
||||
out.push_back(value % 10 + '0');
|
||||
value /= 10;
|
||||
}
|
||||
while (0 < --min_size || value);
|
||||
|
||||
// Revert written characters
|
||||
for (std::size_t i = start, j = out.size() - 1; i < j; i++, j--)
|
||||
{
|
||||
std::swap(out[i], out[j]);
|
||||
}
|
||||
};
|
||||
|
||||
// Single pass over fmt string (null-terminated), TODO: check correct order
|
||||
while (const Char ch = *fmt++) if (ctx.size == 0)
|
||||
{
|
||||
if (ch == '%')
|
||||
{
|
||||
ctx.size = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
out.push_back(ch);
|
||||
}
|
||||
}
|
||||
else if (ctx.size == 1 && ch == '%')
|
||||
{
|
||||
ctx = {0};
|
||||
out.push_back(ch);
|
||||
}
|
||||
else if (ctx.size == -1)
|
||||
{
|
||||
out.push_back(ch);
|
||||
}
|
||||
else switch (ctx.size++, ch)
|
||||
{
|
||||
case '-': ctx.left = true; break;
|
||||
case '+': ctx.sign = true; break;
|
||||
case ' ': ctx.space = true; break;
|
||||
case '#': ctx.alter = true; break;
|
||||
case '0': ctx.zeros = true; break;
|
||||
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
if (UNLIKELY(ctx.width))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.width = read_decimal(ch - '0');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '*':
|
||||
{
|
||||
if (UNLIKELY(ctx.width || !src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else
|
||||
{
|
||||
const int warg = src.template get<int>(ctx.args++);
|
||||
ctx.width = std::abs(warg);
|
||||
ctx.left |= warg < 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '.':
|
||||
{
|
||||
if (UNLIKELY(ctx.dot || ctx.prec))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else if (*fmt >= '0' && *fmt <= '9') // TODO: does it allow '0'?
|
||||
{
|
||||
ctx.prec = read_decimal(0);
|
||||
ctx.dot = true;
|
||||
}
|
||||
else if (*fmt == '*')
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt++, ctx.size++;
|
||||
const int parg = src.template get<int>(ctx.args++);
|
||||
ctx.prec = std::max(parg, 0);
|
||||
ctx.dot = parg >= 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.prec = 0;
|
||||
ctx.dot = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'h':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else if (fmt[0] == 'h')
|
||||
{
|
||||
fmt++, ctx.size++;
|
||||
ctx.type = sizeof(char);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.type = sizeof(short);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'l':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else if (fmt[0] == 'l')
|
||||
{
|
||||
fmt++, ctx.size++;
|
||||
ctx.type = sizeof(llong);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.type = sizeof(long);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'z':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.type = sizeof(std::size_t);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'j':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.type = sizeof(std::intmax_t);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 't':
|
||||
{
|
||||
if (UNLIKELY(ctx.type))
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.type = sizeof(std::ptrdiff_t);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'c':
|
||||
{
|
||||
if (UNLIKELY(ctx.type || !src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
const std::size_t start = out.size();
|
||||
out.push_back(src.template get<Char>(ctx.args));
|
||||
|
||||
if (1 < ctx.width)
|
||||
{
|
||||
// Add spaces if necessary
|
||||
out.insert(out.begin() + start + ctx.left, ctx.width - 1, ' ');
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 's':
|
||||
{
|
||||
if (UNLIKELY(ctx.type || !src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
const std::size_t start = out.size();
|
||||
const std::size_t size1 = src.fmt_string(out, ctx.args);
|
||||
|
||||
if (ctx.dot && size1 > ctx.prec)
|
||||
{
|
||||
// Shrink if necessary
|
||||
out.resize(start + ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
// Add spaces if necessary
|
||||
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ctx.type)
|
||||
{
|
||||
ctx.type = (u8)src.type(ctx.args);
|
||||
}
|
||||
|
||||
// Sign-extended argument expected
|
||||
const u64 val = src.template get<u64>(ctx.args);
|
||||
const bool negative = ctx.type && static_cast<s64>(val) < 0;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
|
||||
if (!ctx.dot || ctx.prec)
|
||||
{
|
||||
if (negative)
|
||||
{
|
||||
out.push_back('-');
|
||||
}
|
||||
else if (ctx.sign)
|
||||
{
|
||||
out.push_back('+');
|
||||
}
|
||||
else if (ctx.space)
|
||||
{
|
||||
out.push_back(' ');
|
||||
}
|
||||
|
||||
write_decimal(negative ? 0 - val : val, ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
// Add padding if necessary
|
||||
if (ctx.zeros && !ctx.left && !ctx.dot)
|
||||
{
|
||||
out.insert(out.begin() + start + (negative || ctx.sign || ctx.space), ctx.width - size2, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ctx.type)
|
||||
{
|
||||
ctx.type = (u8)src.type(ctx.args);
|
||||
}
|
||||
|
||||
const u64 mask =
|
||||
ctx.type == 1 ? 0xffull :
|
||||
ctx.type == 2 ? 0xffffull :
|
||||
ctx.type == 4 ? 0xffffffffull : 0xffffffffffffffffull;
|
||||
|
||||
// Trunc sign-extended signed types
|
||||
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
|
||||
if (ctx.alter)
|
||||
{
|
||||
out.push_back('0');
|
||||
|
||||
if (val)
|
||||
{
|
||||
write_octal(val, ctx.prec ? ctx.prec - 1 : 0);
|
||||
}
|
||||
}
|
||||
else if (!ctx.dot || ctx.prec)
|
||||
{
|
||||
write_octal(val, ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
// Add padding if necessary
|
||||
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ctx.zeros && !ctx.left && !ctx.dot ? '0' : ' ');
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ctx.type)
|
||||
{
|
||||
ctx.type = (u8)src.type(ctx.args);
|
||||
}
|
||||
|
||||
const u64 mask =
|
||||
ctx.type == 1 ? 0xffull :
|
||||
ctx.type == 2 ? 0xffffull :
|
||||
ctx.type == 4 ? 0xffffffffull : 0xffffffffffffffffull;
|
||||
|
||||
// Trunc sign-extended signed types
|
||||
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
|
||||
if (ctx.alter)
|
||||
{
|
||||
out.push_back('0');
|
||||
|
||||
if (val)
|
||||
{
|
||||
out.push_back(ch); // Prepend 0x or 0X
|
||||
write_hex(val, ch == 'X', ctx.prec);
|
||||
}
|
||||
}
|
||||
else if (!ctx.dot || ctx.prec)
|
||||
{
|
||||
write_hex(val, ch == 'X', ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
// Add padding if necessary
|
||||
if (ctx.zeros && !ctx.left && !ctx.dot)
|
||||
{
|
||||
out.insert(out.begin() + start + (ctx.alter && val ? 2 : 0), ctx.width - size2, '0');
|
||||
}
|
||||
else
|
||||
{
|
||||
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'u':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args)))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ctx.type)
|
||||
{
|
||||
ctx.type = (u8)src.type(ctx.args);
|
||||
}
|
||||
|
||||
const u64 mask =
|
||||
ctx.type == 1 ? 0xffull :
|
||||
ctx.type == 2 ? 0xffffull :
|
||||
ctx.type == 4 ? 0xffffffffull : 0xffffffffffffffffull;
|
||||
|
||||
// Trunc sign-extended signed types
|
||||
const u64 val = src.template get<u64>(ctx.args) & mask;
|
||||
|
||||
const std::size_t start = out.size();
|
||||
|
||||
if (!ctx.dot || ctx.prec)
|
||||
{
|
||||
write_decimal(val, ctx.prec);
|
||||
}
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
// Add padding if necessary
|
||||
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ctx.zeros && !ctx.left && !ctx.dot ? '0' : ' ');
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args) || ctx.type))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
const u64 val = src.template get<u64>(ctx.args);
|
||||
|
||||
const std::size_t start = out.size();
|
||||
|
||||
write_hex(val, false, sizeof(void*) * 2);
|
||||
|
||||
const std::size_t size2 = out.size() - start;
|
||||
|
||||
if (size2 < ctx.width)
|
||||
{
|
||||
// Add padding if necessary
|
||||
out.insert(ctx.left ? out.end() : out.begin() + start, ctx.width - size2, ' ');
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'a':
|
||||
case 'A':
|
||||
case 'g':
|
||||
case 'G':
|
||||
{
|
||||
if (UNLIKELY(!src.test(ctx.args) || ctx.type))
|
||||
{
|
||||
drop_sequence();
|
||||
break;
|
||||
}
|
||||
|
||||
// Fallback (TODO)
|
||||
|
||||
const std::string _fmt(fmt - ctx.size, fmt);
|
||||
|
||||
const u64 arg0 = src.template get<u64>(0);
|
||||
const u64 arg1 = ctx.args >= 1 ? src.template get<u64>(1) : 0;
|
||||
const u64 arg2 = ctx.args >= 2 ? src.template get<u64>(2) : 0;
|
||||
|
||||
if (const std::size_t _size = std::snprintf(0, 0, _fmt.c_str(), arg0, arg1, arg2))
|
||||
{
|
||||
out.resize(out.size() + _size);
|
||||
std::snprintf(&out.front() + out.size() - _size, _size + 1, _fmt.c_str(), arg0, arg1, arg2);
|
||||
}
|
||||
|
||||
src.skip(ctx.args);
|
||||
ctx = {0};
|
||||
break;
|
||||
}
|
||||
|
||||
case 'L': // long double, not supported
|
||||
case 'n': // writeback, not supported
|
||||
default:
|
||||
{
|
||||
drop_sequence();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle unfinished sequence
|
||||
if (ctx.size && ctx.size != -1)
|
||||
{
|
||||
fmt--, drop_sequence();
|
||||
}
|
||||
|
||||
return out.size() - start_pos;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
#include "stdafx.h"
|
||||
#include "config_context.h"
|
||||
#include "StrFmt.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
void config_context_t::group::init()
|
||||
{
|
||||
if(!m_cfg->m_groups[full_name()])
|
||||
m_cfg->m_groups[full_name()] = this;
|
||||
}
|
||||
|
||||
config_context_t::group::group(config_context_t* cfg, const std::string& name)
|
||||
: m_cfg(cfg)
|
||||
, m_name(name)
|
||||
, m_parent(nullptr)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
config_context_t::group::group(group* parent, const std::string& name)
|
||||
: m_cfg(parent->m_cfg)
|
||||
, m_name(name)
|
||||
, m_parent(parent)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
void config_context_t::group::set_parent(config_context_t* cfg)
|
||||
{
|
||||
m_cfg = cfg;
|
||||
init();
|
||||
}
|
||||
|
||||
std::string config_context_t::group::name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
std::string config_context_t::group::full_name() const
|
||||
{
|
||||
if (m_parent)
|
||||
return m_parent->full_name() + "/" + m_name;
|
||||
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void config_context_t::assign(const config_context_t& rhs)
|
||||
{
|
||||
for (auto &rhs_g : rhs.m_groups)
|
||||
{
|
||||
auto g = m_groups.at(rhs_g.first);
|
||||
|
||||
for (auto rhs_e : rhs_g.second->entries)
|
||||
{
|
||||
if (g->entries[rhs_e.first])
|
||||
g->entries[rhs_e.first]->value_from(rhs_e.second);
|
||||
else
|
||||
g->add_entry(rhs_e.first, rhs_e.second->string_value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void config_context_t::deserialize(std::istream& stream)
|
||||
{
|
||||
set_defaults();
|
||||
|
||||
uint line_index = 0;
|
||||
std::string line;
|
||||
group *current_group = nullptr;
|
||||
|
||||
while (std::getline(stream, line))
|
||||
{
|
||||
++line_index;
|
||||
line = fmt::trim(line);
|
||||
|
||||
if (line.empty())
|
||||
continue;
|
||||
|
||||
if (line.front() == '[' && line.back() == ']')
|
||||
{
|
||||
std::string group_name = line.substr(1, line.length() - 2);
|
||||
|
||||
auto found = m_groups.find(group_name);
|
||||
|
||||
if (found == m_groups.end())
|
||||
{
|
||||
std::cerr << line_index << ": group '" << group_name << "' not exists. ignored" << std::endl;
|
||||
current_group = nullptr;
|
||||
continue;
|
||||
}
|
||||
|
||||
current_group = found->second;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current_group == nullptr)
|
||||
{
|
||||
std::cerr << line_index << ": line '" << line << "' ignored, no group." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto name_value = fmt::split(line, { "=" });
|
||||
switch (name_value.size())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if (current_group->entries[fmt::trim(name_value[0])])
|
||||
current_group->entries[fmt::trim(name_value[0])]->string_value({});
|
||||
|
||||
else
|
||||
current_group->add_entry(fmt::trim(name_value[0]), std::string{});
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
std::cerr << line_index << ": line '" << line << "' has more than one symbol '='. used only first" << std::endl;
|
||||
case 2:
|
||||
{
|
||||
if (current_group->entries[fmt::trim(name_value[0])])
|
||||
current_group->entries[fmt::trim(name_value[0])]->string_value(fmt::trim(name_value[1]));
|
||||
|
||||
else
|
||||
current_group->add_entry(fmt::trim(name_value[0]), fmt::trim(name_value[1]));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void config_context_t::serialize(std::ostream& stream) const
|
||||
{
|
||||
for (auto &g : m_groups)
|
||||
{
|
||||
stream << "[" + g.first + "]" << std::endl;
|
||||
|
||||
for (auto &e : g.second->entries)
|
||||
{
|
||||
stream << e.first << "=" << e.second->string_value() << std::endl;
|
||||
}
|
||||
|
||||
stream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void config_context_t::set_defaults()
|
||||
{
|
||||
for (auto &g : m_groups)
|
||||
{
|
||||
for (auto &e : g.second->entries)
|
||||
{
|
||||
e.second->to_default();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string config_context_t::to_string() const
|
||||
{
|
||||
std::ostringstream result;
|
||||
|
||||
serialize(result);
|
||||
|
||||
return result.str();
|
||||
}
|
||||
|
||||
void config_context_t::from_string(const std::string& str)
|
||||
{
|
||||
std::istringstream source(str);
|
||||
|
||||
deserialize(source);
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include "convert.h"
|
||||
|
||||
class config_context_t
|
||||
{
|
||||
public:
|
||||
class entry_base;
|
||||
|
||||
protected:
|
||||
class group
|
||||
{
|
||||
group* m_parent;
|
||||
config_context_t* m_cfg;
|
||||
std::string m_name;
|
||||
std::vector<std::unique_ptr<entry_base>> m_entries;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
std::unordered_map<std::string, entry_base *> entries;
|
||||
|
||||
group(config_context_t* cfg, const std::string& name);
|
||||
group(group* parent, const std::string& name);
|
||||
void set_parent(config_context_t* cfg);
|
||||
|
||||
std::string name() const;
|
||||
std::string full_name() const;
|
||||
|
||||
template<typename T>
|
||||
void add_entry(const std::string& name, const T& def_value)
|
||||
{
|
||||
m_entries.emplace_back(std::make_unique<entry<T>>(this, name, def_value));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T get_entry_value(const std::string& name, const T& def_value)
|
||||
{
|
||||
if (!entries[name])
|
||||
add_entry(name, def_value);
|
||||
|
||||
return convert::to<T>(entries[name]->string_value());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void set_entry_value(const std::string& name, const T& value)
|
||||
{
|
||||
if (entries[name])
|
||||
entries[name]->string_value(convert::to<std::string>(value));
|
||||
|
||||
else
|
||||
add_entry(name, value);
|
||||
}
|
||||
|
||||
friend config_context_t;
|
||||
};
|
||||
|
||||
public:
|
||||
class entry_base
|
||||
{
|
||||
public:
|
||||
virtual std::string name() = 0;
|
||||
virtual void to_default() = 0;
|
||||
virtual std::string string_value() = 0;
|
||||
virtual void string_value(const std::string& value) = 0;
|
||||
virtual void value_from(const entry_base* rhs) = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class entry : public entry_base
|
||||
{
|
||||
T m_default_value;
|
||||
T m_value;
|
||||
group* m_parent;
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
entry(group* parent, const std::string& name, const T& default_value)
|
||||
: m_parent(parent)
|
||||
, m_name(name)
|
||||
, m_default_value(default_value)
|
||||
, m_value(default_value)
|
||||
{
|
||||
if(!parent->entries[name])
|
||||
parent->entries[name] = this;
|
||||
}
|
||||
|
||||
T default_value() const
|
||||
{
|
||||
return m_default_value;
|
||||
}
|
||||
|
||||
T value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void value(const T& new_value)
|
||||
{
|
||||
m_value = new_value;
|
||||
}
|
||||
|
||||
std::string name() override
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void to_default() override
|
||||
{
|
||||
value(default_value());
|
||||
}
|
||||
|
||||
std::string string_value() override
|
||||
{
|
||||
return convert::to<std::string>(value());
|
||||
}
|
||||
|
||||
void string_value(const std::string &new_value) override
|
||||
{
|
||||
value(convert::to<T>(new_value));
|
||||
}
|
||||
|
||||
void value_from(const entry_base* rhs) override
|
||||
{
|
||||
value(static_cast<const entry*>(rhs)->value());
|
||||
}
|
||||
|
||||
entry& operator = (const T& new_value)
|
||||
{
|
||||
value(new_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T2>
|
||||
entry& operator = (const T2& new_value)
|
||||
{
|
||||
value(static_cast<T>(new_value));
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator const T&() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, group*> m_groups;
|
||||
|
||||
public:
|
||||
config_context_t() = default;
|
||||
|
||||
void assign(const config_context_t& rhs);
|
||||
|
||||
void serialize(std::ostream& stream) const;
|
||||
void deserialize(std::istream& stream);
|
||||
|
||||
void set_defaults();
|
||||
|
||||
std::string to_string() const;
|
||||
void from_string(const std::string&);
|
||||
};
|
||||
@@ -0,0 +1,279 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include "types.h"
|
||||
|
||||
namespace convert
|
||||
{
|
||||
template<typename ReturnType, typename FromType>
|
||||
struct to_impl_t;
|
||||
|
||||
template<typename Type>
|
||||
struct to_impl_t<Type, Type>
|
||||
{
|
||||
static Type func(const Type& value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, bool>
|
||||
{
|
||||
static std::string func(bool value)
|
||||
{
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<bool, std::string>
|
||||
{
|
||||
static bool func(const std::string& value)
|
||||
{
|
||||
return value == "true" ? true : value == "false" ? false : throw std::invalid_argument(__FUNCTION__);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, signed char>
|
||||
{
|
||||
static std::string func(signed char value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, unsigned char>
|
||||
{
|
||||
static std::string func(unsigned char value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, short>
|
||||
{
|
||||
static std::string func(short value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, unsigned short>
|
||||
{
|
||||
static std::string func(unsigned short value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, int>
|
||||
{
|
||||
static std::string func(int value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, unsigned int>
|
||||
{
|
||||
static std::string func(unsigned int value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, long>
|
||||
{
|
||||
static std::string func(long value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, unsigned long>
|
||||
{
|
||||
static std::string func(unsigned long value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, long long>
|
||||
{
|
||||
static std::string func(long long value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, unsigned long long>
|
||||
{
|
||||
static std::string func(unsigned long long value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, float>
|
||||
{
|
||||
static std::string func(float value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, double>
|
||||
{
|
||||
static std::string func(double value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, long double>
|
||||
{
|
||||
static std::string func(long double value)
|
||||
{
|
||||
return std::to_string(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, size2i>
|
||||
{
|
||||
static std::string func(size2i value)
|
||||
{
|
||||
return std::to_string(value.width) + "x" + std::to_string(value.height);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<std::string, position2i>
|
||||
{
|
||||
static std::string func(position2i value)
|
||||
{
|
||||
return std::to_string(value.x) + ":" + std::to_string(value.y);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<int, std::string>
|
||||
{
|
||||
static int func(const std::string& value)
|
||||
{
|
||||
return std::stoi(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<unsigned int, std::string>
|
||||
{
|
||||
static unsigned int func(const std::string& value)
|
||||
{
|
||||
return (unsigned long)std::stoul(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<long, std::string>
|
||||
{
|
||||
static long func(const std::string& value)
|
||||
{
|
||||
return std::stol(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<unsigned long, std::string>
|
||||
{
|
||||
static unsigned long func(const std::string& value)
|
||||
{
|
||||
return std::stoul(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<long long, std::string>
|
||||
{
|
||||
static long long func(const std::string& value)
|
||||
{
|
||||
return std::stoll(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<unsigned long long, std::string>
|
||||
{
|
||||
static unsigned long long func(const std::string& value)
|
||||
{
|
||||
return std::stoull(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<float, std::string>
|
||||
{
|
||||
static float func(const std::string& value)
|
||||
{
|
||||
return std::stof(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<double, std::string>
|
||||
{
|
||||
static double func(const std::string& value)
|
||||
{
|
||||
return std::stod(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<long double, std::string>
|
||||
{
|
||||
static long double func(const std::string& value)
|
||||
{
|
||||
return std::stold(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<size2i, std::string>
|
||||
{
|
||||
static size2i func(const std::string& value)
|
||||
{
|
||||
const auto& data = fmt::split(value, { "x" });
|
||||
return { std::stoi(data[0]), std::stoi(data[1]) };
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct to_impl_t<position2i, std::string>
|
||||
{
|
||||
static position2i func(const std::string& value)
|
||||
{
|
||||
const auto& data = fmt::split(value, { ":" });
|
||||
return { std::stoi(data[0]), std::stoi(data[1]) };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ReturnType, typename FromType>
|
||||
ReturnType to(FromType value)
|
||||
{
|
||||
return to_impl_t<std::remove_all_extents_t<ReturnType>, std::remove_all_extents_t<FromType>>::func(value);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
Copyright (C) 2011-2012 Andrzej Krzemienski
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0
|
||||
(see accompanying file LICENSE_1_0.txt or a copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
The idea and interface is based on Boost.Optional library
|
||||
authored by Fernando Luis Cacciola Carballal
|
||||
|
||||
Home at https://github.com/akrzemi1/Optional
|
||||
@@ -1,60 +0,0 @@
|
||||
#include "stdafx.h"
|
||||
#include "dynamic_library.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
namespace utils
|
||||
{
|
||||
dynamic_library::dynamic_library(const std::string &path)
|
||||
{
|
||||
load(path);
|
||||
}
|
||||
|
||||
dynamic_library::~dynamic_library()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool dynamic_library::load(const std::string &path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
m_handle = LoadLibraryA(path.c_str());
|
||||
#else
|
||||
m_handle = dlopen(path.c_str(), RTLD_LAZY);
|
||||
#endif
|
||||
return loaded();
|
||||
}
|
||||
|
||||
void dynamic_library::close()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
FreeLibrary((HMODULE)m_handle);
|
||||
#else
|
||||
dlclose(m_handle);
|
||||
#endif
|
||||
m_handle = nullptr;
|
||||
}
|
||||
|
||||
void *dynamic_library::get_impl(const std::string &name) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (void*)GetProcAddress((HMODULE)m_handle, name.c_str());
|
||||
#else
|
||||
return dlsym(m_handle, (char *)name.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool dynamic_library::loaded() const
|
||||
{
|
||||
return !m_handle;
|
||||
}
|
||||
|
||||
dynamic_library::operator bool() const
|
||||
{
|
||||
return loaded();
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class dynamic_library
|
||||
{
|
||||
void *m_handle = nullptr;
|
||||
|
||||
public:
|
||||
dynamic_library() = default;
|
||||
dynamic_library(const std::string &path);
|
||||
|
||||
~dynamic_library();
|
||||
|
||||
bool load(const std::string &path);
|
||||
void close();
|
||||
|
||||
private:
|
||||
void *get_impl(const std::string &name) const;
|
||||
|
||||
public:
|
||||
template<typename Type = void>
|
||||
Type *get(const std::string &name) const
|
||||
{
|
||||
Type *result;
|
||||
*(void **)(&result) = get_impl(name);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
bool get(Type *&function, const std::string &name) const
|
||||
{
|
||||
*(void **)(&function) = get_impl(name);
|
||||
|
||||
return !!function;
|
||||
}
|
||||
|
||||
bool loaded() const;
|
||||
explicit operator bool() const;
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,147 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
//! Simple sizeless array base for concurrent access. Cannot shrink, only growths automatically.
|
||||
//! There is no way to know the current size. The smaller index is, the faster it's accessed.
|
||||
//!
|
||||
//! T is the type of elements. Currently, default constructor of T shall be constexpr.
|
||||
//! N is initial element count, available without any memory allocation and only stored contiguously.
|
||||
template<typename T, std::size_t N>
|
||||
class lf_array
|
||||
{
|
||||
// Data (default-initialized)
|
||||
T m_data[N]{};
|
||||
|
||||
// Next array block
|
||||
atomic_t<lf_array*> m_next{};
|
||||
|
||||
public:
|
||||
constexpr lf_array() = default;
|
||||
|
||||
~lf_array()
|
||||
{
|
||||
for (auto ptr = m_next.raw(); UNLIKELY(ptr);)
|
||||
{
|
||||
delete std::exchange(ptr, std::exchange(ptr->m_next.raw(), nullptr));
|
||||
}
|
||||
}
|
||||
|
||||
T& operator [](std::size_t index)
|
||||
{
|
||||
if (LIKELY(index < N))
|
||||
{
|
||||
return m_data[index];
|
||||
}
|
||||
else if (UNLIKELY(!m_next))
|
||||
{
|
||||
// Create new array block. It's not a full-fledged once-synchronization, unlikely needed.
|
||||
for (auto _new = new lf_array, ptr = this; UNLIKELY(ptr);)
|
||||
{
|
||||
// Install the pointer. If failed, go deeper.
|
||||
ptr = ptr->m_next.compare_and_swap(nullptr, _new);
|
||||
}
|
||||
}
|
||||
|
||||
// Access recursively
|
||||
return (*m_next)[index - N];
|
||||
}
|
||||
};
|
||||
|
||||
//! Simple lock-free FIFO queue base. Based on lf_array<T, N> itself. Currently uses 32-bit counters.
|
||||
//! There is no "push_end" or "pop_begin" provided, the queue element must signal its state on its own.
|
||||
template<typename T, std::size_t N>
|
||||
class lf_fifo : public lf_array<T, N>
|
||||
{
|
||||
struct alignas(8) ctrl_t
|
||||
{
|
||||
u32 push;
|
||||
u32 pop;
|
||||
};
|
||||
|
||||
atomic_t<ctrl_t> m_ctrl{};
|
||||
|
||||
public:
|
||||
constexpr lf_fifo() = default;
|
||||
|
||||
// Get current "push" position
|
||||
u32 size()
|
||||
{
|
||||
return reinterpret_cast<atomic_t<u32>&>(m_ctrl).load(); // Hack
|
||||
}
|
||||
|
||||
// Acquire the place for one or more elements.
|
||||
u32 push_begin(u32 count = 1)
|
||||
{
|
||||
return reinterpret_cast<atomic_t<u32>&>(m_ctrl).fetch_add(count); // Hack
|
||||
}
|
||||
|
||||
// Get current "pop" position
|
||||
u32 peek()
|
||||
{
|
||||
return m_ctrl.load().pop;
|
||||
}
|
||||
|
||||
// Acknowledge processed element, return number of the next one.
|
||||
// Perform clear if possible, zero is returned in this case.
|
||||
u32 pop_end(u32 count = 1)
|
||||
{
|
||||
return m_ctrl.atomic_op([&](ctrl_t& ctrl)
|
||||
{
|
||||
ctrl.pop += count;
|
||||
|
||||
if (ctrl.pop == ctrl.push)
|
||||
{
|
||||
// Clean if possible
|
||||
ctrl.push = 0;
|
||||
ctrl.pop = 0;
|
||||
}
|
||||
|
||||
return ctrl.pop;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//! Simple lock-free map. Based on lf_array<>. All elements are accessible, implicitly initialized.
|
||||
template<typename K, typename T, typename Hash = value_hash<K>, std::size_t Size = 256>
|
||||
class lf_hashmap
|
||||
{
|
||||
struct pair_t
|
||||
{
|
||||
// Default-constructed key means "no key"
|
||||
atomic_t<K> key{};
|
||||
T value{};
|
||||
};
|
||||
|
||||
//
|
||||
lf_array<pair_t, Size> m_data{};
|
||||
|
||||
// Value for default-constructed key
|
||||
T m_default_key_data{};
|
||||
|
||||
public:
|
||||
constexpr lf_hashmap() = default;
|
||||
|
||||
// Access element (added implicitly)
|
||||
T& operator [](const K& key)
|
||||
{
|
||||
if (UNLIKELY(key == K{}))
|
||||
{
|
||||
return m_default_key_data;
|
||||
}
|
||||
|
||||
// Calculate hash and array position
|
||||
for (std::size_t pos = Hash{}(key) % Size;; pos += Size)
|
||||
{
|
||||
// Access the array
|
||||
auto& pair = m_data[pos];
|
||||
|
||||
// Check the key value (optimistic)
|
||||
if (LIKELY(pair.key == key) || pair.key.compare_and_swap_test(K{}, key))
|
||||
{
|
||||
return pair.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,41 @@
|
||||
#include "stdafx.h"
|
||||
#include "restore_new.h"
|
||||
#include "Utilities/Log.h"
|
||||
#pragma warning(push)
|
||||
#pragma message("TODO: remove wx dependency: <wx/image.h>")
|
||||
#pragma warning(disable : 4996)
|
||||
#include <wx/image.h>
|
||||
#pragma warning(pop)
|
||||
#include "define_new_memleakdetect.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include "rPlatform.h"
|
||||
|
||||
rImage::rImage()
|
||||
{
|
||||
handle = static_cast<void*>(new wxImage());
|
||||
}
|
||||
|
||||
rImage::~rImage()
|
||||
{
|
||||
delete static_cast<wxImage*>(handle);
|
||||
}
|
||||
|
||||
void rImage::Create(int width, int height, void *data, void *alpha)
|
||||
{
|
||||
static_cast<wxImage*>(handle)->Create(width, height, static_cast<unsigned char*>(data), static_cast<unsigned char*>(alpha));
|
||||
}
|
||||
void rImage::SaveFile(const std::string& name, rImageType type)
|
||||
{
|
||||
if (type == rBITMAP_TYPE_PNG)
|
||||
{
|
||||
static_cast<wxImage*>(handle)->SaveFile(fmt::FromUTF8(name),wxBITMAP_TYPE_PNG);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("unsupported type");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
/**********************************************************************
|
||||
*********** RSX Debugger
|
||||
************************************************************************/
|
||||
|
||||
struct RSXDebuggerProgram
|
||||
{
|
||||
u32 id;
|
||||
u32 vp_id;
|
||||
u32 fp_id;
|
||||
std::string vp_shader;
|
||||
std::string fp_shader;
|
||||
bool modified;
|
||||
|
||||
RSXDebuggerProgram()
|
||||
: modified(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
extern std::vector<RSXDebuggerProgram> m_debug_programs;
|
||||
|
||||
/**********************************************************************
|
||||
*********** Image stuff
|
||||
************************************************************************/
|
||||
enum rImageType
|
||||
{
|
||||
rBITMAP_TYPE_PNG
|
||||
};
|
||||
struct rImage
|
||||
{
|
||||
rImage();
|
||||
rImage(const rImage &) = delete;
|
||||
~rImage();
|
||||
void Create(int width , int height, void *data, void *alpha);
|
||||
void SaveFile(const std::string& name, rImageType type);
|
||||
|
||||
void *handle;
|
||||
};
|
||||
@@ -0,0 +1,235 @@
|
||||
#include "stdafx.h"
|
||||
#include "rTime.h"
|
||||
#pragma warning(push)
|
||||
#pragma message("TODO: remove wx dependency: <wx/datetime.h>")
|
||||
#pragma warning(disable : 4996)
|
||||
#include <wx/datetime.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
std::string rDefaultDateTimeFormat = "%c";
|
||||
|
||||
rTimeSpan::rTimeSpan()
|
||||
{
|
||||
handle = static_cast<void *>(new wxTimeSpan());
|
||||
}
|
||||
|
||||
rTimeSpan::~rTimeSpan()
|
||||
{
|
||||
delete static_cast<wxTimeSpan*>(handle);
|
||||
}
|
||||
|
||||
rTimeSpan::rTimeSpan(const rTimeSpan& other)
|
||||
|
||||
{
|
||||
handle = static_cast<void *>(new wxTimeSpan(*static_cast<wxTimeSpan*>(other.handle)));
|
||||
|
||||
}
|
||||
|
||||
rTimeSpan::rTimeSpan(int a, int b , int c, int d)
|
||||
{
|
||||
handle = static_cast<void *>(new wxTimeSpan(a,b,c,d));
|
||||
}
|
||||
|
||||
|
||||
rDateSpan::rDateSpan()
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateSpan());
|
||||
}
|
||||
|
||||
rDateSpan::~rDateSpan()
|
||||
{
|
||||
delete static_cast<wxDateSpan*>(handle);
|
||||
}
|
||||
|
||||
rDateSpan::rDateSpan(const rDateSpan& other)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateSpan(*static_cast<wxDateSpan*>(other.handle)));
|
||||
}
|
||||
|
||||
rDateSpan::rDateSpan(int a, int b, int c, int d)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateSpan(a,b,c,d));
|
||||
}
|
||||
|
||||
rDateTime::rDateTime()
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime());
|
||||
}
|
||||
|
||||
rDateTime::~rDateTime()
|
||||
{
|
||||
delete static_cast<wxDateTime*>(handle);
|
||||
}
|
||||
|
||||
rDateTime::rDateTime(const rDateTime& other)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime(*static_cast<wxDateTime*>(other.handle)));
|
||||
}
|
||||
|
||||
rDateTime::rDateTime(const time_t& time)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime(time));
|
||||
}
|
||||
|
||||
rDateTime::rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime(day,(wxDateTime::Month)month,year,hour,minute,second,millisecond));
|
||||
}
|
||||
|
||||
rDateTime rDateTime::UNow()
|
||||
{
|
||||
rDateTime time;
|
||||
delete static_cast<wxDateTime*>(time.handle);
|
||||
time.handle = static_cast<void *>(new wxDateTime(wxDateTime::UNow()));
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
rDateTime rDateTime::FromUTC(bool val)
|
||||
{
|
||||
rDateTime time(*this);
|
||||
void *temp = time.handle;
|
||||
|
||||
time.handle = static_cast<void *>(new wxDateTime(static_cast<wxDateTime*>(temp)->FromTimezone(wxDateTime::GMT0, val)));
|
||||
delete static_cast<wxDateTime*>(temp);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
rDateTime rDateTime::ToUTC(bool val)
|
||||
{
|
||||
rDateTime time(*this);
|
||||
void *temp = time.handle;
|
||||
|
||||
time.handle = static_cast<void *>(new wxDateTime(static_cast<wxDateTime*>(temp)->ToTimezone(wxDateTime::GMT0, val)));
|
||||
delete static_cast<wxDateTime*>(temp);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
time_t rDateTime::GetTicks()
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetTicks();
|
||||
}
|
||||
|
||||
void rDateTime::Add(const rTimeSpan& span)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->Add(*static_cast<wxTimeSpan*>(span.handle));
|
||||
}
|
||||
|
||||
void rDateTime::Add(const rDateSpan& span)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->Add(*static_cast<wxDateSpan*>(span.handle));
|
||||
}
|
||||
|
||||
wxDateTime::TimeZone convertTZ(rDateTime::rTimeZone tz)
|
||||
{
|
||||
switch (tz)
|
||||
{
|
||||
case rDateTime::Local:
|
||||
return wxDateTime::Local;
|
||||
case rDateTime::GMT0:
|
||||
return wxDateTime::GMT0;
|
||||
case rDateTime::UTC:
|
||||
return wxDateTime::UTC;
|
||||
default:
|
||||
throw EXCEPTION("WRONG DATETIME");
|
||||
}
|
||||
}
|
||||
|
||||
std::string rDateTime::Format(const std::string &format, const rTimeZone &tz) const
|
||||
{
|
||||
return fmt::ToUTF8(static_cast<wxDateTime*>(handle)->Format(fmt::FromUTF8(format),convertTZ(tz)));
|
||||
}
|
||||
|
||||
void rDateTime::ParseDateTime(const char* format)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->ParseDateTime(format);
|
||||
}
|
||||
|
||||
u32 rDateTime::GetAsDOS()
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetAsDOS();
|
||||
}
|
||||
|
||||
rDateTime &rDateTime::SetFromDOS(u32 fromdos)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->SetFromDOS(fromdos);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool rDateTime::IsLeapYear(int year, rDateTime::Calender cal)
|
||||
{
|
||||
if (cal == Gregorian)
|
||||
{
|
||||
return wxDateTime::IsLeapYear(year, wxDateTime::Gregorian);
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxDateTime::IsLeapYear(year, wxDateTime::Julian);
|
||||
}
|
||||
}
|
||||
|
||||
int rDateTime::GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal)
|
||||
{
|
||||
if (cal == Gregorian)
|
||||
{
|
||||
return wxDateTime::GetNumberOfDays(static_cast<wxDateTime::Month>(month), year, wxDateTime::Gregorian);
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxDateTime::GetNumberOfDays(static_cast<wxDateTime::Month>(month), year, wxDateTime::Julian);
|
||||
}
|
||||
}
|
||||
|
||||
void rDateTime::SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->SetToWeekDay(
|
||||
static_cast<wxDateTime::WeekDay>(day)
|
||||
, n
|
||||
, static_cast<wxDateTime::Month>(month)
|
||||
, year
|
||||
);
|
||||
}
|
||||
|
||||
int rDateTime::GetWeekDay()
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetWeekDay();
|
||||
}
|
||||
|
||||
u16 rDateTime::GetYear(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetYear(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetMonth(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetMonth(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetDay(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetDay(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetHour(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetHour(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetMinute(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetMinute(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetSecond(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetSecond(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u32 rDateTime::GetMillisecond(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetMillisecond(convertTZ(timezone));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
extern std::string rDefaultDateTimeFormat;
|
||||
|
||||
|
||||
struct rTimeSpan
|
||||
{
|
||||
rTimeSpan();
|
||||
~rTimeSpan();
|
||||
rTimeSpan(const rTimeSpan& other);
|
||||
rTimeSpan(int, int, int, int);
|
||||
|
||||
void *handle;
|
||||
};
|
||||
|
||||
struct rDateSpan
|
||||
{
|
||||
rDateSpan();
|
||||
~rDateSpan();
|
||||
rDateSpan(const rDateSpan& other);
|
||||
rDateSpan(int, int, int, int);
|
||||
|
||||
void *handle;
|
||||
};
|
||||
|
||||
struct rDateTime
|
||||
{
|
||||
enum TZ
|
||||
{
|
||||
Local, GMT0,UTC
|
||||
};
|
||||
enum Calender
|
||||
{
|
||||
Gregorian, Julian
|
||||
};
|
||||
|
||||
using rTimeZone = TZ;
|
||||
|
||||
enum WeekDay
|
||||
{
|
||||
Sun = 0,
|
||||
Mon,
|
||||
Tue,
|
||||
Wed,
|
||||
Thu,
|
||||
Fri,
|
||||
Sat,
|
||||
Inv_WeekDay
|
||||
};
|
||||
|
||||
enum Month {
|
||||
Jan = 0,
|
||||
Feb = 1,
|
||||
Mar = 2,
|
||||
Apr = 3,
|
||||
May = 4,
|
||||
Jun = 5,
|
||||
Jul = 6,
|
||||
Aug = 7,
|
||||
Sep = 8,
|
||||
Oct = 9,
|
||||
Nov = 10,
|
||||
Dec = 11,
|
||||
Inv_Month = 12
|
||||
};
|
||||
|
||||
rDateTime();
|
||||
~rDateTime();
|
||||
rDateTime(const rDateTime& other);
|
||||
rDateTime(const time_t &time);
|
||||
rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond);
|
||||
|
||||
static rDateTime UNow();
|
||||
rDateTime FromUTC(bool val);
|
||||
rDateTime ToUTC(bool val);
|
||||
time_t GetTicks();
|
||||
void Add(const rTimeSpan& span);
|
||||
void Add(const rDateSpan& span);
|
||||
void Close();
|
||||
std::string Format(const std::string &format = rDefaultDateTimeFormat, const rTimeZone &tz = Local) const;
|
||||
|
||||
void ParseDateTime(const char* format);
|
||||
|
||||
u32 GetAsDOS();
|
||||
rDateTime &SetFromDOS(u32 fromdos);
|
||||
|
||||
static bool IsLeapYear(int year, rDateTime::Calender cal);
|
||||
static int GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal);
|
||||
void SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year);
|
||||
int GetWeekDay();
|
||||
|
||||
u16 GetYear( rDateTime::TZ timezone);
|
||||
u16 GetMonth(rDateTime::TZ timezone);
|
||||
u16 GetDay(rDateTime::TZ timezone);
|
||||
u16 GetHour(rDateTime::TZ timezone);
|
||||
u16 GetMinute(rDateTime::TZ timezone);
|
||||
u16 GetSecond(rDateTime::TZ timezone);
|
||||
u32 GetMillisecond(rDateTime::TZ timezone);
|
||||
|
||||
void *handle;
|
||||
};
|
||||
|
||||
+67
-22
@@ -1,72 +1,117 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/rXml.h"
|
||||
#pragma warning(push)
|
||||
#pragma message("TODO: remove wx dependency: <wx/xml/xml.h>")
|
||||
#pragma warning(disable : 4996)
|
||||
#include <wx/xml/xml.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
rXmlNode::rXmlNode() : handle()
|
||||
rXmlNode::rXmlNode()
|
||||
{
|
||||
ownPtr = true;
|
||||
handle = reinterpret_cast<void *>(new wxXmlNode());
|
||||
}
|
||||
|
||||
rXmlNode::rXmlNode(const pugi::xml_node &node)
|
||||
rXmlNode::rXmlNode(void *ptr)
|
||||
{
|
||||
handle = node;
|
||||
ownPtr = false;
|
||||
handle = ptr;
|
||||
}
|
||||
|
||||
rXmlNode::rXmlNode(const rXmlNode& other)
|
||||
{
|
||||
ownPtr = true;
|
||||
handle = reinterpret_cast<void *>(new wxXmlNode(*reinterpret_cast<wxXmlNode*>(other.handle)));
|
||||
}
|
||||
|
||||
rXmlNode &rXmlNode::operator=(const rXmlNode& other)
|
||||
{
|
||||
if (ownPtr)
|
||||
{
|
||||
delete reinterpret_cast<wxXmlNode*>(handle);
|
||||
}
|
||||
handle = reinterpret_cast<void *>(new wxXmlNode(*reinterpret_cast<wxXmlNode*>(other.handle)));
|
||||
ownPtr = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rXmlNode::~rXmlNode()
|
||||
{
|
||||
if (ownPtr)
|
||||
{
|
||||
delete reinterpret_cast<wxXmlNode*>(handle);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<rXmlNode> rXmlNode::GetChildren()
|
||||
{
|
||||
// it.begin() returns node_iterator*, *it.begin() return node*.
|
||||
pugi::xml_object_range<pugi::xml_node_iterator> it = handle.children();
|
||||
pugi::xml_node begin = *it.begin();
|
||||
|
||||
if (begin)
|
||||
wxXmlNode* result = reinterpret_cast<wxXmlNode*>(handle)->GetChildren();
|
||||
if (result)
|
||||
{
|
||||
return std::make_shared<rXmlNode>(begin);
|
||||
return std::make_shared<rXmlNode>(reinterpret_cast<void*>(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
return std::shared_ptr<rXmlNode>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<rXmlNode> rXmlNode::GetNext()
|
||||
{
|
||||
pugi::xml_node result = handle.next_sibling();
|
||||
wxXmlNode* result = reinterpret_cast<wxXmlNode*>(handle)->GetNext();
|
||||
if (result)
|
||||
{
|
||||
return std::make_shared<rXmlNode>(result);
|
||||
return std::make_shared<rXmlNode>(reinterpret_cast<void*>(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
return std::shared_ptr<rXmlNode>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::string rXmlNode::GetName()
|
||||
{
|
||||
return handle.name();
|
||||
return fmt::ToUTF8(reinterpret_cast<wxXmlNode*>(handle)->GetName());
|
||||
}
|
||||
|
||||
std::string rXmlNode::GetAttribute(const std::string &name)
|
||||
{
|
||||
auto pred = [&name](pugi::xml_attribute attr) { return (name == attr.name()); };
|
||||
return handle.find_attribute(pred).value();
|
||||
return fmt::ToUTF8(reinterpret_cast<wxXmlNode*>(handle)->GetAttribute(fmt::FromUTF8(name)));
|
||||
}
|
||||
|
||||
std::string rXmlNode::GetNodeContent()
|
||||
{
|
||||
return handle.text().get();
|
||||
return fmt::ToUTF8(reinterpret_cast<wxXmlNode*>(handle)->GetNodeContent());
|
||||
}
|
||||
|
||||
rXmlDocument::rXmlDocument() : handle()
|
||||
rXmlDocument::rXmlDocument()
|
||||
{
|
||||
handle = reinterpret_cast<void *>(new wxXmlDocument());
|
||||
}
|
||||
|
||||
rXmlDocument::rXmlDocument(const rXmlDocument& other)
|
||||
{
|
||||
handle = reinterpret_cast<void *>(new wxXmlDocument(*reinterpret_cast<wxXmlDocument*>(other.handle)));
|
||||
}
|
||||
|
||||
rXmlDocument &rXmlDocument::operator = (const rXmlDocument& other)
|
||||
{
|
||||
delete reinterpret_cast<wxXmlDocument*>(handle);
|
||||
handle = reinterpret_cast<void *>(new wxXmlDocument(*reinterpret_cast<wxXmlDocument*>(other.handle)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
rXmlDocument::~rXmlDocument()
|
||||
{
|
||||
delete reinterpret_cast<wxXmlDocument*>(handle);
|
||||
}
|
||||
|
||||
void rXmlDocument::Load(const std::string & path)
|
||||
{
|
||||
// TODO: Unsure of use of c_str.
|
||||
handle.load_file(path.c_str());
|
||||
reinterpret_cast<wxXmlDocument*>(handle)->Load(fmt::FromUTF8(path));
|
||||
}
|
||||
|
||||
std::shared_ptr<rXmlNode> rXmlDocument::GetRoot()
|
||||
{
|
||||
return std::make_shared<rXmlNode>(handle.root());
|
||||
return std::make_shared<rXmlNode>(reinterpret_cast<void*>(reinterpret_cast<wxXmlDocument*>(handle)->GetRoot()));
|
||||
}
|
||||
|
||||
|
||||
+11
-12
@@ -1,31 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PUGIXML_HEADER_ONLY
|
||||
#define PUGIXML_HEADER_ONLY 1
|
||||
#endif // !PUGIXML_HEADER_ONLY
|
||||
#include "pugixml.hpp"
|
||||
#undef PUGIXML_HEADER_ONLY
|
||||
|
||||
struct rXmlNode
|
||||
{
|
||||
rXmlNode();
|
||||
rXmlNode(const pugi::xml_node &);
|
||||
rXmlNode(void *);
|
||||
rXmlNode(const rXmlNode& other);
|
||||
rXmlNode &operator=(const rXmlNode& other);
|
||||
~rXmlNode();
|
||||
std::shared_ptr<rXmlNode> GetChildren();
|
||||
std::shared_ptr<rXmlNode> GetNext();
|
||||
std::string GetName();
|
||||
std::string GetAttribute( const std::string &name);
|
||||
std::string GetNodeContent();
|
||||
|
||||
pugi::xml_node handle;
|
||||
void *handle;
|
||||
bool ownPtr;
|
||||
};
|
||||
|
||||
struct rXmlDocument
|
||||
{
|
||||
rXmlDocument();
|
||||
rXmlDocument(const rXmlDocument& other) = delete;
|
||||
rXmlDocument &operator=(const rXmlDocument& other) = delete;
|
||||
rXmlDocument(const rXmlDocument& other);
|
||||
rXmlDocument &operator=(const rXmlDocument& other);
|
||||
~rXmlDocument();
|
||||
void Load(const std::string & path);
|
||||
std::shared_ptr<rXmlNode> GetRoot();
|
||||
|
||||
pugi::xml_document handle;
|
||||
};
|
||||
void *handle;
|
||||
};
|
||||
@@ -1,124 +0,0 @@
|
||||
#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
|
||||
#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
|
||||
|
||||
// Based on variant/recursive_wrapper.hpp from boost.
|
||||
//
|
||||
// Original license:
|
||||
//
|
||||
// Copyright (c) 2002-2003
|
||||
// Eric Friedman, Itay Maman
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
//namespace mapbox {
|
||||
//namespace util {
|
||||
namespace std {
|
||||
|
||||
template <typename T>
|
||||
class recursive_wrapper
|
||||
{
|
||||
|
||||
T* p_;
|
||||
|
||||
void assign(T const& rhs)
|
||||
{
|
||||
this->get() = rhs;
|
||||
}
|
||||
|
||||
public:
|
||||
using type = T;
|
||||
|
||||
/**
|
||||
* Default constructor default initializes the internally stored value.
|
||||
* For POD types this means nothing is done and the storage is
|
||||
* uninitialized.
|
||||
*
|
||||
* @throws std::bad_alloc if there is insufficient memory for an object
|
||||
* of type T.
|
||||
* @throws any exception thrown by the default constructur of T.
|
||||
*/
|
||||
recursive_wrapper()
|
||||
: p_(new T){}
|
||||
|
||||
~recursive_wrapper() noexcept { delete p_; }
|
||||
|
||||
recursive_wrapper(recursive_wrapper const& operand)
|
||||
: p_(new T(operand.get())) {}
|
||||
|
||||
recursive_wrapper(T const& operand)
|
||||
: p_(new T(operand)) {}
|
||||
|
||||
recursive_wrapper(recursive_wrapper&& operand)
|
||||
: p_(new T(std::move(operand.get()))) {}
|
||||
|
||||
recursive_wrapper(T&& operand)
|
||||
: p_(new T(std::move(operand))) {}
|
||||
|
||||
inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
|
||||
{
|
||||
assign(rhs.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline recursive_wrapper& operator=(T const& rhs)
|
||||
{
|
||||
assign(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void swap(recursive_wrapper& operand) noexcept
|
||||
{
|
||||
T* temp = operand.p_;
|
||||
operand.p_ = p_;
|
||||
p_ = temp;
|
||||
}
|
||||
|
||||
recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
|
||||
{
|
||||
swap(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
recursive_wrapper& operator=(T&& rhs)
|
||||
{
|
||||
get() = std::move(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T& get()
|
||||
{
|
||||
assert(p_);
|
||||
return *get_pointer();
|
||||
}
|
||||
|
||||
T const& get() const
|
||||
{
|
||||
assert(p_);
|
||||
return *get_pointer();
|
||||
}
|
||||
|
||||
T* get_pointer() { return p_; }
|
||||
|
||||
const T* get_pointer() const { return p_; }
|
||||
|
||||
operator T const&() const { return this->get(); }
|
||||
|
||||
operator T&() { return this->get(); }
|
||||
|
||||
}; // class recursive_wrapper
|
||||
|
||||
template <typename T>
|
||||
inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
}
|
||||
//} // namespace util
|
||||
//} // namespace mapbox
|
||||
|
||||
#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
|
||||
@@ -1,188 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/* For internal use. Don't include. */
|
||||
|
||||
#include "types.h"
|
||||
#include "Atomic.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#define DYNAMIC_IMPORT(handle, name) do { name = reinterpret_cast<decltype(name)>(GetProcAddress(handle, #name)); } while (0)
|
||||
|
||||
static NTSTATUS(*NtSetTimerResolution)(ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution);
|
||||
static NTSTATUS(*NtWaitForKeyedEvent)(HANDLE Handle, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout);
|
||||
static NTSTATUS(*NtReleaseKeyedEvent)(HANDLE Handle, PVOID Key, BOOLEAN Alertable, PLARGE_INTEGER Timeout);
|
||||
|
||||
namespace util
|
||||
{
|
||||
static const bool keyed_init = []
|
||||
{
|
||||
const auto handle = LoadLibraryA("ntdll.dll");
|
||||
DYNAMIC_IMPORT(handle, NtSetTimerResolution);
|
||||
DYNAMIC_IMPORT(handle, NtWaitForKeyedEvent);
|
||||
DYNAMIC_IMPORT(handle, NtReleaseKeyedEvent);
|
||||
FreeLibrary(handle);
|
||||
|
||||
ULONG res = 100;
|
||||
NtSetTimerResolution(100, TRUE, &res);
|
||||
|
||||
return NtWaitForKeyedEvent && NtReleaseKeyedEvent;
|
||||
}();
|
||||
|
||||
// Wait for specified condition. func() acknowledges success by value modification.
|
||||
template<typename F>
|
||||
inline void keyed_wait(atomic_t<u32>& key, F&& func)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
u32 read = key.load();
|
||||
u32 copy = read;
|
||||
|
||||
while (func(read), read != copy)
|
||||
{
|
||||
read = key.compare_and_swap(copy, read);
|
||||
|
||||
if (copy == read)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
copy = read;
|
||||
}
|
||||
|
||||
NtWaitForKeyedEvent(NULL, &key, FALSE, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to wake up a thread.
|
||||
inline bool keyed_post(atomic_t<u32>& key, u32 acknowledged_value)
|
||||
{
|
||||
LARGE_INTEGER timeout;
|
||||
timeout.QuadPart = -50;
|
||||
|
||||
while (UNLIKELY(NtReleaseKeyedEvent(NULL, &key, FALSE, &timeout) != ERROR_SUCCESS))
|
||||
{
|
||||
if (key.load() != acknowledged_value)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct native_rwlock
|
||||
{
|
||||
SRWLOCK rwlock = SRWLOCK_INIT;
|
||||
|
||||
constexpr native_rwlock() = default;
|
||||
|
||||
native_rwlock(const native_rwlock&) = delete;
|
||||
|
||||
void lock()
|
||||
{
|
||||
AcquireSRWLockExclusive(&rwlock);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return TryAcquireSRWLockExclusive(&rwlock) != 0;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
ReleaseSRWLockExclusive(&rwlock);
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
AcquireSRWLockShared(&rwlock);
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
return TryAcquireSRWLockShared(&rwlock) != 0;
|
||||
}
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
ReleaseSRWLockShared(&rwlock);
|
||||
}
|
||||
};
|
||||
|
||||
struct native_cond
|
||||
{
|
||||
CONDITION_VARIABLE cond = CONDITION_VARIABLE_INIT;
|
||||
|
||||
constexpr native_cond() = default;
|
||||
|
||||
native_cond(const native_cond&) = delete;
|
||||
|
||||
void notify_one()
|
||||
{
|
||||
WakeConditionVariable(&cond);
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
WakeAllConditionVariable(&cond);
|
||||
}
|
||||
|
||||
void wait(native_rwlock& rwlock)
|
||||
{
|
||||
SleepConditionVariableSRW(&cond, &rwlock.rwlock, INFINITE, 0);
|
||||
}
|
||||
|
||||
void wait_shared(native_rwlock& rwlock)
|
||||
{
|
||||
SleepConditionVariableSRW(&cond, &rwlock.rwlock, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED);
|
||||
}
|
||||
};
|
||||
|
||||
class exclusive_lock
|
||||
{
|
||||
native_rwlock& m_rwlock;
|
||||
|
||||
public:
|
||||
exclusive_lock(native_rwlock& rwlock)
|
||||
: m_rwlock(rwlock)
|
||||
{
|
||||
m_rwlock.lock();
|
||||
}
|
||||
|
||||
~exclusive_lock()
|
||||
{
|
||||
m_rwlock.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
class shared_lock
|
||||
{
|
||||
native_rwlock& m_rwlock;
|
||||
|
||||
public:
|
||||
shared_lock(native_rwlock& rwlock)
|
||||
: m_rwlock(rwlock)
|
||||
{
|
||||
m_rwlock.lock_shared();
|
||||
}
|
||||
|
||||
~shared_lock()
|
||||
{
|
||||
m_rwlock.unlock_shared();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace util
|
||||
{
|
||||
struct native_rwlock;
|
||||
struct native_cond;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
CHECK_SIZE_ALIGN(util::native_rwlock, sizeof(void*), alignof(void*));
|
||||
CHECK_SIZE_ALIGN(util::native_cond, sizeof(void*), alignof(void*));
|
||||
+1000
-836
File diff suppressed because it is too large
Load Diff
@@ -1,973 +0,0 @@
|
||||
#ifndef MAPBOX_UTIL_VARIANT_HPP
|
||||
#define MAPBOX_UTIL_VARIANT_HPP
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef> // size_t
|
||||
#include <new> // operator new
|
||||
#include <stdexcept> // runtime_error
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
|
||||
#include "recursive_wrapper.hpp"
|
||||
|
||||
// clang-format off
|
||||
// [[deprecated]] is only available in C++14, use this for the time being
|
||||
#if __cplusplus <= 201103L
|
||||
# ifdef __GNUC__
|
||||
# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
|
||||
# elif defined(_MSC_VER)
|
||||
# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
|
||||
# else
|
||||
# define MAPBOX_VARIANT_DEPRECATED
|
||||
# endif
|
||||
#else
|
||||
# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
|
||||
# ifdef NDEBUG
|
||||
# define VARIANT_INLINE __forceinline
|
||||
# else
|
||||
# define VARIANT_INLINE //__declspec(noinline)
|
||||
# endif
|
||||
#else
|
||||
# ifdef NDEBUG
|
||||
# define VARIANT_INLINE //inline __attribute__((always_inline))
|
||||
# else
|
||||
# define VARIANT_INLINE __attribute__((noinline))
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// Exceptions
|
||||
#if defined( __EXCEPTIONS) || defined( _MSC_VER)
|
||||
#define HAS_EXCEPTIONS
|
||||
#endif
|
||||
|
||||
#define VARIANT_MAJOR_VERSION 1
|
||||
#define VARIANT_MINOR_VERSION 1
|
||||
#define VARIANT_PATCH_VERSION 0
|
||||
|
||||
#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
|
||||
|
||||
//namespace mapbox {
|
||||
// namespace util {
|
||||
namespace std {
|
||||
|
||||
// XXX This should derive from std::logic_error instead of std::runtime_error.
|
||||
// See https://github.com/mapbox/variant/issues/48 for details.
|
||||
class bad_variant_access : public std::runtime_error
|
||||
{
|
||||
|
||||
public:
|
||||
explicit bad_variant_access(const std::string& what_arg)
|
||||
: runtime_error(what_arg) {}
|
||||
|
||||
explicit bad_variant_access(const char* what_arg)
|
||||
: runtime_error(what_arg) {}
|
||||
|
||||
}; // class bad_variant_access
|
||||
|
||||
template <typename R = void>
|
||||
struct MAPBOX_VARIANT_DEPRECATED static_visitor
|
||||
{
|
||||
using result_type = R;
|
||||
|
||||
protected:
|
||||
static_visitor() {}
|
||||
~static_visitor() {}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
static constexpr std::size_t invalid_value = std::size_t(-1);
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct direct_type;
|
||||
|
||||
template <typename T, typename First, typename... Types>
|
||||
struct direct_type<T, First, Types...>
|
||||
{
|
||||
static constexpr std::size_t index = std::is_same<T, First>::value
|
||||
? sizeof...(Types)
|
||||
: direct_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct direct_type<T>
|
||||
{
|
||||
static constexpr std::size_t index = invalid_value;
|
||||
};
|
||||
|
||||
#if __cpp_lib_logical_traits >= 201510L
|
||||
|
||||
using std::disjunction;
|
||||
|
||||
#else
|
||||
|
||||
template <typename...>
|
||||
struct disjunction : std::false_type {};
|
||||
|
||||
template <typename B1>
|
||||
struct disjunction<B1> : B1 {};
|
||||
|
||||
template <typename B1, typename B2>
|
||||
struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {};
|
||||
|
||||
template <typename B1, typename... Bs>
|
||||
struct disjunction<B1, Bs...> : std::conditional<B1::value, B1, disjunction<Bs...>>::type {};
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct convertible_type;
|
||||
|
||||
template <typename T, typename First, typename... Types>
|
||||
struct convertible_type<T, First, Types...>
|
||||
{
|
||||
static constexpr std::size_t index = std::is_convertible<T, First>::value
|
||||
? disjunction<std::is_convertible<T, Types>...>::value ? invalid_value : sizeof...(Types)
|
||||
: convertible_type<T, Types...>::index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct convertible_type<T>
|
||||
{
|
||||
static constexpr std::size_t index = invalid_value;
|
||||
};
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct value_traits
|
||||
{
|
||||
using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
|
||||
static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
|
||||
static constexpr bool is_direct = direct_index != invalid_value;
|
||||
static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
|
||||
static constexpr bool is_valid = index != invalid_value;
|
||||
static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
|
||||
using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
|
||||
};
|
||||
|
||||
template <typename T, typename R = void>
|
||||
struct enable_if_type
|
||||
{
|
||||
using type = R;
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename Enable = void>
|
||||
struct result_of_unary_visit
|
||||
{
|
||||
using type = typename std::result_of<F(V&)>::type;
|
||||
};
|
||||
|
||||
template <typename F, typename V>
|
||||
struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
|
||||
{
|
||||
using type = typename F::result_type;
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename Enable = void>
|
||||
struct result_of_binary_visit
|
||||
{
|
||||
using type = typename std::result_of<F(V&, V&)>::type;
|
||||
};
|
||||
|
||||
template <typename F, typename V>
|
||||
struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
|
||||
{
|
||||
using type = typename F::result_type;
|
||||
};
|
||||
|
||||
template <std::size_t arg1, std::size_t... others>
|
||||
struct static_max;
|
||||
|
||||
template <std::size_t arg>
|
||||
struct static_max<arg>
|
||||
{
|
||||
static const std::size_t value = arg;
|
||||
};
|
||||
|
||||
template <std::size_t arg1, std::size_t arg2, std::size_t... others>
|
||||
struct static_max<arg1, arg2, others...>
|
||||
{
|
||||
static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
struct variant_helper;
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct variant_helper<T, Types...>
|
||||
{
|
||||
VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
|
||||
{
|
||||
if (type_index == sizeof...(Types))
|
||||
{
|
||||
reinterpret_cast<T*>(data)->~T();
|
||||
}
|
||||
else
|
||||
{
|
||||
variant_helper<Types...>::destroy(type_index, data);
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
|
||||
{
|
||||
if (old_type_index == sizeof...(Types))
|
||||
{
|
||||
new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
|
||||
}
|
||||
else
|
||||
{
|
||||
variant_helper<Types...>::move(old_type_index, old_value, new_value);
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
|
||||
{
|
||||
if (old_type_index == sizeof...(Types))
|
||||
{
|
||||
new (new_value) T(*reinterpret_cast<const T*>(old_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
variant_helper<Types...>::copy(old_type_index, old_value, new_value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct variant_helper<>
|
||||
{
|
||||
VARIANT_INLINE static void destroy(const std::size_t, void*) {}
|
||||
VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
|
||||
VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper
|
||||
{
|
||||
static T const& apply_const(T const& obj) { return obj; }
|
||||
static T& apply(T& obj) { return obj; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper<recursive_wrapper<T>>
|
||||
{
|
||||
static auto apply_const(recursive_wrapper<T> const& obj)
|
||||
-> typename recursive_wrapper<T>::type const&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
static auto apply(recursive_wrapper<T>& obj)
|
||||
-> typename recursive_wrapper<T>::type&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unwrapper<std::reference_wrapper<T>>
|
||||
{
|
||||
static auto apply_const(std::reference_wrapper<T> const& obj)
|
||||
-> typename std::reference_wrapper<T>::type const&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
static auto apply(std::reference_wrapper<T>& obj)
|
||||
-> typename std::reference_wrapper<T>::type&
|
||||
{
|
||||
return obj.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename... Types>
|
||||
struct dispatcher;
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v, F&& f)
|
||||
{
|
||||
if (v.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v, F&& f)
|
||||
{
|
||||
if (v.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T>
|
||||
struct dispatcher<F, V, R, T>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct binary_dispatcher_rhs;
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
|
||||
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
if (rhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
if (rhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1>
|
||||
struct binary_dispatcher_rhs<F, V, R, T0, T1>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
|
||||
unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct binary_dispatcher_lhs;
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
|
||||
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
if (lhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
if (lhs.template is<T1>()) // call binary functor
|
||||
{
|
||||
return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T0, typename T1>
|
||||
struct binary_dispatcher_lhs<F, V, R, T0, T1>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
|
||||
{
|
||||
return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
|
||||
unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename... Types>
|
||||
struct binary_dispatcher;
|
||||
|
||||
template <typename F, typename V, typename R, typename T, typename... Types>
|
||||
struct binary_dispatcher<F, V, R, T, Types...>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
|
||||
{
|
||||
if (v0.template is<T>())
|
||||
{
|
||||
if (v1.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
else if (v1.template is<T>())
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
|
||||
{
|
||||
if (v0.template is<T>())
|
||||
{
|
||||
if (v1.template is<T>())
|
||||
{
|
||||
return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
|
||||
}
|
||||
else
|
||||
{
|
||||
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
}
|
||||
else if (v1.template is<T>())
|
||||
{
|
||||
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename F, typename V, typename R, typename T>
|
||||
struct binary_dispatcher<F, V, R, T>
|
||||
{
|
||||
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
|
||||
}
|
||||
|
||||
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
|
||||
{
|
||||
return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
|
||||
unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
|
||||
}
|
||||
};
|
||||
|
||||
// comparator functors
|
||||
struct equal_comp
|
||||
{
|
||||
template <typename T>
|
||||
bool operator()(T const& lhs, T const& rhs) const
|
||||
{
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
struct less_comp
|
||||
{
|
||||
template <typename T>
|
||||
bool operator()(T const& lhs, T const& rhs) const
|
||||
{
|
||||
return lhs < rhs;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Variant, typename Comp>
|
||||
class comparer
|
||||
{
|
||||
public:
|
||||
explicit comparer(Variant const& lhs) noexcept
|
||||
: lhs_(lhs) {}
|
||||
comparer& operator=(comparer const&) = delete;
|
||||
// visitor
|
||||
template <typename T>
|
||||
bool operator()(T const& rhs_content) const
|
||||
{
|
||||
T const& lhs_content = lhs_.template get_unchecked<T>();
|
||||
return Comp()(lhs_content, rhs_content);
|
||||
}
|
||||
|
||||
private:
|
||||
Variant const& lhs_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
struct no_init
|
||||
{
|
||||
};
|
||||
|
||||
template <typename... Types>
|
||||
class variant
|
||||
{
|
||||
static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
|
||||
static_assert(!detail::disjunction<std::is_reference<Types>...>::value, "Variant can not hold reference types. Maybe use std::reference_wrapper?");
|
||||
|
||||
private:
|
||||
static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
|
||||
static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
|
||||
|
||||
using first_type = typename std::tuple_element<0, std::tuple<Types...>>::type;
|
||||
using data_type = typename std::aligned_storage<data_size, data_align>::type;
|
||||
using helper_type = detail::variant_helper<Types...>;
|
||||
|
||||
std::size_t type_index;
|
||||
data_type data;
|
||||
|
||||
public:
|
||||
VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
|
||||
: type_index(sizeof...(Types)-1)
|
||||
{
|
||||
static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
|
||||
new (&data) first_type();
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(no_init) noexcept
|
||||
: type_index(detail::invalid_value) {}
|
||||
|
||||
// http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
|
||||
template <typename T, typename Traits = detail::value_traits<T, Types...>,
|
||||
typename Enable = typename std::enable_if<Traits::is_valid>::type>
|
||||
VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
|
||||
: type_index(Traits::index)
|
||||
{
|
||||
new (&data) typename Traits::target_type(std::forward<T>(val));
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(variant<Types...> const& old)
|
||||
: type_index(old.type_index)
|
||||
{
|
||||
helper_type::copy(old.type_index, &old.data, &data);
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<std::tuple<Types...>>::value)
|
||||
: type_index(old.type_index)
|
||||
{
|
||||
helper_type::move(old.type_index, &old.data, &data);
|
||||
}
|
||||
|
||||
private:
|
||||
VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
type_index = detail::invalid_value;
|
||||
helper_type::copy(rhs.type_index, &rhs.data, &data);
|
||||
type_index = rhs.type_index;
|
||||
}
|
||||
|
||||
VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
type_index = detail::invalid_value;
|
||||
helper_type::move(rhs.type_index, &rhs.data, &data);
|
||||
type_index = rhs.type_index;
|
||||
}
|
||||
|
||||
public:
|
||||
VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
|
||||
{
|
||||
move_assign(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
|
||||
{
|
||||
copy_assign(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// conversions
|
||||
// move-assign
|
||||
template <typename T>
|
||||
VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
|
||||
{
|
||||
variant<Types...> temp(std::forward<T>(rhs));
|
||||
move_assign(std::move(temp));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// copy-assign
|
||||
template <typename T>
|
||||
VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
|
||||
{
|
||||
variant<Types...> temp(rhs);
|
||||
copy_assign(temp);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE bool is() const
|
||||
{
|
||||
return type_index == detail::direct_type<T, Types...>::index;
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE bool is() const
|
||||
{
|
||||
return type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index;
|
||||
}
|
||||
|
||||
VARIANT_INLINE bool valid() const
|
||||
{
|
||||
return type_index != detail::invalid_value;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
VARIANT_INLINE void set(Args&&... args)
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
type_index = detail::invalid_value;
|
||||
new (&data) T(std::forward<Args>(args)...);
|
||||
type_index = detail::direct_type<T, Types...>::index;
|
||||
}
|
||||
|
||||
// get_unchecked<T>()
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get_unchecked()
|
||||
{
|
||||
return *reinterpret_cast<T*>(&data);
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
// get<T>()
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_index == detail::direct_type<T, Types...>::index)
|
||||
{
|
||||
return *reinterpret_cast<T*>(&data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get_unchecked() const
|
||||
{
|
||||
return *reinterpret_cast<T const*>(&data);
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get() const
|
||||
{
|
||||
if (type_index == detail::direct_type<T, Types...>::index)
|
||||
{
|
||||
return *reinterpret_cast<T const*>(&data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// get_unchecked<T>() - T stored as recursive_wrapper<T>
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get_unchecked()
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
// get<T>() - T stored as recursive_wrapper<T>
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get_unchecked() const
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get() const
|
||||
{
|
||||
if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// get_unchecked<T>() - T stored as std::reference_wrapper<T>
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get_unchecked()
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
// get<T>() - T stored as std::reference_wrapper<T>
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T& get()
|
||||
{
|
||||
if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get_unchecked() const
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE T const& get() const
|
||||
{
|
||||
if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
|
||||
{
|
||||
return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw bad_variant_access("in get<T>()");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// This function is deprecated because it returns an internal index field.
|
||||
// Use which() instead.
|
||||
MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
|
||||
{
|
||||
return type_index;
|
||||
}
|
||||
|
||||
VARIANT_INLINE int which() const noexcept
|
||||
{
|
||||
return static_cast<int>(sizeof...(Types)-type_index - 1);
|
||||
}
|
||||
|
||||
template <typename T, typename std::enable_if<
|
||||
(detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
|
||||
VARIANT_INLINE static constexpr int which() noexcept
|
||||
{
|
||||
return static_cast<int>(sizeof...(Types)-detail::direct_type<T, Types...>::index - 1);
|
||||
}
|
||||
|
||||
// visitor
|
||||
// unary
|
||||
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static visit(V const& v, F&& f)
|
||||
-> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
|
||||
{
|
||||
return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
|
||||
}
|
||||
// non-const
|
||||
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static visit(V& v, F&& f)
|
||||
-> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
|
||||
{
|
||||
return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// binary
|
||||
// const
|
||||
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
|
||||
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
// non-const
|
||||
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
|
||||
auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
|
||||
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
~variant() noexcept // no-throw destructor
|
||||
{
|
||||
helper_type::destroy(type_index, &data);
|
||||
}
|
||||
|
||||
// comparison operators
|
||||
// equality
|
||||
VARIANT_INLINE bool operator==(variant const& rhs) const
|
||||
{
|
||||
assert(valid() && rhs.valid());
|
||||
if (this->which() != rhs.which())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
detail::comparer<variant, detail::equal_comp> visitor(*this);
|
||||
return visit(rhs, visitor);
|
||||
}
|
||||
|
||||
VARIANT_INLINE bool operator!=(variant const& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
// less than
|
||||
VARIANT_INLINE bool operator<(variant const& rhs) const
|
||||
{
|
||||
assert(valid() && rhs.valid());
|
||||
if (this->which() != rhs.which())
|
||||
{
|
||||
return this->which() < rhs.which();
|
||||
}
|
||||
detail::comparer<variant, detail::less_comp> visitor(*this);
|
||||
return visit(rhs, visitor);
|
||||
}
|
||||
VARIANT_INLINE bool operator>(variant const& rhs) const
|
||||
{
|
||||
return rhs < *this;
|
||||
}
|
||||
VARIANT_INLINE bool operator<=(variant const& rhs) const
|
||||
{
|
||||
return !(*this > rhs);
|
||||
}
|
||||
VARIANT_INLINE bool operator>=(variant const& rhs) const
|
||||
{
|
||||
return !(*this < rhs);
|
||||
}
|
||||
};
|
||||
|
||||
// unary visitor interface
|
||||
// const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
|
||||
{
|
||||
return V::visit(v, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// non-const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
|
||||
{
|
||||
return V::visit(v, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// binary visitor interface
|
||||
// const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return V::binary_visit(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// non-const
|
||||
template <typename F, typename V>
|
||||
auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
|
||||
{
|
||||
return V::binary_visit(v0, v1, std::forward<F>(f));
|
||||
}
|
||||
|
||||
// getter interface
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
template <typename ResultType, typename T>
|
||||
auto get(T& var)->decltype(var.template get<ResultType>())
|
||||
{
|
||||
return var.template get<ResultType>();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ResultType, typename T>
|
||||
ResultType& get_unchecked(T& var)
|
||||
{
|
||||
return var.template get_unchecked<ResultType>();
|
||||
}
|
||||
|
||||
#ifdef HAS_EXCEPTIONS
|
||||
template <typename ResultType, typename T>
|
||||
auto get(T const& var)->decltype(var.template get<ResultType>())
|
||||
{
|
||||
return var.template get<ResultType>();
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ResultType, typename T>
|
||||
ResultType const& get_unchecked(T const& var)
|
||||
{
|
||||
return var.template get_unchecked<ResultType>();
|
||||
}
|
||||
}
|
||||
// } // namespace util
|
||||
//} // namespace mapbox
|
||||
|
||||
#endif // MAPBOX_UTIL_VARIANT_HPP
|
||||
@@ -1,51 +0,0 @@
|
||||
#include "stdafx.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
std::string to_string(version_type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case version_type::pre_alpha: return "Pre-Alpha";
|
||||
case version_type::alpha: return "Alpha";
|
||||
case version_type::beta: return "Beta";
|
||||
case version_type::release_candidate: return "RC";
|
||||
case version_type::release: return "Release";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
uint version::to_hex() const
|
||||
{
|
||||
return (m_hi << 24) | (m_mid << 16) | (m_lo << 8) | ((uint(m_type) & 0xf) << 4) | (m_type_index & 0xf);
|
||||
}
|
||||
|
||||
std::string version::to_string() const
|
||||
{
|
||||
std::string version = std::to_string(hi()) + "." + std::to_string(mid());
|
||||
|
||||
if (lo())
|
||||
{
|
||||
version += "." + std::to_string(lo());
|
||||
}
|
||||
|
||||
if (type() != version_type::release)
|
||||
{
|
||||
if (!postfix().empty())
|
||||
{
|
||||
version += "-" + postfix();
|
||||
}
|
||||
|
||||
version += " " + utils::to_string(type());
|
||||
|
||||
if (type_index() > 1)
|
||||
{
|
||||
version += " " + std::to_string(type_index());
|
||||
}
|
||||
}
|
||||
|
||||
return version;
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
enum class version_type : uint
|
||||
{
|
||||
pre_alpha,
|
||||
alpha,
|
||||
beta,
|
||||
release_candidate,
|
||||
release
|
||||
};
|
||||
|
||||
std::string to_string(version_type type);
|
||||
|
||||
class version
|
||||
{
|
||||
uint m_hi;
|
||||
uint m_mid;
|
||||
uint m_lo;
|
||||
version_type m_type = version_type::release;
|
||||
uint m_type_index = 1;
|
||||
const char* m_postfix;
|
||||
|
||||
public:
|
||||
constexpr version(uint hi, uint mid, uint lo, version_type type, uint type_index, const char* postfix)
|
||||
: m_hi(hi)
|
||||
, m_mid(mid)
|
||||
, m_lo(lo)
|
||||
, m_type(type)
|
||||
, m_type_index(type_index)
|
||||
, m_postfix(postfix)
|
||||
{
|
||||
}
|
||||
|
||||
uint hi() const
|
||||
{
|
||||
return m_hi;
|
||||
}
|
||||
|
||||
uint mid() const
|
||||
{
|
||||
return m_mid;
|
||||
}
|
||||
|
||||
uint lo() const
|
||||
{
|
||||
return m_lo;
|
||||
}
|
||||
|
||||
version_type type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
std::string postfix() const
|
||||
{
|
||||
return m_postfix;
|
||||
}
|
||||
|
||||
uint type_index() const
|
||||
{
|
||||
return m_type_index;
|
||||
}
|
||||
|
||||
uint to_hex() const;
|
||||
std::string to_string() const;
|
||||
};
|
||||
}
|
||||
@@ -22,9 +22,6 @@
|
||||
#define wxUSE_GUI 1
|
||||
#endif // wxUSE_GUI
|
||||
|
||||
// No winRT support
|
||||
#define wxUSE_WINRT 0
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// compatibility settings
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -300,7 +297,7 @@
|
||||
// Recommended setting: 0 as the options below already provide a relatively
|
||||
// good level of interoperability and changing this option arguably isn't worth
|
||||
// diverging from the official builds of the library.
|
||||
#define wxUSE_STL 1
|
||||
#define wxUSE_STL 0
|
||||
|
||||
// This is not a real option but is used as the default value for
|
||||
// wxUSE_STD_IOSTREAM, wxUSE_STD_STRING and wxUSE_STD_CONTAINERS_COMPATIBLY.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user