mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-14 08:04:40 +00:00
update openal-soft
sync point: master-ac5d40e40a0155351fe1be4aab30017b6a13a859
This commit is contained in:
parent
762a84550f
commit
3603188b7f
365 changed files with 76053 additions and 53126 deletions
144
Engine/lib/openal-soft/common/albit.h
Normal file
144
Engine/lib/openal-soft/common/albit.h
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
#ifndef AL_BIT_H
|
||||
#define AL_BIT_H
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#if !defined(__GNUC__) && (defined(_WIN32) || defined(_WIN64))
|
||||
#include <intrin.h>
|
||||
#include "opthelpers.h"
|
||||
#endif
|
||||
|
||||
namespace al {
|
||||
|
||||
#ifdef __BYTE_ORDER__
|
||||
enum class endian {
|
||||
little = __ORDER_LITTLE_ENDIAN__,
|
||||
big = __ORDER_BIG_ENDIAN__,
|
||||
native = __BYTE_ORDER__
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
/* This doesn't support mixed-endian. */
|
||||
namespace detail_ {
|
||||
constexpr inline bool EndianTest() noexcept
|
||||
{
|
||||
static_assert(sizeof(char) < sizeof(int), "char is too big");
|
||||
|
||||
constexpr int test_val{1};
|
||||
return static_cast<const char&>(test_val);
|
||||
}
|
||||
} // namespace detail_
|
||||
|
||||
enum class endian {
|
||||
little = 0,
|
||||
big = 1,
|
||||
native = detail_::EndianTest() ? little : big
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/* Define popcount (population count/count 1 bits) and countr_zero (count
|
||||
* trailing zero bits, starting from the lsb) methods, for various integer
|
||||
* types.
|
||||
*/
|
||||
#ifdef __GNUC__
|
||||
|
||||
namespace detail_ {
|
||||
inline int popcount(unsigned long long val) noexcept { return __builtin_popcountll(val); }
|
||||
inline int popcount(unsigned long val) noexcept { return __builtin_popcountl(val); }
|
||||
inline int popcount(unsigned int val) noexcept { return __builtin_popcount(val); }
|
||||
|
||||
inline int countr_zero(unsigned long long val) noexcept { return __builtin_ctzll(val); }
|
||||
inline int countr_zero(unsigned long val) noexcept { return __builtin_ctzl(val); }
|
||||
inline int countr_zero(unsigned int val) noexcept { return __builtin_ctz(val); }
|
||||
} // namespace detail_
|
||||
|
||||
template<typename T>
|
||||
inline std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||
int> popcount(T v) noexcept { return detail_::popcount(v); }
|
||||
|
||||
template<typename T>
|
||||
inline std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||
int> countr_zero(T val) noexcept
|
||||
{ return val ? detail_::countr_zero(val) : std::numeric_limits<T>::digits; }
|
||||
|
||||
#else
|
||||
|
||||
/* There be black magics here. The popcount method is derived from
|
||||
* https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
|
||||
* while the ctz-utilizing-popcount algorithm is shown here
|
||||
* http://www.hackersdelight.org/hdcodetxt/ntz.c.txt
|
||||
* as the ntz2 variant. These likely aren't the most efficient methods, but
|
||||
* they're good enough if the GCC built-ins aren't available.
|
||||
*/
|
||||
namespace detail_ {
|
||||
template<typename T>
|
||||
constexpr T repbits(unsigned char bits) noexcept
|
||||
{
|
||||
T ret{bits};
|
||||
for(size_t i{1};i < sizeof(T);++i)
|
||||
ret = (ret<<8) | bits;
|
||||
return ret;
|
||||
}
|
||||
} // namespace detail_
|
||||
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||
int> popcount(T v) noexcept
|
||||
{
|
||||
constexpr T m55{detail_::repbits<T>(0x55)};
|
||||
constexpr T m33{detail_::repbits<T>(0x33)};
|
||||
constexpr T m0f{detail_::repbits<T>(0x0f)};
|
||||
constexpr T m01{detail_::repbits<T>(0x01)};
|
||||
|
||||
v = v - ((v >> 1) & m55);
|
||||
v = (v & m33) + ((v >> 2) & m33);
|
||||
v = (v + (v >> 4)) & m0f;
|
||||
return static_cast<int>((v * m01) >> ((sizeof(T)-1)*8));
|
||||
}
|
||||
|
||||
#if defined(_WIN64)
|
||||
|
||||
template<typename T>
|
||||
inline std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||
int> countr_zero(T v)
|
||||
{
|
||||
unsigned long idx{std::numeric_limits<T>::digits};
|
||||
if_constexpr(std::numeric_limits<T>::digits <= 32)
|
||||
_BitScanForward(&idx, static_cast<uint32_t>(v));
|
||||
else // std::numeric_limits<T>::digits > 32
|
||||
_BitScanForward64(&idx, v);
|
||||
return static_cast<int>(idx);
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
template<typename T>
|
||||
inline std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||
int> countr_zero(T v)
|
||||
{
|
||||
unsigned long idx{std::numeric_limits<T>::digits};
|
||||
if_constexpr(std::numeric_limits<T>::digits <= 32)
|
||||
_BitScanForward(&idx, static_cast<uint32_t>(v));
|
||||
else if(!_BitScanForward(&idx, static_cast<uint32_t>(v)))
|
||||
{
|
||||
if(_BitScanForward(&idx, static_cast<uint32_t>(v>>32)))
|
||||
idx += 32;
|
||||
}
|
||||
return static_cast<int>(idx);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value && std::is_unsigned<T>::value,
|
||||
int> countr_zero(T value)
|
||||
{ return popcount(static_cast<T>(~value & (value - 1))); }
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_BIT_H */
|
||||
67
Engine/lib/openal-soft/common/albyte.h
Normal file
67
Engine/lib/openal-soft/common/albyte.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef AL_BYTE_H
|
||||
#define AL_BYTE_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
using uint = unsigned int;
|
||||
|
||||
namespace al {
|
||||
|
||||
/* The "canonical" way to store raw byte data. Like C++17's std::byte, it's not
|
||||
* treated as a character type and does not work with arithmatic ops. Only
|
||||
* bitwise ops are allowed.
|
||||
*/
|
||||
enum class byte : unsigned char { };
|
||||
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value,T>
|
||||
to_integer(al::byte b) noexcept { return T(b); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value,al::byte>
|
||||
operator<<(al::byte lhs, T rhs) noexcept { return al::byte(to_integer<uint>(lhs) << rhs); }
|
||||
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value,al::byte>
|
||||
operator>>(al::byte lhs, T rhs) noexcept { return al::byte(to_integer<uint>(lhs) >> rhs); }
|
||||
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value,al::byte&>
|
||||
operator<<=(al::byte &lhs, T rhs) noexcept { lhs = lhs << rhs; return lhs; }
|
||||
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value,al::byte&>
|
||||
operator>>=(al::byte &lhs, T rhs) noexcept { lhs = lhs >> rhs; return lhs; }
|
||||
|
||||
#define AL_DECL_OP(op, opeq) \
|
||||
template<typename T> \
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value,al::byte> \
|
||||
operator op (al::byte lhs, T rhs) noexcept \
|
||||
{ return al::byte(to_integer<uint>(lhs) op static_cast<uint>(rhs)); } \
|
||||
\
|
||||
template<typename T> \
|
||||
constexpr std::enable_if_t<std::is_integral<T>::value,al::byte&> \
|
||||
operator opeq (al::byte &lhs, T rhs) noexcept { lhs = lhs op rhs; return lhs; } \
|
||||
\
|
||||
constexpr al::byte operator op (al::byte lhs, al::byte rhs) noexcept \
|
||||
{ return al::byte(lhs op to_integer<uint>(rhs)); } \
|
||||
\
|
||||
constexpr al::byte& operator opeq (al::byte &lhs, al::byte rhs) noexcept \
|
||||
{ lhs = lhs op rhs; return lhs; }
|
||||
|
||||
AL_DECL_OP(|, |=)
|
||||
AL_DECL_OP(&, &=)
|
||||
AL_DECL_OP(^, ^=)
|
||||
|
||||
#undef AL_DECL_OP
|
||||
|
||||
constexpr al::byte operator~(al::byte b) noexcept
|
||||
{ return al::byte(~to_integer<uint>(b)); }
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_BYTE_H */
|
||||
80
Engine/lib/openal-soft/common/alcomplex.cpp
Normal file
80
Engine/lib/openal-soft/common/alcomplex.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "alcomplex.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
#include "albit.h"
|
||||
#include "alnumeric.h"
|
||||
#include "math_defs.h"
|
||||
|
||||
|
||||
void complex_fft(const al::span<std::complex<double>> buffer, const double sign)
|
||||
{
|
||||
const size_t fftsize{buffer.size()};
|
||||
/* Get the number of bits used for indexing. Simplifies bit-reversal and
|
||||
* the main loop count.
|
||||
*/
|
||||
const size_t log2_size{static_cast<size_t>(al::countr_zero(fftsize))};
|
||||
|
||||
/* Bit-reversal permutation applied to a sequence of fftsize items. */
|
||||
for(size_t idx{1u};idx < fftsize-1;++idx)
|
||||
{
|
||||
size_t revidx{0u}, imask{idx};
|
||||
for(size_t i{0};i < log2_size;++i)
|
||||
{
|
||||
revidx = (revidx<<1) | (imask&1);
|
||||
imask >>= 1;
|
||||
}
|
||||
|
||||
if(idx < revidx)
|
||||
std::swap(buffer[idx], buffer[revidx]);
|
||||
}
|
||||
|
||||
/* Iterative form of Danielson-Lanczos lemma */
|
||||
size_t step2{1u};
|
||||
for(size_t i{0};i < log2_size;++i)
|
||||
{
|
||||
const double arg{al::MathDefs<double>::Pi() / static_cast<double>(step2)};
|
||||
|
||||
const std::complex<double> w{std::cos(arg), std::sin(arg)*sign};
|
||||
std::complex<double> u{1.0, 0.0};
|
||||
const size_t step{step2 << 1};
|
||||
for(size_t j{0};j < step2;j++)
|
||||
{
|
||||
for(size_t k{j};k < fftsize;k+=step)
|
||||
{
|
||||
std::complex<double> temp{buffer[k+step2] * u};
|
||||
buffer[k+step2] = buffer[k] - temp;
|
||||
buffer[k] += temp;
|
||||
}
|
||||
|
||||
u *= w;
|
||||
}
|
||||
|
||||
step2 <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
void complex_hilbert(const al::span<std::complex<double>> buffer)
|
||||
{
|
||||
inverse_fft(buffer);
|
||||
|
||||
const double inverse_size = 1.0/static_cast<double>(buffer.size());
|
||||
auto bufiter = buffer.begin();
|
||||
const auto halfiter = bufiter + (buffer.size()>>1);
|
||||
|
||||
*bufiter *= inverse_size; ++bufiter;
|
||||
bufiter = std::transform(bufiter, halfiter, bufiter,
|
||||
[inverse_size](const std::complex<double> &c) -> std::complex<double>
|
||||
{ return c * (2.0*inverse_size); });
|
||||
*bufiter *= inverse_size; ++bufiter;
|
||||
|
||||
std::fill(bufiter, buffer.end(), std::complex<double>{});
|
||||
|
||||
forward_fft(buffer);
|
||||
}
|
||||
38
Engine/lib/openal-soft/common/alcomplex.h
Normal file
38
Engine/lib/openal-soft/common/alcomplex.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef ALCOMPLEX_H
|
||||
#define ALCOMPLEX_H
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include "alspan.h"
|
||||
|
||||
/**
|
||||
* Iterative implementation of 2-radix FFT (In-place algorithm). Sign = -1 is
|
||||
* FFT and 1 is inverse FFT. Applies the Discrete Fourier Transform (DFT) to
|
||||
* the data supplied in the buffer, which MUST BE power of two.
|
||||
*/
|
||||
void complex_fft(const al::span<std::complex<double>> buffer, const double sign);
|
||||
|
||||
/**
|
||||
* Calculate the frequency-domain response of the time-domain signal in the
|
||||
* provided buffer, which MUST BE power of two.
|
||||
*/
|
||||
inline void forward_fft(const al::span<std::complex<double>> buffer)
|
||||
{ complex_fft(buffer, -1.0); }
|
||||
|
||||
/**
|
||||
* Calculate the time-domain signal of the frequency-domain response in the
|
||||
* provided buffer, which MUST BE power of two.
|
||||
*/
|
||||
inline void inverse_fft(const al::span<std::complex<double>> buffer)
|
||||
{ complex_fft(buffer, 1.0); }
|
||||
|
||||
/**
|
||||
* Calculate the complex helical sequence (discrete-time analytical signal) of
|
||||
* the given input using the discrete Hilbert transform (In-place algorithm).
|
||||
* Fills the buffer with the discrete-time analytical signal stored in the
|
||||
* buffer. The buffer is an array of complex numbers and MUST BE power of two,
|
||||
* and the imaginary components should be cleared to 0.
|
||||
*/
|
||||
void complex_hilbert(const al::span<std::complex<double>> buffer);
|
||||
|
||||
#endif /* ALCOMPLEX_H */
|
||||
16
Engine/lib/openal-soft/common/aldeque.h
Normal file
16
Engine/lib/openal-soft/common/aldeque.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef ALDEQUE_H
|
||||
#define ALDEQUE_H
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
|
||||
namespace al {
|
||||
|
||||
template<typename T>
|
||||
using deque = std::deque<T, al::allocator<T>>;
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* ALDEQUE_H */
|
||||
150
Engine/lib/openal-soft/common/alfstream.cpp
Normal file
150
Engine/lib/openal-soft/common/alfstream.cpp
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "alfstream.h"
|
||||
|
||||
#include "strutils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
namespace al {
|
||||
|
||||
auto filebuf::underflow() -> int_type
|
||||
{
|
||||
if(mFile != INVALID_HANDLE_VALUE && gptr() == egptr())
|
||||
{
|
||||
// Read in the next chunk of data, and set the pointers on success
|
||||
DWORD got{};
|
||||
if(ReadFile(mFile, mBuffer.data(), static_cast<DWORD>(mBuffer.size()), &got, nullptr))
|
||||
setg(mBuffer.data(), mBuffer.data(), mBuffer.data()+got);
|
||||
}
|
||||
if(gptr() == egptr())
|
||||
return traits_type::eof();
|
||||
return traits_type::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
auto filebuf::seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) -> pos_type
|
||||
{
|
||||
if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in))
|
||||
return traits_type::eof();
|
||||
|
||||
LARGE_INTEGER fpos{};
|
||||
switch(whence)
|
||||
{
|
||||
case std::ios_base::beg:
|
||||
fpos.QuadPart = offset;
|
||||
if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN))
|
||||
return traits_type::eof();
|
||||
break;
|
||||
|
||||
case std::ios_base::cur:
|
||||
// If the offset remains in the current buffer range, just
|
||||
// update the pointer.
|
||||
if((offset >= 0 && offset < off_type(egptr()-gptr())) ||
|
||||
(offset < 0 && -offset <= off_type(gptr()-eback())))
|
||||
{
|
||||
// Get the current file offset to report the correct read
|
||||
// offset.
|
||||
fpos.QuadPart = 0;
|
||||
if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT))
|
||||
return traits_type::eof();
|
||||
setg(eback(), gptr()+offset, egptr());
|
||||
return fpos.QuadPart - off_type(egptr()-gptr());
|
||||
}
|
||||
// Need to offset for the file offset being at egptr() while
|
||||
// the requested offset is relative to gptr().
|
||||
offset -= off_type(egptr()-gptr());
|
||||
fpos.QuadPart = offset;
|
||||
if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_CURRENT))
|
||||
return traits_type::eof();
|
||||
break;
|
||||
|
||||
case std::ios_base::end:
|
||||
fpos.QuadPart = offset;
|
||||
if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_END))
|
||||
return traits_type::eof();
|
||||
break;
|
||||
|
||||
default:
|
||||
return traits_type::eof();
|
||||
}
|
||||
setg(nullptr, nullptr, nullptr);
|
||||
return fpos.QuadPart;
|
||||
}
|
||||
|
||||
auto filebuf::seekpos(pos_type pos, std::ios_base::openmode mode) -> pos_type
|
||||
{
|
||||
// Simplified version of seekoff
|
||||
if(mFile == INVALID_HANDLE_VALUE || (mode&std::ios_base::out) || !(mode&std::ios_base::in))
|
||||
return traits_type::eof();
|
||||
|
||||
LARGE_INTEGER fpos{};
|
||||
fpos.QuadPart = pos;
|
||||
if(!SetFilePointerEx(mFile, fpos, &fpos, FILE_BEGIN))
|
||||
return traits_type::eof();
|
||||
|
||||
setg(nullptr, nullptr, nullptr);
|
||||
return fpos.QuadPart;
|
||||
}
|
||||
|
||||
filebuf::~filebuf()
|
||||
{ close(); }
|
||||
|
||||
bool filebuf::open(const wchar_t *filename, std::ios_base::openmode mode)
|
||||
{
|
||||
if((mode&std::ios_base::out) || !(mode&std::ios_base::in))
|
||||
return false;
|
||||
HANDLE f{CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, nullptr)};
|
||||
if(f == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
if(mFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(mFile);
|
||||
mFile = f;
|
||||
|
||||
setg(nullptr, nullptr, nullptr);
|
||||
return true;
|
||||
}
|
||||
bool filebuf::open(const char *filename, std::ios_base::openmode mode)
|
||||
{
|
||||
std::wstring wname{utf8_to_wstr(filename)};
|
||||
return open(wname.c_str(), mode);
|
||||
}
|
||||
|
||||
void filebuf::close()
|
||||
{
|
||||
if(mFile != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(mFile);
|
||||
mFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
|
||||
ifstream::ifstream(const wchar_t *filename, std::ios_base::openmode mode)
|
||||
: std::istream{nullptr}
|
||||
{
|
||||
init(&mStreamBuf);
|
||||
|
||||
// Set the failbit if the file failed to open.
|
||||
if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in))
|
||||
clear(failbit);
|
||||
}
|
||||
|
||||
ifstream::ifstream(const char *filename, std::ios_base::openmode mode)
|
||||
: std::istream{nullptr}
|
||||
{
|
||||
init(&mStreamBuf);
|
||||
|
||||
// Set the failbit if the file failed to open.
|
||||
if((mode&std::ios_base::out) || !mStreamBuf.open(filename, mode|std::ios_base::in))
|
||||
clear(failbit);
|
||||
}
|
||||
|
||||
/* This is only here to ensure the compiler doesn't define an implicit
|
||||
* destructor, which it tries to automatically inline and subsequently complain
|
||||
* it can't inline without excessive code growth.
|
||||
*/
|
||||
ifstream::~ifstream() { }
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif
|
||||
74
Engine/lib/openal-soft/common/alfstream.h
Normal file
74
Engine/lib/openal-soft/common/alfstream.h
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#ifndef AL_FSTREAM_H
|
||||
#define AL_FSTREAM_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
namespace al {
|
||||
|
||||
// Windows' std::ifstream fails with non-ANSI paths since the standard only
|
||||
// specifies names using const char* (or std::string). MSVC has a non-standard
|
||||
// extension using const wchar_t* (or std::wstring?) to handle Unicode paths,
|
||||
// but not all Windows compilers support it. So we have to make our own istream
|
||||
// that accepts UTF-8 paths and forwards to Unicode-aware I/O functions.
|
||||
class filebuf final : public std::streambuf {
|
||||
std::array<char_type,4096> mBuffer;
|
||||
HANDLE mFile{INVALID_HANDLE_VALUE};
|
||||
|
||||
int_type underflow() override;
|
||||
pos_type seekoff(off_type offset, std::ios_base::seekdir whence, std::ios_base::openmode mode) override;
|
||||
pos_type seekpos(pos_type pos, std::ios_base::openmode mode) override;
|
||||
|
||||
public:
|
||||
filebuf() = default;
|
||||
~filebuf() override;
|
||||
|
||||
bool open(const wchar_t *filename, std::ios_base::openmode mode);
|
||||
bool open(const char *filename, std::ios_base::openmode mode);
|
||||
|
||||
bool is_open() const noexcept { return mFile != INVALID_HANDLE_VALUE; }
|
||||
|
||||
void close();
|
||||
};
|
||||
|
||||
// Inherit from std::istream to use our custom streambuf
|
||||
class ifstream final : public std::istream {
|
||||
filebuf mStreamBuf;
|
||||
|
||||
public:
|
||||
ifstream(const wchar_t *filename, std::ios_base::openmode mode = std::ios_base::in);
|
||||
ifstream(const std::wstring &filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
: ifstream(filename.c_str(), mode) { }
|
||||
ifstream(const char *filename, std::ios_base::openmode mode = std::ios_base::in);
|
||||
ifstream(const std::string &filename, std::ios_base::openmode mode = std::ios_base::in)
|
||||
: ifstream(filename.c_str(), mode) { }
|
||||
~ifstream() override;
|
||||
|
||||
bool is_open() const noexcept { return mStreamBuf.is_open(); }
|
||||
|
||||
void close() { mStreamBuf.close(); }
|
||||
};
|
||||
|
||||
} // namespace al
|
||||
|
||||
#else /* _WIN32 */
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace al {
|
||||
|
||||
using filebuf = std::filebuf;
|
||||
using ifstream = std::ifstream;
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* AL_FSTREAM_H */
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef AL_ALIGN_H
|
||||
#define AL_ALIGN_H
|
||||
|
||||
#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS)
|
||||
#include <stdalign.h>
|
||||
#endif
|
||||
|
||||
#ifndef alignas
|
||||
#if defined(IN_IDE_PARSER)
|
||||
/* KDevelop has problems with our align macro, so just use nothing for parsing. */
|
||||
#define alignas(x)
|
||||
#elif defined(HAVE_C11_ALIGNAS)
|
||||
#define alignas _Alignas
|
||||
#else
|
||||
/* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For
|
||||
* maximum compatibility, only provide constant integer values to alignas. */
|
||||
#define alignas(_x) ALIGN(_x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* AL_ALIGN_H */
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define LIKELY(x) __builtin_expect(!!(x), !0)
|
||||
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#else
|
||||
#define LIKELY(x) (!!(x))
|
||||
#define UNLIKELY(x) (!!(x))
|
||||
#endif
|
||||
|
||||
|
||||
void *al_malloc(size_t alignment, size_t size)
|
||||
{
|
||||
#if defined(HAVE_ALIGNED_ALLOC)
|
||||
size = (size+(alignment-1))&~(alignment-1);
|
||||
return aligned_alloc(alignment, size);
|
||||
#elif defined(HAVE_POSIX_MEMALIGN)
|
||||
void *ret;
|
||||
if(posix_memalign(&ret, alignment, size) == 0)
|
||||
return ret;
|
||||
return NULL;
|
||||
#elif defined(HAVE__ALIGNED_MALLOC)
|
||||
return _aligned_malloc(size, alignment);
|
||||
#else
|
||||
char *ret = malloc(size+alignment);
|
||||
if(ret != NULL)
|
||||
{
|
||||
*(ret++) = 0x00;
|
||||
while(((ptrdiff_t)ret&(alignment-1)) != 0)
|
||||
*(ret++) = 0x55;
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *al_calloc(size_t alignment, size_t size)
|
||||
{
|
||||
void *ret = al_malloc(alignment, size);
|
||||
if(ret) memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void al_free(void *ptr)
|
||||
{
|
||||
#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN)
|
||||
free(ptr);
|
||||
#elif defined(HAVE__ALIGNED_MALLOC)
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
if(ptr != NULL)
|
||||
{
|
||||
char *finder = ptr;
|
||||
do {
|
||||
--finder;
|
||||
} while(*finder == 0x55);
|
||||
free(finder);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t al_get_page_size(void)
|
||||
{
|
||||
static size_t psize = 0;
|
||||
if(UNLIKELY(!psize))
|
||||
{
|
||||
#ifdef HAVE_SYSCONF
|
||||
#if defined(_SC_PAGESIZE)
|
||||
if(!psize) psize = sysconf(_SC_PAGESIZE);
|
||||
#elif defined(_SC_PAGE_SIZE)
|
||||
if(!psize) psize = sysconf(_SC_PAGE_SIZE);
|
||||
#endif
|
||||
#endif /* HAVE_SYSCONF */
|
||||
#ifdef _WIN32
|
||||
if(!psize)
|
||||
{
|
||||
SYSTEM_INFO sysinfo;
|
||||
memset(&sysinfo, 0, sizeof(sysinfo));
|
||||
|
||||
GetSystemInfo(&sysinfo);
|
||||
psize = sysinfo.dwPageSize;
|
||||
}
|
||||
#endif
|
||||
if(!psize) psize = DEF_ALIGN;
|
||||
}
|
||||
return psize;
|
||||
}
|
||||
|
||||
int al_is_sane_alignment_allocator(void)
|
||||
{
|
||||
#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) || defined(HAVE__ALIGNED_MALLOC)
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
61
Engine/lib/openal-soft/common/almalloc.cpp
Normal file
61
Engine/lib/openal-soft/common/almalloc.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#ifdef HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
|
||||
void *al_malloc(size_t alignment, size_t size)
|
||||
{
|
||||
assert((alignment & (alignment-1)) == 0);
|
||||
alignment = std::max(alignment, alignof(std::max_align_t));
|
||||
|
||||
#if defined(HAVE_POSIX_MEMALIGN)
|
||||
void *ret{};
|
||||
if(posix_memalign(&ret, alignment, size) == 0)
|
||||
return ret;
|
||||
return nullptr;
|
||||
#elif defined(HAVE__ALIGNED_MALLOC)
|
||||
return _aligned_malloc(size, alignment);
|
||||
#else
|
||||
size_t total_size{size + alignment-1 + sizeof(void*)};
|
||||
void *base{std::malloc(total_size)};
|
||||
if(base != nullptr)
|
||||
{
|
||||
void *aligned_ptr{static_cast<char*>(base) + sizeof(void*)};
|
||||
total_size -= sizeof(void*);
|
||||
|
||||
std::align(alignment, size, aligned_ptr, total_size);
|
||||
*(static_cast<void**>(aligned_ptr)-1) = base;
|
||||
base = aligned_ptr;
|
||||
}
|
||||
return base;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *al_calloc(size_t alignment, size_t size)
|
||||
{
|
||||
void *ret{al_malloc(alignment, size)};
|
||||
if(ret) std::memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void al_free(void *ptr) noexcept
|
||||
{
|
||||
#if defined(HAVE_POSIX_MEMALIGN)
|
||||
std::free(ptr);
|
||||
#elif defined(HAVE__ALIGNED_MALLOC)
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
if(ptr != nullptr)
|
||||
std::free(*(static_cast<void**>(ptr) - 1));
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,30 +1,291 @@
|
|||
#ifndef AL_MALLOC_H
|
||||
#define AL_MALLOC_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "pragmadefs.h"
|
||||
|
||||
/* Minimum alignment required by posix_memalign. */
|
||||
#define DEF_ALIGN sizeof(void*)
|
||||
|
||||
void *al_malloc(size_t alignment, size_t size);
|
||||
void *al_calloc(size_t alignment, size_t size);
|
||||
void al_free(void *ptr);
|
||||
[[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_malloc(size_t alignment, size_t size);
|
||||
[[gnu::alloc_align(1), gnu::alloc_size(2)]] void *al_calloc(size_t alignment, size_t size);
|
||||
void al_free(void *ptr) noexcept;
|
||||
|
||||
size_t al_get_page_size(void);
|
||||
|
||||
/**
|
||||
* Returns non-0 if the allocation function has direct alignment handling.
|
||||
* Otherwise, the standard malloc is used with an over-allocation and pointer
|
||||
* offset strategy.
|
||||
#define DISABLE_ALLOC() \
|
||||
void *operator new(size_t) = delete; \
|
||||
void *operator new[](size_t) = delete; \
|
||||
void operator delete(void*) noexcept = delete; \
|
||||
void operator delete[](void*) noexcept = delete;
|
||||
|
||||
#define DEF_NEWDEL(T) \
|
||||
void *operator new(size_t size) \
|
||||
{ \
|
||||
void *ret = al_malloc(alignof(T), size); \
|
||||
if(!ret) throw std::bad_alloc(); \
|
||||
return ret; \
|
||||
} \
|
||||
void *operator new[](size_t size) { return operator new(size); } \
|
||||
void operator delete(void *block) noexcept { al_free(block); } \
|
||||
void operator delete[](void *block) noexcept { operator delete(block); }
|
||||
|
||||
#define DEF_PLACE_NEWDEL() \
|
||||
void *operator new(size_t /*size*/, void *ptr) noexcept { return ptr; } \
|
||||
void *operator new[](size_t /*size*/, void *ptr) noexcept { return ptr; } \
|
||||
void operator delete(void *block, void*) noexcept { al_free(block); } \
|
||||
void operator delete(void *block) noexcept { al_free(block); } \
|
||||
void operator delete[](void *block, void*) noexcept { al_free(block); } \
|
||||
void operator delete[](void *block) noexcept { al_free(block); }
|
||||
|
||||
enum FamCount : size_t { };
|
||||
|
||||
#define DEF_FAM_NEWDEL(T, FamMem) \
|
||||
static constexpr size_t Sizeof(size_t count) noexcept \
|
||||
{ \
|
||||
return std::max<size_t>(sizeof(T), \
|
||||
decltype(FamMem)::Sizeof(count, offsetof(T, FamMem))); \
|
||||
} \
|
||||
\
|
||||
void *operator new(size_t /*size*/, FamCount count) \
|
||||
{ \
|
||||
if(void *ret{al_malloc(alignof(T), T::Sizeof(count))}) \
|
||||
return ret; \
|
||||
throw std::bad_alloc(); \
|
||||
} \
|
||||
void *operator new[](size_t /*size*/) = delete; \
|
||||
void operator delete(void *block, FamCount) { al_free(block); } \
|
||||
void operator delete(void *block) noexcept { al_free(block); } \
|
||||
void operator delete[](void* /*block*/) = delete;
|
||||
|
||||
|
||||
namespace al {
|
||||
|
||||
template<typename T, std::size_t alignment=alignof(T)>
|
||||
struct allocator {
|
||||
using value_type = T;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using is_always_equal = std::true_type;
|
||||
|
||||
template<typename U>
|
||||
struct rebind {
|
||||
using other = allocator<U, (alignment<alignof(U))?alignof(U):alignment>;
|
||||
};
|
||||
|
||||
constexpr explicit allocator() noexcept = default;
|
||||
template<typename U, std::size_t N>
|
||||
constexpr explicit allocator(const allocator<U,N>&) noexcept { }
|
||||
|
||||
T *allocate(std::size_t n)
|
||||
{
|
||||
if(n > std::numeric_limits<std::size_t>::max()/sizeof(T)) throw std::bad_alloc();
|
||||
if(auto p = al_malloc(alignment, n*sizeof(T))) return static_cast<T*>(p);
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
void deallocate(T *p, std::size_t) noexcept { al_free(p); }
|
||||
};
|
||||
template<typename T, std::size_t N, typename U, std::size_t M>
|
||||
bool operator==(const allocator<T,N>&, const allocator<U,M>&) noexcept { return true; }
|
||||
template<typename T, std::size_t N, typename U, std::size_t M>
|
||||
bool operator!=(const allocator<T,N>&, const allocator<U,M>&) noexcept { return false; }
|
||||
|
||||
template<size_t alignment, typename T>
|
||||
[[gnu::assume_aligned(alignment)]] inline T* assume_aligned(T *ptr) noexcept { return ptr; }
|
||||
|
||||
/* At least VS 2015 complains that 'ptr' is unused when the given type's
|
||||
* destructor is trivial (a no-op). So disable that warning for this call.
|
||||
*/
|
||||
int al_is_sane_alignment_allocator(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
DIAGNOSTIC_PUSH
|
||||
msc_pragma(warning(disable : 4100))
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<!std::is_array<T>::value>
|
||||
destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
|
||||
{ ptr->~T(); }
|
||||
DIAGNOSTIC_POP
|
||||
template<typename T>
|
||||
constexpr std::enable_if_t<std::is_array<T>::value>
|
||||
destroy_at(T *ptr) noexcept(std::is_nothrow_destructible<T>::value)
|
||||
{
|
||||
for(auto &elem : *ptr)
|
||||
al::destroy_at(std::addressof(elem));
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
constexpr void destroy(T first, T end)
|
||||
{
|
||||
while(first != end)
|
||||
{
|
||||
al::destroy_at(std::addressof(*first));
|
||||
++first;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename N>
|
||||
constexpr std::enable_if_t<std::is_integral<N>::value,T>
|
||||
destroy_n(T first, N count)
|
||||
{
|
||||
if(count != 0)
|
||||
{
|
||||
do {
|
||||
al::destroy_at(std::addressof(*first));
|
||||
++first;
|
||||
} while(--count);
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
|
||||
template<typename T, typename N>
|
||||
inline std::enable_if_t<std::is_integral<N>::value,T>
|
||||
uninitialized_default_construct_n(T first, N count)
|
||||
{
|
||||
using ValueT = typename std::iterator_traits<T>::value_type;
|
||||
T current{first};
|
||||
if(count != 0)
|
||||
{
|
||||
try {
|
||||
do {
|
||||
::new(static_cast<void*>(std::addressof(*current))) ValueT;
|
||||
++current;
|
||||
} while(--count);
|
||||
}
|
||||
catch(...) {
|
||||
al::destroy(first, current);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
/* Storage for flexible array data. This is trivially destructible if type T is
|
||||
* trivially destructible.
|
||||
*/
|
||||
template<typename T, size_t alignment, bool = std::is_trivially_destructible<T>::value>
|
||||
struct FlexArrayStorage;
|
||||
|
||||
template<typename T, size_t alignment>
|
||||
struct FlexArrayStorage<T,alignment,true> {
|
||||
const size_t mSize;
|
||||
union {
|
||||
char mDummy;
|
||||
alignas(alignment) T mArray[1];
|
||||
};
|
||||
|
||||
static constexpr size_t Sizeof(size_t count, size_t base=0u) noexcept
|
||||
{
|
||||
return std::max<size_t>(offsetof(FlexArrayStorage, mArray) + sizeof(T)*count,
|
||||
sizeof(FlexArrayStorage)) + base;
|
||||
}
|
||||
|
||||
FlexArrayStorage(size_t size) : mSize{size}
|
||||
{ al::uninitialized_default_construct_n(mArray, mSize); }
|
||||
~FlexArrayStorage() = default;
|
||||
|
||||
FlexArrayStorage(const FlexArrayStorage&) = delete;
|
||||
FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
|
||||
};
|
||||
|
||||
template<typename T, size_t alignment>
|
||||
struct FlexArrayStorage<T,alignment,false> {
|
||||
const size_t mSize;
|
||||
union {
|
||||
char mDummy;
|
||||
alignas(alignment) T mArray[1];
|
||||
};
|
||||
|
||||
static constexpr size_t Sizeof(size_t count, size_t base) noexcept
|
||||
{
|
||||
return std::max<size_t>(offsetof(FlexArrayStorage, mArray) + sizeof(T)*count,
|
||||
sizeof(FlexArrayStorage)) + base;
|
||||
}
|
||||
|
||||
FlexArrayStorage(size_t size) : mSize{size}
|
||||
{ al::uninitialized_default_construct_n(mArray, mSize); }
|
||||
~FlexArrayStorage() { al::destroy_n(mArray, mSize); }
|
||||
|
||||
FlexArrayStorage(const FlexArrayStorage&) = delete;
|
||||
FlexArrayStorage& operator=(const FlexArrayStorage&) = delete;
|
||||
};
|
||||
|
||||
/* A flexible array type. Used either standalone or at the end of a parent
|
||||
* struct, with placement new, to have a run-time-sized array that's embedded
|
||||
* with its size.
|
||||
*/
|
||||
template<typename T, size_t alignment=alignof(T)>
|
||||
struct FlexArray {
|
||||
using element_type = T;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using index_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
using Storage_t_ = FlexArrayStorage<element_type,alignment>;
|
||||
|
||||
Storage_t_ mStore;
|
||||
|
||||
static constexpr index_type Sizeof(index_type count, index_type base=0u) noexcept
|
||||
{ return Storage_t_::Sizeof(count, base); }
|
||||
static std::unique_ptr<FlexArray> Create(index_type count)
|
||||
{
|
||||
void *ptr{al_calloc(alignof(FlexArray), Sizeof(count))};
|
||||
return std::unique_ptr<FlexArray>{new(ptr) FlexArray{count}};
|
||||
}
|
||||
|
||||
FlexArray(index_type size) : mStore{size} { }
|
||||
~FlexArray() = default;
|
||||
|
||||
index_type size() const noexcept { return mStore.mSize; }
|
||||
bool empty() const noexcept { return mStore.mSize == 0; }
|
||||
|
||||
pointer data() noexcept { return mStore.mArray; }
|
||||
const_pointer data() const noexcept { return mStore.mArray; }
|
||||
|
||||
reference operator[](index_type i) noexcept { return mStore.mArray[i]; }
|
||||
const_reference operator[](index_type i) const noexcept { return mStore.mArray[i]; }
|
||||
|
||||
reference front() noexcept { return mStore.mArray[0]; }
|
||||
const_reference front() const noexcept { return mStore.mArray[0]; }
|
||||
|
||||
reference back() noexcept { return mStore.mArray[mStore.mSize-1]; }
|
||||
const_reference back() const noexcept { return mStore.mArray[mStore.mSize-1]; }
|
||||
|
||||
iterator begin() noexcept { return mStore.mArray; }
|
||||
const_iterator begin() const noexcept { return mStore.mArray; }
|
||||
const_iterator cbegin() const noexcept { return mStore.mArray; }
|
||||
iterator end() noexcept { return mStore.mArray + mStore.mSize; }
|
||||
const_iterator end() const noexcept { return mStore.mArray + mStore.mSize; }
|
||||
const_iterator cend() const noexcept { return mStore.mArray + mStore.mSize; }
|
||||
|
||||
reverse_iterator rbegin() noexcept { return end(); }
|
||||
const_reverse_iterator rbegin() const noexcept { return end(); }
|
||||
const_reverse_iterator crbegin() const noexcept { return cend(); }
|
||||
reverse_iterator rend() noexcept { return begin(); }
|
||||
const_reverse_iterator rend() const noexcept { return begin(); }
|
||||
const_reverse_iterator crend() const noexcept { return cbegin(); }
|
||||
|
||||
DEF_PLACE_NEWDEL()
|
||||
};
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_MALLOC_H */
|
||||
|
|
|
|||
274
Engine/lib/openal-soft/common/alnumeric.h
Normal file
274
Engine/lib/openal-soft/common/alnumeric.h
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
#ifndef AL_NUMERIC_H
|
||||
#define AL_NUMERIC_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#ifdef HAVE_INTRIN_H
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#ifdef HAVE_SSE_INTRINSICS
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
inline constexpr int64_t operator "" _i64(unsigned long long int n) noexcept { return static_cast<int64_t>(n); }
|
||||
inline constexpr uint64_t operator "" _u64(unsigned long long int n) noexcept { return static_cast<uint64_t>(n); }
|
||||
|
||||
|
||||
constexpr inline float minf(float a, float b) noexcept
|
||||
{ return ((a > b) ? b : a); }
|
||||
constexpr inline float maxf(float a, float b) noexcept
|
||||
{ return ((a > b) ? a : b); }
|
||||
constexpr inline float clampf(float val, float min, float max) noexcept
|
||||
{ return minf(max, maxf(min, val)); }
|
||||
|
||||
constexpr inline double mind(double a, double b) noexcept
|
||||
{ return ((a > b) ? b : a); }
|
||||
constexpr inline double maxd(double a, double b) noexcept
|
||||
{ return ((a > b) ? a : b); }
|
||||
constexpr inline double clampd(double val, double min, double max) noexcept
|
||||
{ return mind(max, maxd(min, val)); }
|
||||
|
||||
constexpr inline unsigned int minu(unsigned int a, unsigned int b) noexcept
|
||||
{ return ((a > b) ? b : a); }
|
||||
constexpr inline unsigned int maxu(unsigned int a, unsigned int b) noexcept
|
||||
{ return ((a > b) ? a : b); }
|
||||
constexpr inline unsigned int clampu(unsigned int val, unsigned int min, unsigned int max) noexcept
|
||||
{ return minu(max, maxu(min, val)); }
|
||||
|
||||
constexpr inline int mini(int a, int b) noexcept
|
||||
{ return ((a > b) ? b : a); }
|
||||
constexpr inline int maxi(int a, int b) noexcept
|
||||
{ return ((a > b) ? a : b); }
|
||||
constexpr inline int clampi(int val, int min, int max) noexcept
|
||||
{ return mini(max, maxi(min, val)); }
|
||||
|
||||
constexpr inline int64_t mini64(int64_t a, int64_t b) noexcept
|
||||
{ return ((a > b) ? b : a); }
|
||||
constexpr inline int64_t maxi64(int64_t a, int64_t b) noexcept
|
||||
{ return ((a > b) ? a : b); }
|
||||
constexpr inline int64_t clampi64(int64_t val, int64_t min, int64_t max) noexcept
|
||||
{ return mini64(max, maxi64(min, val)); }
|
||||
|
||||
constexpr inline uint64_t minu64(uint64_t a, uint64_t b) noexcept
|
||||
{ return ((a > b) ? b : a); }
|
||||
constexpr inline uint64_t maxu64(uint64_t a, uint64_t b) noexcept
|
||||
{ return ((a > b) ? a : b); }
|
||||
constexpr inline uint64_t clampu64(uint64_t val, uint64_t min, uint64_t max) noexcept
|
||||
{ return minu64(max, maxu64(min, val)); }
|
||||
|
||||
constexpr inline size_t minz(size_t a, size_t b) noexcept
|
||||
{ return ((a > b) ? b : a); }
|
||||
constexpr inline size_t maxz(size_t a, size_t b) noexcept
|
||||
{ return ((a > b) ? a : b); }
|
||||
constexpr inline size_t clampz(size_t val, size_t min, size_t max) noexcept
|
||||
{ return minz(max, maxz(min, val)); }
|
||||
|
||||
|
||||
constexpr inline float lerp(float val1, float val2, float mu) noexcept
|
||||
{ return val1 + (val2-val1)*mu; }
|
||||
constexpr inline float cubic(float val1, float val2, float val3, float val4, float mu) noexcept
|
||||
{
|
||||
const float mu2{mu*mu}, mu3{mu2*mu};
|
||||
const float a0{-0.5f*mu3 + mu2 + -0.5f*mu};
|
||||
const float a1{ 1.5f*mu3 + -2.5f*mu2 + 1.0f};
|
||||
const float a2{-1.5f*mu3 + 2.0f*mu2 + 0.5f*mu};
|
||||
const float a3{ 0.5f*mu3 + -0.5f*mu2};
|
||||
return val1*a0 + val2*a1 + val3*a2 + val4*a3;
|
||||
}
|
||||
|
||||
|
||||
/** Find the next power-of-2 for non-power-of-2 numbers. */
|
||||
inline uint32_t NextPowerOf2(uint32_t value) noexcept
|
||||
{
|
||||
if(value > 0)
|
||||
{
|
||||
value--;
|
||||
value |= value>>1;
|
||||
value |= value>>2;
|
||||
value |= value>>4;
|
||||
value |= value>>8;
|
||||
value |= value>>16;
|
||||
}
|
||||
return value+1;
|
||||
}
|
||||
|
||||
/** Round up a value to the next multiple. */
|
||||
inline size_t RoundUp(size_t value, size_t r) noexcept
|
||||
{
|
||||
value += r-1;
|
||||
return value - (value%r);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fast float-to-int conversion. No particular rounding mode is assumed; the
|
||||
* IEEE-754 default is round-to-nearest with ties-to-even, though an app could
|
||||
* change it on its own threads. On some systems, a truncating conversion may
|
||||
* always be the fastest method.
|
||||
*/
|
||||
inline int fastf2i(float f) noexcept
|
||||
{
|
||||
#if defined(HAVE_SSE_INTRINSICS)
|
||||
return _mm_cvt_ss2si(_mm_set_ss(f));
|
||||
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86_FP)
|
||||
|
||||
int i;
|
||||
__asm fld f
|
||||
__asm fistp i
|
||||
return i;
|
||||
|
||||
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
||||
|
||||
int i;
|
||||
#ifdef __SSE_MATH__
|
||||
__asm__("cvtss2si %1, %0" : "=r"(i) : "x"(f));
|
||||
#else
|
||||
__asm__ __volatile__("fistpl %0" : "=m"(i) : "t"(f) : "st");
|
||||
#endif
|
||||
return i;
|
||||
|
||||
#else
|
||||
|
||||
return static_cast<int>(f);
|
||||
#endif
|
||||
}
|
||||
inline unsigned int fastf2u(float f) noexcept
|
||||
{ return static_cast<unsigned int>(fastf2i(f)); }
|
||||
|
||||
/** Converts float-to-int using standard behavior (truncation). */
|
||||
inline int float2int(float f) noexcept
|
||||
{
|
||||
#if defined(HAVE_SSE_INTRINSICS)
|
||||
return _mm_cvtt_ss2si(_mm_set_ss(f));
|
||||
|
||||
#elif (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0) \
|
||||
|| ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) \
|
||||
&& !defined(__SSE_MATH__))
|
||||
int sign, shift, mant;
|
||||
union {
|
||||
float f;
|
||||
int i;
|
||||
} conv;
|
||||
|
||||
conv.f = f;
|
||||
sign = (conv.i>>31) | 1;
|
||||
shift = ((conv.i>>23)&0xff) - (127+23);
|
||||
|
||||
/* Over/underflow */
|
||||
if UNLIKELY(shift >= 31 || shift < -23)
|
||||
return 0;
|
||||
|
||||
mant = (conv.i&0x7fffff) | 0x800000;
|
||||
if LIKELY(shift < 0)
|
||||
return (mant >> -shift) * sign;
|
||||
return (mant << shift) * sign;
|
||||
|
||||
#else
|
||||
|
||||
return static_cast<int>(f);
|
||||
#endif
|
||||
}
|
||||
inline unsigned int float2uint(float f) noexcept
|
||||
{ return static_cast<unsigned int>(float2int(f)); }
|
||||
|
||||
/** Converts double-to-int using standard behavior (truncation). */
|
||||
inline int double2int(double d) noexcept
|
||||
{
|
||||
#if defined(HAVE_SSE_INTRINSICS)
|
||||
return _mm_cvttsd_si32(_mm_set_sd(d));
|
||||
|
||||
#elif (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) \
|
||||
|| ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) \
|
||||
&& !defined(__SSE2_MATH__))
|
||||
int sign, shift;
|
||||
int64_t mant;
|
||||
union {
|
||||
double d;
|
||||
int64_t i64;
|
||||
} conv;
|
||||
|
||||
conv.d = d;
|
||||
sign = (conv.i64 >> 63) | 1;
|
||||
shift = ((conv.i64 >> 52) & 0x7ff) - (1023 + 52);
|
||||
|
||||
/* Over/underflow */
|
||||
if UNLIKELY(shift >= 63 || shift < -52)
|
||||
return 0;
|
||||
|
||||
mant = (conv.i64 & 0xfffffffffffff_i64) | 0x10000000000000_i64;
|
||||
if LIKELY(shift < 0)
|
||||
return (int)(mant >> -shift) * sign;
|
||||
return (int)(mant << shift) * sign;
|
||||
|
||||
#else
|
||||
|
||||
return static_cast<int>(d);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Rounds a float to the nearest integral value, according to the current
|
||||
* rounding mode. This is essentially an inlined version of rintf, although
|
||||
* makes fewer promises (e.g. -0 or -0.25 rounded to 0 may result in +0).
|
||||
*/
|
||||
inline float fast_roundf(float f) noexcept
|
||||
{
|
||||
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) \
|
||||
&& !defined(__SSE_MATH__)
|
||||
|
||||
float out;
|
||||
__asm__ __volatile__("frndint" : "=t"(out) : "0"(f));
|
||||
return out;
|
||||
|
||||
#elif (defined(__GNUC__) || defined(__clang__)) && defined(__aarch64__)
|
||||
|
||||
float out;
|
||||
__asm__ volatile("frintx %s0, %s1" : "=w"(out) : "w"(f));
|
||||
return out;
|
||||
|
||||
#else
|
||||
|
||||
/* Integral limit, where sub-integral precision is not available for
|
||||
* floats.
|
||||
*/
|
||||
static const float ilim[2]{
|
||||
8388608.0f /* 0x1.0p+23 */,
|
||||
-8388608.0f /* -0x1.0p+23 */
|
||||
};
|
||||
unsigned int sign, expo;
|
||||
union {
|
||||
float f;
|
||||
unsigned int i;
|
||||
} conv;
|
||||
|
||||
conv.f = f;
|
||||
sign = (conv.i>>31)&0x01;
|
||||
expo = (conv.i>>23)&0xff;
|
||||
|
||||
if UNLIKELY(expo >= 150/*+23*/)
|
||||
{
|
||||
/* An exponent (base-2) of 23 or higher is incapable of sub-integral
|
||||
* precision, so it's already an integral value. We don't need to worry
|
||||
* about infinity or NaN here.
|
||||
*/
|
||||
return f;
|
||||
}
|
||||
/* Adding the integral limit to the value (with a matching sign) forces a
|
||||
* result that has no sub-integral precision, and is consequently forced to
|
||||
* round to an integral value. Removing the integral limit then restores
|
||||
* the initial value rounded to the integral. The compiler should not
|
||||
* optimize this out because of non-associative rules on floating-point
|
||||
* math (as long as you don't use -fassociative-math,
|
||||
* -funsafe-math-optimizations, -ffast-math, or -Ofast, in which case this
|
||||
* may break).
|
||||
*/
|
||||
f += ilim[sign];
|
||||
return f - ilim[sign];
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* AL_NUMERIC_H */
|
||||
161
Engine/lib/openal-soft/common/aloptional.h
Normal file
161
Engine/lib/openal-soft/common/aloptional.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
#ifndef AL_OPTIONAL_H
|
||||
#define AL_OPTIONAL_H
|
||||
|
||||
#include <initializer_list>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
namespace al {
|
||||
|
||||
struct nullopt_t { };
|
||||
struct in_place_t { };
|
||||
|
||||
constexpr nullopt_t nullopt{};
|
||||
constexpr in_place_t in_place{};
|
||||
|
||||
|
||||
template<typename T, bool = std::is_trivially_destructible<T>::value>
|
||||
struct optional_storage;
|
||||
|
||||
template<typename T>
|
||||
struct optional_storage<T, true> {
|
||||
bool mHasValue{false};
|
||||
union {
|
||||
char mDummy;
|
||||
T mValue;
|
||||
};
|
||||
|
||||
optional_storage() { }
|
||||
template<typename ...Args>
|
||||
explicit optional_storage(in_place_t, Args&& ...args)
|
||||
: mHasValue{true}, mValue{std::forward<Args>(args)...}
|
||||
{ }
|
||||
~optional_storage() = default;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct optional_storage<T, false> {
|
||||
bool mHasValue{false};
|
||||
union {
|
||||
char mDummy;
|
||||
T mValue;
|
||||
};
|
||||
|
||||
optional_storage() { }
|
||||
template<typename ...Args>
|
||||
explicit optional_storage(in_place_t, Args&& ...args)
|
||||
: mHasValue{true}, mValue{std::forward<Args>(args)...}
|
||||
{ }
|
||||
~optional_storage() { if(mHasValue) al::destroy_at(std::addressof(mValue)); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class optional {
|
||||
using storage_t = optional_storage<T>;
|
||||
|
||||
storage_t mStore;
|
||||
|
||||
template<typename... Args>
|
||||
void doConstruct(Args&& ...args)
|
||||
{
|
||||
::new(std::addressof(mStore.mValue)) T{std::forward<Args>(args)...};
|
||||
mStore.mHasValue = true;
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
optional() = default;
|
||||
optional(nullopt_t) noexcept { }
|
||||
optional(const optional &rhs) { if(rhs) doConstruct(*rhs); }
|
||||
optional(optional&& rhs) { if(rhs) doConstruct(std::move(*rhs)); }
|
||||
template<typename ...Args>
|
||||
explicit optional(in_place_t, Args&& ...args)
|
||||
: mStore{al::in_place, std::forward<Args>(args)...}
|
||||
{ }
|
||||
~optional() = default;
|
||||
|
||||
optional& operator=(nullopt_t) noexcept { reset(); return *this; }
|
||||
std::enable_if_t<std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
optional&> operator=(const optional &rhs)
|
||||
{
|
||||
if(!rhs)
|
||||
reset();
|
||||
else if(*this)
|
||||
mStore.mValue = *rhs;
|
||||
else
|
||||
doConstruct(*rhs);
|
||||
return *this;
|
||||
}
|
||||
std::enable_if_t<std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,
|
||||
optional&> operator=(optional&& rhs)
|
||||
{
|
||||
if(!rhs)
|
||||
reset();
|
||||
else if(*this)
|
||||
mStore.mValue = std::move(*rhs);
|
||||
else
|
||||
doConstruct(std::move(*rhs));
|
||||
return *this;
|
||||
}
|
||||
template<typename U=T>
|
||||
std::enable_if_t<std::is_constructible<T, U>::value
|
||||
&& std::is_assignable<T&, U>::value
|
||||
&& !std::is_same<std::decay_t<U>, optional<T>>::value
|
||||
&& (!std::is_same<std::decay_t<U>, T>::value || !std::is_scalar<U>::value),
|
||||
optional&> operator=(U&& rhs)
|
||||
{
|
||||
if(*this)
|
||||
mStore.mValue = std::forward<U>(rhs);
|
||||
else
|
||||
doConstruct(std::forward<U>(rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T* operator->() const { return std::addressof(mStore.mValue); }
|
||||
T* operator->() { return std::addressof(mStore.mValue); }
|
||||
const T& operator*() const& { return this->mValue; }
|
||||
T& operator*() & { return mStore.mValue; }
|
||||
const T&& operator*() const&& { return std::move(mStore.mValue); }
|
||||
T&& operator*() && { return std::move(mStore.mValue); }
|
||||
|
||||
operator bool() const noexcept { return mStore.mHasValue; }
|
||||
bool has_value() const noexcept { return mStore.mHasValue; }
|
||||
|
||||
T& value() & { return mStore.mValue; }
|
||||
const T& value() const& { return mStore.mValue; }
|
||||
T&& value() && { return std::move(mStore.mValue); }
|
||||
const T&& value() const&& { return std::move(mStore.mValue); }
|
||||
|
||||
template<typename U>
|
||||
T value_or(U&& defval) const&
|
||||
{ return bool{*this} ? **this : static_cast<T>(std::forward<U>(defval)); }
|
||||
template<typename U>
|
||||
T value_or(U&& defval) &&
|
||||
{ return bool{*this} ? std::move(**this) : static_cast<T>(std::forward<U>(defval)); }
|
||||
|
||||
void reset() noexcept
|
||||
{
|
||||
if(mStore.mHasValue)
|
||||
al::destroy_at(std::addressof(mStore.mValue));
|
||||
mStore.mHasValue = false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline optional<std::decay_t<T>> make_optional(T&& arg)
|
||||
{ return optional<std::decay_t<T>>{in_place, std::forward<T>(arg)}; }
|
||||
|
||||
template<typename T, typename... Args>
|
||||
inline optional<T> make_optional(Args&& ...args)
|
||||
{ return optional<T>{in_place, std::forward<Args>(args)...}; }
|
||||
|
||||
template<typename T, typename U, typename... Args>
|
||||
inline optional<T> make_optional(std::initializer_list<U> il, Args&& ...args)
|
||||
{ return optional<T>{in_place, il, std::forward<Args>(args)...}; }
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_OPTIONAL_H */
|
||||
315
Engine/lib/openal-soft/common/alspan.h
Normal file
315
Engine/lib/openal-soft/common/alspan.h
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
#ifndef AL_SPAN_H
|
||||
#define AL_SPAN_H
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace al {
|
||||
|
||||
template<typename T>
|
||||
constexpr auto size(T &cont) noexcept(noexcept(cont.size())) -> decltype(cont.size())
|
||||
{ return cont.size(); }
|
||||
|
||||
template<typename T>
|
||||
constexpr auto size(const T &cont) noexcept(noexcept(cont.size())) -> decltype(cont.size())
|
||||
{ return cont.size(); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
constexpr size_t size(T (&)[N]) noexcept
|
||||
{ return N; }
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t size(std::initializer_list<T> list) noexcept
|
||||
{ return list.size(); }
|
||||
|
||||
|
||||
template<typename T>
|
||||
constexpr auto data(T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data())
|
||||
{ return cont.data(); }
|
||||
|
||||
template<typename T>
|
||||
constexpr auto data(const T &cont) noexcept(noexcept(cont.data())) -> decltype(cont.data())
|
||||
{ return cont.data(); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
constexpr T* data(T (&arr)[N]) noexcept
|
||||
{ return arr; }
|
||||
|
||||
template<typename T>
|
||||
constexpr const T* data(std::initializer_list<T> list) noexcept
|
||||
{ return list.begin(); }
|
||||
|
||||
|
||||
constexpr size_t dynamic_extent{static_cast<size_t>(-1)};
|
||||
|
||||
template<typename T, size_t E=dynamic_extent>
|
||||
class span;
|
||||
|
||||
namespace detail_ {
|
||||
template<typename... Ts>
|
||||
struct make_void { using type = void; };
|
||||
template<typename... Ts>
|
||||
using void_t = typename make_void<Ts...>::type;
|
||||
|
||||
template<typename T>
|
||||
struct is_span_ : std::false_type { };
|
||||
template<typename T, size_t E>
|
||||
struct is_span_<span<T,E>> : std::true_type { };
|
||||
template<typename T>
|
||||
using is_span = is_span_<std::remove_cv_t<T>>;
|
||||
|
||||
template<typename T>
|
||||
struct is_std_array_ : std::false_type { };
|
||||
template<typename T, size_t N>
|
||||
struct is_std_array_<std::array<T,N>> : std::true_type { };
|
||||
template<typename T>
|
||||
using is_std_array = is_std_array_<std::remove_cv_t<T>>;
|
||||
|
||||
template<typename T, typename = void>
|
||||
struct has_size_and_data : std::false_type { };
|
||||
template<typename T>
|
||||
struct has_size_and_data<T,
|
||||
void_t<decltype(al::size(std::declval<T>())), decltype(al::data(std::declval<T>()))>>
|
||||
: std::true_type { };
|
||||
} // namespace detail_
|
||||
|
||||
#define REQUIRES(...) bool rt_=true, std::enable_if_t<rt_ && (__VA_ARGS__),bool> = true
|
||||
#define IS_VALID_CONTAINER(C) \
|
||||
!detail_::is_span<C>::value && !detail_::is_std_array<C>::value && \
|
||||
!std::is_array<C>::value && detail_::has_size_and_data<C>::value && \
|
||||
std::is_convertible<std::remove_pointer_t<decltype(al::data(std::declval<C&>()))>(*)[],element_type(*)[]>::value
|
||||
|
||||
template<typename T, size_t E>
|
||||
class span {
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using index_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
static constexpr size_t extent{E};
|
||||
|
||||
template<REQUIRES(extent==0)>
|
||||
constexpr span() noexcept { }
|
||||
constexpr span(pointer ptr, index_type /*count*/) : mData{ptr} { }
|
||||
constexpr span(pointer first, pointer /*last*/) : mData{first} { }
|
||||
constexpr span(element_type (&arr)[E]) noexcept : span{al::data(arr), al::size(arr)} { }
|
||||
constexpr span(std::array<value_type,E> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
|
||||
template<REQUIRES(std::is_const<element_type>::value)>
|
||||
constexpr span(const std::array<value_type,E> &arr) noexcept
|
||||
: span{al::data(arr), al::size(arr)}
|
||||
{ }
|
||||
template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
|
||||
constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
|
||||
template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
|
||||
constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
|
||||
template<typename U, REQUIRES(!std::is_same<element_type,U>::value
|
||||
&& std::is_convertible<U(*)[],element_type(*)[]>::value)>
|
||||
constexpr span(const span<U,E> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
|
||||
constexpr span(const span&) noexcept = default;
|
||||
|
||||
constexpr span& operator=(const span &rhs) noexcept = default;
|
||||
|
||||
constexpr reference front() const { return *mData; }
|
||||
constexpr reference back() const { return *(mData+E-1); }
|
||||
constexpr reference operator[](index_type idx) const { return mData[idx]; }
|
||||
constexpr pointer data() const noexcept { return mData; }
|
||||
|
||||
constexpr index_type size() const noexcept { return E; }
|
||||
constexpr index_type size_bytes() const noexcept { return E * sizeof(value_type); }
|
||||
constexpr bool empty() const noexcept { return E == 0; }
|
||||
|
||||
constexpr iterator begin() const noexcept { return mData; }
|
||||
constexpr iterator end() const noexcept { return mData+E; }
|
||||
constexpr const_iterator cbegin() const noexcept { return mData; }
|
||||
constexpr const_iterator cend() const noexcept { return mData+E; }
|
||||
|
||||
constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
|
||||
constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
|
||||
constexpr const_reverse_iterator crbegin() const noexcept
|
||||
{ return const_reverse_iterator{cend()}; }
|
||||
constexpr const_reverse_iterator crend() const noexcept
|
||||
{ return const_reverse_iterator{cbegin()}; }
|
||||
|
||||
template<size_t C>
|
||||
constexpr span<element_type,C> first() const
|
||||
{
|
||||
static_assert(E >= C, "New size exceeds original capacity");
|
||||
return span<element_type,C>{mData, C};
|
||||
}
|
||||
|
||||
template<size_t C>
|
||||
constexpr span<element_type,C> last() const
|
||||
{
|
||||
static_assert(E >= C, "New size exceeds original capacity");
|
||||
return span<element_type,C>{mData+(E-C), C};
|
||||
}
|
||||
|
||||
template<size_t O, size_t C>
|
||||
constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
|
||||
{
|
||||
static_assert(E >= O, "Offset exceeds extent");
|
||||
static_assert(E-O >= C, "New size exceeds original capacity");
|
||||
return span<element_type,C>{mData+O, C};
|
||||
}
|
||||
|
||||
template<size_t O, size_t C=dynamic_extent>
|
||||
constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,E-O>>
|
||||
{
|
||||
static_assert(E >= O, "Offset exceeds extent");
|
||||
return span<element_type,E-O>{mData+O, E-O};
|
||||
}
|
||||
|
||||
/* NOTE: Can't declare objects of a specialized template class prior to
|
||||
* defining the specialization. As a result, these methods need to be
|
||||
* defined later.
|
||||
*/
|
||||
constexpr span<element_type,dynamic_extent> first(size_t count) const;
|
||||
constexpr span<element_type,dynamic_extent> last(size_t count) const;
|
||||
constexpr span<element_type,dynamic_extent> subspan(size_t offset,
|
||||
size_t count=dynamic_extent) const;
|
||||
|
||||
private:
|
||||
pointer mData{nullptr};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class span<T,dynamic_extent> {
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using index_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
|
||||
using pointer = T*;
|
||||
using const_pointer = const T*;
|
||||
using reference = T&;
|
||||
using const_reference = const T&;
|
||||
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
static constexpr size_t extent{dynamic_extent};
|
||||
|
||||
constexpr span() noexcept = default;
|
||||
constexpr span(pointer ptr, index_type count) : mData{ptr}, mDataEnd{ptr+count} { }
|
||||
constexpr span(pointer first, pointer last) : mData{first}, mDataEnd{last} { }
|
||||
template<size_t N>
|
||||
constexpr span(element_type (&arr)[N]) noexcept : span{al::data(arr), al::size(arr)} { }
|
||||
template<size_t N>
|
||||
constexpr span(std::array<value_type,N> &arr) noexcept : span{al::data(arr), al::size(arr)} { }
|
||||
template<size_t N, REQUIRES(std::is_const<element_type>::value)>
|
||||
constexpr span(const std::array<value_type,N> &arr) noexcept
|
||||
: span{al::data(arr), al::size(arr)}
|
||||
{ }
|
||||
template<typename U, REQUIRES(IS_VALID_CONTAINER(U))>
|
||||
constexpr span(U &cont) : span{al::data(cont), al::size(cont)} { }
|
||||
template<typename U, REQUIRES(IS_VALID_CONTAINER(const U))>
|
||||
constexpr span(const U &cont) : span{al::data(cont), al::size(cont)} { }
|
||||
template<typename U, size_t N, REQUIRES((!std::is_same<element_type,U>::value || extent != N)
|
||||
&& std::is_convertible<U(*)[],element_type(*)[]>::value)>
|
||||
constexpr span(const span<U,N> &span_) noexcept : span{al::data(span_), al::size(span_)} { }
|
||||
constexpr span(const span&) noexcept = default;
|
||||
|
||||
constexpr span& operator=(const span &rhs) noexcept = default;
|
||||
|
||||
constexpr reference front() const { return *mData; }
|
||||
constexpr reference back() const { return *(mDataEnd-1); }
|
||||
constexpr reference operator[](index_type idx) const { return mData[idx]; }
|
||||
constexpr pointer data() const noexcept { return mData; }
|
||||
|
||||
constexpr index_type size() const noexcept { return static_cast<index_type>(mDataEnd-mData); }
|
||||
constexpr index_type size_bytes() const noexcept
|
||||
{ return static_cast<index_type>(mDataEnd-mData) * sizeof(value_type); }
|
||||
constexpr bool empty() const noexcept { return mData == mDataEnd; }
|
||||
|
||||
constexpr iterator begin() const noexcept { return mData; }
|
||||
constexpr iterator end() const noexcept { return mDataEnd; }
|
||||
constexpr const_iterator cbegin() const noexcept { return mData; }
|
||||
constexpr const_iterator cend() const noexcept { return mDataEnd; }
|
||||
|
||||
constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; }
|
||||
constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; }
|
||||
constexpr const_reverse_iterator crbegin() const noexcept
|
||||
{ return const_reverse_iterator{cend()}; }
|
||||
constexpr const_reverse_iterator crend() const noexcept
|
||||
{ return const_reverse_iterator{cbegin()}; }
|
||||
|
||||
template<size_t C>
|
||||
constexpr span<element_type,C> first() const
|
||||
{ return span<element_type,C>{mData, C}; }
|
||||
|
||||
constexpr span first(size_t count) const
|
||||
{ return (count >= size()) ? *this : span{mData, mData+count}; }
|
||||
|
||||
template<size_t C>
|
||||
constexpr span<element_type,C> last() const
|
||||
{ return span<element_type,C>{mDataEnd-C, C}; }
|
||||
|
||||
constexpr span last(size_t count) const
|
||||
{ return (count >= size()) ? *this : span{mDataEnd-count, mDataEnd}; }
|
||||
|
||||
template<size_t O, size_t C>
|
||||
constexpr auto subspan() const -> std::enable_if_t<C!=dynamic_extent,span<element_type,C>>
|
||||
{ return span<element_type,C>{mData+O, C}; }
|
||||
|
||||
template<size_t O, size_t C=dynamic_extent>
|
||||
constexpr auto subspan() const -> std::enable_if_t<C==dynamic_extent,span<element_type,C>>
|
||||
{ return span<element_type,C>{mData+O, mDataEnd}; }
|
||||
|
||||
constexpr span subspan(size_t offset, size_t count=dynamic_extent) const
|
||||
{
|
||||
return (offset > size()) ? span{} :
|
||||
(count >= size()-offset) ? span{mData+offset, mDataEnd} :
|
||||
span{mData+offset, mData+offset+count};
|
||||
}
|
||||
|
||||
private:
|
||||
pointer mData{nullptr};
|
||||
pointer mDataEnd{nullptr};
|
||||
};
|
||||
|
||||
template<typename T, size_t E>
|
||||
constexpr inline auto span<T,E>::first(size_t count) const -> span<element_type,dynamic_extent>
|
||||
{
|
||||
return (count >= size()) ? span<element_type>{mData, extent} :
|
||||
span<element_type>{mData, count};
|
||||
}
|
||||
|
||||
template<typename T, size_t E>
|
||||
constexpr inline auto span<T,E>::last(size_t count) const -> span<element_type,dynamic_extent>
|
||||
{
|
||||
return (count >= size()) ? span<element_type>{mData, extent} :
|
||||
span<element_type>{mData+extent-count, count};
|
||||
}
|
||||
|
||||
template<typename T, size_t E>
|
||||
constexpr inline auto span<T,E>::subspan(size_t offset, size_t count) const
|
||||
-> span<element_type,dynamic_extent>
|
||||
{
|
||||
return (offset > size()) ? span<element_type>{} :
|
||||
(count >= size()-offset) ? span<element_type>{mData+offset, mData+extent} :
|
||||
span<element_type>{mData+offset, mData+offset+count};
|
||||
}
|
||||
|
||||
#undef IS_VALID_CONTAINER
|
||||
#undef REQUIRES
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_SPAN_H */
|
||||
45
Engine/lib/openal-soft/common/alstring.cpp
Normal file
45
Engine/lib/openal-soft/common/alstring.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "alstring.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
int to_upper(const char ch)
|
||||
{
|
||||
using char8_traits = std::char_traits<char>;
|
||||
return std::toupper(char8_traits::to_int_type(ch));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace al {
|
||||
|
||||
int strcasecmp(const char *str0, const char *str1) noexcept
|
||||
{
|
||||
do {
|
||||
const int diff{to_upper(*str0) - to_upper(*str1)};
|
||||
if(diff < 0) return -1;
|
||||
if(diff > 0) return 1;
|
||||
} while(*(str0++) && *(str1++));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strncasecmp(const char *str0, const char *str1, std::size_t len) noexcept
|
||||
{
|
||||
if(len > 0)
|
||||
{
|
||||
do {
|
||||
const int diff{to_upper(*str0) - to_upper(*str1)};
|
||||
if(diff < 0) return -1;
|
||||
if(diff > 0) return 1;
|
||||
} while(--len && *(str0++) && *(str1++));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace al
|
||||
30
Engine/lib/openal-soft/common/alstring.h
Normal file
30
Engine/lib/openal-soft/common/alstring.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef AL_STRING_H
|
||||
#define AL_STRING_H
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
|
||||
namespace al {
|
||||
|
||||
template<typename T, typename Tr=std::char_traits<T>>
|
||||
using basic_string = std::basic_string<T, Tr, al::allocator<T>>;
|
||||
|
||||
using string = basic_string<char>;
|
||||
using wstring = basic_string<wchar_t>;
|
||||
using u16string = basic_string<char16_t>;
|
||||
using u32string = basic_string<char32_t>;
|
||||
|
||||
|
||||
/* These would be better served by using a string_view-like span/view with
|
||||
* case-insensitive char traits.
|
||||
*/
|
||||
int strcasecmp(const char *str0, const char *str1) noexcept;
|
||||
int strncasecmp(const char *str0, const char *str1, std::size_t len) noexcept;
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_STRING_H */
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "atomic.h"
|
||||
|
||||
|
||||
extern inline void InitRef(RefCount *ptr, uint value);
|
||||
extern inline uint ReadRef(RefCount *ptr);
|
||||
extern inline uint IncrementRef(RefCount *ptr);
|
||||
extern inline uint DecrementRef(RefCount *ptr);
|
||||
|
|
@ -1,439 +1,33 @@
|
|||
#ifndef AL_ATOMIC_H
|
||||
#define AL_ATOMIC_H
|
||||
|
||||
#include "static_assert.h"
|
||||
#include "bool.h"
|
||||
#include <atomic>
|
||||
|
||||
#ifdef __GNUC__
|
||||
/* This helps cast away the const-ness of a pointer without accidentally
|
||||
* changing the pointer type. This is necessary due to Clang's inability to use
|
||||
* atomic_load on a const _Atomic variable.
|
||||
*/
|
||||
#define CONST_CAST(T, V) __extension__({ \
|
||||
const T _tmp = (V); \
|
||||
(T)_tmp; \
|
||||
})
|
||||
#else
|
||||
#define CONST_CAST(T, V) ((T)(V))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
using RefCount = std::atomic<unsigned int>;
|
||||
|
||||
/* Atomics using C11 */
|
||||
#ifdef HAVE_C11_ATOMIC
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#define almemory_order memory_order
|
||||
#define almemory_order_relaxed memory_order_relaxed
|
||||
#define almemory_order_consume memory_order_consume
|
||||
#define almemory_order_acquire memory_order_acquire
|
||||
#define almemory_order_release memory_order_release
|
||||
#define almemory_order_acq_rel memory_order_acq_rel
|
||||
#define almemory_order_seq_cst memory_order_seq_cst
|
||||
|
||||
#define ATOMIC(T) T _Atomic
|
||||
#define ATOMIC_FLAG atomic_flag
|
||||
|
||||
#define ATOMIC_INIT atomic_init
|
||||
#define ATOMIC_INIT_STATIC ATOMIC_VAR_INIT
|
||||
/*#define ATOMIC_FLAG_INIT ATOMIC_FLAG_INIT*/
|
||||
|
||||
#define ATOMIC_LOAD atomic_load_explicit
|
||||
#define ATOMIC_STORE atomic_store_explicit
|
||||
|
||||
#define ATOMIC_ADD atomic_fetch_add_explicit
|
||||
#define ATOMIC_SUB atomic_fetch_sub_explicit
|
||||
|
||||
#define ATOMIC_EXCHANGE atomic_exchange_explicit
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG atomic_compare_exchange_strong_explicit
|
||||
#define ATOMIC_COMPARE_EXCHANGE_WEAK atomic_compare_exchange_weak_explicit
|
||||
|
||||
#define ATOMIC_FLAG_TEST_AND_SET atomic_flag_test_and_set_explicit
|
||||
#define ATOMIC_FLAG_CLEAR atomic_flag_clear_explicit
|
||||
|
||||
#define ATOMIC_THREAD_FENCE atomic_thread_fence
|
||||
|
||||
/* Atomics using GCC intrinsics */
|
||||
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__)
|
||||
|
||||
enum almemory_order {
|
||||
almemory_order_relaxed,
|
||||
almemory_order_consume,
|
||||
almemory_order_acquire,
|
||||
almemory_order_release,
|
||||
almemory_order_acq_rel,
|
||||
almemory_order_seq_cst
|
||||
};
|
||||
|
||||
#define ATOMIC(T) struct { T volatile value; }
|
||||
#define ATOMIC_FLAG ATOMIC(int)
|
||||
|
||||
#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
|
||||
#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
|
||||
#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0)
|
||||
|
||||
#define ATOMIC_LOAD(_val, _MO) __extension__({ \
|
||||
__typeof((_val)->value) _r = (_val)->value; \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
_r; \
|
||||
})
|
||||
#define ATOMIC_STORE(_val, _newval, _MO) do { \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
(_val)->value = (_newval); \
|
||||
} while(0)
|
||||
|
||||
#define ATOMIC_ADD(_val, _incr, _MO) __sync_fetch_and_add(&(_val)->value, (_incr))
|
||||
#define ATOMIC_SUB(_val, _decr, _MO) __sync_fetch_and_sub(&(_val)->value, (_decr))
|
||||
|
||||
#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
__sync_lock_test_and_set(&(_val)->value, (_newval)); \
|
||||
})
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \
|
||||
__typeof(*(_oldval)) _o = *(_oldval); \
|
||||
*(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \
|
||||
*(_oldval) == _o; \
|
||||
})
|
||||
|
||||
#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) __extension__({ \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
__sync_lock_test_and_set(&(_val)->value, 1); \
|
||||
})
|
||||
#define ATOMIC_FLAG_CLEAR(_val, _MO) __extension__({ \
|
||||
__sync_lock_release(&(_val)->value); \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
})
|
||||
|
||||
|
||||
#define ATOMIC_THREAD_FENCE(order) do { \
|
||||
enum { must_be_constant = (order) }; \
|
||||
const int _o = must_be_constant; \
|
||||
if(_o > almemory_order_relaxed) \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
} while(0)
|
||||
|
||||
/* Atomics using x86/x86-64 GCC inline assembly */
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
|
||||
|
||||
#define WRAP_ADD(S, ret, dest, incr) __asm__ __volatile__( \
|
||||
"lock; xadd"S" %0,(%1)" \
|
||||
: "=r" (ret) \
|
||||
: "r" (dest), "0" (incr) \
|
||||
: "memory" \
|
||||
)
|
||||
#define WRAP_SUB(S, ret, dest, decr) __asm__ __volatile__( \
|
||||
"lock; xadd"S" %0,(%1)" \
|
||||
: "=r" (ret) \
|
||||
: "r" (dest), "0" (-(decr)) \
|
||||
: "memory" \
|
||||
)
|
||||
|
||||
#define WRAP_XCHG(S, ret, dest, newval) __asm__ __volatile__( \
|
||||
"lock; xchg"S" %0,(%1)" \
|
||||
: "=r" (ret) \
|
||||
: "r" (dest), "0" (newval) \
|
||||
: "memory" \
|
||||
)
|
||||
#define WRAP_CMPXCHG(S, ret, dest, oldval, newval) __asm__ __volatile__( \
|
||||
"lock; cmpxchg"S" %2,(%1)" \
|
||||
: "=a" (ret) \
|
||||
: "r" (dest), "r" (newval), "0" (oldval) \
|
||||
: "memory" \
|
||||
)
|
||||
|
||||
|
||||
enum almemory_order {
|
||||
almemory_order_relaxed,
|
||||
almemory_order_consume,
|
||||
almemory_order_acquire,
|
||||
almemory_order_release,
|
||||
almemory_order_acq_rel,
|
||||
almemory_order_seq_cst
|
||||
};
|
||||
|
||||
#define ATOMIC(T) struct { T volatile value; }
|
||||
|
||||
#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
|
||||
#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
|
||||
|
||||
#define ATOMIC_LOAD(_val, _MO) __extension__({ \
|
||||
__typeof((_val)->value) _r = (_val)->value; \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
_r; \
|
||||
})
|
||||
#define ATOMIC_STORE(_val, _newval, _MO) do { \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
(_val)->value = (_newval); \
|
||||
} while(0)
|
||||
|
||||
#define ATOMIC_ADD(_val, _incr, _MO) __extension__({ \
|
||||
static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \
|
||||
__typeof((_val)->value) _r; \
|
||||
if(sizeof((_val)->value) == 4) WRAP_ADD("l", _r, &(_val)->value, _incr); \
|
||||
else if(sizeof((_val)->value) == 8) WRAP_ADD("q", _r, &(_val)->value, _incr); \
|
||||
_r; \
|
||||
})
|
||||
#define ATOMIC_SUB(_val, _decr, _MO) __extension__({ \
|
||||
static_assert(sizeof((_val)->value)==4 || sizeof((_val)->value)==8, "Unsupported size!"); \
|
||||
__typeof((_val)->value) _r; \
|
||||
if(sizeof((_val)->value) == 4) WRAP_SUB("l", _r, &(_val)->value, _decr); \
|
||||
else if(sizeof((_val)->value) == 8) WRAP_SUB("q", _r, &(_val)->value, _decr); \
|
||||
_r; \
|
||||
})
|
||||
|
||||
#define ATOMIC_EXCHANGE(_val, _newval, _MO) __extension__({ \
|
||||
__typeof((_val)->value) _r; \
|
||||
if(sizeof((_val)->value) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \
|
||||
else if(sizeof((_val)->value) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval)); \
|
||||
_r; \
|
||||
})
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \
|
||||
__typeof(*(_oldval)) _old = *(_oldval); \
|
||||
if(sizeof((_val)->value) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \
|
||||
else if(sizeof((_val)->value) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \
|
||||
*(_oldval) == _old; \
|
||||
})
|
||||
|
||||
#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) __extension__({ \
|
||||
void *_r; \
|
||||
if(sizeof(void*) == 4) WRAP_XCHG("l", _r, &(_val)->value, (_newval)); \
|
||||
else if(sizeof(void*) == 8) WRAP_XCHG("q", _r, &(_val)->value, (_newval));\
|
||||
_r; \
|
||||
})
|
||||
#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2) __extension__({ \
|
||||
void *_old = *(_oldval); \
|
||||
if(sizeof(void*) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (_newval)); \
|
||||
else if(sizeof(void*) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (_newval)); \
|
||||
*(_oldval) == _old; \
|
||||
})
|
||||
|
||||
#define ATOMIC_THREAD_FENCE(order) do { \
|
||||
enum { must_be_constant = (order) }; \
|
||||
const int _o = must_be_constant; \
|
||||
if(_o > almemory_order_relaxed) \
|
||||
__asm__ __volatile__("" ::: "memory"); \
|
||||
} while(0)
|
||||
|
||||
/* Atomics using Windows methods */
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
/* NOTE: This mess is *extremely* touchy. It lacks quite a bit of safety
|
||||
* checking due to the lack of multi-statement expressions, typeof(), and C99
|
||||
* compound literals. It is incapable of properly exchanging floats, which get
|
||||
* casted to LONG/int, and could cast away potential warnings.
|
||||
*
|
||||
* Unfortunately, it's the only semi-safe way that doesn't rely on C99 (because
|
||||
* MSVC).
|
||||
*/
|
||||
|
||||
inline LONG AtomicAdd32(volatile LONG *dest, LONG incr)
|
||||
{
|
||||
return InterlockedExchangeAdd(dest, incr);
|
||||
}
|
||||
inline LONGLONG AtomicAdd64(volatile LONGLONG *dest, LONGLONG incr)
|
||||
{
|
||||
return InterlockedExchangeAdd64(dest, incr);
|
||||
}
|
||||
inline LONG AtomicSub32(volatile LONG *dest, LONG decr)
|
||||
{
|
||||
return InterlockedExchangeAdd(dest, -decr);
|
||||
}
|
||||
inline LONGLONG AtomicSub64(volatile LONGLONG *dest, LONGLONG decr)
|
||||
{
|
||||
return InterlockedExchangeAdd64(dest, -decr);
|
||||
}
|
||||
|
||||
inline LONG AtomicSwap32(volatile LONG *dest, LONG newval)
|
||||
{
|
||||
return InterlockedExchange(dest, newval);
|
||||
}
|
||||
inline LONGLONG AtomicSwap64(volatile LONGLONG *dest, LONGLONG newval)
|
||||
{
|
||||
return InterlockedExchange64(dest, newval);
|
||||
}
|
||||
inline void *AtomicSwapPtr(void *volatile *dest, void *newval)
|
||||
{
|
||||
return InterlockedExchangePointer(dest, newval);
|
||||
}
|
||||
|
||||
inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval)
|
||||
{
|
||||
LONG old = *oldval;
|
||||
*oldval = InterlockedCompareExchange(dest, newval, *oldval);
|
||||
return old == *oldval;
|
||||
}
|
||||
inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval)
|
||||
{
|
||||
LONGLONG old = *oldval;
|
||||
*oldval = InterlockedCompareExchange64(dest, newval, *oldval);
|
||||
return old == *oldval;
|
||||
}
|
||||
inline bool CompareAndSwapPtr(void *volatile *dest, void *newval, void **oldval)
|
||||
{
|
||||
void *old = *oldval;
|
||||
*oldval = InterlockedCompareExchangePointer(dest, newval, *oldval);
|
||||
return old == *oldval;
|
||||
}
|
||||
|
||||
#define WRAP_ADDSUB(T, _func, _ptr, _amnt) _func((T volatile*)(_ptr), (_amnt))
|
||||
#define WRAP_XCHG(T, _func, _ptr, _newval) _func((T volatile*)(_ptr), (_newval))
|
||||
#define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) _func((T volatile*)(_ptr), (_newval), (T*)(_oldval))
|
||||
|
||||
|
||||
enum almemory_order {
|
||||
almemory_order_relaxed,
|
||||
almemory_order_consume,
|
||||
almemory_order_acquire,
|
||||
almemory_order_release,
|
||||
almemory_order_acq_rel,
|
||||
almemory_order_seq_cst
|
||||
};
|
||||
|
||||
#define ATOMIC(T) struct { T volatile value; }
|
||||
|
||||
#define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0)
|
||||
#define ATOMIC_INIT_STATIC(_newval) {(_newval)}
|
||||
|
||||
#define ATOMIC_LOAD(_val, _MO) ((_val)->value)
|
||||
#define ATOMIC_STORE(_val, _newval, _MO) do { \
|
||||
(_val)->value = (_newval); \
|
||||
} while(0)
|
||||
|
||||
int _al_invalid_atomic_size(); /* not defined */
|
||||
void *_al_invalid_atomic_ptr_size(); /* not defined */
|
||||
|
||||
#define ATOMIC_ADD(_val, _incr, _MO) \
|
||||
((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicAdd32, &(_val)->value, (_incr)) : \
|
||||
(sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicAdd64, &(_val)->value, (_incr)) : \
|
||||
_al_invalid_atomic_size())
|
||||
#define ATOMIC_SUB(_val, _decr, _MO) \
|
||||
((sizeof((_val)->value)==4) ? WRAP_ADDSUB(LONG, AtomicSub32, &(_val)->value, (_decr)) : \
|
||||
(sizeof((_val)->value)==8) ? WRAP_ADDSUB(LONGLONG, AtomicSub64, &(_val)->value, (_decr)) : \
|
||||
_al_invalid_atomic_size())
|
||||
|
||||
#define ATOMIC_EXCHANGE(_val, _newval, _MO) \
|
||||
((sizeof((_val)->value)==4) ? WRAP_XCHG(LONG, AtomicSwap32, &(_val)->value, (_newval)) : \
|
||||
(sizeof((_val)->value)==8) ? WRAP_XCHG(LONGLONG, AtomicSwap64, &(_val)->value, (_newval)) : \
|
||||
(LONG)_al_invalid_atomic_size())
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, _MO1, _MO2) \
|
||||
((sizeof((_val)->value)==4) ? WRAP_CMPXCHG(LONG, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \
|
||||
(sizeof((_val)->value)==8) ? WRAP_CMPXCHG(LONGLONG, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \
|
||||
(bool)_al_invalid_atomic_size())
|
||||
|
||||
#define ATOMIC_EXCHANGE_PTR(_val, _newval, _MO) \
|
||||
((sizeof((_val)->value)==sizeof(void*)) ? AtomicSwapPtr((void*volatile*)&(_val)->value, (_newval)) : \
|
||||
_al_invalid_atomic_ptr_size())
|
||||
#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, _MO1, _MO2)\
|
||||
((sizeof((_val)->value)==sizeof(void*)) ? CompareAndSwapPtr((void*volatile*)&(_val)->value, (_newval), (void**)(_oldval)) : \
|
||||
(bool)_al_invalid_atomic_size())
|
||||
|
||||
#define ATOMIC_THREAD_FENCE(order) do { \
|
||||
enum { must_be_constant = (order) }; \
|
||||
const int _o = must_be_constant; \
|
||||
if(_o > almemory_order_relaxed) \
|
||||
_ReadWriteBarrier(); \
|
||||
} while(0)
|
||||
|
||||
#else
|
||||
|
||||
#error "No atomic functions available on this platform!"
|
||||
|
||||
#define ATOMIC(T) T
|
||||
|
||||
#define ATOMIC_INIT(_val, _newval) ((void)0)
|
||||
#define ATOMIC_INIT_STATIC(_newval) (0)
|
||||
|
||||
#define ATOMIC_LOAD(...) (0)
|
||||
#define ATOMIC_STORE(...) ((void)0)
|
||||
|
||||
#define ATOMIC_ADD(...) (0)
|
||||
#define ATOMIC_SUB(...) (0)
|
||||
|
||||
#define ATOMIC_EXCHANGE(...) (0)
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG(...) (0)
|
||||
|
||||
#define ATOMIC_THREAD_FENCE(...) ((void)0)
|
||||
#endif
|
||||
|
||||
/* If no PTR xchg variants are provided, the normal ones can handle it. */
|
||||
#ifndef ATOMIC_EXCHANGE_PTR
|
||||
#define ATOMIC_EXCHANGE_PTR ATOMIC_EXCHANGE
|
||||
#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG ATOMIC_COMPARE_EXCHANGE_STRONG
|
||||
#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_WEAK
|
||||
#endif
|
||||
|
||||
/* If no weak cmpxchg is provided (not all systems will have one), substitute a
|
||||
* strong cmpxchg. */
|
||||
#ifndef ATOMIC_COMPARE_EXCHANGE_WEAK
|
||||
#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG
|
||||
#endif
|
||||
#ifndef ATOMIC_COMPARE_EXCHANGE_PTR_WEAK
|
||||
#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK ATOMIC_COMPARE_EXCHANGE_PTR_STRONG
|
||||
#endif
|
||||
|
||||
/* If no ATOMIC_FLAG is defined, simulate one with an atomic int using exchange
|
||||
* and store ops.
|
||||
*/
|
||||
#ifndef ATOMIC_FLAG
|
||||
#define ATOMIC_FLAG ATOMIC(int)
|
||||
#define ATOMIC_FLAG_INIT ATOMIC_INIT_STATIC(0)
|
||||
#define ATOMIC_FLAG_TEST_AND_SET(_val, _MO) ATOMIC_EXCHANGE(_val, 1, _MO)
|
||||
#define ATOMIC_FLAG_CLEAR(_val, _MO) ATOMIC_STORE(_val, 0, _MO)
|
||||
#endif
|
||||
|
||||
|
||||
#define ATOMIC_LOAD_SEQ(_val) ATOMIC_LOAD(_val, almemory_order_seq_cst)
|
||||
#define ATOMIC_STORE_SEQ(_val, _newval) ATOMIC_STORE(_val, _newval, almemory_order_seq_cst)
|
||||
|
||||
#define ATOMIC_ADD_SEQ(_val, _incr) ATOMIC_ADD(_val, _incr, almemory_order_seq_cst)
|
||||
#define ATOMIC_SUB_SEQ(_val, _decr) ATOMIC_SUB(_val, _decr, almemory_order_seq_cst)
|
||||
|
||||
#define ATOMIC_EXCHANGE_SEQ(_val, _newval) ATOMIC_EXCHANGE(_val, _newval, almemory_order_seq_cst)
|
||||
#define ATOMIC_COMPARE_EXCHANGE_STRONG_SEQ(_val, _oldval, _newval) \
|
||||
ATOMIC_COMPARE_EXCHANGE_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst)
|
||||
#define ATOMIC_COMPARE_EXCHANGE_WEAK_SEQ(_val, _oldval, _newval) \
|
||||
ATOMIC_COMPARE_EXCHANGE_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst)
|
||||
|
||||
#define ATOMIC_EXCHANGE_PTR_SEQ(_val, _newval) ATOMIC_EXCHANGE_PTR(_val, _newval, almemory_order_seq_cst)
|
||||
#define ATOMIC_COMPARE_EXCHANGE_PTR_STRONG_SEQ(_val, _oldval, _newval) \
|
||||
ATOMIC_COMPARE_EXCHANGE_PTR_STRONG(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst)
|
||||
#define ATOMIC_COMPARE_EXCHANGE_PTR_WEAK_SEQ(_val, _oldval, _newval) \
|
||||
ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_val, _oldval, _newval, almemory_order_seq_cst, almemory_order_seq_cst)
|
||||
|
||||
|
||||
typedef unsigned int uint;
|
||||
typedef ATOMIC(uint) RefCount;
|
||||
|
||||
inline void InitRef(RefCount *ptr, uint value)
|
||||
{ ATOMIC_INIT(ptr, value); }
|
||||
inline uint ReadRef(RefCount *ptr)
|
||||
{ return ATOMIC_LOAD(ptr, almemory_order_acquire); }
|
||||
inline uint IncrementRef(RefCount *ptr)
|
||||
{ return ATOMIC_ADD(ptr, 1, almemory_order_acq_rel)+1; }
|
||||
inline uint DecrementRef(RefCount *ptr)
|
||||
{ return ATOMIC_SUB(ptr, 1, almemory_order_acq_rel)-1; }
|
||||
inline void InitRef(RefCount &ref, unsigned int value)
|
||||
{ ref.store(value, std::memory_order_relaxed); }
|
||||
inline unsigned int ReadRef(RefCount &ref)
|
||||
{ return ref.load(std::memory_order_acquire); }
|
||||
inline unsigned int IncrementRef(RefCount &ref)
|
||||
{ return ref.fetch_add(1u, std::memory_order_acq_rel)+1u; }
|
||||
inline unsigned int DecrementRef(RefCount &ref)
|
||||
{ return ref.fetch_sub(1u, std::memory_order_acq_rel)-1u; }
|
||||
|
||||
|
||||
/* WARNING: A livelock is theoretically possible if another thread keeps
|
||||
* changing the head without giving this a chance to actually swap in the new
|
||||
* one (practically impossible with this little code, but...).
|
||||
*/
|
||||
#define ATOMIC_REPLACE_HEAD(T, _head, _entry) do { \
|
||||
T _first = ATOMIC_LOAD(_head, almemory_order_acquire); \
|
||||
do { \
|
||||
ATOMIC_STORE(&(_entry)->next, _first, almemory_order_relaxed); \
|
||||
} while(ATOMIC_COMPARE_EXCHANGE_PTR_WEAK(_head, &_first, _entry, \
|
||||
almemory_order_acq_rel, almemory_order_acquire) == 0); \
|
||||
} while(0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
template<typename T>
|
||||
inline void AtomicReplaceHead(std::atomic<T> &head, T newhead)
|
||||
{
|
||||
T first_ = head.load(std::memory_order_acquire);
|
||||
do {
|
||||
newhead->next.store(first_, std::memory_order_relaxed);
|
||||
} while(!head.compare_exchange_weak(first_, newhead,
|
||||
std::memory_order_acq_rel, std::memory_order_acquire));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AL_ATOMIC_H */
|
||||
|
|
|
|||
|
|
@ -1,18 +0,0 @@
|
|||
#ifndef AL_BOOL_H
|
||||
#define AL_BOOL_H
|
||||
|
||||
#ifdef HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#ifndef bool
|
||||
#ifdef HAVE_C99_BOOL
|
||||
#define bool _Bool
|
||||
#else
|
||||
#define bool int
|
||||
#endif
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
#endif /* AL_BOOL_H */
|
||||
44
Engine/lib/openal-soft/common/dynload.cpp
Normal file
44
Engine/lib/openal-soft/common/dynload.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "dynload.h"
|
||||
|
||||
#include "strutils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
void *LoadLib(const char *name)
|
||||
{
|
||||
std::wstring wname{utf8_to_wstr(name)};
|
||||
return LoadLibraryW(wname.c_str());
|
||||
}
|
||||
void CloseLib(void *handle)
|
||||
{ FreeLibrary(static_cast<HMODULE>(handle)); }
|
||||
void *GetSymbol(void *handle, const char *name)
|
||||
{ return reinterpret_cast<void*>(GetProcAddress(static_cast<HMODULE>(handle), name)); }
|
||||
|
||||
#elif defined(HAVE_DLFCN_H)
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
void *LoadLib(const char *name)
|
||||
{
|
||||
dlerror();
|
||||
void *handle{dlopen(name, RTLD_NOW)};
|
||||
const char *err{dlerror()};
|
||||
if(err) handle = nullptr;
|
||||
return handle;
|
||||
}
|
||||
void CloseLib(void *handle)
|
||||
{ dlclose(handle); }
|
||||
void *GetSymbol(void *handle, const char *name)
|
||||
{
|
||||
dlerror();
|
||||
void *sym{dlsym(handle, name)};
|
||||
const char *err{dlerror()};
|
||||
if(err) sym = nullptr;
|
||||
return sym;
|
||||
}
|
||||
#endif
|
||||
14
Engine/lib/openal-soft/common/dynload.h
Normal file
14
Engine/lib/openal-soft/common/dynload.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef AL_DYNLOAD_H
|
||||
#define AL_DYNLOAD_H
|
||||
|
||||
#if defined(_WIN32) || defined(HAVE_DLFCN_H)
|
||||
|
||||
#define HAVE_DYNLOAD
|
||||
|
||||
void *LoadLib(const char *name);
|
||||
void CloseLib(void *handle);
|
||||
void *GetSymbol(void *handle, const char *name);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* AL_DYNLOAD_H */
|
||||
120
Engine/lib/openal-soft/common/intrusive_ptr.h
Normal file
120
Engine/lib/openal-soft/common/intrusive_ptr.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
#ifndef INTRUSIVE_PTR_H
|
||||
#define INTRUSIVE_PTR_H
|
||||
|
||||
#include "atomic.h"
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
namespace al {
|
||||
|
||||
template<typename T>
|
||||
class intrusive_ref {
|
||||
RefCount mRef{1u};
|
||||
|
||||
public:
|
||||
unsigned int add_ref() noexcept { return IncrementRef(mRef); }
|
||||
unsigned int release() noexcept
|
||||
{
|
||||
auto ref = DecrementRef(mRef);
|
||||
if UNLIKELY(ref == 0)
|
||||
delete static_cast<T*>(this);
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release only if doing so would not bring the object to 0 references and
|
||||
* delete it. Returns false if the object could not be released.
|
||||
*
|
||||
* NOTE: The caller is responsible for handling a failed release, as it
|
||||
* means the object has no other references and needs to be be deleted
|
||||
* somehow.
|
||||
*/
|
||||
bool releaseIfNoDelete() noexcept
|
||||
{
|
||||
auto val = mRef.load(std::memory_order_acquire);
|
||||
while(val > 1 && !mRef.compare_exchange_strong(val, val-1, std::memory_order_acq_rel))
|
||||
{
|
||||
/* val was updated with the current value on failure, so just try
|
||||
* again.
|
||||
*/
|
||||
}
|
||||
|
||||
return val >= 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class intrusive_ptr {
|
||||
T *mPtr{nullptr};
|
||||
|
||||
public:
|
||||
intrusive_ptr() noexcept = default;
|
||||
intrusive_ptr(const intrusive_ptr &rhs) noexcept : mPtr{rhs.mPtr}
|
||||
{ if(mPtr) mPtr->add_ref(); }
|
||||
intrusive_ptr(intrusive_ptr&& rhs) noexcept : mPtr{rhs.mPtr}
|
||||
{ rhs.mPtr = nullptr; }
|
||||
intrusive_ptr(std::nullptr_t) noexcept { }
|
||||
explicit intrusive_ptr(T *ptr) noexcept : mPtr{ptr} { }
|
||||
~intrusive_ptr() { if(mPtr) mPtr->release(); }
|
||||
|
||||
intrusive_ptr& operator=(const intrusive_ptr &rhs) noexcept
|
||||
{
|
||||
if(rhs.mPtr) rhs.mPtr->add_ref();
|
||||
if(mPtr) mPtr->release();
|
||||
mPtr = rhs.mPtr;
|
||||
return *this;
|
||||
}
|
||||
intrusive_ptr& operator=(intrusive_ptr&& rhs) noexcept
|
||||
{
|
||||
if(mPtr)
|
||||
mPtr->release();
|
||||
mPtr = rhs.mPtr;
|
||||
rhs.mPtr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator bool() const noexcept { return mPtr != nullptr; }
|
||||
|
||||
T& operator*() const noexcept { return *mPtr; }
|
||||
T* operator->() const noexcept { return mPtr; }
|
||||
T* get() const noexcept { return mPtr; }
|
||||
|
||||
void reset(T *ptr=nullptr) noexcept
|
||||
{
|
||||
if(mPtr)
|
||||
mPtr->release();
|
||||
mPtr = ptr;
|
||||
}
|
||||
|
||||
T* release() noexcept
|
||||
{
|
||||
T *ret{mPtr};
|
||||
mPtr = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void swap(intrusive_ptr &rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
|
||||
void swap(intrusive_ptr&& rhs) noexcept { std::swap(mPtr, rhs.mPtr); }
|
||||
};
|
||||
|
||||
#define AL_DECL_OP(op) \
|
||||
template<typename T> \
|
||||
inline bool operator op(const intrusive_ptr<T> &lhs, const T *rhs) noexcept \
|
||||
{ return lhs.get() op rhs; } \
|
||||
template<typename T> \
|
||||
inline bool operator op(const T *lhs, const intrusive_ptr<T> &rhs) noexcept \
|
||||
{ return lhs op rhs.get(); }
|
||||
|
||||
AL_DECL_OP(==)
|
||||
AL_DECL_OP(!=)
|
||||
AL_DECL_OP(<=)
|
||||
AL_DECL_OP(>=)
|
||||
AL_DECL_OP(<)
|
||||
AL_DECL_OP(>)
|
||||
|
||||
#undef AL_DECL_OP
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* INTRUSIVE_PTR_H */
|
||||
|
|
@ -1,46 +1,26 @@
|
|||
#ifndef AL_MATH_DEFS_H
|
||||
#define AL_MATH_DEFS_H
|
||||
|
||||
#include <math.h>
|
||||
#ifdef HAVE_FLOAT_H
|
||||
#include <float.h>
|
||||
#endif
|
||||
constexpr float Deg2Rad(float x) noexcept { return x * 1.74532925199432955e-02f/*pi/180*/; }
|
||||
constexpr float Rad2Deg(float x) noexcept { return x * 5.72957795130823229e+01f/*180/pi*/; }
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265358979323846)
|
||||
#endif
|
||||
namespace al {
|
||||
|
||||
#define F_PI (3.14159265358979323846f)
|
||||
#define F_PI_2 (1.57079632679489661923f)
|
||||
#define F_TAU (6.28318530717958647692f)
|
||||
template<typename Real>
|
||||
struct MathDefs { };
|
||||
|
||||
#ifndef FLT_EPSILON
|
||||
#define FLT_EPSILON (1.19209290e-07f)
|
||||
#endif
|
||||
template<>
|
||||
struct MathDefs<float> {
|
||||
static constexpr float Pi() noexcept { return 3.14159265358979323846e+00f; }
|
||||
static constexpr float Tau() noexcept { return 6.28318530717958647692e+00f; }
|
||||
};
|
||||
|
||||
#ifndef HUGE_VALF
|
||||
static const union msvc_inf_hack {
|
||||
unsigned char b[4];
|
||||
float f;
|
||||
} msvc_inf_union = {{ 0x00, 0x00, 0x80, 0x7F }};
|
||||
#define HUGE_VALF (msvc_inf_union.f)
|
||||
#endif
|
||||
template<>
|
||||
struct MathDefs<double> {
|
||||
static constexpr double Pi() noexcept { return 3.14159265358979323846e+00; }
|
||||
static constexpr double Tau() noexcept { return 6.28318530717958647692e+00; }
|
||||
};
|
||||
|
||||
#ifndef HAVE_LOG2F
|
||||
static inline float log2f(float f)
|
||||
{
|
||||
return logf(f) / logf(2.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_CBRTF
|
||||
static inline float cbrtf(float f)
|
||||
{
|
||||
return powf(f, 1.0f/3.0f);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define DEG2RAD(x) ((float)(x) * (F_PI/180.0f))
|
||||
#define RAD2DEG(x) ((float)(x) * (180.0f/F_PI))
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_MATH_DEFS_H */
|
||||
|
|
|
|||
45
Engine/lib/openal-soft/common/opthelpers.h
Normal file
45
Engine/lib/openal-soft/common/opthelpers.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef OPTHELPERS_H
|
||||
#define OPTHELPERS_H
|
||||
|
||||
#ifdef __has_builtin
|
||||
#define HAS_BUILTIN __has_builtin
|
||||
#else
|
||||
#define HAS_BUILTIN(x) (0)
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || HAS_BUILTIN(__builtin_expect)
|
||||
/* LIKELY optimizes the case where the condition is true. The condition is not
|
||||
* required to be true, but it can result in more optimal code for the true
|
||||
* path at the expense of a less optimal false path.
|
||||
*/
|
||||
#define LIKELY(x) (__builtin_expect(!!(x), !false))
|
||||
/* The opposite of LIKELY, optimizing the case where the condition is false. */
|
||||
#define UNLIKELY(x) (__builtin_expect(!!(x), false))
|
||||
|
||||
#else
|
||||
|
||||
#define LIKELY(x) (!!(x))
|
||||
#define UNLIKELY(x) (!!(x))
|
||||
#endif
|
||||
|
||||
#if HAS_BUILTIN(__builtin_assume)
|
||||
/* Unlike LIKELY, ASSUME requires the condition to be true or else it invokes
|
||||
* undefined behavior. It's essentially an assert without actually checking the
|
||||
* condition at run-time, allowing for stronger optimizations than LIKELY.
|
||||
*/
|
||||
#define ASSUME __builtin_assume
|
||||
#elif defined(_MSC_VER)
|
||||
#define ASSUME __assume
|
||||
#elif defined(__GNUC__)
|
||||
#define ASSUME(x) do { if(!(x)) __builtin_unreachable(); } while(0)
|
||||
#else
|
||||
#define ASSUME(x) ((void)0)
|
||||
#endif
|
||||
|
||||
#if __cplusplus >= 201703L || defined(__cpp_if_constexpr)
|
||||
#define if_constexpr if constexpr
|
||||
#else
|
||||
#define if_constexpr if
|
||||
#endif
|
||||
|
||||
#endif /* OPTHELPERS_H */
|
||||
222
Engine/lib/openal-soft/common/polyphase_resampler.cpp
Normal file
222
Engine/lib/openal-soft/common/polyphase_resampler.cpp
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
|
||||
#include "polyphase_resampler.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
#include "math_defs.h"
|
||||
#include "opthelpers.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr double Epsilon{1e-9};
|
||||
|
||||
using uint = unsigned int;
|
||||
|
||||
/* This is the normalized cardinal sine (sinc) function.
|
||||
*
|
||||
* sinc(x) = { 1, x = 0
|
||||
* { sin(pi x) / (pi x), otherwise.
|
||||
*/
|
||||
double Sinc(const double x)
|
||||
{
|
||||
if UNLIKELY(std::abs(x) < Epsilon)
|
||||
return 1.0;
|
||||
return std::sin(al::MathDefs<double>::Pi()*x) / (al::MathDefs<double>::Pi()*x);
|
||||
}
|
||||
|
||||
/* The zero-order modified Bessel function of the first kind, used for the
|
||||
* Kaiser window.
|
||||
*
|
||||
* I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k)
|
||||
* = sum_{k=0}^inf ((x / 2)^k / k!)^2
|
||||
*/
|
||||
constexpr double BesselI_0(const double x)
|
||||
{
|
||||
// Start at k=1 since k=0 is trivial.
|
||||
const double x2{x/2.0};
|
||||
double term{1.0};
|
||||
double sum{1.0};
|
||||
int k{1};
|
||||
|
||||
// Let the integration converge until the term of the sum is no longer
|
||||
// significant.
|
||||
double last_sum{};
|
||||
do {
|
||||
const double y{x2 / k};
|
||||
++k;
|
||||
last_sum = sum;
|
||||
term *= y * y;
|
||||
sum += term;
|
||||
} while(sum != last_sum);
|
||||
return sum;
|
||||
}
|
||||
|
||||
/* Calculate a Kaiser window from the given beta value and a normalized k
|
||||
* [-1, 1].
|
||||
*
|
||||
* w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1
|
||||
* { 0, elsewhere.
|
||||
*
|
||||
* Where k can be calculated as:
|
||||
*
|
||||
* k = i / l, where -l <= i <= l.
|
||||
*
|
||||
* or:
|
||||
*
|
||||
* k = 2 i / M - 1, where 0 <= i <= M.
|
||||
*/
|
||||
double Kaiser(const double b, const double k)
|
||||
{
|
||||
if(!(k >= -1.0 && k <= 1.0))
|
||||
return 0.0;
|
||||
return BesselI_0(b * std::sqrt(1.0 - k*k)) / BesselI_0(b);
|
||||
}
|
||||
|
||||
// Calculates the greatest common divisor of a and b.
|
||||
constexpr uint Gcd(uint x, uint y)
|
||||
{
|
||||
while(y > 0)
|
||||
{
|
||||
const uint z{y};
|
||||
y = x % y;
|
||||
x = z;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/* Calculates the size (order) of the Kaiser window. Rejection is in dB and
|
||||
* the transition width is normalized frequency (0.5 is nyquist).
|
||||
*
|
||||
* M = { ceil((r - 7.95) / (2.285 2 pi f_t)), r > 21
|
||||
* { ceil(5.79 / 2 pi f_t), r <= 21.
|
||||
*
|
||||
*/
|
||||
constexpr uint CalcKaiserOrder(const double rejection, const double transition)
|
||||
{
|
||||
const double w_t{2.0 * al::MathDefs<double>::Pi() * transition};
|
||||
if LIKELY(rejection > 21.0)
|
||||
return static_cast<uint>(std::ceil((rejection - 7.95) / (2.285 * w_t)));
|
||||
return static_cast<uint>(std::ceil(5.79 / w_t));
|
||||
}
|
||||
|
||||
// Calculates the beta value of the Kaiser window. Rejection is in dB.
|
||||
constexpr double CalcKaiserBeta(const double rejection)
|
||||
{
|
||||
if LIKELY(rejection > 50.0)
|
||||
return 0.1102 * (rejection - 8.7);
|
||||
if(rejection >= 21.0)
|
||||
return (0.5842 * std::pow(rejection - 21.0, 0.4)) +
|
||||
(0.07886 * (rejection - 21.0));
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* Calculates a point on the Kaiser-windowed sinc filter for the given half-
|
||||
* width, beta, gain, and cutoff. The point is specified in non-normalized
|
||||
* samples, from 0 to M, where M = (2 l + 1).
|
||||
*
|
||||
* w(k) 2 p f_t sinc(2 f_t x)
|
||||
*
|
||||
* x -- centered sample index (i - l)
|
||||
* k -- normalized and centered window index (x / l)
|
||||
* w(k) -- window function (Kaiser)
|
||||
* p -- gain compensation factor when sampling
|
||||
* f_t -- normalized center frequency (or cutoff; 0.5 is nyquist)
|
||||
*/
|
||||
double SincFilter(const uint l, const double b, const double gain, const double cutoff,
|
||||
const uint i)
|
||||
{
|
||||
const double x{static_cast<double>(i) - l};
|
||||
return Kaiser(b, x / l) * 2.0 * gain * cutoff * Sinc(2.0 * cutoff * x);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Calculate the resampling metrics and build the Kaiser-windowed sinc filter
|
||||
// that's used to cut frequencies above the destination nyquist.
|
||||
void PPhaseResampler::init(const uint srcRate, const uint dstRate)
|
||||
{
|
||||
const uint gcd{Gcd(srcRate, dstRate)};
|
||||
mP = dstRate / gcd;
|
||||
mQ = srcRate / gcd;
|
||||
|
||||
/* The cutoff is adjusted by half the transition width, so the transition
|
||||
* ends before the nyquist (0.5). Both are scaled by the downsampling
|
||||
* factor.
|
||||
*/
|
||||
double cutoff, width;
|
||||
if(mP > mQ)
|
||||
{
|
||||
cutoff = 0.475 / mP;
|
||||
width = 0.05 / mP;
|
||||
}
|
||||
else
|
||||
{
|
||||
cutoff = 0.475 / mQ;
|
||||
width = 0.05 / mQ;
|
||||
}
|
||||
// A rejection of -180 dB is used for the stop band. Round up when
|
||||
// calculating the left offset to avoid increasing the transition width.
|
||||
const uint l{(CalcKaiserOrder(180.0, width)+1) / 2};
|
||||
const double beta{CalcKaiserBeta(180.0)};
|
||||
mM = l*2 + 1;
|
||||
mL = l;
|
||||
mF.resize(mM);
|
||||
for(uint i{0};i < mM;i++)
|
||||
mF[i] = SincFilter(l, beta, mP, cutoff, i);
|
||||
}
|
||||
|
||||
// Perform the upsample-filter-downsample resampling operation using a
|
||||
// polyphase filter implementation.
|
||||
void PPhaseResampler::process(const uint inN, const double *in, const uint outN, double *out)
|
||||
{
|
||||
if UNLIKELY(outN == 0)
|
||||
return;
|
||||
|
||||
// Handle in-place operation.
|
||||
std::vector<double> workspace;
|
||||
double *work{out};
|
||||
if UNLIKELY(work == in)
|
||||
{
|
||||
workspace.resize(outN);
|
||||
work = workspace.data();
|
||||
}
|
||||
|
||||
// Resample the input.
|
||||
const uint p{mP}, q{mQ}, m{mM}, l{mL};
|
||||
const double *f{mF.data()};
|
||||
for(uint i{0};i < outN;i++)
|
||||
{
|
||||
// Input starts at l to compensate for the filter delay. This will
|
||||
// drop any build-up from the first half of the filter.
|
||||
size_t j_f{(l + q*i) % p};
|
||||
size_t j_s{(l + q*i) / p};
|
||||
|
||||
// Only take input when 0 <= j_s < inN.
|
||||
double r{0.0};
|
||||
if LIKELY(j_f < m)
|
||||
{
|
||||
size_t filt_len{(m-j_f+p-1) / p};
|
||||
if LIKELY(j_s+1 > inN)
|
||||
{
|
||||
size_t skip{std::min<size_t>(j_s+1 - inN, filt_len)};
|
||||
j_f += p*skip;
|
||||
j_s -= skip;
|
||||
filt_len -= skip;
|
||||
}
|
||||
if(size_t todo{std::min<size_t>(j_s+1, filt_len)})
|
||||
{
|
||||
do {
|
||||
r += f[j_f] * in[j_s];
|
||||
j_f += p;
|
||||
--j_s;
|
||||
} while(--todo);
|
||||
}
|
||||
}
|
||||
work[i] = r;
|
||||
}
|
||||
// Clean up after in-place operation.
|
||||
if(work != out)
|
||||
std::copy_n(work, outN, out);
|
||||
}
|
||||
45
Engine/lib/openal-soft/common/polyphase_resampler.h
Normal file
45
Engine/lib/openal-soft/common/polyphase_resampler.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef POLYPHASE_RESAMPLER_H
|
||||
#define POLYPHASE_RESAMPLER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
/* This is a polyphase sinc-filtered resampler. It is built for very high
|
||||
* quality results, rather than real-time performance.
|
||||
*
|
||||
* Upsample Downsample
|
||||
*
|
||||
* p/q = 3/2 p/q = 3/5
|
||||
*
|
||||
* M-+-+-+-> M-+-+-+->
|
||||
* -------------------+ ---------------------+
|
||||
* p s * f f f f|f| | p s * f f f f f |
|
||||
* | 0 * 0 0 0|0|0 | | 0 * 0 0 0 0|0| |
|
||||
* v 0 * 0 0|0|0 0 | v 0 * 0 0 0|0|0 |
|
||||
* s * f|f|f f f | s * f f|f|f f |
|
||||
* 0 * |0|0 0 0 0 | 0 * 0|0|0 0 0 |
|
||||
* --------+=+--------+ 0 * |0|0 0 0 0 |
|
||||
* d . d .|d|. d . d ----------+=+--------+
|
||||
* d . . . .|d|. . . .
|
||||
* q->
|
||||
* q-+-+-+->
|
||||
*
|
||||
* P_f(i,j) = q i mod p + pj
|
||||
* P_s(i,j) = floor(q i / p) - j
|
||||
* d[i=0..N-1] = sum_{j=0}^{floor((M - 1) / p)} {
|
||||
* { f[P_f(i,j)] s[P_s(i,j)], P_f(i,j) < M
|
||||
* { 0, P_f(i,j) >= M. }
|
||||
*/
|
||||
|
||||
struct PPhaseResampler {
|
||||
using uint = unsigned int;
|
||||
|
||||
void init(const uint srcRate, const uint dstRate);
|
||||
void process(const uint inN, const double *in, const uint outN, double *out);
|
||||
|
||||
private:
|
||||
uint mP, mQ, mM, mL;
|
||||
std::vector<double> mF;
|
||||
};
|
||||
|
||||
#endif /* POLYPHASE_RESAMPLER_H */
|
||||
21
Engine/lib/openal-soft/common/pragmadefs.h
Normal file
21
Engine/lib/openal-soft/common/pragmadefs.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef PRAGMADEFS_H
|
||||
#define PRAGMADEFS_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define DIAGNOSTIC_PUSH __pragma(warning(push))
|
||||
#define DIAGNOSTIC_POP __pragma(warning(pop))
|
||||
#define std_pragma(...)
|
||||
#define msc_pragma __pragma
|
||||
#else
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
|
||||
#define DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define DIAGNOSTIC_PUSH
|
||||
#define DIAGNOSTIC_POP
|
||||
#endif
|
||||
#define std_pragma _Pragma
|
||||
#define msc_pragma(...)
|
||||
#endif
|
||||
|
||||
#endif /* PRAGMADEFS_H */
|
||||
224
Engine/lib/openal-soft/common/ringbuffer.cpp
Normal file
224
Engine/lib/openal-soft/common/ringbuffer.cpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2007 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ringbuffer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
|
||||
RingBufferPtr RingBuffer::Create(size_t sz, size_t elem_sz, int limit_writes)
|
||||
{
|
||||
size_t power_of_two{0u};
|
||||
if(sz > 0)
|
||||
{
|
||||
power_of_two = sz;
|
||||
power_of_two |= power_of_two>>1;
|
||||
power_of_two |= power_of_two>>2;
|
||||
power_of_two |= power_of_two>>4;
|
||||
power_of_two |= power_of_two>>8;
|
||||
power_of_two |= power_of_two>>16;
|
||||
#if SIZE_MAX > UINT_MAX
|
||||
power_of_two |= power_of_two>>32;
|
||||
#endif
|
||||
}
|
||||
++power_of_two;
|
||||
if(power_of_two <= sz || power_of_two > std::numeric_limits<size_t>::max()/elem_sz)
|
||||
throw std::overflow_error{"Ring buffer size overflow"};
|
||||
|
||||
const size_t bufbytes{power_of_two * elem_sz};
|
||||
RingBufferPtr rb{new(FamCount(bufbytes)) RingBuffer{bufbytes}};
|
||||
rb->mWriteSize = limit_writes ? sz : (power_of_two-1);
|
||||
rb->mSizeMask = power_of_two - 1;
|
||||
rb->mElemSize = elem_sz;
|
||||
|
||||
return rb;
|
||||
}
|
||||
|
||||
void RingBuffer::reset() noexcept
|
||||
{
|
||||
mWritePtr.store(0, std::memory_order_relaxed);
|
||||
mReadPtr.store(0, std::memory_order_relaxed);
|
||||
std::fill_n(mBuffer.begin(), (mSizeMask+1)*mElemSize, al::byte{});
|
||||
}
|
||||
|
||||
|
||||
size_t RingBuffer::read(void *dest, size_t cnt) noexcept
|
||||
{
|
||||
const size_t free_cnt{readSpace()};
|
||||
if(free_cnt == 0) return 0;
|
||||
|
||||
const size_t to_read{std::min(cnt, free_cnt)};
|
||||
size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask};
|
||||
|
||||
size_t n1, n2;
|
||||
const size_t cnt2{read_ptr + to_read};
|
||||
if(cnt2 > mSizeMask+1)
|
||||
{
|
||||
n1 = mSizeMask+1 - read_ptr;
|
||||
n2 = cnt2 & mSizeMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
n1 = to_read;
|
||||
n2 = 0;
|
||||
}
|
||||
|
||||
auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize,
|
||||
static_cast<al::byte*>(dest));
|
||||
read_ptr += n1;
|
||||
if(n2 > 0)
|
||||
{
|
||||
std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
|
||||
read_ptr += n2;
|
||||
}
|
||||
mReadPtr.store(read_ptr, std::memory_order_release);
|
||||
return to_read;
|
||||
}
|
||||
|
||||
size_t RingBuffer::peek(void *dest, size_t cnt) const noexcept
|
||||
{
|
||||
const size_t free_cnt{readSpace()};
|
||||
if(free_cnt == 0) return 0;
|
||||
|
||||
const size_t to_read{std::min(cnt, free_cnt)};
|
||||
size_t read_ptr{mReadPtr.load(std::memory_order_relaxed) & mSizeMask};
|
||||
|
||||
size_t n1, n2;
|
||||
const size_t cnt2{read_ptr + to_read};
|
||||
if(cnt2 > mSizeMask+1)
|
||||
{
|
||||
n1 = mSizeMask+1 - read_ptr;
|
||||
n2 = cnt2 & mSizeMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
n1 = to_read;
|
||||
n2 = 0;
|
||||
}
|
||||
|
||||
auto outiter = std::copy_n(mBuffer.begin() + read_ptr*mElemSize, n1*mElemSize,
|
||||
static_cast<al::byte*>(dest));
|
||||
if(n2 > 0)
|
||||
std::copy_n(mBuffer.begin(), n2*mElemSize, outiter);
|
||||
return to_read;
|
||||
}
|
||||
|
||||
size_t RingBuffer::write(const void *src, size_t cnt) noexcept
|
||||
{
|
||||
const size_t free_cnt{writeSpace()};
|
||||
if(free_cnt == 0) return 0;
|
||||
|
||||
const size_t to_write{std::min(cnt, free_cnt)};
|
||||
size_t write_ptr{mWritePtr.load(std::memory_order_relaxed) & mSizeMask};
|
||||
|
||||
size_t n1, n2;
|
||||
const size_t cnt2{write_ptr + to_write};
|
||||
if(cnt2 > mSizeMask+1)
|
||||
{
|
||||
n1 = mSizeMask+1 - write_ptr;
|
||||
n2 = cnt2 & mSizeMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
n1 = to_write;
|
||||
n2 = 0;
|
||||
}
|
||||
|
||||
auto srcbytes = static_cast<const al::byte*>(src);
|
||||
std::copy_n(srcbytes, n1*mElemSize, mBuffer.begin() + write_ptr*mElemSize);
|
||||
write_ptr += n1;
|
||||
if(n2 > 0)
|
||||
{
|
||||
std::copy_n(srcbytes + n1*mElemSize, n2*mElemSize, mBuffer.begin());
|
||||
write_ptr += n2;
|
||||
}
|
||||
mWritePtr.store(write_ptr, std::memory_order_release);
|
||||
return to_write;
|
||||
}
|
||||
|
||||
|
||||
ll_ringbuffer_data_pair RingBuffer::getReadVector() const noexcept
|
||||
{
|
||||
ll_ringbuffer_data_pair ret;
|
||||
|
||||
size_t w{mWritePtr.load(std::memory_order_acquire)};
|
||||
size_t r{mReadPtr.load(std::memory_order_acquire)};
|
||||
w &= mSizeMask;
|
||||
r &= mSizeMask;
|
||||
const size_t free_cnt{(w-r) & mSizeMask};
|
||||
|
||||
const size_t cnt2{r + free_cnt};
|
||||
if(cnt2 > mSizeMask+1)
|
||||
{
|
||||
/* Two part vector: the rest of the buffer after the current read ptr,
|
||||
* plus some from the start of the buffer. */
|
||||
ret.first.buf = const_cast<al::byte*>(mBuffer.data() + r*mElemSize);
|
||||
ret.first.len = mSizeMask+1 - r;
|
||||
ret.second.buf = const_cast<al::byte*>(mBuffer.data());
|
||||
ret.second.len = cnt2 & mSizeMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Single part vector: just the rest of the buffer */
|
||||
ret.first.buf = const_cast<al::byte*>(mBuffer.data() + r*mElemSize);
|
||||
ret.first.len = free_cnt;
|
||||
ret.second.buf = nullptr;
|
||||
ret.second.len = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ll_ringbuffer_data_pair RingBuffer::getWriteVector() const noexcept
|
||||
{
|
||||
ll_ringbuffer_data_pair ret;
|
||||
|
||||
size_t w{mWritePtr.load(std::memory_order_acquire)};
|
||||
size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
|
||||
w &= mSizeMask;
|
||||
r &= mSizeMask;
|
||||
const size_t free_cnt{(r-w-1) & mSizeMask};
|
||||
|
||||
const size_t cnt2{w + free_cnt};
|
||||
if(cnt2 > mSizeMask+1)
|
||||
{
|
||||
/* Two part vector: the rest of the buffer after the current write ptr,
|
||||
* plus some from the start of the buffer. */
|
||||
ret.first.buf = const_cast<al::byte*>(mBuffer.data() + w*mElemSize);
|
||||
ret.first.len = mSizeMask+1 - w;
|
||||
ret.second.buf = const_cast<al::byte*>(mBuffer.data());
|
||||
ret.second.len = cnt2 & mSizeMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.first.buf = const_cast<al::byte*>(mBuffer.data() + w*mElemSize);
|
||||
ret.first.len = free_cnt;
|
||||
ret.second.buf = nullptr;
|
||||
ret.second.len = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
113
Engine/lib/openal-soft/common/ringbuffer.h
Normal file
113
Engine/lib/openal-soft/common/ringbuffer.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#ifndef RINGBUFFER_H
|
||||
#define RINGBUFFER_H
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <stddef.h>
|
||||
#include <utility>
|
||||
|
||||
#include "albyte.h"
|
||||
#include "almalloc.h"
|
||||
|
||||
|
||||
/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended
|
||||
* to include an element size. Consequently, parameters and return values for a
|
||||
* size or count is in 'elements', not bytes. Additionally, it only supports
|
||||
* single-consumer/single-provider operation.
|
||||
*/
|
||||
|
||||
struct ll_ringbuffer_data {
|
||||
al::byte *buf;
|
||||
size_t len;
|
||||
};
|
||||
using ll_ringbuffer_data_pair = std::pair<ll_ringbuffer_data,ll_ringbuffer_data>;
|
||||
|
||||
|
||||
struct RingBuffer {
|
||||
private:
|
||||
std::atomic<size_t> mWritePtr{0u};
|
||||
std::atomic<size_t> mReadPtr{0u};
|
||||
size_t mWriteSize{0u};
|
||||
size_t mSizeMask{0u};
|
||||
size_t mElemSize{0u};
|
||||
|
||||
al::FlexArray<al::byte, 16> mBuffer;
|
||||
|
||||
public:
|
||||
RingBuffer(const size_t count) : mBuffer{count} { }
|
||||
|
||||
/** Reset the read and write pointers to zero. This is not thread safe. */
|
||||
void reset() noexcept;
|
||||
|
||||
/**
|
||||
* The non-copying data reader. Returns two ringbuffer data pointers that
|
||||
* hold the current readable data. If the readable data is in one segment
|
||||
* the second segment has zero length.
|
||||
*/
|
||||
ll_ringbuffer_data_pair getReadVector() const noexcept;
|
||||
/**
|
||||
* The non-copying data writer. Returns two ringbuffer data pointers that
|
||||
* hold the current writeable data. If the writeable data is in one segment
|
||||
* the second segment has zero length.
|
||||
*/
|
||||
ll_ringbuffer_data_pair getWriteVector() const noexcept;
|
||||
|
||||
/**
|
||||
* Return the number of elements available for reading. This is the number
|
||||
* of elements in front of the read pointer and behind the write pointer.
|
||||
*/
|
||||
size_t readSpace() const noexcept
|
||||
{
|
||||
const size_t w{mWritePtr.load(std::memory_order_acquire)};
|
||||
const size_t r{mReadPtr.load(std::memory_order_acquire)};
|
||||
return (w-r) & mSizeMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* The copying data reader. Copy at most `cnt' elements into `dest'.
|
||||
* Returns the actual number of elements copied.
|
||||
*/
|
||||
size_t read(void *dest, size_t cnt) noexcept;
|
||||
/**
|
||||
* The copying data reader w/o read pointer advance. Copy at most `cnt'
|
||||
* elements into `dest'. Returns the actual number of elements copied.
|
||||
*/
|
||||
size_t peek(void *dest, size_t cnt) const noexcept;
|
||||
/** Advance the read pointer `cnt' places. */
|
||||
void readAdvance(size_t cnt) noexcept
|
||||
{ mReadPtr.fetch_add(cnt, std::memory_order_acq_rel); }
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of elements available for writing. This is the number
|
||||
* of elements in front of the write pointer and behind the read pointer.
|
||||
*/
|
||||
size_t writeSpace() const noexcept
|
||||
{
|
||||
const size_t w{mWritePtr.load(std::memory_order_acquire)};
|
||||
const size_t r{mReadPtr.load(std::memory_order_acquire) + mWriteSize - mSizeMask};
|
||||
return (r-w-1) & mSizeMask;
|
||||
}
|
||||
|
||||
/**
|
||||
* The copying data writer. Copy at most `cnt' elements from `src'. Returns
|
||||
* the actual number of elements copied.
|
||||
*/
|
||||
size_t write(const void *src, size_t cnt) noexcept;
|
||||
/** Advance the write pointer `cnt' places. */
|
||||
void writeAdvance(size_t cnt) noexcept
|
||||
{ mWritePtr.fetch_add(cnt, std::memory_order_acq_rel); }
|
||||
|
||||
/**
|
||||
* Create a new ringbuffer to hold at least `sz' elements of `elem_sz'
|
||||
* bytes. The number of elements is rounded up to the next power of two
|
||||
* (even if it is already a power of two, to ensure the requested amount
|
||||
* can be written).
|
||||
*/
|
||||
static std::unique_ptr<RingBuffer> Create(size_t sz, size_t elem_sz, int limit_writes);
|
||||
|
||||
DEF_FAM_NEWDEL(RingBuffer, mBuffer)
|
||||
};
|
||||
using RingBufferPtr = std::unique_ptr<RingBuffer>;
|
||||
|
||||
#endif /* RINGBUFFER_H */
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "rwlock.h"
|
||||
|
||||
#include "bool.h"
|
||||
#include "atomic.h"
|
||||
#include "threads.h"
|
||||
|
||||
|
||||
/* A simple spinlock. Yield the thread while the given integer is set by
|
||||
* another. Could probably be improved... */
|
||||
#define LOCK(l) do { \
|
||||
while(ATOMIC_FLAG_TEST_AND_SET(&(l), almemory_order_acq_rel) == true) \
|
||||
althrd_yield(); \
|
||||
} while(0)
|
||||
#define UNLOCK(l) ATOMIC_FLAG_CLEAR(&(l), almemory_order_release)
|
||||
|
||||
|
||||
void RWLockInit(RWLock *lock)
|
||||
{
|
||||
InitRef(&lock->read_count, 0);
|
||||
InitRef(&lock->write_count, 0);
|
||||
ATOMIC_FLAG_CLEAR(&lock->read_lock, almemory_order_relaxed);
|
||||
ATOMIC_FLAG_CLEAR(&lock->read_entry_lock, almemory_order_relaxed);
|
||||
ATOMIC_FLAG_CLEAR(&lock->write_lock, almemory_order_relaxed);
|
||||
}
|
||||
|
||||
void ReadLock(RWLock *lock)
|
||||
{
|
||||
LOCK(lock->read_entry_lock);
|
||||
LOCK(lock->read_lock);
|
||||
/* NOTE: ATOMIC_ADD returns the *old* value! */
|
||||
if(ATOMIC_ADD(&lock->read_count, 1, almemory_order_acq_rel) == 0)
|
||||
LOCK(lock->write_lock);
|
||||
UNLOCK(lock->read_lock);
|
||||
UNLOCK(lock->read_entry_lock);
|
||||
}
|
||||
|
||||
void ReadUnlock(RWLock *lock)
|
||||
{
|
||||
/* NOTE: ATOMIC_SUB returns the *old* value! */
|
||||
if(ATOMIC_SUB(&lock->read_count, 1, almemory_order_acq_rel) == 1)
|
||||
UNLOCK(lock->write_lock);
|
||||
}
|
||||
|
||||
void WriteLock(RWLock *lock)
|
||||
{
|
||||
if(ATOMIC_ADD(&lock->write_count, 1, almemory_order_acq_rel) == 0)
|
||||
LOCK(lock->read_lock);
|
||||
LOCK(lock->write_lock);
|
||||
}
|
||||
|
||||
void WriteUnlock(RWLock *lock)
|
||||
{
|
||||
UNLOCK(lock->write_lock);
|
||||
if(ATOMIC_SUB(&lock->write_count, 1, almemory_order_acq_rel) == 1)
|
||||
UNLOCK(lock->read_lock);
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
#ifndef AL_RWLOCK_H
|
||||
#define AL_RWLOCK_H
|
||||
|
||||
#include "bool.h"
|
||||
#include "atomic.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
RefCount read_count;
|
||||
RefCount write_count;
|
||||
ATOMIC_FLAG read_lock;
|
||||
ATOMIC_FLAG read_entry_lock;
|
||||
ATOMIC_FLAG write_lock;
|
||||
} RWLock;
|
||||
#define RWLOCK_STATIC_INITIALIZE { ATOMIC_INIT_STATIC(0), ATOMIC_INIT_STATIC(0), \
|
||||
ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT, ATOMIC_FLAG_INIT }
|
||||
|
||||
void RWLockInit(RWLock *lock);
|
||||
void ReadLock(RWLock *lock);
|
||||
void ReadUnlock(RWLock *lock);
|
||||
void WriteLock(RWLock *lock);
|
||||
void WriteUnlock(RWLock *lock);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AL_RWLOCK_H */
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#ifndef AL_STATIC_ASSERT_H
|
||||
#define AL_STATIC_ASSERT_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#ifndef static_assert
|
||||
#ifdef HAVE_C11_STATIC_ASSERT
|
||||
#define static_assert _Static_assert
|
||||
#else
|
||||
#define CTASTR2(_pre,_post) _pre##_post
|
||||
#define CTASTR(_pre,_post) CTASTR2(_pre,_post)
|
||||
#if defined(__COUNTER__)
|
||||
#define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__)
|
||||
#else
|
||||
#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); }
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* AL_STATIC_ASSERT_H */
|
||||
64
Engine/lib/openal-soft/common/strutils.cpp
Normal file
64
Engine/lib/openal-soft/common/strutils.cpp
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "strutils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
std::string wstr_to_utf8(const WCHAR *wstr)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
|
||||
if(len > 0)
|
||||
{
|
||||
ret.resize(len);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &ret[0], len, nullptr, nullptr);
|
||||
ret.pop_back();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::wstring utf8_to_wstr(const char *str)
|
||||
{
|
||||
std::wstring ret;
|
||||
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
|
||||
if(len > 0)
|
||||
{
|
||||
ret.resize(len);
|
||||
MultiByteToWideChar(CP_UTF8, 0, str, -1, &ret[0], len);
|
||||
ret.pop_back();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace al {
|
||||
|
||||
al::optional<std::string> getenv(const char *envname)
|
||||
{
|
||||
const char *str{std::getenv(envname)};
|
||||
if(str && str[0] != '\0')
|
||||
return al::make_optional<std::string>(str);
|
||||
return al::nullopt;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
al::optional<std::wstring> getenv(const WCHAR *envname)
|
||||
{
|
||||
const WCHAR *str{_wgetenv(envname)};
|
||||
if(str && str[0] != L'\0')
|
||||
return al::make_optional<std::wstring>(str);
|
||||
return al::nullopt;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace al
|
||||
24
Engine/lib/openal-soft/common/strutils.h
Normal file
24
Engine/lib/openal-soft/common/strutils.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef AL_STRUTILS_H
|
||||
#define AL_STRUTILS_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "aloptional.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <wchar.h>
|
||||
|
||||
std::string wstr_to_utf8(const wchar_t *wstr);
|
||||
std::wstring utf8_to_wstr(const char *str);
|
||||
#endif
|
||||
|
||||
namespace al {
|
||||
|
||||
al::optional<std::string> getenv(const char *envname);
|
||||
#ifdef _WIN32
|
||||
al::optional<std::wstring> getenv(const wchar_t *envname);
|
||||
#endif
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_STRUTILS_H */
|
||||
|
|
@ -1,712 +0,0 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2007 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "threads.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "uintmap.h"
|
||||
|
||||
|
||||
extern inline althrd_t althrd_current(void);
|
||||
extern inline int althrd_equal(althrd_t thr0, althrd_t thr1);
|
||||
extern inline void althrd_exit(int res);
|
||||
extern inline void althrd_yield(void);
|
||||
|
||||
extern inline int almtx_lock(almtx_t *mtx);
|
||||
extern inline int almtx_unlock(almtx_t *mtx);
|
||||
extern inline int almtx_trylock(almtx_t *mtx);
|
||||
|
||||
extern inline void *altss_get(altss_t tss_id);
|
||||
extern inline int altss_set(altss_t tss_id, void *val);
|
||||
|
||||
|
||||
#ifndef UNUSED
|
||||
#if defined(__cplusplus)
|
||||
#define UNUSED(x)
|
||||
#elif defined(__GNUC__)
|
||||
#define UNUSED(x) UNUSED_##x __attribute__((unused))
|
||||
#elif defined(__LCLINT__)
|
||||
#define UNUSED(x) /*@unused@*/ x
|
||||
#else
|
||||
#define UNUSED(x) x
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#define THREAD_STACK_SIZE (2*1024*1024) /* 2MB */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
|
||||
|
||||
/* An associative map of uint:void* pairs. The key is the unique Thread ID and
|
||||
* the value is the thread HANDLE. The thread ID is passed around as the
|
||||
* althrd_t since there is only one ID per thread, whereas a thread may be
|
||||
* referenced by multiple different HANDLEs. This map allows retrieving the
|
||||
* original handle which is needed to join the thread and get its return value.
|
||||
*/
|
||||
static UIntMap ThrdIdHandle = UINTMAP_STATIC_INITIALIZE;
|
||||
|
||||
/* An associative map of uint:void* pairs. The key is the TLS index (given by
|
||||
* TlsAlloc), and the value is the altss_dtor_t callback. When a thread exits,
|
||||
* we iterate over the TLS indices for their thread-local value and call the
|
||||
* destructor function with it if they're both not NULL.
|
||||
*/
|
||||
static UIntMap TlsDestructors = UINTMAP_STATIC_INITIALIZE;
|
||||
|
||||
|
||||
void althrd_setname(althrd_t thr, const char *name)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
#define MS_VC_EXCEPTION 0x406D1388
|
||||
#pragma pack(push,8)
|
||||
struct {
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} info;
|
||||
#pragma pack(pop)
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = thr;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try {
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION) {
|
||||
}
|
||||
#undef MS_VC_EXCEPTION
|
||||
#else
|
||||
(void)thr;
|
||||
(void)name;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
typedef struct thread_cntr {
|
||||
althrd_start_t func;
|
||||
void *arg;
|
||||
} thread_cntr;
|
||||
|
||||
static DWORD WINAPI althrd_starter(void *arg)
|
||||
{
|
||||
thread_cntr cntr;
|
||||
memcpy(&cntr, arg, sizeof(cntr));
|
||||
free(arg);
|
||||
|
||||
return (DWORD)((*cntr.func)(cntr.arg));
|
||||
}
|
||||
|
||||
|
||||
int althrd_create(althrd_t *thr, althrd_start_t func, void *arg)
|
||||
{
|
||||
thread_cntr *cntr;
|
||||
DWORD thrid;
|
||||
HANDLE hdl;
|
||||
|
||||
cntr = malloc(sizeof(*cntr));
|
||||
if(!cntr) return althrd_nomem;
|
||||
|
||||
cntr->func = func;
|
||||
cntr->arg = arg;
|
||||
|
||||
hdl = CreateThread(NULL, THREAD_STACK_SIZE, althrd_starter, cntr, 0, &thrid);
|
||||
if(!hdl)
|
||||
{
|
||||
free(cntr);
|
||||
return althrd_error;
|
||||
}
|
||||
InsertUIntMapEntry(&ThrdIdHandle, thrid, hdl);
|
||||
|
||||
*thr = thrid;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int althrd_detach(althrd_t thr)
|
||||
{
|
||||
HANDLE hdl = RemoveUIntMapKey(&ThrdIdHandle, thr);
|
||||
if(!hdl) return althrd_error;
|
||||
|
||||
CloseHandle(hdl);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int althrd_join(althrd_t thr, int *res)
|
||||
{
|
||||
DWORD code;
|
||||
|
||||
HANDLE hdl = RemoveUIntMapKey(&ThrdIdHandle, thr);
|
||||
if(!hdl) return althrd_error;
|
||||
|
||||
WaitForSingleObject(hdl, INFINITE);
|
||||
GetExitCodeThread(hdl, &code);
|
||||
CloseHandle(hdl);
|
||||
|
||||
if(res != NULL)
|
||||
*res = (int)code;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int althrd_sleep(const struct timespec *ts, struct timespec* UNUSED(rem))
|
||||
{
|
||||
DWORD msec;
|
||||
|
||||
if(ts->tv_sec < 0 || ts->tv_sec >= (0x7fffffff / 1000) ||
|
||||
ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000)
|
||||
return -2;
|
||||
|
||||
msec = (DWORD)(ts->tv_sec * 1000);
|
||||
msec += (DWORD)((ts->tv_nsec+999999) / 1000000);
|
||||
Sleep(msec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int almtx_init(almtx_t *mtx, int type)
|
||||
{
|
||||
if(!mtx) return althrd_error;
|
||||
|
||||
type &= ~almtx_recursive;
|
||||
if(type != almtx_plain)
|
||||
return althrd_error;
|
||||
|
||||
InitializeCriticalSection(mtx);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
void almtx_destroy(almtx_t *mtx)
|
||||
{
|
||||
DeleteCriticalSection(mtx);
|
||||
}
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
|
||||
int alcnd_init(alcnd_t *cond)
|
||||
{
|
||||
InitializeConditionVariable(cond);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int alcnd_signal(alcnd_t *cond)
|
||||
{
|
||||
WakeConditionVariable(cond);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int alcnd_broadcast(alcnd_t *cond)
|
||||
{
|
||||
WakeAllConditionVariable(cond);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int alcnd_wait(alcnd_t *cond, almtx_t *mtx)
|
||||
{
|
||||
if(SleepConditionVariableCS(cond, mtx, INFINITE) != 0)
|
||||
return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
void alcnd_destroy(alcnd_t* UNUSED(cond))
|
||||
{
|
||||
/* Nothing to delete? */
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* WARNING: This is a rather poor implementation of condition variables, with
|
||||
* known problems. However, it's simple, efficient, and good enough for now to
|
||||
* not require Vista. Based on "Strategies for Implementing POSIX Condition
|
||||
* Variables" by Douglas C. Schmidt and Irfan Pyarali:
|
||||
* http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
|
||||
*/
|
||||
/* A better solution may be using Wine's implementation. It requires internals
|
||||
* (NtCreateKeyedEvent, NtReleaseKeyedEvent, and NtWaitForKeyedEvent) from
|
||||
* ntdll, and implemention of exchange and compare-exchange for RefCounts.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
RefCount wait_count;
|
||||
|
||||
HANDLE events[2];
|
||||
} _int_alcnd_t;
|
||||
enum {
|
||||
SIGNAL = 0,
|
||||
BROADCAST = 1
|
||||
};
|
||||
|
||||
int alcnd_init(alcnd_t *cond)
|
||||
{
|
||||
_int_alcnd_t *icond = calloc(1, sizeof(*icond));
|
||||
if(!icond) return althrd_nomem;
|
||||
|
||||
InitRef(&icond->wait_count, 0);
|
||||
|
||||
icond->events[SIGNAL] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
icond->events[BROADCAST] = CreateEventW(NULL, TRUE, FALSE, NULL);
|
||||
if(!icond->events[SIGNAL] || !icond->events[BROADCAST])
|
||||
{
|
||||
if(icond->events[SIGNAL])
|
||||
CloseHandle(icond->events[SIGNAL]);
|
||||
if(icond->events[BROADCAST])
|
||||
CloseHandle(icond->events[BROADCAST]);
|
||||
free(icond);
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
cond->Ptr = icond;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int alcnd_signal(alcnd_t *cond)
|
||||
{
|
||||
_int_alcnd_t *icond = cond->Ptr;
|
||||
if(ReadRef(&icond->wait_count) > 0)
|
||||
SetEvent(icond->events[SIGNAL]);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int alcnd_broadcast(alcnd_t *cond)
|
||||
{
|
||||
_int_alcnd_t *icond = cond->Ptr;
|
||||
if(ReadRef(&icond->wait_count) > 0)
|
||||
SetEvent(icond->events[BROADCAST]);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int alcnd_wait(alcnd_t *cond, almtx_t *mtx)
|
||||
{
|
||||
_int_alcnd_t *icond = cond->Ptr;
|
||||
int res;
|
||||
|
||||
IncrementRef(&icond->wait_count);
|
||||
LeaveCriticalSection(mtx);
|
||||
|
||||
res = WaitForMultipleObjects(2, icond->events, FALSE, INFINITE);
|
||||
|
||||
if(DecrementRef(&icond->wait_count) == 0 && res == WAIT_OBJECT_0+BROADCAST)
|
||||
ResetEvent(icond->events[BROADCAST]);
|
||||
EnterCriticalSection(mtx);
|
||||
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
void alcnd_destroy(alcnd_t *cond)
|
||||
{
|
||||
_int_alcnd_t *icond = cond->Ptr;
|
||||
CloseHandle(icond->events[SIGNAL]);
|
||||
CloseHandle(icond->events[BROADCAST]);
|
||||
free(icond);
|
||||
}
|
||||
#endif /* defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600 */
|
||||
|
||||
|
||||
int alsem_init(alsem_t *sem, unsigned int initial)
|
||||
{
|
||||
*sem = CreateSemaphore(NULL, initial, INT_MAX, NULL);
|
||||
if(*sem != NULL) return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
void alsem_destroy(alsem_t *sem)
|
||||
{
|
||||
CloseHandle(*sem);
|
||||
}
|
||||
|
||||
int alsem_post(alsem_t *sem)
|
||||
{
|
||||
DWORD ret = ReleaseSemaphore(*sem, 1, NULL);
|
||||
if(ret) return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int alsem_wait(alsem_t *sem)
|
||||
{
|
||||
DWORD ret = WaitForSingleObject(*sem, INFINITE);
|
||||
if(ret == WAIT_OBJECT_0) return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int alsem_trywait(alsem_t *sem)
|
||||
{
|
||||
DWORD ret = WaitForSingleObject(*sem, 0);
|
||||
if(ret == WAIT_OBJECT_0) return althrd_success;
|
||||
if(ret == WAIT_TIMEOUT) return althrd_busy;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
|
||||
int altss_create(altss_t *tss_id, altss_dtor_t callback)
|
||||
{
|
||||
DWORD key = TlsAlloc();
|
||||
if(key == TLS_OUT_OF_INDEXES)
|
||||
return althrd_error;
|
||||
|
||||
*tss_id = key;
|
||||
if(callback != NULL)
|
||||
InsertUIntMapEntry(&TlsDestructors, key, callback);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
void altss_delete(altss_t tss_id)
|
||||
{
|
||||
RemoveUIntMapKey(&TlsDestructors, tss_id);
|
||||
TlsFree(tss_id);
|
||||
}
|
||||
|
||||
|
||||
int altimespec_get(struct timespec *ts, int base)
|
||||
{
|
||||
static_assert(sizeof(FILETIME) == sizeof(ULARGE_INTEGER),
|
||||
"Size of FILETIME does not match ULARGE_INTEGER");
|
||||
if(base == AL_TIME_UTC)
|
||||
{
|
||||
union {
|
||||
FILETIME ftime;
|
||||
ULARGE_INTEGER ulint;
|
||||
} systime;
|
||||
GetSystemTimeAsFileTime(&systime.ftime);
|
||||
/* FILETIME is in 100-nanosecond units, or 1/10th of a microsecond. */
|
||||
ts->tv_sec = systime.ulint.QuadPart/10000000;
|
||||
ts->tv_nsec = (systime.ulint.QuadPart%10000000) * 100;
|
||||
return base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void alcall_once(alonce_flag *once, void (*callback)(void))
|
||||
{
|
||||
LONG ret;
|
||||
while((ret=InterlockedExchange(once, 1)) == 1)
|
||||
althrd_yield();
|
||||
if(ret == 0)
|
||||
(*callback)();
|
||||
InterlockedExchange(once, 2);
|
||||
}
|
||||
|
||||
|
||||
void althrd_deinit(void)
|
||||
{
|
||||
ResetUIntMap(&ThrdIdHandle);
|
||||
ResetUIntMap(&TlsDestructors);
|
||||
}
|
||||
|
||||
void althrd_thread_detach(void)
|
||||
{
|
||||
ALsizei i;
|
||||
|
||||
LockUIntMapRead(&TlsDestructors);
|
||||
for(i = 0;i < TlsDestructors.size;i++)
|
||||
{
|
||||
void *ptr = altss_get(TlsDestructors.keys[i]);
|
||||
altss_dtor_t callback = (altss_dtor_t)TlsDestructors.values[i];
|
||||
if(ptr && callback) callback(ptr);
|
||||
}
|
||||
UnlockUIntMapRead(&TlsDestructors);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
|
||||
extern inline int althrd_sleep(const struct timespec *ts, struct timespec *rem);
|
||||
extern inline void alcall_once(alonce_flag *once, void (*callback)(void));
|
||||
|
||||
extern inline void althrd_deinit(void);
|
||||
extern inline void althrd_thread_detach(void);
|
||||
|
||||
void althrd_setname(althrd_t thr, const char *name)
|
||||
{
|
||||
#if defined(HAVE_PTHREAD_SETNAME_NP)
|
||||
#if defined(PTHREAD_SETNAME_NP_ONE_PARAM)
|
||||
if(althrd_equal(thr, althrd_current()))
|
||||
pthread_setname_np(name);
|
||||
#elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS)
|
||||
pthread_setname_np(thr, "%s", (void*)name);
|
||||
#else
|
||||
pthread_setname_np(thr, name);
|
||||
#endif
|
||||
#elif defined(HAVE_PTHREAD_SET_NAME_NP)
|
||||
pthread_set_name_np(thr, name);
|
||||
#else
|
||||
(void)thr;
|
||||
(void)name;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
typedef struct thread_cntr {
|
||||
althrd_start_t func;
|
||||
void *arg;
|
||||
} thread_cntr;
|
||||
|
||||
static void *althrd_starter(void *arg)
|
||||
{
|
||||
thread_cntr cntr;
|
||||
memcpy(&cntr, arg, sizeof(cntr));
|
||||
free(arg);
|
||||
|
||||
return (void*)(intptr_t)((*cntr.func)(cntr.arg));
|
||||
}
|
||||
|
||||
|
||||
int althrd_create(althrd_t *thr, althrd_start_t func, void *arg)
|
||||
{
|
||||
thread_cntr *cntr;
|
||||
pthread_attr_t attr;
|
||||
size_t stackmult = 1;
|
||||
int err;
|
||||
|
||||
cntr = malloc(sizeof(*cntr));
|
||||
if(!cntr) return althrd_nomem;
|
||||
|
||||
if(pthread_attr_init(&attr) != 0)
|
||||
{
|
||||
free(cntr);
|
||||
return althrd_error;
|
||||
}
|
||||
retry_stacksize:
|
||||
if(pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE*stackmult) != 0)
|
||||
{
|
||||
pthread_attr_destroy(&attr);
|
||||
free(cntr);
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
cntr->func = func;
|
||||
cntr->arg = arg;
|
||||
if((err=pthread_create(thr, &attr, althrd_starter, cntr)) == 0)
|
||||
{
|
||||
pthread_attr_destroy(&attr);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
if(err == EINVAL)
|
||||
{
|
||||
/* If an invalid stack size, try increasing it (limit x4, 8MB). */
|
||||
if(stackmult < 4)
|
||||
{
|
||||
stackmult *= 2;
|
||||
goto retry_stacksize;
|
||||
}
|
||||
/* If still nothing, try defaults and hope they're good enough. */
|
||||
if(pthread_create(thr, NULL, althrd_starter, cntr) == 0)
|
||||
{
|
||||
pthread_attr_destroy(&attr);
|
||||
return althrd_success;
|
||||
}
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
free(cntr);
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int althrd_detach(althrd_t thr)
|
||||
{
|
||||
if(pthread_detach(thr) != 0)
|
||||
return althrd_error;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
int althrd_join(althrd_t thr, int *res)
|
||||
{
|
||||
void *code;
|
||||
|
||||
if(pthread_join(thr, &code) != 0)
|
||||
return althrd_error;
|
||||
if(res != NULL)
|
||||
*res = (int)(intptr_t)code;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
|
||||
int almtx_init(almtx_t *mtx, int type)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(!mtx) return althrd_error;
|
||||
if((type&~almtx_recursive) != 0)
|
||||
return althrd_error;
|
||||
|
||||
if(type == almtx_plain)
|
||||
ret = pthread_mutex_init(mtx, NULL);
|
||||
else
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
ret = pthread_mutexattr_init(&attr);
|
||||
if(ret) return althrd_error;
|
||||
|
||||
if(type == almtx_recursive)
|
||||
{
|
||||
ret = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
#ifdef HAVE_PTHREAD_MUTEXATTR_SETKIND_NP
|
||||
if(ret != 0)
|
||||
ret = pthread_mutexattr_setkind_np(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
ret = 1;
|
||||
if(ret == 0)
|
||||
ret = pthread_mutex_init(mtx, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
return ret ? althrd_error : althrd_success;
|
||||
}
|
||||
|
||||
void almtx_destroy(almtx_t *mtx)
|
||||
{
|
||||
pthread_mutex_destroy(mtx);
|
||||
}
|
||||
|
||||
int alcnd_init(alcnd_t *cond)
|
||||
{
|
||||
if(pthread_cond_init(cond, NULL) == 0)
|
||||
return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int alcnd_signal(alcnd_t *cond)
|
||||
{
|
||||
if(pthread_cond_signal(cond) == 0)
|
||||
return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int alcnd_broadcast(alcnd_t *cond)
|
||||
{
|
||||
if(pthread_cond_broadcast(cond) == 0)
|
||||
return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int alcnd_wait(alcnd_t *cond, almtx_t *mtx)
|
||||
{
|
||||
if(pthread_cond_wait(cond, mtx) == 0)
|
||||
return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
void alcnd_destroy(alcnd_t *cond)
|
||||
{
|
||||
pthread_cond_destroy(cond);
|
||||
}
|
||||
|
||||
|
||||
int alsem_init(alsem_t *sem, unsigned int initial)
|
||||
{
|
||||
if(sem_init(sem, 0, initial) == 0)
|
||||
return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
void alsem_destroy(alsem_t *sem)
|
||||
{
|
||||
sem_destroy(sem);
|
||||
}
|
||||
|
||||
int alsem_post(alsem_t *sem)
|
||||
{
|
||||
if(sem_post(sem) == 0)
|
||||
return althrd_success;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int alsem_wait(alsem_t *sem)
|
||||
{
|
||||
if(sem_wait(sem) == 0) return althrd_success;
|
||||
if(errno == EINTR) return -2;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
int alsem_trywait(alsem_t *sem)
|
||||
{
|
||||
if(sem_trywait(sem) == 0) return althrd_success;
|
||||
if(errno == EWOULDBLOCK) return althrd_busy;
|
||||
if(errno == EINTR) return -2;
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
|
||||
int altss_create(altss_t *tss_id, altss_dtor_t callback)
|
||||
{
|
||||
if(pthread_key_create(tss_id, callback) != 0)
|
||||
return althrd_error;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
void altss_delete(altss_t tss_id)
|
||||
{
|
||||
pthread_key_delete(tss_id);
|
||||
}
|
||||
|
||||
|
||||
int altimespec_get(struct timespec *ts, int base)
|
||||
{
|
||||
if(base == AL_TIME_UTC)
|
||||
{
|
||||
int ret;
|
||||
#if _POSIX_TIMERS > 0
|
||||
ret = clock_gettime(CLOCK_REALTIME, ts);
|
||||
if(ret == 0) return base;
|
||||
#else /* _POSIX_TIMERS > 0 */
|
||||
struct timeval tv;
|
||||
ret = gettimeofday(&tv, NULL);
|
||||
if(ret == 0)
|
||||
{
|
||||
ts->tv_sec = tv.tv_sec;
|
||||
ts->tv_nsec = tv.tv_usec * 1000;
|
||||
return base;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void al_nssleep(unsigned long nsec)
|
||||
{
|
||||
struct timespec ts, rem;
|
||||
ts.tv_sec = nsec / 1000000000ul;
|
||||
ts.tv_nsec = nsec % 1000000000ul;
|
||||
|
||||
while(althrd_sleep(&ts, &rem) == -1)
|
||||
ts = rem;
|
||||
}
|
||||
176
Engine/lib/openal-soft/common/threads.cpp
Normal file
176
Engine/lib/openal-soft/common/threads.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
* OpenAL cross platform audio library
|
||||
* Copyright (C) 1999-2007 by authors.
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "opthelpers.h"
|
||||
#include "threads.h"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
void althrd_setname(const char *name)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
#define MS_VC_EXCEPTION 0x406D1388
|
||||
#pragma pack(push,8)
|
||||
struct {
|
||||
DWORD dwType; // Must be 0x1000.
|
||||
LPCSTR szName; // Pointer to name (in user addr space).
|
||||
DWORD dwThreadID; // Thread ID (-1=caller thread).
|
||||
DWORD dwFlags; // Reserved for future use, must be zero.
|
||||
} info;
|
||||
#pragma pack(pop)
|
||||
info.dwType = 0x1000;
|
||||
info.szName = name;
|
||||
info.dwThreadID = ~DWORD{0};
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try {
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION) {
|
||||
}
|
||||
#undef MS_VC_EXCEPTION
|
||||
#else
|
||||
(void)name;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace al {
|
||||
|
||||
semaphore::semaphore(unsigned int initial)
|
||||
{
|
||||
if(initial > static_cast<unsigned int>(std::numeric_limits<int>::max()))
|
||||
throw std::system_error(std::make_error_code(std::errc::value_too_large));
|
||||
mSem = CreateSemaphore(nullptr, initial, std::numeric_limits<int>::max(), nullptr);
|
||||
if(mSem == nullptr)
|
||||
throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again));
|
||||
}
|
||||
|
||||
semaphore::~semaphore()
|
||||
{ CloseHandle(mSem); }
|
||||
|
||||
void semaphore::post()
|
||||
{
|
||||
if UNLIKELY(!ReleaseSemaphore(static_cast<HANDLE>(mSem), 1, nullptr))
|
||||
throw std::system_error(std::make_error_code(std::errc::value_too_large));
|
||||
}
|
||||
|
||||
void semaphore::wait() noexcept
|
||||
{ WaitForSingleObject(static_cast<HANDLE>(mSem), INFINITE); }
|
||||
|
||||
bool semaphore::try_wait() noexcept
|
||||
{ return WaitForSingleObject(static_cast<HANDLE>(mSem), 0) == WAIT_OBJECT_0; }
|
||||
|
||||
} // namespace al
|
||||
|
||||
#else
|
||||
|
||||
#if defined(HAVE_PTHREAD_SETNAME_NP) || defined(HAVE_PTHREAD_SET_NAME_NP)
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
void althrd_setname(const char *name)
|
||||
{
|
||||
#if defined(HAVE_PTHREAD_SET_NAME_NP)
|
||||
pthread_set_name_np(pthread_self(), name);
|
||||
#elif defined(PTHREAD_SETNAME_NP_ONE_PARAM)
|
||||
pthread_setname_np(name);
|
||||
#elif defined(PTHREAD_SETNAME_NP_THREE_PARAMS)
|
||||
pthread_setname_np(pthread_self(), "%s", (void*)name);
|
||||
#else
|
||||
pthread_setname_np(pthread_self(), name);
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void althrd_setname(const char*) { }
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
namespace al {
|
||||
|
||||
semaphore::semaphore(unsigned int initial)
|
||||
{
|
||||
mSem = dispatch_semaphore_create(initial);
|
||||
if(!mSem)
|
||||
throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again));
|
||||
}
|
||||
|
||||
semaphore::~semaphore()
|
||||
{ dispatch_release(mSem); }
|
||||
|
||||
void semaphore::post()
|
||||
{ dispatch_semaphore_signal(mSem); }
|
||||
|
||||
void semaphore::wait() noexcept
|
||||
{ dispatch_semaphore_wait(mSem, DISPATCH_TIME_FOREVER); }
|
||||
|
||||
bool semaphore::try_wait() noexcept
|
||||
{ return dispatch_semaphore_wait(mSem, DISPATCH_TIME_NOW) == 0; }
|
||||
|
||||
} // namespace al
|
||||
|
||||
#else /* !__APPLE__ */
|
||||
|
||||
#include <cerrno>
|
||||
|
||||
namespace al {
|
||||
|
||||
semaphore::semaphore(unsigned int initial)
|
||||
{
|
||||
if(sem_init(&mSem, 0, initial) != 0)
|
||||
throw std::system_error(std::make_error_code(std::errc::resource_unavailable_try_again));
|
||||
}
|
||||
|
||||
semaphore::~semaphore()
|
||||
{ sem_destroy(&mSem); }
|
||||
|
||||
void semaphore::post()
|
||||
{
|
||||
if(sem_post(&mSem) != 0)
|
||||
throw std::system_error(std::make_error_code(std::errc::value_too_large));
|
||||
}
|
||||
|
||||
void semaphore::wait() noexcept
|
||||
{
|
||||
while(sem_wait(&mSem) == -1 && errno == EINTR) {
|
||||
}
|
||||
}
|
||||
|
||||
bool semaphore::try_wait() noexcept
|
||||
{ return sem_trywait(&mSem) == 0; }
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef AL_THREADS_H
|
||||
#define AL_THREADS_H
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#if defined(__GNUC__) && defined(__i386__)
|
||||
/* force_align_arg_pointer is required for proper function arguments aligning
|
||||
* when SSE code is used. Some systems (Windows, QNX) do not guarantee our
|
||||
|
|
@ -13,248 +11,38 @@
|
|||
#define FORCE_ALIGN
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
althrd_success = 0,
|
||||
althrd_error,
|
||||
althrd_nomem,
|
||||
althrd_timedout,
|
||||
althrd_busy
|
||||
};
|
||||
|
||||
enum {
|
||||
almtx_plain = 0,
|
||||
almtx_recursive = 1,
|
||||
};
|
||||
|
||||
typedef int (*althrd_start_t)(void*);
|
||||
typedef void (*altss_dtor_t)(void*);
|
||||
|
||||
|
||||
#define AL_TIME_UTC 1
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
#ifndef HAVE_STRUCT_TIMESPEC
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef DWORD althrd_t;
|
||||
typedef CRITICAL_SECTION almtx_t;
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0600
|
||||
typedef CONDITION_VARIABLE alcnd_t;
|
||||
#else
|
||||
typedef struct { void *Ptr; } alcnd_t;
|
||||
#endif
|
||||
typedef HANDLE alsem_t;
|
||||
typedef DWORD altss_t;
|
||||
typedef LONG alonce_flag;
|
||||
|
||||
#define AL_ONCE_FLAG_INIT 0
|
||||
|
||||
int althrd_sleep(const struct timespec *ts, struct timespec *rem);
|
||||
void alcall_once(alonce_flag *once, void (*callback)(void));
|
||||
|
||||
void althrd_deinit(void);
|
||||
void althrd_thread_detach(void);
|
||||
|
||||
|
||||
inline althrd_t althrd_current(void)
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
inline int althrd_equal(althrd_t thr0, althrd_t thr1)
|
||||
{
|
||||
return thr0 == thr1;
|
||||
}
|
||||
|
||||
inline void althrd_exit(int res)
|
||||
{
|
||||
ExitThread(res);
|
||||
}
|
||||
|
||||
inline void althrd_yield(void)
|
||||
{
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
|
||||
inline int almtx_lock(almtx_t *mtx)
|
||||
{
|
||||
if(!mtx) return althrd_error;
|
||||
EnterCriticalSection(mtx);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
inline int almtx_unlock(almtx_t *mtx)
|
||||
{
|
||||
if(!mtx) return althrd_error;
|
||||
LeaveCriticalSection(mtx);
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
inline int almtx_trylock(almtx_t *mtx)
|
||||
{
|
||||
if(!mtx) return althrd_error;
|
||||
if(!TryEnterCriticalSection(mtx))
|
||||
return althrd_busy;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
|
||||
inline void *altss_get(altss_t tss_id)
|
||||
{
|
||||
return TlsGetValue(tss_id);
|
||||
}
|
||||
|
||||
inline int altss_set(altss_t tss_id, void *val)
|
||||
{
|
||||
if(TlsSetValue(tss_id, val) == 0)
|
||||
return althrd_error;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#if defined(__APPLE__)
|
||||
#include <dispatch/dispatch.h>
|
||||
#elif !defined(_WIN32)
|
||||
#include <semaphore.h>
|
||||
|
||||
|
||||
typedef pthread_t althrd_t;
|
||||
typedef pthread_mutex_t almtx_t;
|
||||
typedef pthread_cond_t alcnd_t;
|
||||
typedef sem_t alsem_t;
|
||||
typedef pthread_key_t altss_t;
|
||||
typedef pthread_once_t alonce_flag;
|
||||
|
||||
#define AL_ONCE_FLAG_INIT PTHREAD_ONCE_INIT
|
||||
|
||||
|
||||
inline althrd_t althrd_current(void)
|
||||
{
|
||||
return pthread_self();
|
||||
}
|
||||
|
||||
inline int althrd_equal(althrd_t thr0, althrd_t thr1)
|
||||
{
|
||||
return pthread_equal(thr0, thr1);
|
||||
}
|
||||
|
||||
inline void althrd_exit(int res)
|
||||
{
|
||||
pthread_exit((void*)(intptr_t)res);
|
||||
}
|
||||
|
||||
inline void althrd_yield(void)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
inline int althrd_sleep(const struct timespec *ts, struct timespec *rem)
|
||||
{
|
||||
int ret = nanosleep(ts, rem);
|
||||
if(ret != 0)
|
||||
{
|
||||
ret = ((errno==EINTR) ? -1 : -2);
|
||||
errno = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
inline int almtx_lock(almtx_t *mtx)
|
||||
{
|
||||
if(pthread_mutex_lock(mtx) != 0)
|
||||
return althrd_error;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
inline int almtx_unlock(almtx_t *mtx)
|
||||
{
|
||||
if(pthread_mutex_unlock(mtx) != 0)
|
||||
return althrd_error;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
inline int almtx_trylock(almtx_t *mtx)
|
||||
{
|
||||
int ret = pthread_mutex_trylock(mtx);
|
||||
switch(ret)
|
||||
{
|
||||
case 0: return althrd_success;
|
||||
case EBUSY: return althrd_busy;
|
||||
}
|
||||
return althrd_error;
|
||||
}
|
||||
|
||||
|
||||
inline void *altss_get(altss_t tss_id)
|
||||
{
|
||||
return pthread_getspecific(tss_id);
|
||||
}
|
||||
|
||||
inline int altss_set(altss_t tss_id, void *val)
|
||||
{
|
||||
if(pthread_setspecific(tss_id, val) != 0)
|
||||
return althrd_error;
|
||||
return althrd_success;
|
||||
}
|
||||
|
||||
|
||||
inline void alcall_once(alonce_flag *once, void (*callback)(void))
|
||||
{
|
||||
pthread_once(once, callback);
|
||||
}
|
||||
|
||||
|
||||
inline void althrd_deinit(void) { }
|
||||
inline void althrd_thread_detach(void) { }
|
||||
|
||||
#endif
|
||||
|
||||
void althrd_setname(const char *name);
|
||||
|
||||
int althrd_create(althrd_t *thr, althrd_start_t func, void *arg);
|
||||
int althrd_detach(althrd_t thr);
|
||||
int althrd_join(althrd_t thr, int *res);
|
||||
void althrd_setname(althrd_t thr, const char *name);
|
||||
namespace al {
|
||||
|
||||
int almtx_init(almtx_t *mtx, int type);
|
||||
void almtx_destroy(almtx_t *mtx);
|
||||
|
||||
int alcnd_init(alcnd_t *cond);
|
||||
int alcnd_signal(alcnd_t *cond);
|
||||
int alcnd_broadcast(alcnd_t *cond);
|
||||
int alcnd_wait(alcnd_t *cond, almtx_t *mtx);
|
||||
void alcnd_destroy(alcnd_t *cond);
|
||||
|
||||
int alsem_init(alsem_t *sem, unsigned int initial);
|
||||
void alsem_destroy(alsem_t *sem);
|
||||
int alsem_post(alsem_t *sem);
|
||||
int alsem_wait(alsem_t *sem);
|
||||
int alsem_trywait(alsem_t *sem);
|
||||
|
||||
int altss_create(altss_t *tss_id, altss_dtor_t callback);
|
||||
void altss_delete(altss_t tss_id);
|
||||
|
||||
int altimespec_get(struct timespec *ts, int base);
|
||||
|
||||
void al_nssleep(unsigned long nsec);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
class semaphore {
|
||||
#ifdef _WIN32
|
||||
using native_type = void*;
|
||||
#elif defined(__APPLE__)
|
||||
using native_type = dispatch_semaphore_t;
|
||||
#else
|
||||
using native_type = sem_t;
|
||||
#endif
|
||||
native_type mSem;
|
||||
|
||||
public:
|
||||
semaphore(unsigned int initial=0);
|
||||
semaphore(const semaphore&) = delete;
|
||||
~semaphore();
|
||||
|
||||
semaphore& operator=(const semaphore&) = delete;
|
||||
|
||||
void post();
|
||||
void wait() noexcept;
|
||||
bool try_wait() noexcept;
|
||||
};
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_THREADS_H */
|
||||
|
|
|
|||
|
|
@ -1,182 +0,0 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "uintmap.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
|
||||
extern inline void LockUIntMapRead(UIntMap *map);
|
||||
extern inline void UnlockUIntMapRead(UIntMap *map);
|
||||
extern inline void LockUIntMapWrite(UIntMap *map);
|
||||
extern inline void UnlockUIntMapWrite(UIntMap *map);
|
||||
|
||||
|
||||
void InitUIntMap(UIntMap *map, ALsizei limit)
|
||||
{
|
||||
map->keys = NULL;
|
||||
map->values = NULL;
|
||||
map->size = 0;
|
||||
map->capacity = 0;
|
||||
map->limit = limit;
|
||||
RWLockInit(&map->lock);
|
||||
}
|
||||
|
||||
void ResetUIntMap(UIntMap *map)
|
||||
{
|
||||
WriteLock(&map->lock);
|
||||
al_free(map->keys);
|
||||
map->keys = NULL;
|
||||
map->values = NULL;
|
||||
map->size = 0;
|
||||
map->capacity = 0;
|
||||
WriteUnlock(&map->lock);
|
||||
}
|
||||
|
||||
ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value)
|
||||
{
|
||||
ALsizei pos = 0;
|
||||
|
||||
WriteLock(&map->lock);
|
||||
if(map->size > 0)
|
||||
{
|
||||
ALsizei count = map->size;
|
||||
do {
|
||||
ALsizei step = count>>1;
|
||||
ALsizei i = pos+step;
|
||||
if(!(map->keys[i] < key))
|
||||
count = step;
|
||||
else
|
||||
{
|
||||
pos = i+1;
|
||||
count -= step+1;
|
||||
}
|
||||
} while(count > 0);
|
||||
}
|
||||
|
||||
if(pos == map->size || map->keys[pos] != key)
|
||||
{
|
||||
if(map->size >= map->limit)
|
||||
{
|
||||
WriteUnlock(&map->lock);
|
||||
return AL_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if(map->size == map->capacity)
|
||||
{
|
||||
ALuint *keys = NULL;
|
||||
ALvoid **values;
|
||||
ALsizei newcap, keylen;
|
||||
|
||||
newcap = (map->capacity ? (map->capacity<<1) : 4);
|
||||
if(map->limit > 0 && newcap > map->limit)
|
||||
newcap = map->limit;
|
||||
if(newcap > map->capacity)
|
||||
{
|
||||
/* Round the memory size for keys up to a multiple of the
|
||||
* pointer size.
|
||||
*/
|
||||
keylen = newcap * sizeof(map->keys[0]);
|
||||
keylen += sizeof(map->values[0]) - 1;
|
||||
keylen -= keylen%sizeof(map->values[0]);
|
||||
|
||||
keys = al_malloc(16, keylen + newcap*sizeof(map->values[0]));
|
||||
}
|
||||
if(!keys)
|
||||
{
|
||||
WriteUnlock(&map->lock);
|
||||
return AL_OUT_OF_MEMORY;
|
||||
}
|
||||
values = (ALvoid**)((ALbyte*)keys + keylen);
|
||||
|
||||
if(map->keys)
|
||||
{
|
||||
memcpy(keys, map->keys, map->size*sizeof(map->keys[0]));
|
||||
memcpy(values, map->values, map->size*sizeof(map->values[0]));
|
||||
}
|
||||
al_free(map->keys);
|
||||
map->keys = keys;
|
||||
map->values = values;
|
||||
map->capacity = newcap;
|
||||
}
|
||||
|
||||
if(pos < map->size)
|
||||
{
|
||||
memmove(&map->keys[pos+1], &map->keys[pos],
|
||||
(map->size-pos)*sizeof(map->keys[0]));
|
||||
memmove(&map->values[pos+1], &map->values[pos],
|
||||
(map->size-pos)*sizeof(map->values[0]));
|
||||
}
|
||||
map->size++;
|
||||
}
|
||||
map->keys[pos] = key;
|
||||
map->values[pos] = value;
|
||||
WriteUnlock(&map->lock);
|
||||
|
||||
return AL_NO_ERROR;
|
||||
}
|
||||
|
||||
ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key)
|
||||
{
|
||||
ALvoid *ptr = NULL;
|
||||
WriteLock(&map->lock);
|
||||
if(map->size > 0)
|
||||
{
|
||||
ALsizei pos = 0;
|
||||
ALsizei count = map->size;
|
||||
do {
|
||||
ALsizei step = count>>1;
|
||||
ALsizei i = pos+step;
|
||||
if(!(map->keys[i] < key))
|
||||
count = step;
|
||||
else
|
||||
{
|
||||
pos = i+1;
|
||||
count -= step+1;
|
||||
}
|
||||
} while(count > 0);
|
||||
if(pos < map->size && map->keys[pos] == key)
|
||||
{
|
||||
ptr = map->values[pos];
|
||||
if(pos < map->size-1)
|
||||
{
|
||||
memmove(&map->keys[pos], &map->keys[pos+1],
|
||||
(map->size-1-pos)*sizeof(map->keys[0]));
|
||||
memmove(&map->values[pos], &map->values[pos+1],
|
||||
(map->size-1-pos)*sizeof(map->values[0]));
|
||||
}
|
||||
map->size--;
|
||||
}
|
||||
}
|
||||
WriteUnlock(&map->lock);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key)
|
||||
{
|
||||
ALvoid *ptr = NULL;
|
||||
ReadLock(&map->lock);
|
||||
if(map->size > 0)
|
||||
{
|
||||
ALsizei pos = 0;
|
||||
ALsizei count = map->size;
|
||||
do {
|
||||
ALsizei step = count>>1;
|
||||
ALsizei i = pos+step;
|
||||
if(!(map->keys[i] < key))
|
||||
count = step;
|
||||
else
|
||||
{
|
||||
pos = i+1;
|
||||
count -= step+1;
|
||||
}
|
||||
} while(count > 0);
|
||||
if(pos < map->size && map->keys[pos] == key)
|
||||
ptr = map->values[pos];
|
||||
}
|
||||
ReadUnlock(&map->lock);
|
||||
return ptr;
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
#ifndef AL_UINTMAP_H
|
||||
#define AL_UINTMAP_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "rwlock.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct UIntMap {
|
||||
ALuint *keys;
|
||||
/* Shares memory with keys. */
|
||||
ALvoid **values;
|
||||
|
||||
ALsizei size;
|
||||
ALsizei capacity;
|
||||
ALsizei limit;
|
||||
RWLock lock;
|
||||
} UIntMap;
|
||||
#define UINTMAP_STATIC_INITIALIZE_N(_n) { NULL, NULL, 0, 0, (_n), RWLOCK_STATIC_INITIALIZE }
|
||||
#define UINTMAP_STATIC_INITIALIZE UINTMAP_STATIC_INITIALIZE_N(INT_MAX)
|
||||
|
||||
void InitUIntMap(UIntMap *map, ALsizei limit);
|
||||
void ResetUIntMap(UIntMap *map);
|
||||
ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value);
|
||||
ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key);
|
||||
ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key);
|
||||
|
||||
inline void LockUIntMapRead(UIntMap *map) { ReadLock(&map->lock); }
|
||||
inline void UnlockUIntMapRead(UIntMap *map) { ReadUnlock(&map->lock); }
|
||||
inline void LockUIntMapWrite(UIntMap *map) { WriteLock(&map->lock); }
|
||||
inline void UnlockUIntMapWrite(UIntMap *map) { WriteUnlock(&map->lock); }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* AL_UINTMAP_H */
|
||||
118
Engine/lib/openal-soft/common/vecmat.h
Normal file
118
Engine/lib/openal-soft/common/vecmat.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef COMMON_VECMAT_H
|
||||
#define COMMON_VECMAT_H
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
|
||||
#include "alspan.h"
|
||||
|
||||
|
||||
namespace alu {
|
||||
|
||||
template<typename T>
|
||||
class VectorR {
|
||||
static_assert(std::is_floating_point<T>::value, "Must use floating-point types");
|
||||
alignas(16) std::array<T,4> mVals;
|
||||
|
||||
public:
|
||||
constexpr VectorR() noexcept = default;
|
||||
constexpr VectorR(const VectorR&) noexcept = default;
|
||||
constexpr VectorR(T a, T b, T c, T d) noexcept : mVals{{a, b, c, d}} { }
|
||||
|
||||
constexpr VectorR& operator=(const VectorR&) noexcept = default;
|
||||
|
||||
T& operator[](size_t idx) noexcept { return mVals[idx]; }
|
||||
constexpr const T& operator[](size_t idx) const noexcept { return mVals[idx]; }
|
||||
|
||||
VectorR& operator+=(const VectorR &rhs) noexcept
|
||||
{
|
||||
mVals[0] += rhs.mVals[0];
|
||||
mVals[1] += rhs.mVals[1];
|
||||
mVals[2] += rhs.mVals[2];
|
||||
mVals[3] += rhs.mVals[3];
|
||||
return *this;
|
||||
}
|
||||
|
||||
T normalize()
|
||||
{
|
||||
const T length{std::sqrt(mVals[0]*mVals[0] + mVals[1]*mVals[1] + mVals[2]*mVals[2])};
|
||||
if(length > std::numeric_limits<T>::epsilon())
|
||||
{
|
||||
T inv_length{T{1}/length};
|
||||
mVals[0] *= inv_length;
|
||||
mVals[1] *= inv_length;
|
||||
mVals[2] *= inv_length;
|
||||
return length;
|
||||
}
|
||||
mVals[0] = mVals[1] = mVals[2] = T{0};
|
||||
return T{0};
|
||||
}
|
||||
|
||||
constexpr VectorR cross_product(const alu::VectorR<T> &rhs) const
|
||||
{
|
||||
return VectorR{
|
||||
(*this)[1]*rhs[2] - (*this)[2]*rhs[1],
|
||||
(*this)[2]*rhs[0] - (*this)[0]*rhs[2],
|
||||
(*this)[0]*rhs[1] - (*this)[1]*rhs[0],
|
||||
T{0}};
|
||||
}
|
||||
|
||||
constexpr T dot_product(const alu::VectorR<T> &rhs) const
|
||||
{ return (*this)[0]*rhs[0] + (*this)[1]*rhs[1] + (*this)[2]*rhs[2]; }
|
||||
};
|
||||
using Vector = VectorR<float>;
|
||||
|
||||
template<typename T>
|
||||
class MatrixR {
|
||||
static_assert(std::is_floating_point<T>::value, "Must use floating-point types");
|
||||
alignas(16) std::array<T,16> mVals;
|
||||
|
||||
public:
|
||||
constexpr MatrixR() noexcept = default;
|
||||
constexpr MatrixR(const MatrixR&) noexcept = default;
|
||||
constexpr MatrixR(T aa, T ab, T ac, T ad,
|
||||
T ba, T bb, T bc, T bd,
|
||||
T ca, T cb, T cc, T cd,
|
||||
T da, T db, T dc, T dd) noexcept
|
||||
: mVals{{aa,ab,ac,ad, ba,bb,bc,bd, ca,cb,cc,cd, da,db,dc,dd}}
|
||||
{ }
|
||||
|
||||
constexpr MatrixR& operator=(const MatrixR&) noexcept = default;
|
||||
|
||||
auto operator[](size_t idx) noexcept { return al::span<T,4>{&mVals[idx*4], 4}; }
|
||||
constexpr auto operator[](size_t idx) const noexcept
|
||||
{ return al::span<const T,4>{&mVals[idx*4], 4}; }
|
||||
|
||||
static constexpr MatrixR Identity() noexcept
|
||||
{
|
||||
return MatrixR{
|
||||
T{1}, T{0}, T{0}, T{0},
|
||||
T{0}, T{1}, T{0}, T{0},
|
||||
T{0}, T{0}, T{1}, T{0},
|
||||
T{0}, T{0}, T{0}, T{1}};
|
||||
}
|
||||
};
|
||||
using Matrix = MatrixR<float>;
|
||||
|
||||
template<typename T>
|
||||
inline VectorR<T> operator*(const MatrixR<T> &mtx, const VectorR<T> &vec) noexcept
|
||||
{
|
||||
return VectorR<T>{
|
||||
vec[0]*mtx[0][0] + vec[1]*mtx[1][0] + vec[2]*mtx[2][0] + vec[3]*mtx[3][0],
|
||||
vec[0]*mtx[0][1] + vec[1]*mtx[1][1] + vec[2]*mtx[2][1] + vec[3]*mtx[3][1],
|
||||
vec[0]*mtx[0][2] + vec[1]*mtx[1][2] + vec[2]*mtx[2][2] + vec[3]*mtx[3][2],
|
||||
vec[0]*mtx[0][3] + vec[1]*mtx[1][3] + vec[2]*mtx[2][3] + vec[3]*mtx[3][3]};
|
||||
}
|
||||
|
||||
template<typename U, typename T>
|
||||
inline VectorR<U> cast_to(const VectorR<T> &vec) noexcept
|
||||
{
|
||||
return VectorR<U>{static_cast<U>(vec[0]), static_cast<U>(vec[1]),
|
||||
static_cast<U>(vec[2]), static_cast<U>(vec[3])};
|
||||
}
|
||||
|
||||
} // namespace alu
|
||||
|
||||
#endif /* COMMON_VECMAT_H */
|
||||
15
Engine/lib/openal-soft/common/vector.h
Normal file
15
Engine/lib/openal-soft/common/vector.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef AL_VECTOR_H
|
||||
#define AL_VECTOR_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "almalloc.h"
|
||||
|
||||
namespace al {
|
||||
|
||||
template<typename T, size_t alignment=alignof(T)>
|
||||
using vector = std::vector<T, al::allocator<T, alignment>>;
|
||||
|
||||
} // namespace al
|
||||
|
||||
#endif /* AL_VECTOR_H */
|
||||
|
|
@ -13,10 +13,23 @@
|
|||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <memory>
|
||||
|
||||
#define STATIC_CAST(...) static_cast<__VA_ARGS__>
|
||||
#define REINTERPRET_CAST(...) reinterpret_cast<__VA_ARGS__>
|
||||
|
||||
#else
|
||||
|
||||
#define STATIC_CAST(...) (__VA_ARGS__)
|
||||
#define REINTERPRET_CAST(...) (__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
static FILE *my_fopen(const char *fname, const char *mode)
|
||||
{
|
||||
WCHAR *wname=NULL, *wmode=NULL;
|
||||
wchar_t *wname=NULL, *wmode=NULL;
|
||||
int namelen, modelen;
|
||||
FILE *file = NULL;
|
||||
errno_t err;
|
||||
|
|
@ -30,7 +43,12 @@ static FILE *my_fopen(const char *fname, const char *mode)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
wname = calloc(sizeof(WCHAR), namelen+modelen);
|
||||
#ifdef __cplusplus
|
||||
auto strbuf = std::make_unique<wchar_t[]>(static_cast<size_t>(namelen+modelen));
|
||||
wname = strbuf.get();
|
||||
#else
|
||||
wname = (wchar_t*)calloc(sizeof(wchar_t), (size_t)(namelen+modelen));
|
||||
#endif
|
||||
wmode = wname + namelen;
|
||||
MultiByteToWideChar(CP_UTF8, 0, fname, -1, wname, namelen);
|
||||
MultiByteToWideChar(CP_UTF8, 0, mode, -1, wmode, modelen);
|
||||
|
|
@ -42,56 +60,58 @@ static FILE *my_fopen(const char *fname, const char *mode)
|
|||
file = NULL;
|
||||
}
|
||||
|
||||
#ifndef __cplusplus
|
||||
free(wname);
|
||||
|
||||
#endif
|
||||
return file;
|
||||
}
|
||||
#define fopen my_fopen
|
||||
|
||||
|
||||
static char **arglist;
|
||||
static void cleanup_arglist(void)
|
||||
{
|
||||
free(arglist);
|
||||
}
|
||||
|
||||
static void GetUnicodeArgs(int *argc, char ***argv)
|
||||
{
|
||||
size_t total;
|
||||
wchar_t **args;
|
||||
int nargs, i;
|
||||
|
||||
args = CommandLineToArgvW(GetCommandLineW(), &nargs);
|
||||
if(!args)
|
||||
{
|
||||
fprintf(stderr, "Failed to get command line args: %ld\n", GetLastError());
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
total = sizeof(**argv) * nargs;
|
||||
for(i = 0;i < nargs;i++)
|
||||
total += WideCharToMultiByte(CP_UTF8, 0, args[i], -1, NULL, 0, NULL, NULL);
|
||||
|
||||
atexit(cleanup_arglist);
|
||||
arglist = *argv = calloc(1, total);
|
||||
(*argv)[0] = (char*)(*argv + nargs);
|
||||
for(i = 0;i < nargs-1;i++)
|
||||
{
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, args[i], -1, (*argv)[i], 65535, NULL, NULL);
|
||||
(*argv)[i+1] = (*argv)[i] + len;
|
||||
}
|
||||
WideCharToMultiByte(CP_UTF8, 0, args[i], -1, (*argv)[i], 65535, NULL, NULL);
|
||||
*argc = nargs;
|
||||
|
||||
LocalFree(args);
|
||||
}
|
||||
#define GET_UNICODE_ARGS(argc, argv) GetUnicodeArgs(argc, argv)
|
||||
|
||||
#else
|
||||
|
||||
/* Do nothing. */
|
||||
#define GET_UNICODE_ARGS(argc, argv)
|
||||
/* SDL overrides main and provides UTF-8 args for us. */
|
||||
#if !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE)
|
||||
int my_main(int, char**);
|
||||
#define main my_main
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
int wmain(int argc, wchar_t **wargv)
|
||||
{
|
||||
char **argv;
|
||||
size_t total;
|
||||
int i;
|
||||
|
||||
total = sizeof(*argv) * STATIC_CAST(size_t)(argc);
|
||||
for(i = 0;i < argc;i++)
|
||||
total += STATIC_CAST(size_t)(WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, NULL, 0, NULL,
|
||||
NULL));
|
||||
|
||||
#ifdef __cplusplus
|
||||
auto argbuf = std::make_unique<char[]>(total);
|
||||
argv = reinterpret_cast<char**>(argbuf.get());
|
||||
#else
|
||||
argv = (char**)calloc(1, total);
|
||||
#endif
|
||||
argv[0] = REINTERPRET_CAST(char*)(argv + argc);
|
||||
for(i = 0;i < argc-1;i++)
|
||||
{
|
||||
int len = WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL);
|
||||
argv[i+1] = argv[i] + len;
|
||||
}
|
||||
WideCharToMultiByte(CP_UTF8, 0, wargv[i], -1, argv[i], 65535, NULL, NULL);
|
||||
|
||||
#ifdef __cplusplus
|
||||
return main(argc, argv);
|
||||
#else
|
||||
i = main(argc, argv);
|
||||
|
||||
free(argv);
|
||||
return i;
|
||||
#endif
|
||||
}
|
||||
#endif /* !defined(SDL_MAIN_NEEDED) && !defined(SDL_MAIN_AVAILABLE) */
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* WIN_MAIN_UTF8_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue