Compare commits

..

1 Commits

Author SHA1 Message Date
Zangetsu38 83437e59e2 Some Change in Gui. 2016-01-07 09:22:27 +01:00
1158 changed files with 158313 additions and 94835 deletions
-2
View File
@@ -38,8 +38,6 @@
/rpcs3/Debug
/rpcs3/Release
/llvm_build
/Vulkan/Vulkan-build
/Vulkan/glslang-build
/wxWidgets/lib
/bin/rpcs3.ini
+4 -20
View File
@@ -3,7 +3,7 @@
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
@@ -13,25 +13,9 @@
path = llvm
url = https://github.com/llvm-mirror/llvm
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/RPCS3/rsx_program_decompiler
[submodule "GSL"]
path = 3rdparty/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
+2 -2
View File
@@ -1,3 +1,3 @@
{
"userBlacklist": ["AlexAltea", "tambry"]
}
"userBlacklist": [AlexAltea]
}
+17 -13
View File
@@ -1,6 +1,4 @@
language: cpp
sudo: required
dist: trusty
os:
- linux
@@ -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,11 +33,14 @@ 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 CXX="g++-4.9" CC="gcc-4.9" 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
@@ -46,7 +51,7 @@ before_install:
fi;
before_script:
- git submodule update --init rsx_program_decompiler asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp
- git submodule update --init asmjit ffmpeg rsx_program_decompiler
- mkdir build
- cd build
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi
@@ -62,22 +67,21 @@ addons:
apt:
sources:
- ubuntu-toolchain-r-test
# - llvm-toolchain-trusty-3.6 temporarily disabled
- llvm-toolchain-precise-3.6
- kubuntu-backports
packages:
- cmake
- libopenal-dev
- freeglut3-dev
- libglew-dev
- libc6-dev
# - llvm-3.6
# - llvm-3.6-dev
- llvm-3.6
- llvm-3.6-dev
- libedit-dev
- g++-5
- gcc-5
# - clang-3.6
- libstdc++-5-dev
- g++-4.9
- clang-3.6
- libstdc++-4.8-dev
- lib32stdc++6
- zlib1g-dev
coverity_scan:
project:
name: $TRAVIS_REPO_SLUG
-1
Submodule 3rdparty/GSL deleted from fc5fce4f4f
-1295
View File
File diff suppressed because it is too large Load Diff
-263
View File
@@ -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__
-65
View File
@@ -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_
-18
View File
@@ -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_
-718
View File
@@ -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__
-1
Submodule 3rdparty/libpng deleted from ea77a6fd49
-1
Submodule 3rdparty/pugixml deleted from f205aaf6e1
-6698
View File
File diff suppressed because it is too large Load Diff
-3301
View File
File diff suppressed because it is too large Load Diff
+1 -13
View File
@@ -11,20 +11,8 @@ if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
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()
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 )
View File
+10 -20
View File
@@ -13,7 +13,7 @@ You can find some basic information in the [FAQ](https://github.com/RPCS3/rpcs3/
### 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
@@ -21,40 +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+
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libopenal-dev libwxgtk3.0-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev`
* GCC 4.9.0+ 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__
* 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
To initialize the repository don't forget to execute `git submodule update --init` to pull the submodules.
To initialize the repository don't forget to execute `git submodule update --init` to pull the wxWidgets source.
* __Windows__:
1) Open the *.SLN* file.
2) Build the projects in *__BUILD_BEFORE* folder: right-click on every project > *Build*.
3) Press *BUILD* > *Build Solution* or *Rebuild Solution*.
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.8 is required.
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=...` (or wherever llvm brew was installed) to cmake invocation.
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.
### Support
* [Donate by PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MPJ3S9XQXCE3G)
+603 -900
View File
File diff suppressed because it is too large Load Diff
-150
View File
@@ -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
View File
@@ -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, "Auto Pause at System Call");
cfg::bool_entry g_cfg_debug_autopause_func_call(cfg::root.misc, "Auto 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
View File
@@ -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);
};
}
}
+232 -216
View File
@@ -1,14 +1,16 @@
#pragma once
#include "types.h"
#include "Platform.h"
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
union alignas(16) v128
#define IS_LE_MACHINE // only draft
union v128
{
char _bytes[16];
template<typename T, std::size_t N, std::size_t M>
struct masked_array_t // array type accessed as (index ^ M)
template<typename T, std::size_t N, std::size_t M> class masked_array_t // array type accessed as (index ^ M)
{
T m_data[N];
@@ -22,11 +24,24 @@ union alignas(16) v128
{
return m_data[index ^ M];
}
T& at(std::size_t index)
{
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__);
}
const T& at(std::size_t index) const
{
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__);
}
};
#if IS_LE_MACHINE == 1
#ifdef IS_LE_MACHINE
template<typename T, std::size_t N = 16 / sizeof(T)> using normal_array_t = masked_array_t<T, N, 0>;
template<typename T, std::size_t N = 16 / sizeof(T)> using reversed_array_t = masked_array_t<T, N, N - 1>;
#else
template<typename T, std::size_t N = 16 / sizeof(T)> using normal_array_t = masked_array_t<T, N, N - 1>;
template<typename T, std::size_t N = 16 / sizeof(T)> using reversed_array_t = masked_array_t<T, N, 0>;
#endif
normal_array_t<u64> _u64;
@@ -58,7 +73,7 @@ union alignas(16) v128
__m128i vi;
__m128d vd;
struct bit_array_128
class bit_array_128
{
u64 m_data[2];
@@ -110,18 +125,36 @@ union alignas(16) v128
// Index 0 returns the MSB and index 127 returns the LSB
bit_element operator [](u32 index)
{
#if IS_LE_MACHINE == 1
#ifdef IS_LE_MACHINE
return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
#else
return bit_element(m_data[index >> 6], 0x8000000000000000ull >> (index & 0x3F));
#endif
}
// Index 0 returns the MSB and index 127 returns the LSB
bool operator [](u32 index) const
{
#if IS_LE_MACHINE == 1
#ifdef IS_LE_MACHINE
return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
#else
return (m_data[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
#endif
}
bit_element at(u32 index)
{
if (index >= 128) throw std::out_of_range(__FUNCTION__);
return operator[](index);
}
bool at(u32 index) const
{
if (index >= 128) throw std::out_of_range(__FUNCTION__);
return operator[](index);
}
}
_bit;
@@ -287,6 +320,16 @@ union alignas(16) v128
return _u64[0] != right._u64[0] || _u64[1] != right._u64[1];
}
bool is_any_1() const // check if any bit is 1
{
return _u64[0] || _u64[1];
}
bool is_any_0() const // check if any bit is 0
{
return ~_u64[0] || ~_u64[1];
}
// result = (~left) & (right)
static inline v128 andnot(const v128& left, const v128& right)
{
@@ -302,8 +345,15 @@ union alignas(16) v128
std::string to_hex() const;
std::string to_xyzw() const;
static inline v128 byteswap(const v128 val)
{
return fromV(_mm_shuffle_epi8(val.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)));
}
};
CHECK_SIZE_ALIGN(v128, 16, 16);
inline v128 operator |(const v128& left, const v128& right)
{
return v128::fromV(_mm_or_si128(left.vi, right.vi));
@@ -324,21 +374,21 @@ inline v128 operator ~(const v128& other)
return v128::from64(~other._u64[0], ~other._u64[1]);
}
#define IS_INTEGER(t) (std::is_integral<t>::value || std::is_enum<t>::value)
#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2))
template<typename T, std::size_t Size = sizeof(T)>
struct se_storage
template<typename T, std::size_t Size = sizeof(T)> struct se_storage
{
static_assert(!Size, "Bad se_storage<> type");
};
template<typename T>
struct se_storage<T, 2>
template<typename T> struct se_storage<T, 2>
{
using type = u16;
static constexpr u16 swap(u16 src)
[[deprecated]] static constexpr u16 _swap(u16 src) // for reference
{
return (src >> 8) | (src << 8);
}
static inline u16 swap(u16 src)
{
#if defined(__GNUG__)
return __builtin_bswap16(src);
@@ -359,12 +409,16 @@ struct se_storage<T, 2>
}
};
template<typename T>
struct se_storage<T, 4>
template<typename T> struct se_storage<T, 4>
{
using type = u32;
static constexpr u32 swap(u32 src)
[[deprecated]] static constexpr u32 _swap(u32 src) // for reference
{
return (src >> 24) | (src << 24) | ((src >> 8) & 0x0000ff00) | ((src << 8) & 0x00ff0000);
}
static inline u32 swap(u32 src)
{
#if defined(__GNUG__)
return __builtin_bswap32(src);
@@ -385,12 +439,22 @@ struct se_storage<T, 4>
}
};
template<typename T>
struct se_storage<T, 8>
template<typename T> struct se_storage<T, 8>
{
using type = u64;
static constexpr u64 swap(u64 src)
[[deprecated]] static constexpr u64 _swap(u64 src) // for reference
{
return (src >> 56) | (src << 56) |
((src >> 40) & 0x000000000000ff00) |
((src >> 24) & 0x0000000000ff0000) |
((src >> 8) & 0x00000000ff000000) |
((src << 8) & 0x000000ff00000000) |
((src << 24) & 0x0000ff0000000000) |
((src << 40) & 0x00ff000000000000);
}
static inline u64 swap(u64 src)
{
#if defined(__GNUG__)
return __builtin_bswap64(src);
@@ -411,32 +475,25 @@ struct se_storage<T, 8>
}
};
template<typename T>
struct se_storage<T, 16>
template<typename T> struct se_storage<T, 16>
{
using type = v128;
static inline v128 swap(const v128& src)
{
return v128::fromV(_mm_shuffle_epi8(src.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)));
}
static inline v128 to(const T& src)
{
return swap(reinterpret_cast<const v128&>(src));
return v128::byteswap(reinterpret_cast<const v128&>(src));
}
static inline T from(const v128& src)
{
const v128 result = swap(src);
const v128 result = v128::byteswap(src);
return reinterpret_cast<const T&>(result);
}
};
template<typename T> using se_storage_t = typename se_storage<T>::type;
template<typename T1, typename T2>
struct se_convert
template<typename T1, typename T2> struct se_convert
{
using type_from = std::remove_cv_t<T1>;
using type_to = std::remove_cv_t<T2>;
@@ -458,12 +515,10 @@ struct se_convert
static struct se_raw_tag_t {} constexpr se_raw{};
template<typename T, bool Se = true>
class se_t;
template<typename T, bool Se = true> class se_t;
// Switched endianness
template<typename T>
class se_t<T, true>
// se_t with switched endianness
template<typename T> class se_t<T, true>
{
using type = typename std::remove_cv<T>::type;
using stype = se_storage_t<type>;
@@ -471,13 +526,14 @@ class se_t<T, true>
stype m_data;
static_assert(!std::is_union<type>::value && !std::is_class<type>::value || std::is_same<type, v128>::value || std::is_same<type, u128>::value, "se_t<> error: invalid type (struct or union)");
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment");
static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment");
template<typename T2, typename = void>
struct bool_converter
template<typename T2, typename = void> struct bool_converter
{
static inline bool to_bool(const se_t<T2>& value)
{
@@ -485,8 +541,7 @@ class se_t<T, true>
}
};
template<typename T2>
struct bool_converter<T2, std::enable_if_t<std::is_integral<T2>::value>>
template<typename T2> struct bool_converter<T2, std::enable_if_t<std::is_integral<T2>::value>>
{
static inline bool to_bool(const se_t<T2>& value)
{
@@ -504,7 +559,7 @@ public:
{
}
// Construct directly from raw data (don't use)
// construct directly from raw data (don't use)
constexpr se_t(const stype& raw_value, const se_raw_tag_t&)
: m_data(raw_value)
{
@@ -515,7 +570,7 @@ public:
return storage::from(m_data);
}
// Access underlying raw data (don't use)
// access underlying raw data (don't use)
constexpr const stype& raw_data() const noexcept
{
return m_data;
@@ -528,96 +583,78 @@ public:
return m_data = storage::to(value), *this;
}
using simple_type = simple_t<T>;
operator type() const
{
return storage::from(m_data);
}
// Optimization
// optimization
explicit operator bool() const
{
return bool_converter<type>::to_bool(*this);
}
// Optimization
template<typename T2>
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator &=(const se_t<T2>& right)
// optimization
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator &=(const se_t<T2>& right)
{
return m_data &= right.raw_data(), *this;
}
// Optimization
template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator &=(CT right)
// optimization
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(CT right)
{
return m_data &= storage::to(right), *this;
}
// Optimization
template<typename T2>
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator |=(const se_t<T2>& right)
// optimization
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator |=(const se_t<T2>& right)
{
return m_data |= right.raw_data(), *this;
}
// Optimization
template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator |=(CT right)
// optimization
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(CT right)
{
return m_data |= storage::to(right), *this;
}
// Optimization
template<typename T2>
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator ^=(const se_t<T2>& right)
// optimization
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator ^=(const se_t<T2>& right)
{
return m_data ^= right.raw_data(), *this;
}
// Optimization
template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator ^=(CT right)
// optimization
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(CT right)
{
return m_data ^= storage::to(right), *this;
}
};
// Native endianness
template<typename T>
class se_t<T, false>
// se_t with native endianness
template<typename T> class se_t<T, false>
{
using type = typename std::remove_cv<T>::type;
type m_data;
static_assert(!std::is_union<type>::value && !std::is_class<type>::value || std::is_same<type, v128>::value || std::is_same<type, u128>::value, "se_t<> error: invalid type (struct or union)");
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment");
type m_data;
static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead");
public:
se_t() = default;
se_t(const se_t&) = default;
constexpr se_t(type value)
: m_data(value)
{
}
// Construct directly from raw data (don't use)
constexpr se_t(const type& raw_value, const se_raw_tag_t&)
: m_data(raw_value)
{
}
constexpr type value() const
{
return m_data;
}
// Access underlying raw data (don't use)
constexpr const type& raw_data() const noexcept
type value() const
{
return m_data;
}
@@ -629,27 +666,22 @@ public:
return m_data = value, *this;
}
using simple_type = simple_t<T>;
constexpr operator type() const
operator type() const
{
return m_data;
}
template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator &=(const CT& right)
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(const CT& right)
{
return m_data &= right, *this;
}
template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator |=(const CT& right)
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(const CT& right)
{
return m_data |= right, *this;
}
template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator ^=(const CT& right)
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(const CT& right)
{
return m_data ^= right, *this;
}
@@ -658,57 +690,49 @@ public:
// se_t with native endianness (alias)
template<typename T> using nse_t = se_t<T, false>;
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator +=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator +=(se_t<T, Se>& left, const T1& right)
{
auto value = left.value();
return left = (value += right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator -=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator -=(se_t<T, Se>& left, const T1& right)
{
auto value = left.value();
return left = (value -= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator *=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator *=(se_t<T, Se>& left, const T1& right)
{
auto value = left.value();
return left = (value *= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator /=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator /=(se_t<T, Se>& left, const T1& right)
{
auto value = left.value();
return left = (value /= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator %=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator %=(se_t<T, Se>& left, const T1& right)
{
auto value = left.value();
return left = (value %= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator <<=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator <<=(se_t<T, Se>& left, const T1& right)
{
auto value = left.value();
return left = (value <<= right);
}
template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator >>=(se_t<T, Se>& left, const T1& right)
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator >>=(se_t<T, Se>& left, const T1& right)
{
auto value = left.value();
return left = (value >>= right);
}
template<typename T, bool Se>
inline se_t<T, Se> operator ++(se_t<T, Se>& left, int)
template<typename T, bool Se> inline se_t<T, Se> operator ++(se_t<T, Se>& left, int)
{
auto value = left.value();
auto result = value++;
@@ -716,8 +740,7 @@ inline se_t<T, Se> operator ++(se_t<T, Se>& left, int)
return result;
}
template<typename T, bool Se>
inline se_t<T, Se> operator --(se_t<T, Se>& left, int)
template<typename T, bool Se> inline se_t<T, Se> operator --(se_t<T, Se>& left, int)
{
auto value = left.value();
auto result = value--;
@@ -725,200 +748,193 @@ inline se_t<T, Se> operator --(se_t<T, Se>& left, int)
return result;
}
template<typename T, bool Se>
inline se_t<T, Se>& operator ++(se_t<T, Se>& right)
template<typename T, bool Se> inline se_t<T, Se>& operator ++(se_t<T, Se>& right)
{
auto value = right.value();
return right = ++value;
}
template<typename T, bool Se>
inline se_t<T, Se>& operator --(se_t<T, Se>& right)
template<typename T, bool Se> inline se_t<T, Se>& operator --(se_t<T, Se>& right)
{
auto value = right.value();
return right = --value;
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator ==(const se_t<T1>& left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator ==(const se_t<T1>& left, const se_t<T2>& right)
{
return left.raw_data() == right.raw_data();
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator ==(const se_t<T1>& left, T2 right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator ==(const se_t<T1>& left, T2 right)
{
return left.raw_data() == se_storage<T1>::to(right);
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2), bool> operator ==(T1 left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2), bool> operator ==(T1 left, const se_t<T2>& right)
{
return se_storage<T2>::to(left) == right.raw_data();
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator !=(const se_t<T1>& left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator !=(const se_t<T1>& left, const se_t<T2>& right)
{
return left.raw_data() != right.raw_data();
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator !=(const se_t<T1>& left, T2 right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator !=(const se_t<T1>& left, T2 right)
{
return left.raw_data() != se_storage<T1>::to(right);
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2), bool> operator !=(T1 left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2), bool> operator !=(T1 left, const se_t<T2>& right)
{
return se_storage<T2>::to(left) != right.raw_data();
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, const se_t<T2>& right)
{
return{ left.raw_data() & right.raw_data(), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, T2 right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, T2 right)
{
return{ left.raw_data() & se_storage<T1>::to(right), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() & T2())>> operator &(T1 left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() & T2())>> operator &(T1 left, const se_t<T2>& right)
{
return{ se_storage<T2>::to(left) & right.raw_data(), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, const se_t<T2>& right)
{
return{ left.raw_data() | right.raw_data(), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, T2 right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, T2 right)
{
return{ left.raw_data() | se_storage<T1>::to(right), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() | T2())>> operator |(T1 left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() | T2())>> operator |(T1 left, const se_t<T2>& right)
{
return{ se_storage<T2>::to(left) | right.raw_data(), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, const se_t<T2>& right)
{
return{ left.raw_data() ^ right.raw_data(), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, T2 right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, T2 right)
{
return{ left.raw_data() ^ se_storage<T1>::to(right), se_raw };
}
// Optimization
template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(T1 left, const se_t<T2>& right)
// optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(T1 left, const se_t<T2>& right)
{
return{ se_storage<T2>::to(left) ^ right.raw_data(), se_raw };
}
// Optimization
template<typename T>
inline std::enable_if_t<std::is_integral<T>::value && sizeof(T) >= 4, se_t<decltype(~T())>> operator ~(const se_t<T>& right)
// optimization
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T) && sizeof(T) >= 4, se_t<decltype(~T())>> operator ~(const se_t<T>& right)
{
return{ ~right.raw_data(), se_raw };
}
#if IS_LE_MACHINE == 1
#ifdef IS_LE_MACHINE
template<typename T> using be_t = se_t<T, true>;
template<typename T> using le_t = se_t<T, false>;
#else
template<typename T> using be_t = se_t<T, false>;
template<typename T> using le_t = se_t<T, true>;
#endif
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
template<typename T, bool Se, typename = void>
struct to_se
template<typename T, bool Se, typename = void> struct to_se
{
// Convert arithmetic and enum types
using type = typename std::conditional<std::is_arithmetic<T>::value || std::is_enum<T>::value, se_t<T, Se>, T>::type;
};
template<typename T, bool Se> struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>> // move const qualifier
{
using type = const typename to_se<T, Se>::type;
};
template<typename T, bool Se> struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>> // move volatile qualifier
{
using type = volatile typename to_se<T, Se>::type;
};
template<typename T, bool Se> struct to_se<T[], Se>
{
using type = typename to_se<T, Se>::type[];
};
template<typename T, bool Se, std::size_t N> struct to_se<T[N], Se>
{
using type = typename to_se<T, Se>::type[N];
};
template<bool Se> struct to_se<u128, Se> { using type = se_t<u128, Se>; };
template<bool Se> struct to_se<v128, Se> { using type = se_t<v128, Se>; };
template<bool Se> struct to_se<bool, Se> { using type = bool; };
template<bool Se> struct to_se<char, Se> { using type = char; };
template<bool Se> struct to_se<u8, Se> { using type = u8; };
template<bool Se> struct to_se<s8, Se> { using type = s8; };
template<typename T, bool Se>
struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>>
{
// Move const qualifier
using type = const typename to_se<T, Se>::type;
};
template<typename T, bool Se>
struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>>
{
// Move volatile qualifier
using type = volatile typename to_se<T, Se>::type;
};
template<typename T, bool Se>
struct to_se<T[], Se>
{
// Move array qualifier
using type = typename to_se<T, Se>::type[];
};
template<typename T, bool Se, std::size_t N>
struct to_se<T[N], Se>
{
// Move array qualifier
using type = typename to_se<T, Se>::type[N];
};
// BE/LE aliases for to_se<>
#if IS_LE_MACHINE == 1
#ifdef IS_LE_MACHINE
template<typename T> using to_be_t = typename to_se<T, true>::type;
template<typename T> using to_le_t = typename to_se<T, false>::type;
#else
template<typename T> using to_be_t = typename to_se<T, false>::type;
template<typename T> using to_le_t = typename to_se<T, true>::type;
#endif
// BE/LE aliases for atomic_t
#if IS_LE_MACHINE == 1
template<typename T> using atomic_be_t = atomic_t<be_t<T>>;
template<typename T> using atomic_le_t = atomic_t<le_t<T>>;
#endif
// Formatting for BE/LE data
template<typename T, bool Se>
struct unveil<se_t<T, Se>, void>
template<typename T, typename = void> struct to_ne
{
static inline auto get(const se_t<T, Se>& arg)
{
return unveil<T>::get(arg);
}
using type = T;
};
#undef IS_BINARY_COMPARABLE
#undef IS_INTEGER
template<typename T, bool Se> struct to_ne<se_t<T, Se>>
{
using type = typename std::remove_cv<T>::type;
};
template<typename T> struct to_ne<const T, std::enable_if_t<!std::is_array<T>::value>> // move const qualifier
{
using type = const typename to_ne<T>::type;
};
template<typename T> struct to_ne<volatile T, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>> // move volatile qualifier
{
using type = volatile typename to_ne<T>::type;
};
template<typename T> struct to_ne<T[]>
{
using type = typename to_ne<T>::type[];
};
template<typename T, std::size_t N> struct to_ne<T[N]>
{
using type = typename to_ne<T>::type[N];
};
// restore native endianness for T: returns T for be_t<T> or le_t<T>, T otherwise
template<typename T> using to_ne_t = typename to_ne<T>::type;
+50 -154
View File
@@ -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) * CHAR_BIT; 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,125 +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, u32 I, u32 N> using bf_le_t = bf_t<le_t<T>, I, N>;
-258
View File
@@ -1,258 +0,0 @@
#pragma once
#include "types.h"
// Small bitset for enum class types with available values [0, BitSize).
// T must be either enum type or convertible to (registered with via simple_t<T>).
// Internal representation is single value of type T.
template<typename T, std::size_t BitSize = sizeof(T) * CHAR_BIT>
struct bitset_t
{
using type = simple_t<T>;
using under = std::underlying_type_t<type>;
enum class raw_type : under {};
static constexpr auto bitsize = BitSize;
bitset_t() = default;
constexpr bitset_t(type _enum_const)
: m_value(static_cast<type>(shift(_enum_const)))
{
}
constexpr bitset_t(raw_type raw_value)
: m_value(static_cast<T>(static_cast<under>(raw_value)))
{
}
// Get underlying value
constexpr under _value() const
{
return static_cast<under>(m_value);
}
explicit constexpr operator bool() const
{
return _value() ? true : false;
}
bitset_t& operator +=(bitset_t rhs)
{
return *this = static_cast<raw_type>(_value() | rhs._value());
}
bitset_t& operator -=(bitset_t rhs)
{
return *this = static_cast<raw_type>(_value() & ~rhs._value());
}
bitset_t& operator &=(bitset_t rhs)
{
return *this = static_cast<raw_type>(_value() & rhs._value());
}
bitset_t& operator ^=(bitset_t rhs)
{
return *this = static_cast<raw_type>(_value() ^ rhs._value());
}
friend constexpr bitset_t operator +(bitset_t lhs, bitset_t rhs)
{
return static_cast<raw_type>(lhs._value() | rhs._value());
}
friend constexpr bitset_t operator -(bitset_t lhs, bitset_t rhs)
{
return static_cast<raw_type>(lhs._value() & ~rhs._value());
}
friend constexpr bitset_t operator &(bitset_t lhs, bitset_t rhs)
{
return static_cast<raw_type>(lhs._value() & rhs._value());
}
friend constexpr bitset_t operator ^(bitset_t lhs, bitset_t rhs)
{
return static_cast<raw_type>(lhs._value() ^ rhs._value());
}
bool test(bitset_t rhs) const
{
const under v = _value();
const under s = rhs._value();
return (v & s) != 0;
}
bool test_and_set(bitset_t rhs)
{
const under v = _value();
const under s = rhs._value();
*this = static_cast<raw_type>(v | s);
return (v & s) != 0;
}
bool test_and_reset(bitset_t rhs)
{
const under v = _value();
const under s = rhs._value();
*this = static_cast<raw_type>(v & ~s);
return (v & s) != 0;
}
bool test_and_complement(bitset_t rhs)
{
const under v = _value();
const under s = rhs._value();
*this = static_cast<raw_type>(v ^ s);
return (v & s) != 0;
}
private:
static constexpr under shift(const T& value)
{
return static_cast<under>(value) < BitSize ? static_cast<under>(1) << static_cast<under>(value) : throw value;
}
T m_value;
};
template<typename T, typename RT = T>
constexpr RT make_bitset()
{
return RT{};
}
// Fold enum constants into bitset_t<> (must be implemented with constexpr initializer_list constructor instead)
template<typename T = void, typename Arg, typename... Args, typename RT = std::conditional_t<std::is_void<T>::value, bitset_t<Arg>, T>>
constexpr RT make_bitset(Arg&& _enum_const, Args&&... args)
{
return RT{ std::forward<Arg>(_enum_const) } + make_bitset<RT>(std::forward<Args>(args)...);
}
template<typename T, typename CT>
struct atomic_add<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
using raw_type = typename bitset_t<T>::raw_type;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), right._value()));
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), right._value()));
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_sub<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
using raw_type = typename bitset_t<T>::raw_type;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~right._value()));
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~right._value()));
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_and<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
using raw_type = typename bitset_t<T>::raw_type;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), right._value()));
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), right._value()));
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_xor<bitset_t<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
using raw_type = typename bitset_t<T>::raw_type;
static inline bitset_t<T> op1(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), right._value()));
}
static constexpr auto fetch_op = &op1;
static inline bitset_t<T> op2(bitset_t<T>& left, bitset_t<T> right)
{
return static_cast<raw_type>(atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), right._value()));
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T>
struct atomic_test_and_set<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bool _op(bitset_t<T>& left, const T& value)
{
return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_reset<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bool _op(bitset_t<T>& left, const T& value)
{
return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_complement<bitset_t<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename bitset_t<T>::under;
static inline bool _op(bitset_t<T>& left, const T& value)
{
return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
-203
View File
@@ -1,203 +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)
{
throw std::logic_error("Invalid root node");
}
}
entry_base::entry_base(type _type, node& owner, const std::string& name)
: m_type(_type)
{
if (!owner.m_nodes.emplace(name, this).second)
{
throw std::logic_error("Node already exists");
}
}
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);
}
throw std::logic_error("Invalid node type");
}
entry_base& entry_base::operator[](const char* name) const
{
if (m_type == type::node)
{
return *static_cast<const node&>(*this).m_nodes.at(name);
}
throw std::logic_error("Invalid node type");
}
// 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;
}
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;
}
-532
View File
@@ -1,532 +0,0 @@
#pragma once
#include "Utilities/types.h"
#include "Utilities/Atomic.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);
// 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&)
{
throw std::logic_error("from_string() not specified");
}
// 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>&&)
{
throw std::logic_error("from_list() not specified");
}
};
// 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(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, def_index < init.size() ? (init.begin() + def_index)->first : throw std::logic_error("Invalid default value index"), 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
{
for (std::size_t i = 0; i < sizeof(bijective<T, const char*>::map) / sizeof(bijective_pair<T, const char*>); i++)
{
if (bijective<T, const char*>::map[i].v1 == m_value)
{
return bijective<T, const char*>::map[i].v2;
}
}
return{}; // TODO: ???
}
bool from_string(const std::string& value) override
{
for (std::size_t i = 0; i < sizeof(bijective<T, const char*>::map) / sizeof(bijective_pair<T, const char*>); i++)
{
if (bijective<T, const char*>::map[i].v2 == value)
{
m_value = bijective<T, const char*>::map[i].v1;
return true;
}
}
return false;
}
std::vector<std::string> to_list() const override
{
std::vector<std::string> result;
for (std::size_t i = 0; i < sizeof(bijective<T, const char*>::map) / sizeof(bijective_pair<T, const char*>); i++)
{
result.emplace_back(bijective<T, const char*>::map[i].v2);
}
return result;
}
};
// 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)
{
throw fmt::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); }
+528 -904
View File
File diff suppressed because it is too large Load Diff
+180 -268
View File
@@ -1,48 +1,37 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <type_traits>
enum class fsm : u32 // file seek mode
{
begin,
cur,
end,
};
#include "types.h"
#include "BitSet.h"
namespace fom // file open mode
{
enum : 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`)
rewrite = write | create | trunc, // write + create + trunc
};
};
enum class fse : u32 // filesystem (file or dir) error
{
ok, // no error
invalid_arguments,
};
namespace fs
{
// File open mode flags
enum struct open_mode : u32
{
read,
write,
append,
create,
trunc,
excl,
};
thread_local extern fse g_tls_error;
constexpr bitset_t<open_mode> read = open_mode::read; // Enable reading
constexpr bitset_t<open_mode> write = open_mode::write; // Enable writing
constexpr bitset_t<open_mode> append = open_mode::append; // Always append to the end of the file
constexpr bitset_t<open_mode> create = open_mode::create; // Create file if it doesn't exist
constexpr bitset_t<open_mode> trunc = open_mode::trunc; // Clear opened file if it's not empty
constexpr bitset_t<open_mode> excl = open_mode::excl; // Failure if the file already exists (used with `create`)
constexpr bitset_t<open_mode> rewrite = write + create + trunc;
// File seek mode
enum class seek_mode : u32
{
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;
@@ -53,59 +42,6 @@ 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, bitset_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)
std::string get_parent_dir(const std::string& path);
// Get file information
bool stat(const std::string& path, stat_t& info);
@@ -113,16 +49,16 @@ namespace fs
bool exists(const std::string& path);
// Check whether the file exists and is NOT a directory
bool is_file(const std::string& path);
bool is_file(const std::string& file);
// Check whether the directory exists and is NOT a file
bool is_dir(const std::string& path);
bool is_dir(const std::string& dir);
// Delete empty directory
bool remove_dir(const std::string& path);
bool remove_dir(const std::string& dir);
// Create directory
bool create_dir(const std::string& path);
bool create_dir(const std::string& dir);
// Create directories
bool create_path(const std::string& path);
@@ -134,250 +70,238 @@ namespace fs
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
// Delete file
bool remove_file(const std::string& path);
bool remove_file(const std::string& file);
// Change file size (possibly appending zeros)
bool truncate_file(const std::string& path, u64 length);
bool truncate_file(const std::string& file, u64 length);
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_ptr;
public:
// Default constructor
file() = default;
// Open file with specified mode
explicit file(const std::string& path, bitset_t<open_mode> mode = ::fs::read)
explicit file(const std::string& filename, u32 mode = fom::read)
{
open(path, mode);
open(filename, mode);
}
// Open file with specified mode
bool open(const std::string& path, bitset_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& filename, 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)
bool 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, fsm seek_mode = fsm::begin) const;
// Get file size
u64 size() const
{
if (!m_file) xnull();
return m_file->size();
}
u64 size() const;
// Get current position
u64 pos() const
// Write std::string
const file& operator <<(const std::string& str) const
{
if (!m_file) xnull();
return m_file->seek(0, seek_cur);
}
// 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;
}
// Write POD unconditionally
// Write POD
template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> operator <<(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;
}
// Write POD std::vector unconditionally
// Write POD std::vector
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
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> operator <<(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;
}
// Read std::string, size must be set by resize() method
// Read std::string
bool read(std::string& str) const
{
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
// Read POD
template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, bool> read(T& data) const
{
return read(&data, sizeof(T)) == sizeof(T);
}
// Read POD std::vector, size must be set by resize() method
// 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) const
{
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();
return result;
}
// Read full file to std::string
std::string to_string() const
// Convert to std::string
operator std::string() const
{
std::string result;
result.resize(size());
if (seek(0), !read(result)) xfail();
result.resize(size() - seek(0, fsm::cur));
CHECK_ASSERTION(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
class file_ptr final
{
char* m_ptr = nullptr;
u64 m_size;
public:
file_ptr() = default;
file_ptr(file_ptr&& 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_ptr& operator =(file_ptr&& right)
{
std::swap(m_ptr, right.m_ptr);
std::swap(m_size, right.m_size);
return *this;
}
file_ptr(const file& f)
{
reset(f);
}
~file_ptr()
{
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)
bool 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
@@ -394,18 +318,24 @@ namespace fs
return;
}
bool is_ok;
if (mode_ == mode::from_first)
{
m_parent->rewind();
is_ok = m_parent->first(m_entry.name, m_entry.info);
}
else
{
is_ok = m_parent->read(m_entry.name, m_entry.info);
}
if (!m_parent->read(m_entry))
if (!is_ok)
{
m_parent = nullptr;
}
}
dir_entry& operator *()
entry& operator *()
{
return m_entry;
}
@@ -424,7 +354,7 @@ namespace fs
iterator begin()
{
return{ m_dir ? this : nullptr };
return{ this };
}
iterator end()
@@ -434,26 +364,8 @@ namespace fs
};
// Get configuration directory
const std::string& get_config_dir();
std::string get_config_dir();
// Get executable directory
const std::string& get_executable_dir();
// 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;
std::string get_executable_dir();
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include "Platform.h"
#include "GNU.h"
#ifdef __APPLE__
#include <sys/types.h>
+296
View File
@@ -0,0 +1,296 @@
#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>
#ifndef __APPLE__
#include <malloc.h>
#endif
#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));
}
-10
View File
@@ -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
-327
View File
@@ -1,327 +0,0 @@
#ifdef LLVM_AVAILABLE
#include <unordered_map>
#include <map>
#include <unordered_set>
#include <set>
#include <array>
#include "types.h"
#include "Macro.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 = 0x1000000; 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
}();
// 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()
{
throw std::runtime_error("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 0x%p", m_next);
return nullptr;
}
LOG_SUCCESS(GENERAL, "LLVM: Code section %u '%s' allocated -> 0x%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;
}
#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 0x%p", m_next);
return nullptr;
}
LOG_SUCCESS(GENERAL, "LLVM: Data section %u '%s' allocated -> 0x%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 sections read-only when necessary
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(addr=0x%p) failed! Error %u", s_unwind_info, GetLastError());
}
if (!VirtualFree(s_memory, 0, MEM_DECOMMIT))
{
LOG_FATAL(GENERAL, "VirtualFree(0x%p) failed! Error %u", s_memory, GetLastError());
}
#else
if (::mprotect(s_memory, s_memory_size, PROT_NONE))
{
LOG_FATAL(GENERAL, "mprotect(0x%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)
{
EXPECTS(s_memory);
std::string result;
const auto module_ptr = _module.get();
// Initialization
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
LLVMLinkInMCJIT();
m_engine.reset(llvm::EngineBuilder(std::move(_module))
.setErrorStr(&result)
.setMCJITMemoryManager(std::make_unique<MemoryManager>(std::move(table)))
.setOptLevel(llvm::CodeGenOpt::Aggressive)
.setRelocationModel(llvm::Reloc::PIC_)
.setCodeModel((u64)s_memory <= 0x60000000 ? llvm::CodeModel::Medium : llvm::CodeModel::Large) // TODO
.setMCPU(llvm::sys::getHostCPUName())
.create());
if (!m_engine)
{
throw fmt::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);
}
// Hack (cannot obtain last function size)
func_set.emplace(::align(*--func_set.end() + 4096, 4096));
const u64 base = (u64)s_memory;
const u8* bits = s_unwind_info;
s_unwind.clear();
s_unwind.reserve(m_map.size());
for (auto it = func_set.begin(), end = --func_set.end(); it != end; it++)
{
const u64 addr = *it;
const u64 next = *func_set.upper_bound(addr);
// 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)
{
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_FATAL(GENERAL, "LLVM: .xdata analysis failed! (0x%p != 0x%p)", s_unwind_info + s_unwind_size, bits);
}
else if (!RtlAddFunctionTable(s_unwind.data(), (DWORD)s_unwind.size(), base))
{
LOG_FATAL(GENERAL, "RtlAddFunctionTable(addr=0x%p) failed! Error %u", s_unwind_info, GetLastError());
}
else
{
LOG_SUCCESS(GENERAL, "LLVM: UNWIND_INFO registered (addr=0x%p, size=0x%llx)", s_unwind_info, s_unwind_size);
}
#endif
}
jit_compiler::~jit_compiler()
{
}
#endif
-50
View File
@@ -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
+257 -119
View File
@@ -1,147 +1,285 @@
#include "Log.h"
#include "stdafx.h"
#include <iostream>
#include <cinttypes>
#include "Thread.h"
#include "File.h"
#include "StrFmt.h"
#include "Log.h"
#include <cstdarg>
#include <string>
// Thread-specific log prefix provider
thread_local std::string(*g_tls_log_prefix)() = nullptr;
#ifndef _MSC_VER
constexpr DECLARE(bijective<logs::level, const char*>::map);
#ifdef _WIN32
#include <Windows.h>
#endif
namespace logs
using namespace Log;
std::unique_ptr<LogManager> g_log_manager;
u32 LogMessage::size() const
{
struct listener
//1 byte for NULL terminator
return (u32)(sizeof(LogMessage::size_type) + sizeof(LogType) + sizeof(Severity) + sizeof(std::string::value_type) * mText.size() + 1);
}
void LogMessage::serialize(char *output) const
{
LogMessage::size_type size = this->size();
memcpy(output, &size, sizeof(LogMessage::size_type));
output += sizeof(LogMessage::size_type);
memcpy(output, &mType, sizeof(LogType));
output += sizeof(LogType);
memcpy(output, &mServerity, sizeof(Severity));
output += sizeof(Severity);
memcpy(output, mText.c_str(), mText.size() );
output += sizeof(std::string::value_type)*mText.size();
*output = '\0';
}
LogMessage LogMessage::deserialize(char *input, u32* size_out)
{
LogMessage msg;
LogMessage::size_type msgSize = *(reinterpret_cast<LogMessage::size_type*>(input));
input += sizeof(LogMessage::size_type);
msg.mType = *(reinterpret_cast<LogType*>(input));
input += sizeof(LogType);
msg.mServerity = *(reinterpret_cast<Severity*>(input));
input += sizeof(Severity);
if (msgSize > 9000)
{
listener() = default;
virtual ~listener() = default;
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;
};
static file_listener& get_logger()
{
// Use magic static
static file_listener logger("RPCS3.log");
return logger;
int wtf = 6;
}
channel GENERAL(nullptr, level::notice);
channel LOADER("LDR", level::notice);
channel MEMORY("MEM", level::notice);
channel RSX("RSX", level::notice);
channel HLE("HLE", level::notice);
channel PPU("PPU", level::notice);
channel SPU("SPU", level::notice);
channel ARMv7("ARMv7");
msg.mText.append(input, msgSize - 1 - sizeof(Severity) - sizeof(LogType));
if (size_out){(*size_out) = msgSize;}
return msg;
}
void logs::channel::broadcast(const logs::channel& ch, logs::level sev, const char* fmt...)
{
va_list args;
va_start(args, fmt);
get_logger().log(ch, sev, fmt::unsafe_vformat(fmt, args));
va_end(args);
}
[[noreturn]] extern void catch_all_exceptions();
logs::file_writer::file_writer(const std::string& name)
LogChannel::LogChannel() : LogChannel("unknown")
{}
LogChannel::LogChannel(const std::string& name) :
name(name)
, mEnabled(true)
, mLogLevel(Severity::Warning)
{}
void LogChannel::log(const LogMessage &msg)
{
try
std::lock_guard<std::mutex> lock(mListenerLock);
for (auto &listener : mListeners)
{
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
listener->log(msg);
}
}
void LogChannel::addListener(std::shared_ptr<LogListener> listener)
{
std::lock_guard<std::mutex> lock(mListenerLock);
mListeners.insert(listener);
}
void LogChannel::removeListener(std::shared_ptr<LogListener> listener)
{
std::lock_guard<std::mutex> lock(mListenerLock);
mListeners.erase(listener);
}
struct CoutListener : LogListener
{
void log(const LogMessage &msg) override
{
std::cerr << msg.mText << std::endl;
}
};
struct FileListener : LogListener
{
fs::file mFile;
bool mPrependChannelName;
FileListener(const std::string& name = _PRGNAME_ ".log", bool prependChannel = true)
: mFile(fs::get_config_dir() + name, fom::rewrite)
, mPrependChannelName(prependChannel)
{
if (!mFile)
{
throw fmt::exception("Can't create log file %s (error %d)", name, fs::g_tls_error);
#ifdef _WIN32
MessageBoxA(0, ("Can't create log file: " + name).c_str(), "Error", MB_ICONERROR);
#else
std::printf("Can't create log file: %s\n", name.c_str());
#endif
}
}
catch (...)
{
catch_all_exceptions();
}
}
void logs::file_writer::log(const std::string& text)
void log(const LogMessage &msg) override
{
std::string text = msg.mText;
if (mPrependChannelName)
{
text.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName);
if (msg.mType == Log::TTY)
{
text = fmt::escape(text);
if (text[text.length() - 1] != '\n')
{
text += '\n';
}
}
}
mFile << text;
}
};
LogManager::LogManager()
#ifdef BUFFERED_LOGGING
: mExiting(false), mLogConsumer()
#endif
{
m_file.write(text);
auto it = mChannels.begin();
std::shared_ptr<LogListener> listener(new FileListener());
for (const LogTypeName& name : gTypeNameTable)
{
it->name = name.mName;
it->addListener(listener);
it++;
}
std::shared_ptr<LogListener> TTYListener(new FileListener("TTY.log", false));
getChannel(TTY).addListener(TTYListener);
#ifdef BUFFERED_LOGGING
mLogConsumer = std::thread(&LogManager::consumeLog, this);
#endif
}
std::size_t logs::file_writer::size() const
LogManager::~LogManager()
{
return m_file.pos();
#ifdef BUFFERED_LOGGING
mExiting = true;
mBufferReady.notify_all();
mLogConsumer.join();
}
void logs::file_listener::log(const logs::channel& ch, logs::level sev, const std::string& text)
void LogManager::consumeLog()
{
std::string msg; msg.reserve(text.size() + 200);
// Used character: U+00B7 (Middle Dot)
switch (sev)
std::unique_lock<std::mutex> lock(mStatusMut);
while (!mExiting)
{
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;
}
mBufferReady.wait(lock);
mBuffer.lockGet();
size_t size = mBuffer.size();
std::vector<char> local_messages(size);
mBuffer.popN(&local_messages.front(), size);
mBuffer.unlockGet();
// TODO: print time?
if (auto prefix = g_tls_log_prefix)
{
msg += '{';
msg += prefix();
msg += "} ";
u32 cursor = 0;
u32 removed = 0;
while (cursor < size)
{
Log::LogMessage msg = Log::LogMessage::deserialize(local_messages.data() + cursor, &removed);
cursor += removed;
getChannel(msg.mType).log(msg);
}
}
#endif
}
void LogManager::log(LogMessage msg)
{
//don't do any formatting changes or filtering to the TTY output since we
//use the raw output to do diffs with the output of a real PS3 and some
//programs write text in single bytes to the console
if (msg.mType != TTY)
{
std::string prefix;
switch (msg.mServerity)
{
case Severity::Success:
prefix = "S ";
break;
case Severity::Notice:
prefix = "! ";
break;
case Severity::Warning:
prefix = "W ";
break;
case Severity::Error:
prefix = "E ";
break;
}
if (auto thr = thread_ctrl::get_current())
{
prefix += "{" + thr->get_name() + "} ";
}
msg.mText.insert(0, prefix);
msg.mText.append(1,'\n');
}
#ifdef BUFFERED_LOGGING
size_t size = msg.size();
std::vector<char> temp_buffer(size);
msg.serialize(temp_buffer.data());
mBuffer.pushRange(temp_buffer.begin(), temp_buffer.end());
mBufferReady.notify_one();
#else
mChannels[static_cast<u32>(msg.mType)].log(msg);
#endif
}
void LogManager::addListener(std::shared_ptr<LogListener> listener)
{
for (auto& channel : mChannels)
{
channel.addListener(listener);
}
}
void LogManager::removeListener(std::shared_ptr<LogListener> listener)
{
for (auto& channel : mChannels)
{
channel.removeListener(listener);
}
}
LogManager& LogManager::getInstance()
{
if (!g_log_manager)
{
g_log_manager.reset(new LogManager());
}
return *g_log_manager;
}
LogChannel &LogManager::getChannel(LogType type)
{
return mChannels[static_cast<u32>(type)];
}
void log_message(Log::LogType type, Log::Severity sev, const char* text)
{
log_message(type, sev, std::string(text));
}
void log_message(Log::LogType type, Log::Severity sev, std::string text)
{
if (g_log_manager)
{
g_log_manager->log({ type, sev, std::move(text) });
}
else
{
const auto severity =
sev == Severity::Notice ? "Notice" :
sev == Severity::Warning ? "Warning" :
sev == Severity::Success ? "Success" :
sev == Severity::Error ? "Error" : "Unknown";
#ifdef _WIN32
MessageBoxA(0, text.c_str(), severity,
sev == Severity::Notice ? MB_ICONINFORMATION :
sev == Severity::Warning ? MB_ICONEXCLAMATION :
sev == Severity::Error ? MB_ICONERROR : MB_ICONINFORMATION);
#else
std::printf("[Log:%s] %s\n", severity, text.c_str());
#endif
}
if (ch.name)
{
msg += ch.name;
msg += sev == level::todo ? " TODO: " : ": ";
}
else if (sev == level::todo)
{
msg += "TODO: ";
}
msg += text;
msg += '\n';
file_writer::log(msg);
}
+114 -85
View File
@@ -1,105 +1,134 @@
#pragma once
#include "Utilities/MTRingbuffer.h"
#include "types.h"
#include "Atomic.h"
//#define BUFFERED_LOGGING 1
namespace logs
//first parameter is of type Log::LogType and text is of type std::string
#define LOG_SUCCESS(logType, text, ...) log_message(logType, Log::Severity::Success, text, ##__VA_ARGS__)
#define LOG_NOTICE(logType, text, ...) log_message(logType, Log::Severity::Notice, text, ##__VA_ARGS__)
#define LOG_WARNING(logType, text, ...) log_message(logType, Log::Severity::Warning, text, ##__VA_ARGS__)
#define LOG_ERROR(logType, text, ...) log_message(logType, Log::Severity::Error, text, ##__VA_ARGS__)
namespace Log
{
enum class level : uint
const unsigned int MAX_LOG_BUFFER_LENGTH = 1024*1024;
const unsigned int gBuffSize = 1000;
enum LogType : u32
{
always, // highest level (unused, cannot be disabled)
fatal,
error,
todo,
success,
warning,
notice,
trace, // lowest level (usually disabled)
GENERAL = 0,
LOADER,
MEMORY,
RSX,
HLE,
PPU,
SPU,
ARMv7,
TTY,
};
struct channel
struct LogTypeName
{
// Channel prefix (added to every log message)
const char* const name;
LogType mType;
std::string mName;
};
// The lowest logging level enabled for this channel (used for early filtering)
atomic_t<level> enabled;
//well I'd love make_array() but alas manually counting is not the end of the world
static const std::array<LogTypeName, 9> gTypeNameTable = { {
{ GENERAL, "G: " },
{ LOADER, "LDR: " },
{ MEMORY, "MEM: " },
{ RSX, "RSX: " },
{ HLE, "HLE: " },
{ PPU, "PPU: " },
{ SPU, "SPU: " },
{ ARMv7, "ARM: " },
{ TTY, "TTY: " }
} };
// Constant initialization: name and initial log level
constexpr channel(const char* name, level enabled = level::trace)
: name(name)
, enabled(enabled)
{
}
enum class Severity : u32
{
Notice = 0,
Warning,
Success,
Error,
};
// Formatting function
template<typename... Args>
void format(level sev, const char* fmt, const Args&... args) const
{
#ifdef _MSC_VER
if (sev <= enabled)
#else
if (__builtin_expect(sev <= enabled, 0))
#endif
broadcast(*this, sev, fmt, ::unveil<Args>::get(args)...);
}
struct LogMessage
{
using size_type = u32;
LogType mType;
Severity mServerity;
std::string mText;
#define GEN_LOG_METHOD(_sev)\
template<typename... Args>\
void _sev(const char* fmt, const Args&... args) const\
{\
return format<Args...>(level::_sev, fmt, args...);\
}
u32 size() const;
void serialize(char *output) const;
static LogMessage deserialize(char *input, u32* size_out=nullptr);
};
GEN_LOG_METHOD(fatal)
GEN_LOG_METHOD(error)
GEN_LOG_METHOD(todo)
GEN_LOG_METHOD(success)
GEN_LOG_METHOD(warning)
GEN_LOG_METHOD(notice)
GEN_LOG_METHOD(trace)
#undef GEN_LOG_METHOD
struct LogListener
{
virtual ~LogListener() {};
virtual void log(const LogMessage &msg) = 0;
};
struct LogChannel
{
LogChannel();
LogChannel(const std::string& name);
LogChannel(LogChannel& other) = delete;
void log(const LogMessage &msg);
void addListener(std::shared_ptr<LogListener> listener);
void removeListener(std::shared_ptr<LogListener> listener);
std::string name;
private:
// Send log message to global logger instance
static void broadcast(const channel& ch, level sev, const char* fmt...);
bool mEnabled;
Severity mLogLevel;
std::mutex mListenerLock;
std::set<std::shared_ptr<LogListener>> mListeners;
};
/* Small set of predefined channels */
extern channel GENERAL;
extern channel LOADER;
extern channel MEMORY;
extern channel RSX;
extern channel HLE;
extern channel PPU;
extern channel SPU;
extern channel ARMv7;
struct LogManager
{
LogManager();
~LogManager();
static LogManager& getInstance();
LogChannel& getChannel(LogType type);
void log(LogMessage msg);
void addListener(std::shared_ptr<LogListener> listener);
void removeListener(std::shared_ptr<LogListener> listener);
#ifdef BUFFERED_LOGGING
void consumeLog();
#endif
private:
#ifdef BUFFERED_LOGGING
MTRingbuffer<char, MAX_LOG_BUFFER_LENGTH> mBuffer;
std::condition_variable mBufferReady;
std::mutex mStatusMut;
std::atomic<bool> mExiting;
std::thread mLogConsumer;
#endif
std::array<LogChannel, std::tuple_size<decltype(gTypeNameTable)>::value> mChannels;
//std::array<LogChannel,gTypeNameTable.size()> mChannels; //TODO: use this once Microsoft sorts their shit out
};
}
template<>
struct bijective<logs::level, const char*>
static struct { inline operator Log::LogType() { return Log::LogType::GENERAL; } } GENERAL;
static struct { inline operator Log::LogType() { return Log::LogType::LOADER; } } LOADER;
static struct { inline operator Log::LogType() { return Log::LogType::MEMORY; } } MEMORY;
static struct { inline operator Log::LogType() { return Log::LogType::RSX; } } RSX;
static struct { inline operator Log::LogType() { return Log::LogType::HLE; } } HLE;
static struct { inline operator Log::LogType() { return Log::LogType::PPU; } } PPU;
static struct { inline operator Log::LogType() { return Log::LogType::SPU; } } SPU;
static struct { inline operator Log::LogType() { return Log::LogType::ARMv7; } } ARMv7;
static struct { inline operator Log::LogType() { return Log::LogType::TTY; } } TTY;
void log_message(Log::LogType type, Log::Severity sev, const char* text);
void log_message(Log::LogType type, Log::Severity sev, std::string text);
template<typename... Args> never_inline void log_message(Log::LogType type, Log::Severity sev, const char* fmt, Args... args)
{
static constexpr bijective_pair<logs::level, const char*> map[]
{
{ logs::level::always, "Nothing" },
{ logs::level::fatal, "Fatal" },
{ logs::level::error, "Error" },
{ logs::level::todo, "TODO" },
{ logs::level::success, "Success" },
{ logs::level::warning, "Warning" },
{ logs::level::notice, "Notice" },
{ logs::level::trace, "Trace" },
};
};
// 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__)
log_message(type, sev, fmt::format(fmt, fmt::do_unveil(args)...));
}
+155
View File
@@ -0,0 +1,155 @@
#pragma once
//Simple non-resizable FIFO Ringbuffer that can be simultaneously be read from and written to
//if we ever get to use boost please replace this with boost::circular_buffer, there's no reason
//why we would have to keep this amateur attempt at such a fundamental data-structure around
template< typename T, unsigned int MAX_MTRINGBUFFER_BUFFER_SIZE>
class MTRingbuffer{
std::array<T, MAX_MTRINGBUFFER_BUFFER_SIZE> mBuffer;
//this is a recursive mutex because the get methods lock it but the only
//way to be sure that they do not block is to check the size and the only
//way to check the size and use get atomically is to lock this mutex,
//so it goes:
//lock get mutex-->check size-->call get-->lock get mutex-->unlock get mutex-->return from get-->unlock get mutex
std::recursive_mutex mMutGet;
std::mutex mMutPut;
size_t mGet;
size_t mPut;
size_t moveGet(size_t by = 1){ return (mGet + by) % MAX_MTRINGBUFFER_BUFFER_SIZE; }
size_t movePut(size_t by = 1){ return (mPut + by) % MAX_MTRINGBUFFER_BUFFER_SIZE; }
public:
MTRingbuffer() : mGet(0), mPut(0){}
//blocks until there's something to get, so check "spaceLeft()" if you want to avoid blocking
//also lock the get mutex around the spaceLeft() check and the pop if you want to avoid racing
T pop()
{
std::lock_guard<std::recursive_mutex> lock(mMutGet);
while (mGet == mPut)
{
//wait until there's actually something to get
//throwing an exception might be better, blocking here is a little awkward
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
size_t ret = mGet;
mGet = moveGet();
return mBuffer[ret];
}
//blocks if the buffer is full until there's enough room
void push(T &putEle)
{
std::lock_guard<std::mutex> lock(mMutPut);
while (movePut() == mGet)
{
//if this is reached a lot it's time to increase the buffer size
//or implement dynamic re-sizing
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
mBuffer[mPut] = std::forward(putEle);
mPut = movePut();
}
bool empty()
{
return mGet == mPut;
}
//returns the amount of free places, this is the amount of actual free spaces-1
//since mGet==mPut signals an empty buffer we can't actually use the last free
//space, so we shouldn't report it as free.
size_t spaceLeft() //apparently free() is a macro definition in msvc in some conditions
{
if (mGet < mPut)
{
return mBuffer.size() - (mPut - mGet) - 1;
}
else if (mGet > mPut)
{
return mGet - mPut - 1;
}
else
{
return mBuffer.size() - 1;
}
}
size_t size()
{
//the magic -1 is the same magic 1 that is explained in the spaceLeft() function
return mBuffer.size() - spaceLeft() - 1;
}
//takes random access iterator to T
template<typename IteratorType>
void pushRange(IteratorType from, IteratorType until)
{
std::lock_guard<std::mutex> lock(mMutPut);
size_t length = until - from;
//if whatever we're trying to store is greater than the entire buffer the following loop will be infinite
assert(mBuffer.size() > length);
while (spaceLeft() < length)
{
//if this is reached a lot it's time to increase the buffer size
//or implement dynamic re-sizing
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
if (mPut + length <= mBuffer.size())
{
std::copy(from, until, mBuffer.begin() + mPut);
}
else
{
size_t tillEnd = mBuffer.size() - mPut;
std::copy(from, from + tillEnd, mBuffer.begin() + mPut);
std::copy(from + tillEnd, until, mBuffer.begin());
}
mPut = movePut(length);
}
//takes output iterator to T
template<typename IteratorType>
void popN(IteratorType output, size_t n)
{
std::lock_guard<std::recursive_mutex> lock(mMutGet);
//make sure we're not trying to retrieve more than is in
assert(n <= size());
peekN<IteratorType>(output, n);
mGet = moveGet(n);
}
//takes output iterator to T
template<typename IteratorType>
void peekN(IteratorType output, size_t n)
{
size_t lGet = mGet;
if (lGet + n <= mBuffer.size())
{
std::copy_n(mBuffer.begin() + lGet, n, output);
}
else
{
auto next = std::copy(mBuffer.begin() + lGet, mBuffer.end(), output);
std::copy_n(mBuffer.begin(), n - (mBuffer.size() - lGet), next);
}
}
//well this is just asking for trouble
//but the comment above the declaration of mMutGet explains why it's there
//if there's a better way please remove this
void lockGet()
{
mMutGet.lock();
}
//well this is just asking for trouble
//but the comment above the declaration of mMutGet explains why it's there
//if there's a better way please remove this
void unlockGet()
{
mMutGet.unlock();
}
};
-83
View File
@@ -1,83 +0,0 @@
#pragma once
#include <cstdint>
#include <exception>
template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr T align(const T& value, std::uint64_t align)
{
return static_cast<T>((value + (align - 1)) & ~(align - 1));
}
template<typename To, typename From>
constexpr To narrow_impl(const To& result, const From& value, const char* message)
{
return static_cast<From>(result) != value ? throw std::runtime_error(message) : result;
}
// Narrow cast (similar to gsl::narrow) with fixed message
template<typename To, typename From>
constexpr auto narrow(const From& value, const char* fixed_msg = "::narrow() failed") -> decltype(static_cast<To>(static_cast<From>(std::declval<To>())))
{
return narrow_impl(static_cast<To>(value), value, fixed_msg);
}
// Return 32 bit .size() for container
template<typename CT>
constexpr auto size32(const CT& container, const char* fixed_msg = "::size32() failed") -> decltype(static_cast<std::uint32_t>(container.size()))
{
return narrow<std::uint32_t>(container.size(), fixed_msg);
}
// Return 32 bit size for an array
template<typename T, std::size_t Size>
constexpr std::uint32_t size32(const T(&)[Size])
{
static_assert(Size <= UINT32_MAX, "size32() error: too big");
return static_cast<std::uint32_t>(Size);
}
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size")
#define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment")
#define CHECK_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big")
#define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align)
#define CHECK_STORAGE(type, storage) static_assert(sizeof(type) <= sizeof(storage) && alignof(type) <= alignof(decltype(storage)), #type " is too small")
// Return 32 bit sizeof() to avoid widening/narrowing conversions with size_t
#define SIZE_32(type) static_cast<std::uint32_t>(sizeof(type))
// Return 32 bit alignof() to avoid widening/narrowing conversions with size_t
#define ALIGN_32(type) static_cast<std::uint32_t>(alignof(type))
// Return 32 bit custom offsetof()
#define OFFSET_32(type, x) static_cast<std::uint32_t>(reinterpret_cast<std::uintptr_t>(&reinterpret_cast<const volatile char&>(reinterpret_cast<type*>(0ull)->x)))
// Sometimes to avoid writing std::remove_cv_t<>, example: std::is_same<CV T1, CV T2>
#define CV const volatile
#define CONCATENATE_DETAIL(x, y) x ## y
#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y)
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
// Macro set, wraps an expression into lambda
#define WRAP_EXPR(expr, ...) [&](__VA_ARGS__) { return expr; }
#define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; }
#define PURE_EXPR(expr, ...) [] (__VA_ARGS__) { return expr; }
#define return_ return
#define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")"
// Ensure that the expression is evaluated to true. Always evaluated and allowed to have side effects (unlike assert() macro).
#define VERIFY(expr) do { if (!(expr)) throw std::runtime_error("Verification failed: " #expr HERE); } while (0)
// EXPECTS() and ENSURES() are intended to check function arguments and results.
// Expressions are not guaranteed to evaluate.
#define EXPECTS(expr) do { if (!(expr)) throw std::runtime_error("Precondition failed: " #expr HERE); } while (0)
#define ENSURES(expr) do { if (!(expr)) throw std::runtime_error("Postcondition failed: " #expr HERE); } while (0)
#define DECLARE(...) decltype(__VA_ARGS__) __VA_ARGS__
#define STR_CASE(value) case value: return #value
-122
View File
@@ -1,122 +0,0 @@
#pragma once
#include <cstdint>
#include <immintrin.h>
#include <emmintrin.h>
#define IS_LE_MACHINE 1
#define IS_BE_MACHINE 0
#ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif
#ifdef _MSC_VER
#define ASSUME(cond) __assume(cond)
#define LIKELY(cond) (cond)
#define UNLIKELY(cond) (cond)
#else
#define ASSUME(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
#define LIKELY(cond) __builtin_expect(!!(cond), 1)
#define UNLIKELY(cond) __builtin_expect(!!(cond), 0)
#endif
// Some platforms don't support thread_local well yet.
#ifndef _MSC_VER
#define thread_local __thread
#endif
#ifdef _MSC_VER
#define never_inline __declspec(noinline)
#else
#define never_inline __attribute__((noinline))
#endif
#ifdef _MSC_VER
#define force_inline __forceinline
#else
#define force_inline __attribute__((always_inline)) inline
#endif
#if defined(__GNUG__)
#include <stdlib.h>
#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__ */
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
}
// Helper function, used by ""_u16, ""_u32, ""_u64
constexpr std::uint8_t to_u8(char c)
{
return static_cast<std::uint8_t>(c);
}
// Convert 2-byte string to u16 value like reinterpret_cast does
constexpr std::uint16_t operator""_u16(const char* s, std::size_t length)
{
return length != 2 ? throw s :
#if IS_LE_MACHINE == 1
to_u8(s[1]) << 8 | to_u8(s[0]);
#endif
}
// Convert 4-byte string to u32 value like reinterpret_cast does
constexpr std::uint32_t operator""_u32(const char* s, std::size_t length)
{
return length != 4 ? throw s :
#if IS_LE_MACHINE == 1
to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
#endif
}
// Convert 8-byte string to u64 value like reinterpret_cast does
constexpr std::uint64_t operator""_u64(const char* s, std::size_t length)
{
return length != 8 ? throw s :
#if IS_LE_MACHINE == 1
static_cast<std::uint64_t>(to_u8(s[7]) << 24 | to_u8(s[6]) << 16 | to_u8(s[5]) << 8 | to_u8(s[4])) << 32 | to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
#endif
}
+106 -76
View File
@@ -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 -35
View File
@@ -1,48 +1,37 @@
#pragma once
#include "types.h"
#include "Atomic.h"
#include "Platform.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
View File
@@ -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 -115
View File
@@ -1,123 +1,120 @@
#pragma once
#include "types.h"
#include "Atomic.h"
#include "Platform.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
{
@@ -137,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();
}
};
+55
View File
@@ -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 -63
View File
@@ -1,85 +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 is called in the constructor (if not null)
// Awake is called in the destructor (if not null)
// Sleep queue is actually std::deque with pointers, be careful about the lifetime
template<typename T, void(T::*Sleep)() = &T::sleep, void(T::*Awake)() = &T::awake>
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)
{
if (Sleep) (m_thread.*Sleep)();
}
// 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();
if (Awake) (m_thread.*Awake)();
}
// 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();
}
};
+171 -54
View File
@@ -1,11 +1,9 @@
#include "StrFmt.h"
#include "BEType.h"
#include "StrUtil.h"
#include <cassert>
#include <array>
#include <memory>
#include <algorithm>
#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)
std::string v128::to_hex() const
{
@@ -17,59 +15,71 @@ 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::unsafe_vformat(const char* fmt, va_list _args) noexcept
std::string fmt::to_hex(u64 value, u64 count)
{
// 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();;)
if (count - 1 >= 16)
{
va_list args;
va_copy(args, _args);
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-security"
#endif
const std::size_t len = std::vsnprintf(buf_addr, buf_size, fmt, args);
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
va_end(args);
assert(len <= INT_MAX);
if (len < buf_size)
{
return{ buf_addr, len };
}
buf.reset(buf_addr = new char[buf_size = len + 1]);
throw EXCEPTION("Invalid count: 0x%llx", count);
}
count = std::max<u64>(count, 16 - cntlz64(value) / 4);
char res[16] = {};
for (size_t i = count - 1; ~i; i--, value /= 16)
{
res[i] = "0123456789abcdef"[value % 16];
}
return std::string(res, count);
}
std::string fmt::unsafe_format(const char* fmt...) noexcept
std::string fmt::to_udec(u64 value)
{
va_list args;
va_start(args, fmt);
auto result = unsafe_vformat(fmt, args);
va_end(args);
char res[20] = {};
size_t first = sizeof(res);
return result;
if (!value)
{
res[--first] = '0';
}
for (; value; value /= 10)
{
res[--first] = '0' + (value % 10);
}
return std::string(&res[first], sizeof(res) - first);
}
fmt::exception_base::exception_base(const char* fmt...)
: std::runtime_error((va_start(m_args, fmt), unsafe_vformat(fmt, m_args)))
std::string fmt::to_sdec(s64 svalue)
{
va_end(m_args);
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);
@@ -94,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;
@@ -135,12 +222,42 @@ std::string fmt::trim(const std::string& source, const std::string& values)
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;
}
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)
+337 -31
View File
@@ -1,52 +1,358 @@
#pragma once
#include <cstdarg>
#include <exception>
#include <string>
class wxString;
#include "Platform.h"
#include "types.h"
#if defined(_MSC_VER) && _MSC_VER <= 1800
#define snprintf _snprintf
#endif
namespace fmt
{
std::string unsafe_format(const char* fmt...) noexcept;
std::string unsafe_vformat(const char*, va_list) noexcept;
//struct empty_t{};
// Formatting function
template<typename... Args>
inline std::string format(const char* fmt, const Args&... args)
//extern const std::string placeholder;
template <typename T>
std::string AfterLast(const std::string& source, T searchstr)
{
return unsafe_format(fmt, ::unveil<Args>::get(args)...);
size_t search_pos = source.rfind(searchstr);
search_pos = search_pos == std::string::npos ? 0 : search_pos;
return source.substr(search_pos);
}
// Helper class
class exception_base : public std::runtime_error
template <typename T>
std::string BeforeLast(const std::string& source, T searchstr)
{
// Helper (there is no other room)
va_list m_args;
size_t search_pos = source.rfind(searchstr);
search_pos = search_pos == std::string::npos ? 0 : search_pos;
return source.substr(0, search_pos);
}
protected:
// Internal formatting constructor
exception_base(const char* fmt...);
};
// Exception type derived from std::runtime_error with formatting constructor
class exception : public exception_base
template <typename T>
std::string AfterFirst(const std::string& source, T searchstr)
{
public:
template<typename... Args>
exception(const char* fmt, const Args&... args)
: exception_base(fmt, ::unveil<Args>::get(args)...)
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)
{
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::string to_hex(u64 value, u64 count = 1);
std::string to_udec(u64 value);
std::string to_sdec(s64 value);
template<typename T, bool is_enum = std::is_enum<T>::value> struct unveil
{
using result_type = T;
force_inline static result_type get_value(const T& arg)
{
return arg;
}
};
// Narrow cast (similar to gsl::narrow) with exception message formatting
template<typename To, typename From, typename... Args>
inline auto narrow(const char* format_str, const From& value, const Args&... args) -> decltype(static_cast<To>(static_cast<From>(std::declval<To>())))
template<> struct unveil<char*, false>
{
const auto result = static_cast<To>(value);
if (static_cast<From>(result) != value) throw fmt::exception(format_str, value, args...);
using result_type = const char*;
force_inline static result_type get_value(const char* arg)
{
return arg;
}
};
template<std::size_t N> struct unveil<const char[N], false>
{
using result_type = const char*;
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 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, 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;
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 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);
}
-133
View File
@@ -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);
}
+197 -831
View File
File diff suppressed because it is too large Load Diff
+422 -287
View File
@@ -1,264 +1,65 @@
#pragma once
#include <exception>
#include <string>
#include <memory>
#include "Platform.h"
#include "Atomic.h"
// 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 internals
atomic_t<internal*> m_data{};
// Thread result
std::future<void> m_future;
// 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);
// 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(u64 useconds, F&& pred)
{
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 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. 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 unconditionally until aborted. 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
@@ -267,109 +68,443 @@ public:
{
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
thread_ctrl::start(ctrl, std::forward<F>(func));
std::promise<void> promise;
ctrl->m_future = promise.get_future();
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 : public std::enable_shared_from_this<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 bad_weak_ptr in such case)
void start();
// 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()
{
start();
}
// 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();
}
};
// 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();
// Join thread (get future result)
void join();
// Check whether the thread is not in "empty state"
bool is_started() const { return m_thread.operator bool(); }
// Compare with the current thread
bool is_current() const { CHECK_ASSERTION(m_thread); return thread_ctrl::get_current() == m_thread.get(); }
// Get thread_ctrl
const thread_ctrl* get_thread_ctrl() const { return m_thread.get(); }
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)))
{
}
// 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();
}
};
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
{
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();
}
};
+7 -7
View File
@@ -17,29 +17,29 @@ namespace memory_helper
{
#ifdef _WIN32
void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
ENSURES(ret != NULL);
CHECK_ASSERTION(ret != NULL);
#else
void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
ENSURES(ret != 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(VirtualAlloc(pointer, size, MEM_COMMIT, PAGE_READWRITE) != NULL);
CHECK_ASSERTION(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL);
#else
VERIFY(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(VirtualFree(pointer, 0, MEM_DECOMMIT) != 0);
CHECK_ASSERTION(VirtualFree(pointer, 0, MEM_RELEASE) != 0);
#else
VERIFY(mprotect(pointer, size, PROT_NONE) != -1);
CHECK_ASSERTION(munmap(pointer, size) == 0);
#endif
}
}
+7 -7
View File
@@ -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);
}
+172
View File
@@ -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);
}
+163
View File
@@ -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&);
};
+279
View File
@@ -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 : false;
}
};
template<>
struct to_impl_t<std::string, char>
{
static std::string func(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);
}
}
-60
View File
@@ -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();
}
}
-41
View File
@@ -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;
};
}
-1037
View File
File diff suppressed because it is too large Load Diff
-105
View File
@@ -1,105 +0,0 @@
#pragma once
#include "types.h"
#include "Atomic.h"
#include "Platform.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;
});
}
};
+42
View File
@@ -0,0 +1,42 @@
#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>
#include <errno.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");
}
}
+40
View File
@@ -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;
};
+235
View File
@@ -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));
}
+102
View File
@@ -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
View File
@@ -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
View File
@@ -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;
};
-189
View File
@@ -1,189 +0,0 @@
#pragma once
/* For internal use. Don't include. */
#include "types.h"
#include "Macro.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*));
+1021 -466
View File
File diff suppressed because it is too large Load Diff
-65
View File
@@ -1,65 +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";
}
throw;
}
version::version(std::uint8_t hi, std::uint8_t mid, std::uint8_t lo)
: m_hi(hi)
, m_mid(mid)
, m_lo(lo)
{
}
version& version::type(version_type type, std::uint8_t type_index)
{
m_type = type;
m_type_index = type_index;
return *this;
}
std::uint16_t version::to_hex() const
{
return (m_hi << 24) | (m_mid << 16) | (m_lo << 8) | ((std::uint8_t(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;
}
}
-71
View File
@@ -1,71 +0,0 @@
#pragma once
#include <string>
#include <cstdint>
namespace utils
{
enum class version_type : std::uint8_t
{
pre_alpha,
alpha,
beta,
release_candidate,
release
};
std::string to_string(version_type type);
class version
{
std::uint8_t m_hi;
std::uint8_t m_mid;
std::uint8_t m_lo;
version_type m_type = version_type::release;
std::uint8_t m_type_index = 1;
std::string m_postfix;
public:
version(std::uint8_t hi, std::uint8_t mid, std::uint8_t lo = 0);
version& type(version_type type, std::uint8_t type_index = 1);
std::uint8_t hi() const
{
return m_hi;
}
std::uint8_t mid() const
{
return m_mid;
}
std::uint8_t lo() const
{
return m_lo;
}
version_type type() const
{
return m_type;
}
std::string postfix() const
{
return m_postfix;
}
version& postfix(const std::string& value)
{
m_postfix = value;
return *this;
}
std::uint8_t type_index() const
{
return m_type_index;
}
std::uint16_t to_hex() const;
std::string to_string() const;
};
}
+1 -4
View File
@@ -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.
-99
View File
@@ -1,99 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{FDC361C5-7734-493B-8CFB-037308B35122}</ProjectGuid>
<RootNamespace>yamlcpp</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\rpcs3_default.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="..\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="..\rpcs3_release.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="yaml-cpp\src\binary.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\convert.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\directives.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emit.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitfromevents.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitter.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitterstate.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitterutils.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\exp.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\memory.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\node.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\nodebuilder.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\nodeevents.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\node_data.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\null.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\ostream_wrapper.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\parse.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\parser.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\regex_yaml.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scanner.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scanscalar.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scantag.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scantoken.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\simplekey.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\singledocparser.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\stream.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\tag.cpp">
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
-92
View File
@@ -1,92 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\binary.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\convert.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\directives.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitfromevents.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitterstate.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitterutils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\exp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\memory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\node.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\node_data.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\nodebuilder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\nodeevents.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\null.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ostream_wrapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\parse.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\parser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\regex_yaml.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scanner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scanscalar.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scantag.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scantoken.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\simplekey.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\singledocparser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\stream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tag.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
-4
View File
@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>
-10
View File
@@ -1,10 +0,0 @@
if(APPLE)
else()
set(BUILD_TESTS OFF CACHE BOOL "Build tests" FORCE)
set(BUILD_DEMOS OFF CACHE BOOL "Build demos" FORCE)
# TravisCI break build with layers and vkjson
set(BUILD_LAYERS OFF CACHE BOOL "Build demos" FORCE)
set(BUILD_VKJSON OFF CACHE BOOL "Build demos" FORCE)
add_subdirectory( Vulkan-LoaderAndValidationLayers )
add_subdirectory( glslang )
endif()
-66
View File
@@ -1,66 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{58B40697-B15E-429E-B325-D52C28AEBCBF}</ProjectGuid>
<Keyword>MakeFileProj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release
</NMakeBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release</NMakeCleanCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release
</NMakeReBuildCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF ../Vulkan-LoaderAndValidationLayers
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
Submodule Vulkan/glslang deleted from 3c5b1e6b31
@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}</ProjectGuid>
<Keyword>MakeFileProj</Keyword>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Makefile</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release</NMakeCleanCommandLine>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<NMakeBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug
</NMakeBuildCommandLine>
<NMakeReBuildCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug
</NMakeReBuildCommandLine>
<NMakeCleanCommandLine>
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug
</NMakeCleanCommandLine>
</PropertyGroup>
<ItemDefinitionGroup>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
+9 -8
View File
@@ -8,24 +8,25 @@ clone_folder: c:\rpcs3
clone_depth: 3
test: off
branches:
except:
- ppu_recompiler
before_build:
# until git for win 2.5 release with commit checkout
- git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp rsx_program_decompiler
- git submodule update --init ffmpeg asmjit minidx9 rsx_program_decompiler
- 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null
- 7z x zlib.7z -aos -oC:\rpcs3\ > null
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/)
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/share/llvm/cmake -DZLIB_ROOT=C:/rpcs3/zlib/)
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64")
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 14 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/share/llvm/cmake)
build_script:
- cmake --build . --config Release -- /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
install:
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/wxWidgets.7z'
# - ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/llvmlibs.7z'
- ps: Start-FileDownload 'https://drive.google.com/uc?export=download&id=0B-98fOyaZKJ5YWVnb29JZXFQWkU' -FileName llvmlibs.7z
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/zlib.7z'
- ps: Start-FileDownload 'https://402331b94f8e4b87ae2ef4677347f7956cf3861f.googledrive.com/host/0B6v_qtb9hkicfmt0NG0wTTRtUmF4X3VTQk5Oc2JidEVKVnUteDA1dXdrYlNsVW9kREpsSHc/llvmlibs.7z'
- set WXWIN=C:\rpcs3\wxWidgets
- set OPENALDIR=C:\rpcs3\3rdparty\OpenAL
- set OPENALDIR=C:\rpcs3\OpenAL
- set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;C:\wxWidgets;%PATH%
- set COMMIT_SHA=%APPVEYOR_REPO_COMMIT:~0,8%
+46 -36
View File
@@ -1,22 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug - LLVM|x64">
<Configuration>Debug - LLVM</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug - MemLeak|x64">
<Configuration>Debug - MemLeak</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release - LLVM|x64">
<Configuration>Release - LLVM</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
@@ -83,42 +71,64 @@
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v140</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\rpcs3_default.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="..\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - MemLeak|x64'" Label="PropertySheets">
<Import Project="..\rpcs3_debug.props" />
<Import Project="..\rpcs3_memleak.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'" Label="PropertySheets">
<Import Project="..\rpcs3_debug.props" />
<Import Project="..\rpcs3_llvm.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="..\rpcs3_release.props" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'" Label="PropertySheets">
<Import Project="..\rpcs3_release.props" />
<Import Project="..\rpcs3_llvm.props" />
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
<IntDir>
</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
<IntDir>
</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>ASMJIT_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>ASMJIT_STATIC;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>
<PreprocessorDefinitions>ASMJIT_STATIC;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
-4
View File
@@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore
View File
+146
View File
@@ -0,0 +1,146 @@
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
project(glm)
enable_testing()
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
include(GNUInstallDirs)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
option(GLM_TEST_ENABLE "GLM test" OFF)
if(NOT GLM_TEST_ENABLE)
message(STATUS "GLM is a header only library, no need to build it. Set the option GLM_TEST_ENABLE with ON to build and run the test bench")
endif()
if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") OR (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") AND UNIX))
option(GLM_TEST_ENABLE_CXX_98 "Enable C++ 98" OFF)
option(GLM_TEST_ENABLE_CXX_0X "Enable C++ 0x" OFF)
option(GLM_TEST_ENABLE_CXX_11 "Enable C++ 11" OFF)
option(GLM_TEST_ENABLE_CXX_1Y "Enable C++ 1y" OFF)
option(GLM_TEST_ENABLE_CXX_14 "Enable C++ 14" OFF)
option(GLM_TEST_ENABLE_CXX_1Z "Enable C++ 1z" OFF)
if(GLM_TEST_ENABLE_CXX_1Z)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++1z")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_CXX_FLAGS "-std=c++1Z")
elseif(GLM_TEST_ENABLE_CXX_14)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++14")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_CXX_FLAGS "-std=c++14")
elseif(GLM_TEST_ENABLE_CXX_1Y)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++1y")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_CXX_FLAGS "-std=c++1y")
elseif(GLM_TEST_ENABLE_CXX_11)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++11")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_CXX_FLAGS "-std=c++11")
elseif(GLM_TEST_ENABLE_CXX_0X)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++0x")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_CXX_FLAGS "-std=c++0x")
elseif(GLM_TEST_ENABLE_CXX_98)
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "c++98")
set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++")
set(CMAKE_CXX_FLAGS "-std=c++98")
endif()
endif()
option(GLM_TEST_ENABLE_MS_EXTENSIONS "Enable MS extensions" OFF)
if(GLM_TEST_ENABLE_MS_EXTENSIONS)
if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"))
add_definitions(-Wgnu-anonymous-struct)
add_definitions(-Wnested-anon-types)
endif()
else()
if(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") OR (("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") AND WIN32))
add_definitions(/Za)
elseif(("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU"))
add_definitions(-pedantic)
endif()
endif()
option(GLM_TEST_ENABLE_SIMD_SSE2 "Enable SSE2 optimizations" OFF)
option(GLM_TEST_ENABLE_SIMD_SSE3 "Enable SSE3 optimizations" OFF)
option(GLM_TEST_ENABLE_SIMD_AVX "Enable AVX optimizations" OFF)
option(GLM_TEST_ENABLE_SIMD_AVX2 "Enable AVX2 optimizations" OFF)
option(GLM_TEST_FORCE_PURE "Force 'pure' instructions" OFF)
if(GLM_TEST_FORCE_PURE)
add_definitions(-DGLM_FORCE_PURE)
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-mfpmath=387)
endif()
elseif(GLM_TEST_ENABLE_SIMD_AVX2)
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-mavx2)
elseif(GLM_USE_INTEL)
add_definitions(/QxAVX2)
elseif(MSVC)
add_definitions(/arch:AVX2)
endif()
elseif(GLM_TEST_ENABLE_SIMD_AVX)
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-mavx)
elseif(GLM_USE_INTEL)
add_definitions(/QxAVX)
elseif(MSVC)
add_definitions(/arch:AVX)
endif()
elseif(GLM_TEST_ENABLE_SIMD_SSE3)
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-msse3)
elseif(GLM_USE_INTEL)
add_definitions(/QxSSE3)
elseif(MSVC)
add_definitions(/arch:SSE2) # VC doesn't support /arch:SSE3
endif()
elseif(GLM_TEST_ENABLE_SIMD_SSE2)
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-msse2)
elseif(GLM_USE_INTEL)
add_definitions(/QxSSE2)
elseif(MSVC)
if(NOT CMAKE_CL_64)
add_definitions(/arch:SSE2)
endif()
endif()
endif()
option(GLM_TEST_ENABLE_FAST_MATH "Enable fast math optimizations" OFF)
if(GLM_TEST_ENABLE_FAST_MATH)
if(CMAKE_COMPILER_IS_GNUCXX)
add_definitions(-ffast-math)
endif()
if(MSVC)
add_definitions(/fp:fast)
endif()
elseif(NOT GLM_TEST_ENABLE_FAST_MATH)
if(MSVC)
add_definitions(/fp:precise)
endif()
endif()
if(CMAKE_COMPILER_IS_GNUCXX)
#add_definitions(-S)
#add_definitions(-s)
add_definitions(-m64)
add_definitions(-O2)
#add_definitions(-fprofile-arcs -ftest-coverage) gcov
#ctest_enable_coverage()
endif()
include_directories("${PROJECT_SOURCE_DIR}")
include_directories("${PROJECT_SOURCE_DIR}/test/external")
add_subdirectory(glm)
add_subdirectory(test)
add_subdirectory(util)
install(DIRECTORY glm DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR})
+13
View File
@@ -0,0 +1,13 @@
## This file should be placed in the root directory of your project.
## Then modify the CMakeLists.txt file in the root directory of your
## project to incorporate the testing dashboard.
## # The following are required to uses Dart and the Cdash dashboard
## ENABLE_TESTING()
## INCLUDE(CTest)
set(CTEST_PROJECT_NAME "GLM")
set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=GLM")
set(CTEST_DROP_SITE_CDASH TRUE)
+188
View File
@@ -0,0 +1,188 @@
# - Define GNU standard installation directories
# Provides install directory variables as defined for GNU software:
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
# Inclusion of this module defines the following variables:
# CMAKE_INSTALL_<dir> - destination for files of a given type
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
# where <dir> is one of:
# BINDIR - user executables (bin)
# SBINDIR - system admin executables (sbin)
# LIBEXECDIR - program executables (libexec)
# SYSCONFDIR - read-only single-machine data (etc)
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
# LOCALSTATEDIR - modifiable single-machine data (var)
# LIBDIR - object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)
# INCLUDEDIR - C header files (include)
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
# DATAROOTDIR - read-only architecture-independent data root (share)
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
# INFODIR - info documentation (DATAROOTDIR/info)
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
# MANDIR - man documentation (DATAROOTDIR/man)
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
# install() commands for the corresponding file type. If the includer does
# not define a value the above-shown default will be used and the value will
# appear in the cache for editing by the user.
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
# from the corresponding destination by prepending (if necessary) the value
# of CMAKE_INSTALL_PREFIX.
#=============================================================================
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
# Copyright 2011 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Installation directories
#
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(_LIBDIR_DEFAULT "lib")
# Override this default 'lib' with 'lib64' iff:
# - we are on Linux system but NOT cross-compiling
# - we are NOT on debian
# - we are on a 64 bits system
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
# For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
# CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
# See http://wiki.debian.org/Multiarch
if((CMAKE_SYSTEM_NAME MATCHES "Linux|kFreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "GNU")
AND NOT CMAKE_CROSSCOMPILING)
if (EXISTS "/etc/debian_version") # is this a debian system ?
if(CMAKE_LIBRARY_ARCHITECTURE)
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
message(AUTHOR_WARNING
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
"Please enable at least one language before including GNUInstallDirs.")
else()
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_LIBDIR_DEFAULT "lib64")
endif()
endif()
endif()
endif()
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
endif()
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
endif()
#-----------------------------------------------------------------------------
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
# the cache and store the defaults in local variables if the cache values are
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
if(NOT CMAKE_INSTALL_DATADIR)
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
endif()
if(NOT CMAKE_INSTALL_INFODIR)
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
endif()
if(NOT CMAKE_INSTALL_LOCALEDIR)
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
endif()
if(NOT CMAKE_INSTALL_MANDIR)
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
endif()
if(NOT CMAKE_INSTALL_DOCDIR)
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
endif()
#-----------------------------------------------------------------------------
mark_as_advanced(
CMAKE_INSTALL_BINDIR
CMAKE_INSTALL_SBINDIR
CMAKE_INSTALL_LIBEXECDIR
CMAKE_INSTALL_SYSCONFDIR
CMAKE_INSTALL_SHAREDSTATEDIR
CMAKE_INSTALL_LOCALSTATEDIR
CMAKE_INSTALL_LIBDIR
CMAKE_INSTALL_INCLUDEDIR
CMAKE_INSTALL_OLDINCLUDEDIR
CMAKE_INSTALL_DATAROOTDIR
CMAKE_INSTALL_DATADIR
CMAKE_INSTALL_INFODIR
CMAKE_INSTALL_LOCALEDIR
CMAKE_INSTALL_MANDIR
CMAKE_INSTALL_DOCDIR
)
# Result directories
#
foreach(dir
BINDIR
SBINDIR
LIBEXECDIR
SYSCONFDIR
SHAREDSTATEDIR
LOCALSTATEDIR
LIBDIR
INCLUDEDIR
OLDINCLUDEDIR
DATAROOTDIR
DATADIR
INFODIR
LOCALEDIR
MANDIR
DOCDIR
)
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
else()
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
endif()
endforeach()
+55
View File
@@ -0,0 +1,55 @@
================================================================================
OpenGL Mathematics (GLM)
--------------------------------------------------------------------------------
GLM can be distributed and/or modified under the terms of either
a) The Happy Bunny License, or b) the MIT License.
================================================================================
The Happy Bunny License (Modified MIT License)
--------------------------------------------------------------------------------
Copyright (c) 2005 - 2015 G-Truc Creation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
Restrictions:
By making use of the Software for military purposes, you choose to make a
Bunny unhappy.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================================================
The MIT License
--------------------------------------------------------------------------------
Copyright (c) 2005 - 2015 G-Truc Creation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+43
View File
@@ -0,0 +1,43 @@
set(NAME glm_dummy)
file(GLOB ROOT_SOURCE *.cpp)
file(GLOB ROOT_INLINE *.inl)
file(GLOB ROOT_HEADER *.hpp)
file(GLOB ROOT_TEXT ../*.txt)
file(GLOB ROOT_NAT ../util/glm.natvis)
file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp)
file(GLOB_RECURSE CORE_INLINE ./detail/*.inl)
file(GLOB_RECURSE CORE_HEADER ./detail/*.hpp)
file(GLOB_RECURSE GTC_SOURCE ./gtc/*.cpp)
file(GLOB_RECURSE GTC_INLINE ./gtc/*.inl)
file(GLOB_RECURSE GTC_HEADER ./gtc/*.hpp)
file(GLOB_RECURSE GTX_SOURCE ./gtx/*.cpp)
file(GLOB_RECURSE GTX_INLINE ./gtx/*.inl)
file(GLOB_RECURSE GTX_HEADER ./gtx/*.hpp)
source_group("Text Files" FILES ${ROOT_TEXT})
source_group("Core Files" FILES ${CORE_SOURCE})
source_group("Core Files" FILES ${CORE_INLINE})
source_group("Core Files" FILES ${CORE_HEADER})
source_group("GTC Files" FILES ${GTC_SOURCE})
source_group("GTC Files" FILES ${GTC_INLINE})
source_group("GTC Files" FILES ${GTC_HEADER})
source_group("GTX Files" FILES ${GTX_SOURCE})
source_group("GTX Files" FILES ${GTX_INLINE})
source_group("GTX Files" FILES ${GTX_HEADER})
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
if(GLM_TEST_ENABLE)
add_executable(${NAME} ${ROOT_TEXT} ${ROOT_NAT}
${ROOT_SOURCE} ${ROOT_INLINE} ${ROOT_HEADER}
${CORE_SOURCE} ${CORE_INLINE} ${CORE_HEADER}
${GTC_SOURCE} ${GTC_INLINE} ${GTC_HEADER}
${GTX_SOURCE} ${GTX_INLINE} ${GTX_HEADER})
endif(GLM_TEST_ENABLE)
#add_library(glm STATIC glm.cpp)
#add_library(glm_shared SHARED glm.cpp)
+35
View File
@@ -0,0 +1,35 @@
///////////////////////////////////////////////////////////////////////////////////
/// OpenGL Mathematics (glm.g-truc.net)
///
/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net)
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// Restrictions:
/// By making use of the Software for military purposes, you choose to make
/// a Bunny unhappy.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
/// THE SOFTWARE.
///
/// @ref core
/// @file glm/common.hpp
/// @date 2013-12-24 / 2013-12-24
/// @author Christophe Riccio
///////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "detail/func_common.hpp"
+428
View File
@@ -0,0 +1,428 @@
///////////////////////////////////////////////////////////////////////////////////
/// OpenGL Mathematics (glm.g-truc.net)
///
/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net)
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// Restrictions:
/// By making use of the Software for military purposes, you choose to make
/// a Bunny unhappy.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
/// THE SOFTWARE.
///
/// @ref core
/// @file glm/detail/_features.hpp
/// @date 2013-02-20 / 2013-02-20
/// @author Christophe Riccio
///////////////////////////////////////////////////////////////////////////////////
#pragma once
// #define GLM_CXX98_EXCEPTIONS
// #define GLM_CXX98_RTTI
// #define GLM_CXX11_RVALUE_REFERENCES
// Rvalue references - GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
// GLM_CXX11_TRAILING_RETURN
// Rvalue references for *this - GCC not supported
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm
// GLM_CXX11_NONSTATIC_MEMBER_INIT
// Initialization of class objects by rvalues - GCC any
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html
// GLM_CXX11_NONSTATIC_MEMBER_INIT
// Non-static data member initializers - GCC 4.7
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm
// #define GLM_CXX11_VARIADIC_TEMPLATE
// Variadic templates - GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf
//
// Extending variadic template template parameters - GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf
// #define GLM_CXX11_GENERALIZED_INITIALIZERS
// Initializer lists - GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm
// #define GLM_CXX11_STATIC_ASSERT
// Static assertions - GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html
// #define GLM_CXX11_AUTO_TYPE
// auto-typed variables - GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf
// #define GLM_CXX11_AUTO_TYPE
// Multi-declarator auto - GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf
// #define GLM_CXX11_AUTO_TYPE
// Removal of auto as a storage-class specifier - GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm
// #define GLM_CXX11_AUTO_TYPE
// New function declarator syntax - GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm
// #define GLM_CXX11_LAMBDAS
// New wording for C++0x lambdas - GCC 4.5
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf
// #define GLM_CXX11_DECLTYPE
// Declared type of an expression - GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf
//
// Right angle brackets - GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html
//
// Default template arguments for function templates DR226 GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226
//
// Solving the SFINAE problem for expressions DR339 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html
// #define GLM_CXX11_ALIAS_TEMPLATE
// Template aliases N2258 GCC 4.7
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf
//
// Extern templates N1987 Yes
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm
// #define GLM_CXX11_NULLPTR
// Null pointer constant N2431 GCC 4.6
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
// #define GLM_CXX11_STRONG_ENUMS
// Strongly-typed enums N2347 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf
//
// Forward declarations for enums N2764 GCC 4.6
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf
//
// Generalized attributes N2761 GCC 4.8
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf
//
// Generalized constant expressions N2235 GCC 4.6
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf
//
// Alignment support N2341 GCC 4.8
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf
// #define GLM_CXX11_DELEGATING_CONSTRUCTORS
// Delegating constructors N1986 GCC 4.7
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf
//
// Inheriting constructors N2540 GCC 4.8
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm
// #define GLM_CXX11_EXPLICIT_CONVERSIONS
// Explicit conversion operators N2437 GCC 4.5
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf
//
// New character types N2249 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html
//
// Unicode string literals N2442 GCC 4.5
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm
//
// Raw string literals N2442 GCC 4.5
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm
//
// Universal character name literals N2170 GCC 4.5
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html
// #define GLM_CXX11_USER_LITERALS
// User-defined literals N2765 GCC 4.7
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf
//
// Standard Layout Types N2342 GCC 4.5
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm
// #define GLM_CXX11_DEFAULTED_FUNCTIONS
// #define GLM_CXX11_DELETED_FUNCTIONS
// Defaulted and deleted functions N2346 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm
//
// Extended friend declarations N1791 GCC 4.7
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf
//
// Extending sizeof N2253 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html
// #define GLM_CXX11_INLINE_NAMESPACES
// Inline namespaces N2535 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm
// #define GLM_CXX11_UNRESTRICTED_UNIONS
// Unrestricted unions N2544 GCC 4.6
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
// #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS
// Local and unnamed types as template arguments N2657 GCC 4.5
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm
// #define GLM_CXX11_RANGE_FOR
// Range-based for N2930 GCC 4.6
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html
// #define GLM_CXX11_OVERRIDE_CONTROL
// Explicit virtual overrides N2928 N3206 N3272 GCC 4.7
// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm
//
// Minimal support for garbage collection and reachability-based leak detection N2670 No
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm
// #define GLM_CXX11_NOEXCEPT
// Allowing move constructors to throw [noexcept] N3050 GCC 4.6 (core language only)
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html
//
// Defining move special member functions N3053 GCC 4.6
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html
//
// Sequence points N2239 Yes
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html
//
// Atomic operations N2427 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html
//
// Strong Compare and Exchange N2748 GCC 4.5
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html
//
// Bidirectional Fences N2752 GCC 4.8
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm
//
// Memory model N2429 GCC 4.8
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm
//
// Data-dependency ordering: atomics and memory model N2664 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm
//
// Propagating exceptions N2179 GCC 4.4
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html
//
// Abandoning a process and at_quick_exit N2440 GCC 4.8
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm
//
// Allow atomics use in signal handlers N2547 Yes
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm
//
// Thread-local storage N2659 GCC 4.8
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm
//
// Dynamic initialization and destruction with concurrency N2660 GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm
//
// __func__ predefined identifier N2340 GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm
//
// C99 preprocessor N1653 GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm
//
// long long N1811 GCC 4.3
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf
//
// Extended integral types N1988 Yes
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
#if(GLM_COMPILER & GLM_COMPILER_GCC)
# if(GLM_COMPILER >= GLM_COMPILER_GCC43)
# define GLM_CXX11_STATIC_ASSERT
# endif
#elif(GLM_COMPILER & (GLM_COMPILER_APPLE_CLANG | GLM_COMPILER_LLVM))
# if(__has_feature(cxx_exceptions))
# define GLM_CXX98_EXCEPTIONS
# endif
# if(__has_feature(cxx_rtti))
# define GLM_CXX98_RTTI
# endif
# if(__has_feature(cxx_access_control_sfinae))
# define GLM_CXX11_ACCESS_CONTROL_SFINAE
# endif
# if(__has_feature(cxx_alias_templates))
# define GLM_CXX11_ALIAS_TEMPLATE
# endif
# if(__has_feature(cxx_alignas))
# define GLM_CXX11_ALIGNAS
# endif
# if(__has_feature(cxx_attributes))
# define GLM_CXX11_ATTRIBUTES
# endif
# if(__has_feature(cxx_constexpr))
# define GLM_CXX11_CONSTEXPR
# endif
# if(__has_feature(cxx_decltype))
# define GLM_CXX11_DECLTYPE
# endif
# if(__has_feature(cxx_default_function_template_args))
# define GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS
# endif
# if(__has_feature(cxx_defaulted_functions))
# define GLM_CXX11_DEFAULTED_FUNCTIONS
# endif
# if(__has_feature(cxx_delegating_constructors))
# define GLM_CXX11_DELEGATING_CONSTRUCTORS
# endif
# if(__has_feature(cxx_deleted_functions))
# define GLM_CXX11_DELETED_FUNCTIONS
# endif
# if(__has_feature(cxx_explicit_conversions))
# define GLM_CXX11_EXPLICIT_CONVERSIONS
# endif
# if(__has_feature(cxx_generalized_initializers))
# define GLM_CXX11_GENERALIZED_INITIALIZERS
# endif
# if(__has_feature(cxx_implicit_moves))
# define GLM_CXX11_IMPLICIT_MOVES
# endif
# if(__has_feature(cxx_inheriting_constructors))
# define GLM_CXX11_INHERITING_CONSTRUCTORS
# endif
# if(__has_feature(cxx_inline_namespaces))
# define GLM_CXX11_INLINE_NAMESPACES
# endif
# if(__has_feature(cxx_lambdas))
# define GLM_CXX11_LAMBDAS
# endif
# if(__has_feature(cxx_local_type_template_args))
# define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS
# endif
# if(__has_feature(cxx_noexcept))
# define GLM_CXX11_NOEXCEPT
# endif
# if(__has_feature(cxx_nonstatic_member_init))
# define GLM_CXX11_NONSTATIC_MEMBER_INIT
# endif
# if(__has_feature(cxx_nullptr))
# define GLM_CXX11_NULLPTR
# endif
# if(__has_feature(cxx_override_control))
# define GLM_CXX11_OVERRIDE_CONTROL
# endif
# if(__has_feature(cxx_reference_qualified_functions))
# define GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS
# endif
# if(__has_feature(cxx_range_for))
# define GLM_CXX11_RANGE_FOR
# endif
# if(__has_feature(cxx_raw_string_literals))
# define GLM_CXX11_RAW_STRING_LITERALS
# endif
# if(__has_feature(cxx_rvalue_references))
# define GLM_CXX11_RVALUE_REFERENCES
# endif
# if(__has_feature(cxx_static_assert))
# define GLM_CXX11_STATIC_ASSERT
# endif
# if(__has_feature(cxx_auto_type))
# define GLM_CXX11_AUTO_TYPE
# endif
# if(__has_feature(cxx_strong_enums))
# define GLM_CXX11_STRONG_ENUMS
# endif
# if(__has_feature(cxx_trailing_return))
# define GLM_CXX11_TRAILING_RETURN
# endif
# if(__has_feature(cxx_unicode_literals))
# define GLM_CXX11_UNICODE_LITERALS
# endif
# if(__has_feature(cxx_unrestricted_unions))
# define GLM_CXX11_UNRESTRICTED_UNIONS
# endif
# if(__has_feature(cxx_user_literals))
# define GLM_CXX11_USER_LITERALS
# endif
# if(__has_feature(cxx_variadic_templates))
# define GLM_CXX11_VARIADIC_TEMPLATES
# endif
#endif//(GLM_COMPILER & (GLM_COMPILER_APPLE_CLANG | GLM_COMPILER_LLVM))
+59
View File
@@ -0,0 +1,59 @@
///////////////////////////////////////////////////////////////////////////////////
/// OpenGL Mathematics (glm.g-truc.net)
///
/// Copyright (c) 2005 - 2015 G-Truc Creation (www.g-truc.net)
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in
/// all copies or substantial portions of the Software.
///
/// Restrictions:
/// By making use of the Software for military purposes, you choose to make
/// a Bunny unhappy.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
/// THE SOFTWARE.
///
/// @ref core
/// @file glm/detail/_fixes.hpp
/// @date 2011-02-21 / 2011-11-22
/// @author Christophe Riccio
///////////////////////////////////////////////////////////////////////////////////
#include <cmath>
//! Workaround for compatibility with other libraries
#ifdef max
#undef max
#endif
//! Workaround for compatibility with other libraries
#ifdef min
#undef min
#endif
//! Workaround for Android
#ifdef isnan
#undef isnan
#endif
//! Workaround for Android
#ifdef isinf
#undef isinf
#endif
//! Workaround for Chrone Native Client
#ifdef log2
#undef log2
#endif

Some files were not shown because too many files have changed in this diff Show More