Sources: Run clang-format on everything.
This commit is contained in:
parent
fe948af095
commit
dc8479928c
386 changed files with 19560 additions and 18080 deletions
|
@ -18,25 +18,29 @@
|
|||
// enough for our purposes.
|
||||
template <typename Fn>
|
||||
#if defined(_MSC_VER)
|
||||
__declspec(noinline, noreturn)
|
||||
__declspec(noinline, noreturn)
|
||||
#elif defined(__GNUC__)
|
||||
__attribute__((noinline, noreturn, cold))
|
||||
#endif
|
||||
static void assert_noinline_call(const Fn& fn) {
|
||||
static void assert_noinline_call(const Fn& fn) {
|
||||
fn();
|
||||
Crash();
|
||||
exit(1); // Keeps GCC's mouth shut about this actually returning
|
||||
}
|
||||
|
||||
#define ASSERT(_a_) \
|
||||
do if (!(_a_)) { assert_noinline_call([] { \
|
||||
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
||||
}); } while (0)
|
||||
#define ASSERT(_a_) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define ASSERT_MSG(_a_, ...) \
|
||||
do if (!(_a_)) { assert_noinline_call([&] { \
|
||||
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
|
||||
}); } while (0)
|
||||
#define ASSERT_MSG(_a_, ...) \
|
||||
do \
|
||||
if (!(_a_)) { \
|
||||
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define UNREACHABLE() ASSERT_MSG(false, "Unreachable code!")
|
||||
#define UNREACHABLE_MSG(...) ASSERT_MSG(false, __VA_ARGS__)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
// Copyright 2014 Tony Wasserka
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -29,7 +28,6 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
@ -111,9 +109,8 @@
|
|||
* symptoms.
|
||||
*/
|
||||
#pragma pack(1)
|
||||
template<std::size_t position, std::size_t bits, typename T>
|
||||
struct BitField
|
||||
{
|
||||
template <std::size_t position, std::size_t bits, typename T>
|
||||
struct BitField {
|
||||
private:
|
||||
// We hide the copy assigment operator here, because the default copy
|
||||
// assignment would copy the full storage value, rather than just the bits
|
||||
|
@ -141,13 +138,10 @@ public:
|
|||
}
|
||||
|
||||
FORCE_INLINE T Value() const {
|
||||
if (std::numeric_limits<T>::is_signed)
|
||||
{
|
||||
std::size_t shift = 8 * sizeof(T)-bits;
|
||||
if (std::numeric_limits<T>::is_signed) {
|
||||
std::size_t shift = 8 * sizeof(T) - bits;
|
||||
return (T)((storage << (shift - position)) >> shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return (T)((storage & GetMask()) >> position);
|
||||
}
|
||||
}
|
||||
|
@ -162,15 +156,14 @@ private:
|
|||
// T is an enumeration. Note that T is wrapped within an enable_if in the
|
||||
// former case to workaround compile errors which arise when using
|
||||
// std::underlying_type<T>::type directly.
|
||||
typedef typename std::conditional < std::is_enum<T>::value,
|
||||
std::underlying_type<T>,
|
||||
std::enable_if < true, T >> ::type::type StorageType;
|
||||
typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>,
|
||||
std::enable_if<true, T>>::type::type StorageType;
|
||||
|
||||
// Unsigned version of StorageType
|
||||
typedef typename std::make_unsigned<StorageType>::type StorageTypeU;
|
||||
|
||||
FORCE_INLINE StorageType GetMask() const {
|
||||
return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position;
|
||||
return (((StorageTypeU)~0) >> (8 * sizeof(T) - bits)) << position;
|
||||
}
|
||||
|
||||
StorageType storage;
|
||||
|
@ -186,5 +179,6 @@ private:
|
|||
#pragma pack()
|
||||
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, "BitField must be trivially copyable");
|
||||
static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value,
|
||||
"BitField must be trivially copyable");
|
||||
#endif
|
||||
|
|
|
@ -18,49 +18,60 @@ namespace Common {
|
|||
|
||||
#ifdef _WIN32
|
||||
template <typename T>
|
||||
static inline int CountSetBits(T v)
|
||||
{
|
||||
static inline int CountSetBits(T v) {
|
||||
// from https://graphics.stanford.edu/~seander/bithacks.html
|
||||
// GCC has this built in, but MSVC's intrinsic will only emit the actual
|
||||
// POPCNT instruction, which we're not depending on
|
||||
v = v - ((v >> 1) & (T)~(T)0/3);
|
||||
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3);
|
||||
v = (v + (v >> 4)) & (T)~(T)0/255*15;
|
||||
return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * 8;
|
||||
v = v - ((v >> 1) & (T) ~(T)0 / 3);
|
||||
v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
|
||||
v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
|
||||
return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8;
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u8 val)
|
||||
{
|
||||
static inline int LeastSignificantSetBit(u8 val) {
|
||||
unsigned long index;
|
||||
_BitScanForward(&index, val);
|
||||
return (int)index;
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u16 val)
|
||||
{
|
||||
static inline int LeastSignificantSetBit(u16 val) {
|
||||
unsigned long index;
|
||||
_BitScanForward(&index, val);
|
||||
return (int)index;
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u32 val)
|
||||
{
|
||||
static inline int LeastSignificantSetBit(u32 val) {
|
||||
unsigned long index;
|
||||
_BitScanForward(&index, val);
|
||||
return (int)index;
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u64 val)
|
||||
{
|
||||
static inline int LeastSignificantSetBit(u64 val) {
|
||||
unsigned long index;
|
||||
_BitScanForward64(&index, val);
|
||||
return (int)index;
|
||||
}
|
||||
#else
|
||||
static inline int CountSetBits(u8 val) { return __builtin_popcount(val); }
|
||||
static inline int CountSetBits(u16 val) { return __builtin_popcount(val); }
|
||||
static inline int CountSetBits(u32 val) { return __builtin_popcount(val); }
|
||||
static inline int CountSetBits(u64 val) { return __builtin_popcountll(val); }
|
||||
static inline int LeastSignificantSetBit(u8 val) { return __builtin_ctz(val); }
|
||||
static inline int LeastSignificantSetBit(u16 val) { return __builtin_ctz(val); }
|
||||
static inline int LeastSignificantSetBit(u32 val) { return __builtin_ctz(val); }
|
||||
static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val); }
|
||||
static inline int CountSetBits(u8 val) {
|
||||
return __builtin_popcount(val);
|
||||
}
|
||||
static inline int CountSetBits(u16 val) {
|
||||
return __builtin_popcount(val);
|
||||
}
|
||||
static inline int CountSetBits(u32 val) {
|
||||
return __builtin_popcount(val);
|
||||
}
|
||||
static inline int CountSetBits(u64 val) {
|
||||
return __builtin_popcountll(val);
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u8 val) {
|
||||
return __builtin_ctz(val);
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u16 val) {
|
||||
return __builtin_ctz(val);
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u32 val) {
|
||||
return __builtin_ctz(val);
|
||||
}
|
||||
static inline int LeastSignificantSetBit(u64 val) {
|
||||
return __builtin_ctzll(val);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Similar to std::bitset, this is a class which encapsulates a bitset, i.e.
|
||||
|
@ -84,100 +95,144 @@ static inline int LeastSignificantSetBit(u64 val) { return __builtin_ctzll(val);
|
|||
// TODO: use constexpr when MSVC gets out of the Dark Ages
|
||||
|
||||
template <typename IntTy>
|
||||
class BitSet
|
||||
{
|
||||
class BitSet {
|
||||
static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types");
|
||||
|
||||
public:
|
||||
// A reference to a particular bit, returned from operator[].
|
||||
class Ref
|
||||
{
|
||||
class Ref {
|
||||
public:
|
||||
Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {}
|
||||
Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {}
|
||||
operator bool() const { return (m_bs->m_val & m_mask) != 0; }
|
||||
bool operator=(bool set)
|
||||
{
|
||||
Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {
|
||||
}
|
||||
Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {
|
||||
}
|
||||
operator bool() const {
|
||||
return (m_bs->m_val & m_mask) != 0;
|
||||
}
|
||||
bool operator=(bool set) {
|
||||
m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0);
|
||||
return set;
|
||||
}
|
||||
|
||||
private:
|
||||
BitSet* m_bs;
|
||||
IntTy m_mask;
|
||||
};
|
||||
|
||||
// A STL-like iterator is required to be able to use range-based for loops.
|
||||
class Iterator
|
||||
{
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {}
|
||||
Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {}
|
||||
Iterator& operator=(Iterator other) { new (this) Iterator(other); return *this; }
|
||||
int operator*() { return m_bit; }
|
||||
Iterator& operator++()
|
||||
{
|
||||
if (m_val == 0)
|
||||
{
|
||||
Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {
|
||||
}
|
||||
Iterator(IntTy val, int bit) : m_val(val), m_bit(bit) {
|
||||
}
|
||||
Iterator& operator=(Iterator other) {
|
||||
new (this) Iterator(other);
|
||||
return *this;
|
||||
}
|
||||
int operator*() {
|
||||
return m_bit;
|
||||
}
|
||||
Iterator& operator++() {
|
||||
if (m_val == 0) {
|
||||
m_bit = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
int bit = LeastSignificantSetBit(m_val);
|
||||
m_val &= ~(1 << bit);
|
||||
m_bit = bit;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
Iterator operator++(int _)
|
||||
{
|
||||
Iterator operator++(int _) {
|
||||
Iterator other(*this);
|
||||
++*this;
|
||||
return other;
|
||||
}
|
||||
bool operator==(Iterator other) const { return m_bit == other.m_bit; }
|
||||
bool operator!=(Iterator other) const { return m_bit != other.m_bit; }
|
||||
bool operator==(Iterator other) const {
|
||||
return m_bit == other.m_bit;
|
||||
}
|
||||
bool operator!=(Iterator other) const {
|
||||
return m_bit != other.m_bit;
|
||||
}
|
||||
|
||||
private:
|
||||
IntTy m_val;
|
||||
int m_bit;
|
||||
};
|
||||
|
||||
BitSet() : m_val(0) {}
|
||||
explicit BitSet(IntTy val) : m_val(val) {}
|
||||
BitSet(std::initializer_list<int> init)
|
||||
{
|
||||
BitSet() : m_val(0) {
|
||||
}
|
||||
explicit BitSet(IntTy val) : m_val(val) {
|
||||
}
|
||||
BitSet(std::initializer_list<int> init) {
|
||||
m_val = 0;
|
||||
for (int bit : init)
|
||||
m_val |= (IntTy)1 << bit;
|
||||
}
|
||||
|
||||
static BitSet AllTrue(size_t count)
|
||||
{
|
||||
return BitSet(count == sizeof(IntTy)*8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
||||
static BitSet AllTrue(size_t count) {
|
||||
return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1));
|
||||
}
|
||||
|
||||
Ref operator[](size_t bit) { return Ref(this, (IntTy)1 << bit); }
|
||||
const Ref operator[](size_t bit) const { return (*const_cast<BitSet*>(this))[bit]; }
|
||||
bool operator==(BitSet other) const { return m_val == other.m_val; }
|
||||
bool operator!=(BitSet other) const { return m_val != other.m_val; }
|
||||
bool operator<(BitSet other) const { return m_val < other.m_val; }
|
||||
bool operator>(BitSet other) const { return m_val > other.m_val; }
|
||||
BitSet operator|(BitSet other) const { return BitSet(m_val | other.m_val); }
|
||||
BitSet operator&(BitSet other) const { return BitSet(m_val & other.m_val); }
|
||||
BitSet operator^(BitSet other) const { return BitSet(m_val ^ other.m_val); }
|
||||
BitSet operator~() const { return BitSet(~m_val); }
|
||||
BitSet& operator|=(BitSet other) { return *this = *this | other; }
|
||||
BitSet& operator&=(BitSet other) { return *this = *this & other; }
|
||||
BitSet& operator^=(BitSet other) { return *this = *this ^ other; }
|
||||
Ref operator[](size_t bit) {
|
||||
return Ref(this, (IntTy)1 << bit);
|
||||
}
|
||||
const Ref operator[](size_t bit) const {
|
||||
return (*const_cast<BitSet*>(this))[bit];
|
||||
}
|
||||
bool operator==(BitSet other) const {
|
||||
return m_val == other.m_val;
|
||||
}
|
||||
bool operator!=(BitSet other) const {
|
||||
return m_val != other.m_val;
|
||||
}
|
||||
bool operator<(BitSet other) const {
|
||||
return m_val < other.m_val;
|
||||
}
|
||||
bool operator>(BitSet other) const {
|
||||
return m_val > other.m_val;
|
||||
}
|
||||
BitSet operator|(BitSet other) const {
|
||||
return BitSet(m_val | other.m_val);
|
||||
}
|
||||
BitSet operator&(BitSet other) const {
|
||||
return BitSet(m_val & other.m_val);
|
||||
}
|
||||
BitSet operator^(BitSet other) const {
|
||||
return BitSet(m_val ^ other.m_val);
|
||||
}
|
||||
BitSet operator~() const {
|
||||
return BitSet(~m_val);
|
||||
}
|
||||
BitSet& operator|=(BitSet other) {
|
||||
return *this = *this | other;
|
||||
}
|
||||
BitSet& operator&=(BitSet other) {
|
||||
return *this = *this & other;
|
||||
}
|
||||
BitSet& operator^=(BitSet other) {
|
||||
return *this = *this ^ other;
|
||||
}
|
||||
operator u32() = delete;
|
||||
operator bool() { return m_val != 0; }
|
||||
operator bool() {
|
||||
return m_val != 0;
|
||||
}
|
||||
|
||||
// Warning: Even though on modern CPUs this is a single fast instruction,
|
||||
// Dolphin's official builds do not currently assume POPCNT support on x86,
|
||||
// so slower explicit bit twiddling is generated. Still should generally
|
||||
// be faster than a loop.
|
||||
unsigned int Count() const { return CountSetBits(m_val); }
|
||||
unsigned int Count() const {
|
||||
return CountSetBits(m_val);
|
||||
}
|
||||
|
||||
Iterator begin() const { Iterator it(m_val, 0); return ++it; }
|
||||
Iterator end() const { return Iterator(m_val, -1); }
|
||||
Iterator begin() const {
|
||||
Iterator it(m_val, 0);
|
||||
return ++it;
|
||||
}
|
||||
Iterator end() const {
|
||||
return Iterator(m_val, -1);
|
||||
}
|
||||
|
||||
IntTy m_val;
|
||||
};
|
||||
|
|
|
@ -5,30 +5,27 @@
|
|||
#include "common/break_points.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const
|
||||
{
|
||||
bool BreakPoints::IsAddressBreakPoint(u32 iAddress) const {
|
||||
auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress; };
|
||||
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
|
||||
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
|
||||
return it != m_BreakPoints.end();
|
||||
}
|
||||
|
||||
bool BreakPoints::IsTempBreakPoint(u32 iAddress) const
|
||||
{
|
||||
auto cond = [&iAddress](const TBreakPoint& bp) { return bp.iAddress == iAddress && bp.bTemporary; };
|
||||
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
|
||||
bool BreakPoints::IsTempBreakPoint(u32 iAddress) const {
|
||||
auto cond = [&iAddress](const TBreakPoint& bp) {
|
||||
return bp.iAddress == iAddress && bp.bTemporary;
|
||||
};
|
||||
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
|
||||
return it != m_BreakPoints.end();
|
||||
}
|
||||
|
||||
BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const
|
||||
{
|
||||
BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const {
|
||||
TBreakPointsStr bps;
|
||||
for (auto breakpoint : m_BreakPoints)
|
||||
{
|
||||
if (!breakpoint.bTemporary)
|
||||
{
|
||||
for (auto breakpoint : m_BreakPoints) {
|
||||
if (!breakpoint.bTemporary) {
|
||||
std::stringstream bp;
|
||||
bp << std::hex << breakpoint.iAddress << " " << (breakpoint.bOn ? "n" : "");
|
||||
bps.push_back(bp.str());
|
||||
|
@ -38,10 +35,8 @@ BreakPoints::TBreakPointsStr BreakPoints::GetStrings() const
|
|||
return bps;
|
||||
}
|
||||
|
||||
void BreakPoints::AddFromStrings(const TBreakPointsStr& bps)
|
||||
{
|
||||
for (auto bps_item : bps)
|
||||
{
|
||||
void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) {
|
||||
for (auto bps_item : bps) {
|
||||
TBreakPoint bp;
|
||||
std::stringstream bpstr;
|
||||
bpstr << std::hex << bps_item;
|
||||
|
@ -52,18 +47,15 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps)
|
|||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Add(const TBreakPoint& bp)
|
||||
{
|
||||
if (!IsAddressBreakPoint(bp.iAddress))
|
||||
{
|
||||
void BreakPoints::Add(const TBreakPoint& bp) {
|
||||
if (!IsAddressBreakPoint(bp.iAddress)) {
|
||||
m_BreakPoints.push_back(bp);
|
||||
//if (jit)
|
||||
// if (jit)
|
||||
// jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Add(u32 em_address, bool temp)
|
||||
{
|
||||
void BreakPoints::Add(u32 em_address, bool temp) {
|
||||
if (!IsAddressBreakPoint(em_address)) // only add new addresses
|
||||
{
|
||||
TBreakPoint pt; // breakpoint settings
|
||||
|
@ -73,22 +65,20 @@ void BreakPoints::Add(u32 em_address, bool temp)
|
|||
|
||||
m_BreakPoints.push_back(pt);
|
||||
|
||||
//if (jit)
|
||||
// if (jit)
|
||||
// jit->GetBlockCache()->InvalidateICache(em_address, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void BreakPoints::Remove(u32 em_address)
|
||||
{
|
||||
void BreakPoints::Remove(u32 em_address) {
|
||||
auto cond = [&em_address](const TBreakPoint& bp) { return bp.iAddress == em_address; };
|
||||
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
|
||||
auto it = std::find_if(m_BreakPoints.begin(), m_BreakPoints.end(), cond);
|
||||
if (it != m_BreakPoints.end())
|
||||
m_BreakPoints.erase(it);
|
||||
}
|
||||
|
||||
void BreakPoints::Clear()
|
||||
{
|
||||
//if (jit)
|
||||
void BreakPoints::Clear() {
|
||||
// if (jit)
|
||||
//{
|
||||
// std::for_each(m_BreakPoints.begin(), m_BreakPoints.end(),
|
||||
// [](const TBreakPoint& bp)
|
||||
|
|
|
@ -4,28 +4,28 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
class DebugInterface;
|
||||
|
||||
struct TBreakPoint
|
||||
{
|
||||
u32 iAddress;
|
||||
struct TBreakPoint {
|
||||
u32 iAddress;
|
||||
bool bOn;
|
||||
bool bTemporary;
|
||||
};
|
||||
|
||||
// Code breakpoints.
|
||||
class BreakPoints
|
||||
{
|
||||
class BreakPoints {
|
||||
public:
|
||||
typedef std::vector<TBreakPoint> TBreakPoints;
|
||||
typedef std::vector<std::string> TBreakPointsStr;
|
||||
|
||||
const TBreakPoints& GetBreakPoints() { return m_BreakPoints; }
|
||||
const TBreakPoints& GetBreakPoints() {
|
||||
return m_BreakPoints;
|
||||
}
|
||||
|
||||
TBreakPointsStr GetStrings() const;
|
||||
void AddFromStrings(const TBreakPointsStr& bps);
|
||||
|
@ -35,7 +35,7 @@ public:
|
|||
bool IsTempBreakPoint(u32 iAddress) const;
|
||||
|
||||
// Add BreakPoint
|
||||
void Add(u32 em_address, bool temp=false);
|
||||
void Add(u32 em_address, bool temp = false);
|
||||
void Add(const TBreakPoint& bp);
|
||||
|
||||
// Remove Breakpoint
|
||||
|
@ -46,5 +46,5 @@ public:
|
|||
|
||||
private:
|
||||
TBreakPoints m_BreakPoints;
|
||||
u32 m_iBreakOnCount;
|
||||
u32 m_iBreakOnCount;
|
||||
};
|
||||
|
|
|
@ -41,81 +41,86 @@
|
|||
#include "common/logging/log.h"
|
||||
|
||||
template <class T>
|
||||
struct LinkedListItem : public T
|
||||
{
|
||||
LinkedListItem<T> *next;
|
||||
struct LinkedListItem : public T {
|
||||
LinkedListItem<T>* next;
|
||||
};
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
class PointerWrapSection
|
||||
{
|
||||
class PointerWrapSection {
|
||||
public:
|
||||
PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) {
|
||||
PointerWrapSection(PointerWrap& p, int ver, const char* title)
|
||||
: p_(p), ver_(ver), title_(title) {
|
||||
}
|
||||
~PointerWrapSection();
|
||||
|
||||
bool operator == (const int &v) const { return ver_ == v; }
|
||||
bool operator != (const int &v) const { return ver_ != v; }
|
||||
bool operator <= (const int &v) const { return ver_ <= v; }
|
||||
bool operator >= (const int &v) const { return ver_ >= v; }
|
||||
bool operator < (const int &v) const { return ver_ < v; }
|
||||
bool operator > (const int &v) const { return ver_ > v; }
|
||||
bool operator==(const int& v) const {
|
||||
return ver_ == v;
|
||||
}
|
||||
bool operator!=(const int& v) const {
|
||||
return ver_ != v;
|
||||
}
|
||||
bool operator<=(const int& v) const {
|
||||
return ver_ <= v;
|
||||
}
|
||||
bool operator>=(const int& v) const {
|
||||
return ver_ >= v;
|
||||
}
|
||||
bool operator<(const int& v) const {
|
||||
return ver_ < v;
|
||||
}
|
||||
bool operator>(const int& v) const {
|
||||
return ver_ > v;
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
operator bool() const {
|
||||
return ver_ > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
PointerWrap &p_;
|
||||
PointerWrap& p_;
|
||||
int ver_;
|
||||
const char *title_;
|
||||
const char* title_;
|
||||
};
|
||||
|
||||
// Wrapper class
|
||||
class PointerWrap
|
||||
{
|
||||
// This makes it a compile error if you forget to define DoState() on non-POD.
|
||||
// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
|
||||
class PointerWrap {
|
||||
// This makes it a compile error if you forget to define DoState() on non-POD.
|
||||
// Which also can be a problem, for example struct tm is non-POD on linux, for whatever reason...
|
||||
#ifdef _MSC_VER
|
||||
template<typename T, bool isPOD = std::is_pod<T>::value, bool isPointer = std::is_pointer<T>::value>
|
||||
template <typename T, bool isPOD = std::is_pod<T>::value,
|
||||
bool isPointer = std::is_pointer<T>::value>
|
||||
#else
|
||||
template<typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
|
||||
template <typename T, bool isPOD = __is_pod(T), bool isPointer = std::is_pointer<T>::value>
|
||||
#endif
|
||||
struct DoHelper
|
||||
{
|
||||
static void DoArray(PointerWrap *p, T *x, int count)
|
||||
{
|
||||
struct DoHelper {
|
||||
static void DoArray(PointerWrap* p, T* x, int count) {
|
||||
for (int i = 0; i < count; ++i)
|
||||
p->Do(x[i]);
|
||||
}
|
||||
|
||||
static void Do(PointerWrap *p, T &x)
|
||||
{
|
||||
static void Do(PointerWrap* p, T& x) {
|
||||
p->DoClass(x);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct DoHelper<T, true, false>
|
||||
{
|
||||
static void DoArray(PointerWrap *p, T *x, int count)
|
||||
{
|
||||
p->DoVoid((void *)x, sizeof(T) * count);
|
||||
template <typename T>
|
||||
struct DoHelper<T, true, false> {
|
||||
static void DoArray(PointerWrap* p, T* x, int count) {
|
||||
p->DoVoid((void*)x, sizeof(T) * count);
|
||||
}
|
||||
|
||||
static void Do(PointerWrap *p, T &x)
|
||||
{
|
||||
p->DoVoid((void *)&x, sizeof(x));
|
||||
static void Do(PointerWrap* p, T& x) {
|
||||
p->DoVoid((void*)&x, sizeof(x));
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
enum Mode {
|
||||
MODE_READ = 1, // load
|
||||
MODE_WRITE, // save
|
||||
MODE_MEASURE, // calculate size
|
||||
MODE_VERIFY, // compare
|
||||
MODE_WRITE, // save
|
||||
MODE_MEASURE, // calculate size
|
||||
MODE_VERIFY, // compare
|
||||
};
|
||||
|
||||
enum Error {
|
||||
|
@ -124,247 +129,239 @@ public:
|
|||
ERROR_FAILURE = 2,
|
||||
};
|
||||
|
||||
u8 **ptr;
|
||||
u8** ptr;
|
||||
Mode mode;
|
||||
Error error;
|
||||
|
||||
public:
|
||||
PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {}
|
||||
PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {}
|
||||
PointerWrap(u8** ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {
|
||||
}
|
||||
PointerWrap(unsigned char** ptr_, int mode_)
|
||||
: ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {
|
||||
}
|
||||
|
||||
PointerWrapSection Section(const char *title, int ver) {
|
||||
PointerWrapSection Section(const char* title, int ver) {
|
||||
return Section(title, ver, ver);
|
||||
}
|
||||
|
||||
// The returned object can be compared against the version that was loaded.
|
||||
// This can be used to support versions as old as minVer.
|
||||
// Version = 0 means the section was not found.
|
||||
PointerWrapSection Section(const char *title, int minVer, int ver) {
|
||||
PointerWrapSection Section(const char* title, int minVer, int ver) {
|
||||
char marker[16] = {0};
|
||||
int foundVersion = ver;
|
||||
|
||||
strncpy(marker, title, sizeof(marker));
|
||||
if (!ExpectVoid(marker, sizeof(marker)))
|
||||
{
|
||||
if (!ExpectVoid(marker, sizeof(marker))) {
|
||||
// Might be before we added name markers for safety.
|
||||
if (foundVersion == 1 && ExpectVoid(&foundVersion, sizeof(foundVersion)))
|
||||
DoMarker(title);
|
||||
// Wasn't found, but maybe we can still load the state.
|
||||
else
|
||||
foundVersion = 0;
|
||||
}
|
||||
else
|
||||
} else
|
||||
Do(foundVersion);
|
||||
|
||||
if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) {
|
||||
LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, title);
|
||||
LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion,
|
||||
title);
|
||||
SetError(ERROR_FAILURE);
|
||||
return PointerWrapSection(*this, -1, title);
|
||||
}
|
||||
return PointerWrapSection(*this, foundVersion, title);
|
||||
}
|
||||
|
||||
void SetMode(Mode mode_) {mode = mode_;}
|
||||
Mode GetMode() const {return mode;}
|
||||
u8 **GetPPtr() {return ptr;}
|
||||
void SetError(Error error_)
|
||||
{
|
||||
void SetMode(Mode mode_) {
|
||||
mode = mode_;
|
||||
}
|
||||
Mode GetMode() const {
|
||||
return mode;
|
||||
}
|
||||
u8** GetPPtr() {
|
||||
return ptr;
|
||||
}
|
||||
void SetError(Error error_) {
|
||||
if (error < error_)
|
||||
error = error_;
|
||||
if (error > ERROR_WARNING)
|
||||
mode = PointerWrap::MODE_MEASURE;
|
||||
}
|
||||
|
||||
bool ExpectVoid(void *data, int size)
|
||||
{
|
||||
bool ExpectVoid(void* data, int size) {
|
||||
switch (mode) {
|
||||
case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break;
|
||||
case MODE_WRITE: memcpy(*ptr, data, size); break;
|
||||
case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
|
||||
case MODE_READ:
|
||||
if (memcmp(data, *ptr, size) != 0)
|
||||
return false;
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, data, size);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break; // MODE_MEASURE - don't need to do anything
|
||||
case MODE_VERIFY:
|
||||
for (int i = 0; i < size; i++) {
|
||||
DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i],
|
||||
DEBUG_ASSERT_MSG(
|
||||
((u8*)data)[i] == (*ptr)[i],
|
||||
"Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
|
||||
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i],
|
||||
(*ptr)[i], (*ptr)[i], &(*ptr)[i]);
|
||||
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
|
||||
&(*ptr)[i]);
|
||||
}
|
||||
break;
|
||||
default: break; // throw an error?
|
||||
default:
|
||||
break; // throw an error?
|
||||
}
|
||||
(*ptr) += size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DoVoid(void *data, int size)
|
||||
{
|
||||
void DoVoid(void* data, int size) {
|
||||
switch (mode) {
|
||||
case MODE_READ: memcpy(data, *ptr, size); break;
|
||||
case MODE_WRITE: memcpy(*ptr, data, size); break;
|
||||
case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
|
||||
case MODE_READ:
|
||||
memcpy(data, *ptr, size);
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, data, size);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break; // MODE_MEASURE - don't need to do anything
|
||||
case MODE_VERIFY:
|
||||
for (int i = 0; i < size; i++) {
|
||||
DEBUG_ASSERT_MSG(((u8*)data)[i] == (*ptr)[i],
|
||||
DEBUG_ASSERT_MSG(
|
||||
((u8*)data)[i] == (*ptr)[i],
|
||||
"Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
|
||||
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i],
|
||||
(*ptr)[i], (*ptr)[i], &(*ptr)[i]);
|
||||
((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i],
|
||||
&(*ptr)[i]);
|
||||
}
|
||||
break;
|
||||
default: break; // throw an error?
|
||||
default:
|
||||
break; // throw an error?
|
||||
}
|
||||
(*ptr) += size;
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::map<K, T *> &x)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||
{
|
||||
template <class K, class T>
|
||||
void Do(std::map<K, T*>& x) {
|
||||
if (mode == MODE_READ) {
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
|
||||
if (it->second != nullptr)
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
T *dv = nullptr;
|
||||
T* dv = nullptr;
|
||||
DoMap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::map<K, T> &x)
|
||||
{
|
||||
template <class K, class T>
|
||||
void Do(std::map<K, T>& x) {
|
||||
T dv = T();
|
||||
DoMap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void DoMap(std::map<K, T> &x, T &default_val)
|
||||
{
|
||||
template <class K, class T>
|
||||
void DoMap(std::map<K, T>& x, T& default_val) {
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
{
|
||||
x.clear();
|
||||
while (number > 0)
|
||||
{
|
||||
K first = K();
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x[first] = second;
|
||||
--number;
|
||||
}
|
||||
case MODE_READ: {
|
||||
x.clear();
|
||||
while (number > 0) {
|
||||
K first = K();
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x[first] = second;
|
||||
--number;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY:
|
||||
{
|
||||
typename std::map<K, T>::iterator itr = x.begin();
|
||||
while (number > 0)
|
||||
{
|
||||
K first = itr->first;
|
||||
Do(first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
case MODE_VERIFY: {
|
||||
typename std::map<K, T>::iterator itr = x.begin();
|
||||
while (number > 0) {
|
||||
K first = itr->first;
|
||||
Do(first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::multimap<K, T *> &x)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||
{
|
||||
template <class K, class T>
|
||||
void Do(std::multimap<K, T*>& x) {
|
||||
if (mode == MODE_READ) {
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
|
||||
if (it->second != nullptr)
|
||||
delete it->second;
|
||||
}
|
||||
}
|
||||
T *dv = nullptr;
|
||||
T* dv = nullptr;
|
||||
DoMultimap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void Do(std::multimap<K, T> &x)
|
||||
{
|
||||
template <class K, class T>
|
||||
void Do(std::multimap<K, T>& x) {
|
||||
T dv = T();
|
||||
DoMultimap(x, dv);
|
||||
}
|
||||
|
||||
template<class K, class T>
|
||||
void DoMultimap(std::multimap<K, T> &x, T &default_val)
|
||||
{
|
||||
template <class K, class T>
|
||||
void DoMultimap(std::multimap<K, T>& x, T& default_val) {
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
switch (mode) {
|
||||
case MODE_READ:
|
||||
{
|
||||
x.clear();
|
||||
while (number > 0)
|
||||
{
|
||||
K first = K();
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x.insert(std::make_pair(first, second));
|
||||
--number;
|
||||
}
|
||||
case MODE_READ: {
|
||||
x.clear();
|
||||
while (number > 0) {
|
||||
K first = K();
|
||||
Do(first);
|
||||
T second = default_val;
|
||||
Do(second);
|
||||
x.insert(std::make_pair(first, second));
|
||||
--number;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY:
|
||||
{
|
||||
typename std::multimap<K, T>::iterator itr = x.begin();
|
||||
while (number > 0)
|
||||
{
|
||||
Do(itr->first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
case MODE_VERIFY: {
|
||||
typename std::multimap<K, T>::iterator itr = x.begin();
|
||||
while (number > 0) {
|
||||
Do(itr->first);
|
||||
Do(itr->second);
|
||||
--number;
|
||||
++itr;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
// Store vectors.
|
||||
template<class T>
|
||||
void Do(std::vector<T *> &x)
|
||||
{
|
||||
T *dv = nullptr;
|
||||
template <class T>
|
||||
void Do(std::vector<T*>& x) {
|
||||
T* dv = nullptr;
|
||||
DoVector(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::vector<T> &x)
|
||||
{
|
||||
template <class T>
|
||||
void Do(std::vector<T>& x) {
|
||||
T dv = T();
|
||||
DoVector(x, dv);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void DoPOD(std::vector<T> &x)
|
||||
{
|
||||
template <class T>
|
||||
void DoPOD(std::vector<T>& x) {
|
||||
T dv = T();
|
||||
DoVectorPOD(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::vector<T> &x, T &default_val)
|
||||
{
|
||||
template <class T>
|
||||
void Do(std::vector<T>& x, T& default_val) {
|
||||
DoVector(x, default_val);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoVector(std::vector<T> &x, T &default_val)
|
||||
{
|
||||
template <class T>
|
||||
void DoVector(std::vector<T>& x, T& default_val) {
|
||||
u32 vec_size = (u32)x.size();
|
||||
Do(vec_size);
|
||||
x.resize(vec_size, default_val);
|
||||
|
@ -372,9 +369,8 @@ public:
|
|||
DoArray(&x[0], vec_size);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoVectorPOD(std::vector<T> &x, T &default_val)
|
||||
{
|
||||
template <class T>
|
||||
void DoVectorPOD(std::vector<T>& x, T& default_val) {
|
||||
u32 vec_size = (u32)x.size();
|
||||
Do(vec_size);
|
||||
x.resize(vec_size, default_val);
|
||||
|
@ -383,55 +379,48 @@ public:
|
|||
}
|
||||
|
||||
// Store deques.
|
||||
template<class T>
|
||||
void Do(std::deque<T *> &x)
|
||||
{
|
||||
T *dv = nullptr;
|
||||
template <class T>
|
||||
void Do(std::deque<T*>& x) {
|
||||
T* dv = nullptr;
|
||||
DoDeque(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::deque<T> &x)
|
||||
{
|
||||
template <class T>
|
||||
void Do(std::deque<T>& x) {
|
||||
T dv = T();
|
||||
DoDeque(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoDeque(std::deque<T> &x, T &default_val)
|
||||
{
|
||||
template <class T>
|
||||
void DoDeque(std::deque<T>& x, T& default_val) {
|
||||
u32 deq_size = (u32)x.size();
|
||||
Do(deq_size);
|
||||
x.resize(deq_size, default_val);
|
||||
u32 i;
|
||||
for(i = 0; i < deq_size; i++)
|
||||
for (i = 0; i < deq_size; i++)
|
||||
Do(x[i]);
|
||||
}
|
||||
|
||||
// Store STL lists.
|
||||
template<class T>
|
||||
void Do(std::list<T *> &x)
|
||||
{
|
||||
T *dv = nullptr;
|
||||
template <class T>
|
||||
void Do(std::list<T*>& x) {
|
||||
T* dv = nullptr;
|
||||
Do(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::list<T> &x)
|
||||
{
|
||||
template <class T>
|
||||
void Do(std::list<T>& x) {
|
||||
T dv = T();
|
||||
DoList(x, dv);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(std::list<T> &x, T &default_val)
|
||||
{
|
||||
template <class T>
|
||||
void Do(std::list<T>& x, T& default_val) {
|
||||
DoList(x, default_val);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoList(std::list<T> &x, T &default_val)
|
||||
{
|
||||
template <class T>
|
||||
void DoList(std::list<T>& x, T& default_val) {
|
||||
u32 list_size = (u32)x.size();
|
||||
Do(list_size);
|
||||
x.resize(list_size, default_val);
|
||||
|
@ -441,15 +430,11 @@ public:
|
|||
Do(*itr);
|
||||
}
|
||||
|
||||
|
||||
// Store STL sets.
|
||||
template <class T>
|
||||
void Do(std::set<T *> &x)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it)
|
||||
{
|
||||
void Do(std::set<T*>& x) {
|
||||
if (mode == MODE_READ) {
|
||||
for (auto it = x.begin(), end = x.end(); it != end; ++it) {
|
||||
if (*it != nullptr)
|
||||
delete *it;
|
||||
}
|
||||
|
@ -458,39 +443,31 @@ public:
|
|||
}
|
||||
|
||||
template <class T>
|
||||
void Do(std::set<T> &x)
|
||||
{
|
||||
void Do(std::set<T>& x) {
|
||||
DoSet(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void DoSet(std::set<T> &x)
|
||||
{
|
||||
void DoSet(std::set<T>& x) {
|
||||
unsigned int number = (unsigned int)x.size();
|
||||
Do(number);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case MODE_READ:
|
||||
{
|
||||
x.clear();
|
||||
while (number-- > 0)
|
||||
{
|
||||
T it = T();
|
||||
Do(it);
|
||||
x.insert(it);
|
||||
}
|
||||
switch (mode) {
|
||||
case MODE_READ: {
|
||||
x.clear();
|
||||
while (number-- > 0) {
|
||||
T it = T();
|
||||
Do(it);
|
||||
x.insert(it);
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
case MODE_WRITE:
|
||||
case MODE_MEASURE:
|
||||
case MODE_VERIFY:
|
||||
{
|
||||
typename std::set<T>::iterator itr = x.begin();
|
||||
while (number-- > 0)
|
||||
Do(*itr++);
|
||||
}
|
||||
break;
|
||||
case MODE_VERIFY: {
|
||||
typename std::set<T>::iterator itr = x.begin();
|
||||
while (number-- > 0)
|
||||
Do(*itr++);
|
||||
} break;
|
||||
|
||||
default:
|
||||
LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode);
|
||||
|
@ -498,51 +475,58 @@ public:
|
|||
}
|
||||
|
||||
// Store strings.
|
||||
void Do(std::string &x)
|
||||
{
|
||||
void Do(std::string& x) {
|
||||
int stringLen = (int)x.length() + 1;
|
||||
Do(stringLen);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ: x = (char*)*ptr; break;
|
||||
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
|
||||
case MODE_MEASURE: break;
|
||||
case MODE_READ:
|
||||
x = (char*)*ptr;
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, x.c_str(), stringLen);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break;
|
||||
case MODE_VERIFY:
|
||||
DEBUG_ASSERT_MSG((x == (char*)*ptr),
|
||||
"Savestate verification failure: \"%s\" != \"%s\" (at %p).\n",
|
||||
x.c_str(), (char*)*ptr, ptr);
|
||||
"Savestate verification failure: \"%s\" != \"%s\" (at %p).\n",
|
||||
x.c_str(), (char*)*ptr, ptr);
|
||||
break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
||||
void Do(std::wstring &x)
|
||||
{
|
||||
int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
|
||||
void Do(std::wstring& x) {
|
||||
int stringLen = sizeof(wchar_t) * ((int)x.length() + 1);
|
||||
Do(stringLen);
|
||||
|
||||
switch (mode) {
|
||||
case MODE_READ: x = (wchar_t*)*ptr; break;
|
||||
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
|
||||
case MODE_MEASURE: break;
|
||||
case MODE_READ:
|
||||
x = (wchar_t*)*ptr;
|
||||
break;
|
||||
case MODE_WRITE:
|
||||
memcpy(*ptr, x.c_str(), stringLen);
|
||||
break;
|
||||
case MODE_MEASURE:
|
||||
break;
|
||||
case MODE_VERIFY:
|
||||
DEBUG_ASSERT_MSG((x == (wchar_t*)*ptr),
|
||||
"Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n",
|
||||
x.c_str(), (wchar_t*)*ptr, ptr);
|
||||
"Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n",
|
||||
x.c_str(), (wchar_t*)*ptr, ptr);
|
||||
break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoClass(T &x) {
|
||||
template <class T>
|
||||
void DoClass(T& x) {
|
||||
x.DoState(*this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoClass(T *&x) {
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
template <class T>
|
||||
void DoClass(T*& x) {
|
||||
if (mode == MODE_READ) {
|
||||
if (x != nullptr)
|
||||
delete x;
|
||||
x = new T();
|
||||
|
@ -550,81 +534,70 @@ public:
|
|||
x->DoState(*this);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoArray(T *x, int count) {
|
||||
template <class T>
|
||||
void DoArray(T* x, int count) {
|
||||
DoHelper<T>::DoArray(this, x, count);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void Do(T &x) {
|
||||
template <class T>
|
||||
void Do(T& x) {
|
||||
DoHelper<T>::Do(this, x);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoPOD(T &x) {
|
||||
template <class T>
|
||||
void DoPOD(T& x) {
|
||||
DoHelper<T>::Do(this, x);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void DoPointer(T* &x, T*const base) {
|
||||
// pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range
|
||||
template <class T>
|
||||
void DoPointer(T*& x, T* const base) {
|
||||
// pointers can be more than 2^31 apart, but you're using this function wrong if you need
|
||||
// that much range
|
||||
s32 offset = x - base;
|
||||
Do(offset);
|
||||
if (mode == MODE_READ)
|
||||
x = base + offset;
|
||||
}
|
||||
|
||||
template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)>
|
||||
void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr)
|
||||
{
|
||||
template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*),
|
||||
void (*TDo)(PointerWrap&, T*)>
|
||||
void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end = nullptr) {
|
||||
LinkedListItem<T>* list_cur = list_start;
|
||||
LinkedListItem<T>* prev = nullptr;
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
u8 shouldExist = (list_cur ? 1 : 0);
|
||||
Do(shouldExist);
|
||||
if (shouldExist == 1)
|
||||
{
|
||||
if (shouldExist == 1) {
|
||||
LinkedListItem<T>* cur = list_cur ? list_cur : TNew();
|
||||
TDo(*this, (T*)cur);
|
||||
if (!list_cur)
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
if (!list_cur) {
|
||||
if (mode == MODE_READ) {
|
||||
cur->next = nullptr;
|
||||
list_cur = cur;
|
||||
if (prev)
|
||||
prev->next = cur;
|
||||
else
|
||||
list_start = cur;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
TFree(cur);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode == MODE_READ)
|
||||
{
|
||||
} else {
|
||||
if (mode == MODE_READ) {
|
||||
if (prev)
|
||||
prev->next = nullptr;
|
||||
if (list_end)
|
||||
*list_end = prev;
|
||||
if (list_cur)
|
||||
{
|
||||
if (list_cur) {
|
||||
if (list_start == list_cur)
|
||||
list_start = nullptr;
|
||||
do
|
||||
{
|
||||
do {
|
||||
LinkedListItem<T>* next = list_cur->next;
|
||||
TFree(list_cur);
|
||||
list_cur = next;
|
||||
}
|
||||
while (list_cur);
|
||||
} while (list_cur);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -634,13 +607,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void DoMarker(const char* prevName, u32 arbitraryNumber=0x42)
|
||||
{
|
||||
void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42) {
|
||||
u32 cookie = arbitraryNumber;
|
||||
Do(cookie);
|
||||
if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
|
||||
{
|
||||
LOG_ERROR(Common, "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
|
||||
if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) {
|
||||
LOG_ERROR(Common, "After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). "
|
||||
"Aborting savestate load...",
|
||||
prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
|
||||
SetError(ERROR_FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,24 +14,28 @@
|
|||
// having to prefix them with gen-> or something similar.
|
||||
// Example implementation:
|
||||
// class JIT : public CodeBlock<ARMXEmitter> {}
|
||||
template<class T> class CodeBlock : public T, NonCopyable
|
||||
{
|
||||
template <class T>
|
||||
class CodeBlock : public T, NonCopyable {
|
||||
private:
|
||||
// A privately used function to set the executable RAM space to something invalid.
|
||||
// For debugging usefulness it should be used to set the RAM to a host specific breakpoint instruction
|
||||
// For debugging usefulness it should be used to set the RAM to a host specific breakpoint
|
||||
// instruction
|
||||
virtual void PoisonMemory() = 0;
|
||||
|
||||
protected:
|
||||
u8 *region;
|
||||
u8* region;
|
||||
size_t region_size;
|
||||
|
||||
public:
|
||||
CodeBlock() : region(nullptr), region_size(0) {}
|
||||
virtual ~CodeBlock() { if (region) FreeCodeSpace(); }
|
||||
CodeBlock() : region(nullptr), region_size(0) {
|
||||
}
|
||||
virtual ~CodeBlock() {
|
||||
if (region)
|
||||
FreeCodeSpace();
|
||||
}
|
||||
|
||||
// Call this before you generate any code.
|
||||
void AllocCodeSpace(int size)
|
||||
{
|
||||
void AllocCodeSpace(int size) {
|
||||
region_size = size;
|
||||
region = (u8*)AllocateExecutableMemory(region_size);
|
||||
T::SetCodePtr(region);
|
||||
|
@ -39,15 +43,13 @@ public:
|
|||
|
||||
// Always clear code space with breakpoints, so that if someone accidentally executes
|
||||
// uninitialized, it just breaks into the debugger.
|
||||
void ClearCodeSpace()
|
||||
{
|
||||
void ClearCodeSpace() {
|
||||
PoisonMemory();
|
||||
ResetCodePtr();
|
||||
}
|
||||
|
||||
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
|
||||
void FreeCodeSpace()
|
||||
{
|
||||
void FreeCodeSpace() {
|
||||
#ifdef __SYMBIAN32__
|
||||
ResetExecutableMemory(region);
|
||||
#else
|
||||
|
@ -57,33 +59,29 @@ public:
|
|||
region_size = 0;
|
||||
}
|
||||
|
||||
bool IsInSpace(const u8 *ptr)
|
||||
{
|
||||
bool IsInSpace(const u8* ptr) {
|
||||
return (ptr >= region) && (ptr < (region + region_size));
|
||||
}
|
||||
|
||||
// Cannot currently be undone. Will write protect the entire code region.
|
||||
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
|
||||
void WriteProtect()
|
||||
{
|
||||
void WriteProtect() {
|
||||
WriteProtectMemory(region, region_size, true);
|
||||
}
|
||||
|
||||
void ResetCodePtr()
|
||||
{
|
||||
void ResetCodePtr() {
|
||||
T::SetCodePtr(region);
|
||||
}
|
||||
|
||||
size_t GetSpaceLeft() const
|
||||
{
|
||||
size_t GetSpaceLeft() const {
|
||||
return region_size - (T::GetCodePtr() - region);
|
||||
}
|
||||
|
||||
u8 *GetBasePtr() {
|
||||
u8* GetBasePtr() {
|
||||
return region;
|
||||
}
|
||||
|
||||
size_t GetOffset(const u8 *ptr) const {
|
||||
size_t GetOffset(const u8* ptr) const {
|
||||
return ptr - region;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -56,7 +56,7 @@ constexpr u8 Convert8To6(u8 value) {
|
|||
* @return Result color decoded as Math::Vec4<u8>
|
||||
*/
|
||||
inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
||||
return { bytes[3], bytes[2], bytes[1], bytes[0] };
|
||||
return {bytes[3], bytes[2], bytes[1], bytes[0]};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,7 @@ inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) {
|
|||
* @return Result color decoded as Math::Vec4<u8>
|
||||
*/
|
||||
inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
||||
return { bytes[2], bytes[1], bytes[0], 255 };
|
||||
return {bytes[2], bytes[1], bytes[0], 255};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,7 +74,7 @@ inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) {
|
|||
* @return Result color decoded as Math::Vec4<u8>
|
||||
*/
|
||||
inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) {
|
||||
return { bytes[1], bytes[0], 0, 255 };
|
||||
return {bytes[1], bytes[0], 0, 255};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,8 +84,8 @@ inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) {
|
|||
*/
|
||||
inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
||||
const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
|
||||
return { Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
|
||||
Convert5To8(pixel & 0x1F), 255 };
|
||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
|
||||
Convert5To8(pixel & 0x1F), 255};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,8 +95,8 @@ inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) {
|
|||
*/
|
||||
inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
||||
const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
|
||||
return { Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
|
||||
Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1) };
|
||||
return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
|
||||
Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,8 +106,8 @@ inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
|
|||
*/
|
||||
inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) {
|
||||
const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes);
|
||||
return { Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
|
||||
Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF) };
|
||||
return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
|
||||
Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,7 +134,7 @@ inline u32 DecodeD24(const u8* bytes) {
|
|||
* @return Resulting values stored as a Math::Vec2
|
||||
*/
|
||||
inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) {
|
||||
return { static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3] };
|
||||
return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,8 +175,8 @@ inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) {
|
|||
* @param bytes Destination pointer to store encoded color
|
||||
*/
|
||||
inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
|
||||
*reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) |
|
||||
(Convert8To6(color.g()) << 5) | Convert8To5(color.b());
|
||||
*reinterpret_cast<u16_le*>(bytes) =
|
||||
(Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -186,7 +186,8 @@ inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) {
|
|||
*/
|
||||
inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
|
||||
*reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) |
|
||||
(Convert8To5(color.g()) << 6) | (Convert8To5(color.b()) << 1) | Convert8To1(color.a());
|
||||
(Convert8To5(color.g()) << 6) |
|
||||
(Convert8To5(color.b()) << 1) | Convert8To1(color.a());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -196,7 +197,8 @@ inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) {
|
|||
*/
|
||||
inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) {
|
||||
*reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) |
|
||||
(Convert8To4(color.g()) << 8) | (Convert8To4(color.b()) << 4) | Convert8To4(color.a());
|
||||
(Convert8To4(color.g()) << 8) |
|
||||
(Convert8To4(color.b()) << 4) | Convert8To4(color.a());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
/// Textually concatenates two tokens. The double-expansion is required by the C preprocessor.
|
||||
#define CONCAT2(x, y) DO_CONCAT2(x, y)
|
||||
#define DO_CONCAT2(x, y) x ## y
|
||||
#define DO_CONCAT2(x, y) x##y
|
||||
|
||||
// helper macro to properly align structure members.
|
||||
// Calling INSERT_PADDING_BYTES will add a new member variable with a name like "pad121",
|
||||
|
@ -24,9 +24,9 @@
|
|||
|
||||
// Inlining
|
||||
#ifdef _WIN32
|
||||
#define FORCE_INLINE __forceinline
|
||||
#define FORCE_INLINE __forceinline
|
||||
#else
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
#define FORCE_INLINE inline __attribute__((always_inline))
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
@ -46,7 +46,8 @@
|
|||
#else
|
||||
inline u32 rotl(u32 x, int shift) {
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
if (!shift)
|
||||
return x;
|
||||
return (x << shift) | (x >> (32 - shift));
|
||||
}
|
||||
#endif
|
||||
|
@ -56,17 +57,18 @@ inline u32 rotl(u32 x, int shift) {
|
|||
#else
|
||||
inline u32 rotr(u32 x, int shift) {
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
if (!shift)
|
||||
return x;
|
||||
return (x >> shift) | (x << (32 - shift));
|
||||
}
|
||||
#endif
|
||||
|
||||
inline u64 _rotl64(u64 x, unsigned int shift){
|
||||
inline u64 _rotl64(u64 x, unsigned int shift) {
|
||||
unsigned int n = shift % 64;
|
||||
return (x << n) | (x >> (64 - n));
|
||||
}
|
||||
|
||||
inline u64 _rotr64(u64 x, unsigned int shift){
|
||||
inline u64 _rotr64(u64 x, unsigned int shift) {
|
||||
unsigned int n = shift % 64;
|
||||
return (x >> n) | (x << (64 - n));
|
||||
}
|
||||
|
@ -74,17 +76,18 @@ inline u64 _rotr64(u64 x, unsigned int shift){
|
|||
#else // _MSC_VER
|
||||
|
||||
#if (_MSC_VER < 1900)
|
||||
// Function Cross-Compatibility
|
||||
#define snprintf _snprintf
|
||||
// Function Cross-Compatibility
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
// Locale Cross-Compatibility
|
||||
#define locale_t _locale_t
|
||||
|
||||
extern "C" {
|
||||
__declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
__declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
}
|
||||
#define Crash() {DebugBreak();}
|
||||
#define Crash() \
|
||||
{ DebugBreak(); }
|
||||
|
||||
// cstdlib provides these on MSVC
|
||||
#define rotr _rotr
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
#define ROOT_DIR "."
|
||||
#define USERDATA_DIR "user"
|
||||
#ifdef USER_DIR
|
||||
#define EMU_DATA_DIR USER_DIR
|
||||
#define EMU_DATA_DIR USER_DIR
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
#define EMU_DATA_DIR "Citra Emulator"
|
||||
#else
|
||||
#define EMU_DATA_DIR "citra-emu"
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#define EMU_DATA_DIR "Citra Emulator"
|
||||
#else
|
||||
#define EMU_DATA_DIR "citra-emu"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Dirs in both User and Sys
|
||||
|
@ -31,32 +31,32 @@
|
|||
#define JAP_DIR "JAP"
|
||||
|
||||
// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
|
||||
#define CONFIG_DIR "config"
|
||||
#define GAMECONFIG_DIR "game_config"
|
||||
#define MAPS_DIR "maps"
|
||||
#define CACHE_DIR "cache"
|
||||
#define SDMC_DIR "sdmc"
|
||||
#define NAND_DIR "nand"
|
||||
#define SYSDATA_DIR "sysdata"
|
||||
#define SHADERCACHE_DIR "shader_cache"
|
||||
#define STATESAVES_DIR "state_saves"
|
||||
#define SCREENSHOTS_DIR "screenShots"
|
||||
#define DUMP_DIR "dump"
|
||||
#define DUMP_TEXTURES_DIR "textures"
|
||||
#define DUMP_FRAMES_DIR "frames"
|
||||
#define DUMP_AUDIO_DIR "audio"
|
||||
#define LOGS_DIR "logs"
|
||||
#define SHADERS_DIR "shaders"
|
||||
#define SYSCONF_DIR "sysconf"
|
||||
#define CONFIG_DIR "config"
|
||||
#define GAMECONFIG_DIR "game_config"
|
||||
#define MAPS_DIR "maps"
|
||||
#define CACHE_DIR "cache"
|
||||
#define SDMC_DIR "sdmc"
|
||||
#define NAND_DIR "nand"
|
||||
#define SYSDATA_DIR "sysdata"
|
||||
#define SHADERCACHE_DIR "shader_cache"
|
||||
#define STATESAVES_DIR "state_saves"
|
||||
#define SCREENSHOTS_DIR "screenShots"
|
||||
#define DUMP_DIR "dump"
|
||||
#define DUMP_TEXTURES_DIR "textures"
|
||||
#define DUMP_FRAMES_DIR "frames"
|
||||
#define DUMP_AUDIO_DIR "audio"
|
||||
#define LOGS_DIR "logs"
|
||||
#define SHADERS_DIR "shaders"
|
||||
#define SYSCONF_DIR "sysconf"
|
||||
|
||||
// Filenames
|
||||
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
|
||||
#define EMU_CONFIG "emu.ini"
|
||||
#define DEBUGGER_CONFIG "debugger.ini"
|
||||
#define LOGGER_CONFIG "logger.ini"
|
||||
#define EMU_CONFIG "emu.ini"
|
||||
#define DEBUGGER_CONFIG "debugger.ini"
|
||||
#define LOGGER_CONFIG "logger.ini"
|
||||
|
||||
// Sys files
|
||||
#define SHARED_FONT "shared_font.bin"
|
||||
#define SHARED_FONT "shared_font.bin"
|
||||
|
||||
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
|
||||
#define MAIN_LOG "emu.log"
|
||||
|
|
|
@ -32,18 +32,18 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
typedef std::uint8_t u8; ///< 8-bit unsigned byte
|
||||
typedef std::uint8_t u8; ///< 8-bit unsigned byte
|
||||
typedef std::uint16_t u16; ///< 16-bit unsigned short
|
||||
typedef std::uint32_t u32; ///< 32-bit unsigned word
|
||||
typedef std::uint64_t u64; ///< 64-bit unsigned int
|
||||
|
||||
typedef std::int8_t s8; ///< 8-bit signed byte
|
||||
typedef std::int8_t s8; ///< 8-bit signed byte
|
||||
typedef std::int16_t s16; ///< 16-bit signed short
|
||||
typedef std::int32_t s32; ///< 32-bit signed word
|
||||
typedef std::int64_t s64; ///< 64-bit signed int
|
||||
|
||||
typedef float f32; ///< 32-bit floating point
|
||||
typedef double f64; ///< 64-bit floating point
|
||||
typedef float f32; ///< 32-bit floating point
|
||||
typedef double f64; ///< 64-bit floating point
|
||||
|
||||
// TODO: It would be nice to eventually replace these with strong types that prevent accidental
|
||||
// conversion between each other.
|
||||
|
|
|
@ -44,18 +44,17 @@ void EmuWindow::CirclePadUpdated(float x, float y) {
|
|||
*/
|
||||
static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x,
|
||||
unsigned framebuffer_y) {
|
||||
return (framebuffer_y >= layout.bottom_screen.top &&
|
||||
framebuffer_y < layout.bottom_screen.bottom &&
|
||||
framebuffer_x >= layout.bottom_screen.left &&
|
||||
framebuffer_x < layout.bottom_screen.right);
|
||||
return (
|
||||
framebuffer_y >= layout.bottom_screen.top && framebuffer_y < layout.bottom_screen.bottom &&
|
||||
framebuffer_x >= layout.bottom_screen.left && framebuffer_x < layout.bottom_screen.right);
|
||||
}
|
||||
|
||||
std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
|
||||
std::tuple<unsigned, unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) {
|
||||
new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
|
||||
new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
|
||||
new_x = std::min(new_x, framebuffer_layout.bottom_screen.right - 1);
|
||||
|
||||
new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
|
||||
new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
|
||||
new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom - 1);
|
||||
|
||||
return std::make_tuple(new_x, new_y);
|
||||
}
|
||||
|
@ -64,10 +63,12 @@ void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) {
|
|||
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y))
|
||||
return;
|
||||
|
||||
touch_x = VideoCore::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) /
|
||||
(framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left);
|
||||
touch_y = VideoCore::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) /
|
||||
(framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
|
||||
touch_x = VideoCore::kScreenBottomWidth *
|
||||
(framebuffer_x - framebuffer_layout.bottom_screen.left) /
|
||||
(framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left);
|
||||
touch_y = VideoCore::kScreenBottomHeight *
|
||||
(framebuffer_y - framebuffer_layout.bottom_screen.top) /
|
||||
(framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top);
|
||||
|
||||
touch_pressed = true;
|
||||
pad_state.touch.Assign(1);
|
||||
|
@ -90,16 +91,19 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) {
|
|||
TouchPressed(framebuffer_x, framebuffer_y);
|
||||
}
|
||||
|
||||
EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) {
|
||||
EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width,
|
||||
unsigned height) {
|
||||
// When hiding the widget, the function receives a size of 0
|
||||
if (width == 0) width = 1;
|
||||
if (height == 0) height = 1;
|
||||
if (width == 0)
|
||||
width = 1;
|
||||
if (height == 0)
|
||||
height = 1;
|
||||
|
||||
EmuWindow::FramebufferLayout res = { width, height, {}, {} };
|
||||
EmuWindow::FramebufferLayout res = {width, height, {}, {}};
|
||||
|
||||
float window_aspect_ratio = static_cast<float>(height) / width;
|
||||
float emulation_aspect_ratio = static_cast<float>(VideoCore::kScreenTopHeight * 2) /
|
||||
VideoCore::kScreenTopWidth;
|
||||
float emulation_aspect_ratio =
|
||||
static_cast<float>(VideoCore::kScreenTopHeight * 2) / VideoCore::kScreenTopWidth;
|
||||
|
||||
if (window_aspect_ratio > emulation_aspect_ratio) {
|
||||
// Window is narrower than the emulation content => apply borders to the top and bottom
|
||||
|
@ -110,8 +114,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u
|
|||
res.top_screen.top = (height - viewport_height) / 2;
|
||||
res.top_screen.bottom = res.top_screen.top + viewport_height / 2;
|
||||
|
||||
int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) /
|
||||
VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left));
|
||||
int bottom_width = static_cast<int>(
|
||||
(static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) *
|
||||
(res.top_screen.right - res.top_screen.left));
|
||||
int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
|
||||
|
||||
res.bottom_screen.left = bottom_border;
|
||||
|
@ -127,8 +132,9 @@ EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(u
|
|||
res.top_screen.top = 0;
|
||||
res.top_screen.bottom = res.top_screen.top + height / 2;
|
||||
|
||||
int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) /
|
||||
VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left));
|
||||
int bottom_width = static_cast<int>(
|
||||
(static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth) *
|
||||
(res.top_screen.right - res.top_screen.left));
|
||||
int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2;
|
||||
|
||||
res.bottom_screen.left = res.top_screen.left + bottom_border;
|
||||
|
|
|
@ -30,15 +30,14 @@
|
|||
* - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
|
||||
* re-read the upper points again and think about it if you don't see this.
|
||||
*/
|
||||
class EmuWindow
|
||||
{
|
||||
class EmuWindow {
|
||||
public:
|
||||
/// Data structure to store emuwindow configuration
|
||||
struct WindowConfig {
|
||||
bool fullscreen;
|
||||
int res_width;
|
||||
int res_height;
|
||||
std::pair<unsigned,unsigned> min_client_area_size;
|
||||
bool fullscreen;
|
||||
int res_width;
|
||||
int res_height;
|
||||
std::pair<unsigned, unsigned> min_client_area_size;
|
||||
};
|
||||
|
||||
/// Describes the layout of the window framebuffer (size and top/bottom screen positions)
|
||||
|
@ -193,15 +192,18 @@ public:
|
|||
|
||||
/**
|
||||
* Returns currently active configuration.
|
||||
* @note Accesses to the returned object need not be consistent because it may be modified in another thread
|
||||
* @note Accesses to the returned object need not be consistent because it may be modified in
|
||||
* another thread
|
||||
*/
|
||||
const WindowConfig& GetActiveConfig() const {
|
||||
return active_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the internal configuration to be replaced by the specified argument at some point in the future.
|
||||
* @note This method is thread-safe, because it delays configuration changes to the GUI event loop. Hence there is no guarantee on when the requested configuration will be active.
|
||||
* Requests the internal configuration to be replaced by the specified argument at some point in
|
||||
* the future.
|
||||
* @note This method is thread-safe, because it delays configuration changes to the GUI event
|
||||
* loop. Hence there is no guarantee on when the requested configuration will be active.
|
||||
*/
|
||||
void SetConfig(const WindowConfig& val) {
|
||||
config = val;
|
||||
|
@ -227,7 +229,8 @@ protected:
|
|||
circle_pad_y = 0;
|
||||
touch_pressed = false;
|
||||
}
|
||||
virtual ~EmuWindow() {}
|
||||
virtual ~EmuWindow() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes any pending configuration changes from the last SetConfig call.
|
||||
|
@ -258,7 +261,7 @@ protected:
|
|||
* Update internal client area size with the given parameter.
|
||||
* @note EmuWindow implementations will usually use this in window resize event handlers.
|
||||
*/
|
||||
void NotifyClientAreaSizeChanged(const std::pair<unsigned,unsigned>& size) {
|
||||
void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) {
|
||||
client_area_width = size.first;
|
||||
client_area_height = size.second;
|
||||
}
|
||||
|
@ -266,32 +269,35 @@ protected:
|
|||
private:
|
||||
/**
|
||||
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
||||
* For the request to be honored, EmuWindow implementations will usually reimplement this function.
|
||||
* For the request to be honored, EmuWindow implementations will usually reimplement this
|
||||
* function.
|
||||
*/
|
||||
virtual void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
|
||||
virtual void
|
||||
OnMinimalClientAreaChangeRequest(const std::pair<unsigned, unsigned>& minimal_size) {
|
||||
// By default, ignore this request and do nothing.
|
||||
}
|
||||
|
||||
FramebufferLayout framebuffer_layout; ///< Current framebuffer layout
|
||||
|
||||
unsigned client_area_width; ///< Current client width, should be set by window impl.
|
||||
unsigned client_area_height; ///< Current client height, should be set by window impl.
|
||||
unsigned client_area_width; ///< Current client width, should be set by window impl.
|
||||
unsigned client_area_height; ///< Current client height, should be set by window impl.
|
||||
|
||||
WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges)
|
||||
WindowConfig active_config; ///< Internal active configuration
|
||||
WindowConfig config; ///< Internal configuration (changes pending for being applied in
|
||||
/// ProcessConfigurationChanges)
|
||||
WindowConfig active_config; ///< Internal active configuration
|
||||
|
||||
bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
|
||||
bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false
|
||||
|
||||
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
|
||||
u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
|
||||
u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320)
|
||||
u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240)
|
||||
|
||||
s16 circle_pad_x; ///< Circle pad X-position in native 3DS pixel coordinates (-156 - 156)
|
||||
s16 circle_pad_y; ///< Circle pad Y-position in native 3DS pixel coordinates (-156 - 156)
|
||||
|
||||
/**
|
||||
* Clip the provided coordinates to be inside the touchscreen area.
|
||||
*/
|
||||
std::tuple<unsigned,unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
|
||||
/**
|
||||
* Clip the provided coordinates to be inside the touchscreen area.
|
||||
*/
|
||||
std::tuple<unsigned, unsigned> ClipToTouchScreen(unsigned new_x, unsigned new_y);
|
||||
|
||||
Service::HID::PadState pad_state;
|
||||
};
|
||||
|
|
|
@ -2,73 +2,70 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_paths.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <shlobj.h> // for SHGetFolderPath
|
||||
#include <shellapi.h>
|
||||
#include <commdlg.h> // for GetSaveFileName
|
||||
#include <io.h>
|
||||
#include <direct.h> // getcwd
|
||||
#include <tchar.h>
|
||||
#include <windows.h>
|
||||
#include <commdlg.h> // for GetSaveFileName
|
||||
#include <direct.h> // getcwd
|
||||
#include <io.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h> // for SHGetFolderPath
|
||||
#include <tchar.h>
|
||||
|
||||
#include "common/string_util.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
// 64 bit offsets for windows
|
||||
#define fseeko _fseeki64
|
||||
#define ftello _ftelli64
|
||||
#define atoll _atoi64
|
||||
#define stat64 _stat64
|
||||
#define fstat64 _fstat64
|
||||
#define fileno _fileno
|
||||
// 64 bit offsets for windows
|
||||
#define fseeko _fseeki64
|
||||
#define ftello _ftelli64
|
||||
#define atoll _atoi64
|
||||
#define stat64 _stat64
|
||||
#define fstat64 _fstat64
|
||||
#define fileno _fileno
|
||||
#else
|
||||
#ifdef __APPLE__
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __APPLE__
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <CoreFoundation/CFURL.h>
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#include <CoreFoundation/CFString.h>
|
||||
#include <CoreFoundation/CFURL.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#ifndef S_ISDIR
|
||||
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
||||
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
|
||||
#ifdef BSD4_4
|
||||
#define stat64 stat
|
||||
#define fstat64 fstat
|
||||
#define stat64 stat
|
||||
#define fstat64 fstat
|
||||
#endif
|
||||
|
||||
// This namespace has various generic functions related to files and paths.
|
||||
// The code still needs a ton of cleanup.
|
||||
// REMEMBER: strdup considered harmful!
|
||||
namespace FileUtil
|
||||
{
|
||||
namespace FileUtil {
|
||||
|
||||
// Remove any ending forward slashes from directory paths
|
||||
// Modifies argument.
|
||||
static void StripTailDirSlashes(std::string &fname)
|
||||
{
|
||||
if (fname.length() > 1)
|
||||
{
|
||||
static void StripTailDirSlashes(std::string& fname) {
|
||||
if (fname.length() > 1) {
|
||||
size_t i = fname.length();
|
||||
while (i > 0 && fname[i - 1] == DIR_SEP_CHR)
|
||||
--i;
|
||||
|
@ -78,8 +75,7 @@ static void StripTailDirSlashes(std::string &fname)
|
|||
}
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string &filename)
|
||||
{
|
||||
bool Exists(const std::string& filename) {
|
||||
struct stat64 file_info;
|
||||
|
||||
std::string copy(filename);
|
||||
|
@ -99,8 +95,7 @@ bool Exists(const std::string &filename)
|
|||
}
|
||||
|
||||
// Returns true if filename is a directory
|
||||
bool IsDirectory(const std::string &filename)
|
||||
{
|
||||
bool IsDirectory(const std::string& filename) {
|
||||
struct stat64 file_info;
|
||||
|
||||
std::string copy(filename);
|
||||
|
@ -117,8 +112,8 @@ bool IsDirectory(const std::string &filename)
|
|||
#endif
|
||||
|
||||
if (result < 0) {
|
||||
LOG_WARNING(Common_Filesystem, "stat failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
LOG_WARNING(Common_Filesystem, "stat failed on %s: %s", filename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -127,36 +122,32 @@ bool IsDirectory(const std::string &filename)
|
|||
|
||||
// Deletes a given filename, return true on success
|
||||
// Doesn't supports deleting a directory
|
||||
bool Delete(const std::string &filename)
|
||||
{
|
||||
bool Delete(const std::string& filename) {
|
||||
LOG_INFO(Common_Filesystem, "file %s", filename.c_str());
|
||||
|
||||
// Return true because we care about the file no
|
||||
// being there, not the actual delete.
|
||||
if (!Exists(filename))
|
||||
{
|
||||
if (!Exists(filename)) {
|
||||
LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can't delete a directory
|
||||
if (IsDirectory(filename))
|
||||
{
|
||||
if (IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str()))
|
||||
{
|
||||
LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
if (!DeleteFileW(Common::UTF8ToUTF16W(filename).c_str())) {
|
||||
LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s", filename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (unlink(filename.c_str()) == -1) {
|
||||
LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s", filename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
@ -165,16 +156,15 @@ bool Delete(const std::string &filename)
|
|||
}
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string &path)
|
||||
{
|
||||
bool CreateDir(const std::string& path) {
|
||||
LOG_TRACE(Common_Filesystem, "directory %s", path.c_str());
|
||||
#ifdef _WIN32
|
||||
if (::CreateDirectoryW(Common::UTF8ToUTF16W(path).c_str(), nullptr))
|
||||
return true;
|
||||
DWORD error = GetLastError();
|
||||
if (error == ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str());
|
||||
if (error == ERROR_ALREADY_EXISTS) {
|
||||
LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists",
|
||||
path.c_str());
|
||||
return true;
|
||||
}
|
||||
LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error);
|
||||
|
@ -185,8 +175,7 @@ bool CreateDir(const std::string &path)
|
|||
|
||||
int err = errno;
|
||||
|
||||
if (err == EEXIST)
|
||||
{
|
||||
if (err == EEXIST) {
|
||||
LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str());
|
||||
return true;
|
||||
}
|
||||
|
@ -197,20 +186,17 @@ bool CreateDir(const std::string &path)
|
|||
}
|
||||
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const std::string &fullPath)
|
||||
{
|
||||
bool CreateFullPath(const std::string& fullPath) {
|
||||
int panicCounter = 100;
|
||||
LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str());
|
||||
|
||||
if (FileUtil::Exists(fullPath))
|
||||
{
|
||||
if (FileUtil::Exists(fullPath)) {
|
||||
LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t position = 0;
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
// Find next sub path
|
||||
position = fullPath.find(DIR_SEP_CHR, position);
|
||||
|
||||
|
@ -227,8 +213,7 @@ bool CreateFullPath(const std::string &fullPath)
|
|||
|
||||
// A safety check
|
||||
panicCounter--;
|
||||
if (panicCounter <= 0)
|
||||
{
|
||||
if (panicCounter <= 0) {
|
||||
LOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
|
||||
return false;
|
||||
}
|
||||
|
@ -236,15 +221,12 @@ bool CreateFullPath(const std::string &fullPath)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// Deletes a directory filename, returns true on success
|
||||
bool DeleteDir(const std::string &filename)
|
||||
{
|
||||
bool DeleteDir(const std::string& filename) {
|
||||
LOG_INFO(Common_Filesystem, "directory %s", filename.c_str());
|
||||
|
||||
// check if a directory
|
||||
if (!FileUtil::IsDirectory(filename))
|
||||
{
|
||||
if (!FileUtil::IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
@ -262,83 +244,73 @@ bool DeleteDir(const std::string &filename)
|
|||
}
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const std::string &srcFilename, const std::string &destFilename)
|
||||
{
|
||||
LOG_TRACE(Common_Filesystem, "%s --> %s",
|
||||
srcFilename.c_str(), destFilename.c_str());
|
||||
bool Rename(const std::string& srcFilename, const std::string& destFilename) {
|
||||
LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
#ifdef _WIN32
|
||||
if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
|
||||
if (_wrename(Common::UTF8ToUTF16W(srcFilename).c_str(),
|
||||
Common::UTF8ToUTF16W(destFilename).c_str()) == 0)
|
||||
return true;
|
||||
#else
|
||||
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
|
||||
return true;
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const std::string &srcFilename, const std::string &destFilename)
|
||||
{
|
||||
LOG_TRACE(Common_Filesystem, "%s --> %s",
|
||||
srcFilename.c_str(), destFilename.c_str());
|
||||
bool Copy(const std::string& srcFilename, const std::string& destFilename) {
|
||||
LOG_TRACE(Common_Filesystem, "%s --> %s", srcFilename.c_str(), destFilename.c_str());
|
||||
#ifdef _WIN32
|
||||
if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(), Common::UTF8ToUTF16W(destFilename).c_str(), FALSE))
|
||||
if (CopyFileW(Common::UTF8ToUTF16W(srcFilename).c_str(),
|
||||
Common::UTF8ToUTF16W(destFilename).c_str(), FALSE))
|
||||
return true;
|
||||
|
||||
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(),
|
||||
GetLastErrorMsg());
|
||||
return false;
|
||||
#else
|
||||
|
||||
// buffer size
|
||||
// buffer size
|
||||
#define BSIZE 1024
|
||||
|
||||
char buffer[BSIZE];
|
||||
|
||||
// Open input file
|
||||
FILE *input = fopen(srcFilename.c_str(), "rb");
|
||||
if (!input)
|
||||
{
|
||||
LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
FILE* input = fopen(srcFilename.c_str(), "rb");
|
||||
if (!input) {
|
||||
LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s", srcFilename.c_str(),
|
||||
destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// open output file
|
||||
FILE *output = fopen(destFilename.c_str(), "wb");
|
||||
if (!output)
|
||||
{
|
||||
FILE* output = fopen(destFilename.c_str(), "wb");
|
||||
if (!output) {
|
||||
fclose(input);
|
||||
LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s", srcFilename.c_str(),
|
||||
destFilename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
// copy loop
|
||||
while (!feof(input))
|
||||
{
|
||||
while (!feof(input)) {
|
||||
// read input
|
||||
int rnum = fread(buffer, sizeof(char), BSIZE, input);
|
||||
if (rnum != BSIZE)
|
||||
{
|
||||
if (ferror(input) != 0)
|
||||
{
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"failed reading from source, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
if (rnum != BSIZE) {
|
||||
if (ferror(input) != 0) {
|
||||
LOG_ERROR(Common_Filesystem, "failed reading from source, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
// write output
|
||||
int wnum = fwrite(buffer, sizeof(char), rnum, output);
|
||||
if (wnum != rnum)
|
||||
{
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"failed writing to output, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
if (wnum != rnum) {
|
||||
LOG_ERROR(Common_Filesystem, "failed writing to output, %s --> %s: %s",
|
||||
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
@ -356,16 +328,13 @@ bail:
|
|||
}
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string &filename)
|
||||
{
|
||||
if (!Exists(filename))
|
||||
{
|
||||
u64 GetSize(const std::string& filename) {
|
||||
if (!Exists(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IsDirectory(filename))
|
||||
{
|
||||
if (IsDirectory(filename)) {
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str());
|
||||
return 0;
|
||||
}
|
||||
|
@ -377,65 +346,54 @@ u64 GetSize(const std::string &filename)
|
|||
if (stat64(filename.c_str(), &buf) == 0)
|
||||
#endif
|
||||
{
|
||||
LOG_TRACE(Common_Filesystem, "%s: %lld",
|
||||
filename.c_str(), (long long)buf.st_size);
|
||||
LOG_TRACE(Common_Filesystem, "%s: %lld", filename.c_str(), (long long)buf.st_size);
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
LOG_ERROR(Common_Filesystem, "Stat failed %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "Stat failed %s: %s", filename.c_str(), GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
u64 GetSize(const int fd)
|
||||
{
|
||||
u64 GetSize(const int fd) {
|
||||
struct stat64 buf;
|
||||
if (fstat64(fd, &buf) != 0) {
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s",
|
||||
fd, GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s", fd, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
return buf.st_size;
|
||||
}
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
u64 GetSize(FILE *f)
|
||||
{
|
||||
u64 GetSize(FILE* f) {
|
||||
// can't use off_t here because it can be 32-bit
|
||||
u64 pos = ftello(f);
|
||||
if (fseeko(f, 0, SEEK_END) != 0) {
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s",
|
||||
f, GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
u64 size = ftello(f);
|
||||
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s",
|
||||
f, GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s", f, GetLastErrorMsg());
|
||||
return 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string &filename)
|
||||
{
|
||||
bool CreateEmptyFile(const std::string& filename) {
|
||||
LOG_TRACE(Common_Filesystem, "%s", filename.c_str());
|
||||
|
||||
if (!FileUtil::IOFile(filename, "wb"))
|
||||
{
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: %s",
|
||||
filename.c_str(), GetLastErrorMsg());
|
||||
if (!FileUtil::IOFile(filename, "wb")) {
|
||||
LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback)
|
||||
{
|
||||
bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
|
||||
DirectoryEntryCallable callback) {
|
||||
LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
|
||||
|
||||
// How many files + directories we found
|
||||
|
@ -457,7 +415,7 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
|
|||
do {
|
||||
const std::string virtual_name(Common::UTF16ToUTF8(ffd.cFileName));
|
||||
#else
|
||||
DIR *dirp = opendir(directory.c_str());
|
||||
DIR* dirp = opendir(directory.c_str());
|
||||
if (!dirp)
|
||||
return false;
|
||||
|
||||
|
@ -493,8 +451,8 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
|
|||
return true;
|
||||
}
|
||||
|
||||
unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion)
|
||||
{
|
||||
unsigned ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
|
||||
unsigned int recursion) {
|
||||
const auto callback = [recursion, &parent_entry](unsigned* num_entries_out,
|
||||
const std::string& directory,
|
||||
const std::string& virtual_name) -> bool {
|
||||
|
@ -526,11 +484,8 @@ unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry,
|
|||
return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0;
|
||||
}
|
||||
|
||||
|
||||
bool DeleteDirRecursively(const std::string &directory, unsigned int recursion)
|
||||
{
|
||||
const auto callback = [recursion](unsigned* num_entries_out,
|
||||
const std::string& directory,
|
||||
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) {
|
||||
const auto callback = [recursion](unsigned* num_entries_out, const std::string& directory,
|
||||
const std::string& virtual_name) -> bool {
|
||||
std::string new_path = directory + DIR_SEP_CHR + virtual_name;
|
||||
|
||||
|
@ -551,53 +506,53 @@ bool DeleteDirRecursively(const std::string &directory, unsigned int recursion)
|
|||
}
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string &source_path, const std::string &dest_path)
|
||||
{
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path) {
|
||||
#ifndef _WIN32
|
||||
if (source_path == dest_path) return;
|
||||
if (!FileUtil::Exists(source_path)) return;
|
||||
if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path);
|
||||
if (source_path == dest_path)
|
||||
return;
|
||||
if (!FileUtil::Exists(source_path))
|
||||
return;
|
||||
if (!FileUtil::Exists(dest_path))
|
||||
FileUtil::CreateFullPath(dest_path);
|
||||
|
||||
DIR *dirp = opendir(source_path.c_str());
|
||||
if (!dirp) return;
|
||||
DIR* dirp = opendir(source_path.c_str());
|
||||
if (!dirp)
|
||||
return;
|
||||
|
||||
while (struct dirent* result = readdir(dirp)) {
|
||||
const std::string virtualName(result->d_name);
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
(virtualName[2] == '\0')))
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') && (virtualName[2] == '\0')))
|
||||
continue;
|
||||
|
||||
std::string source, dest;
|
||||
source = source_path + virtualName;
|
||||
dest = dest_path + virtualName;
|
||||
if (IsDirectory(source))
|
||||
{
|
||||
if (IsDirectory(source)) {
|
||||
source += '/';
|
||||
dest += '/';
|
||||
if (!FileUtil::Exists(dest)) FileUtil::CreateFullPath(dest);
|
||||
if (!FileUtil::Exists(dest))
|
||||
FileUtil::CreateFullPath(dest);
|
||||
CopyDir(source, dest);
|
||||
}
|
||||
else if (!FileUtil::Exists(dest)) FileUtil::Copy(source, dest);
|
||||
} else if (!FileUtil::Exists(dest))
|
||||
FileUtil::Copy(source, dest);
|
||||
}
|
||||
closedir(dirp);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Returns the current directory
|
||||
std::string GetCurrentDir()
|
||||
{
|
||||
// Get the current working directory (getcwd uses malloc)
|
||||
std::string GetCurrentDir() {
|
||||
// Get the current working directory (getcwd uses malloc)
|
||||
#ifdef _WIN32
|
||||
wchar_t *dir;
|
||||
wchar_t* dir;
|
||||
if (!(dir = _wgetcwd(nullptr, 0))) {
|
||||
#else
|
||||
char *dir;
|
||||
char* dir;
|
||||
if (!(dir = getcwd(nullptr, 0))) {
|
||||
#endif
|
||||
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s",
|
||||
GetLastErrorMsg());
|
||||
LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s", GetLastErrorMsg());
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
|
@ -610,8 +565,7 @@ std::string GetCurrentDir()
|
|||
}
|
||||
|
||||
// Sets the current directory to the given directory
|
||||
bool SetCurrentDir(const std::string &directory)
|
||||
{
|
||||
bool SetCurrentDir(const std::string& directory) {
|
||||
#ifdef _WIN32
|
||||
return _wchdir(Common::UTF8ToUTF16W(directory).c_str()) == 0;
|
||||
#else
|
||||
|
@ -620,8 +574,7 @@ bool SetCurrentDir(const std::string &directory)
|
|||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
std::string GetBundleDirectory()
|
||||
{
|
||||
std::string GetBundleDirectory() {
|
||||
CFURLRef BundleRef;
|
||||
char AppBundlePath[MAXPATHLEN];
|
||||
// Get the main bundle for the app
|
||||
|
@ -636,11 +589,9 @@ std::string GetBundleDirectory()
|
|||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string& GetExeDirectory()
|
||||
{
|
||||
std::string& GetExeDirectory() {
|
||||
static std::string exe_path;
|
||||
if (exe_path.empty())
|
||||
{
|
||||
if (exe_path.empty()) {
|
||||
wchar_t wchar_exe_path[2048];
|
||||
GetModuleFileNameW(nullptr, wchar_exe_path, 2048);
|
||||
exe_path = Common::UTF16ToUTF8(wchar_exe_path);
|
||||
|
@ -660,7 +611,8 @@ static const std::string& GetHomeDirectory() {
|
|||
home_path = envvar;
|
||||
} else {
|
||||
auto pw = getpwuid(getuid());
|
||||
ASSERT_MSG(pw, "$HOME isn’t defined, and the current user can’t be found in /etc/passwd.");
|
||||
ASSERT_MSG(pw,
|
||||
"$HOME isn’t defined, and the current user can’t be found in /etc/passwd.");
|
||||
home_path = pw->pw_dir;
|
||||
}
|
||||
}
|
||||
|
@ -699,11 +651,10 @@ static const std::string GetUserDirectory(const std::string& envvar) {
|
|||
}
|
||||
#endif
|
||||
|
||||
std::string GetSysDirectory()
|
||||
{
|
||||
std::string GetSysDirectory() {
|
||||
std::string sysDir;
|
||||
|
||||
#if defined (__APPLE__)
|
||||
#if defined(__APPLE__)
|
||||
sysDir = GetBundleDirectory();
|
||||
sysDir += DIR_SEP;
|
||||
sysDir += SYSDATA_DIR;
|
||||
|
@ -718,123 +669,114 @@ std::string GetSysDirectory()
|
|||
|
||||
// Returns a string with a Citra data dir or file in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath)
|
||||
{
|
||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath) {
|
||||
static std::string paths[NUM_PATH_INDICES];
|
||||
|
||||
// Set up all paths and files on the first run
|
||||
if (paths[D_USER_IDX].empty())
|
||||
{
|
||||
if (paths[D_USER_IDX].empty()) {
|
||||
#ifdef _WIN32
|
||||
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
#else
|
||||
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
} else {
|
||||
std::string data_dir = GetUserDirectory("XDG_DATA_HOME");
|
||||
std::string data_dir = GetUserDirectory("XDG_DATA_HOME");
|
||||
std::string config_dir = GetUserDirectory("XDG_CONFIG_HOME");
|
||||
std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME");
|
||||
std::string cache_dir = GetUserDirectory("XDG_CACHE_HOME");
|
||||
|
||||
paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
paths[D_USER_IDX] = data_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = config_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
|
||||
}
|
||||
#endif
|
||||
|
||||
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
|
||||
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
|
||||
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
|
||||
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
|
||||
paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
|
||||
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
|
||||
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
|
||||
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
|
||||
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
|
||||
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
|
||||
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
|
||||
paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
|
||||
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
|
||||
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
|
||||
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
}
|
||||
|
||||
if (!newPath.empty())
|
||||
{
|
||||
if (!FileUtil::IsDirectory(newPath))
|
||||
{
|
||||
if (!newPath.empty()) {
|
||||
if (!FileUtil::IsDirectory(newPath)) {
|
||||
LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str());
|
||||
return paths[DirIDX];
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
paths[DirIDX] = newPath;
|
||||
}
|
||||
|
||||
switch (DirIDX)
|
||||
{
|
||||
switch (DirIDX) {
|
||||
case D_ROOT_IDX:
|
||||
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
|
||||
paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
|
||||
paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
|
||||
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
|
||||
paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
|
||||
paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
|
||||
break;
|
||||
|
||||
case D_USER_IDX:
|
||||
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
|
||||
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
|
||||
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
|
||||
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
|
||||
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
|
||||
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP;
|
||||
paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
|
||||
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
|
||||
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
|
||||
paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
|
||||
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
|
||||
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
|
||||
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
|
||||
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
|
||||
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
|
||||
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
|
||||
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
|
||||
paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
|
||||
paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
|
||||
paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP;
|
||||
paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
|
||||
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
break;
|
||||
|
||||
case D_CONFIG_IDX:
|
||||
paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
|
||||
paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
|
||||
paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
|
||||
break;
|
||||
|
||||
case D_DUMP_IDX:
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
|
||||
paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
|
||||
paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
|
||||
break;
|
||||
|
||||
case D_LOGS_IDX:
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
|
||||
}
|
||||
}
|
||||
|
||||
return paths[DirIDX];
|
||||
}
|
||||
|
||||
size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename)
|
||||
{
|
||||
size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename) {
|
||||
return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
|
||||
}
|
||||
|
||||
size_t ReadFileToString(bool text_file, const char *filename, std::string &str)
|
||||
{
|
||||
size_t ReadFileToString(bool text_file, const char* filename, std::string& str) {
|
||||
IOFile file(filename, text_file ? "r" : "rb");
|
||||
|
||||
if (!file)
|
||||
|
@ -886,42 +828,36 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
|
|||
}
|
||||
}
|
||||
|
||||
IOFile::IOFile()
|
||||
{
|
||||
IOFile::IOFile() {
|
||||
}
|
||||
|
||||
IOFile::IOFile(const std::string& filename, const char openmode[])
|
||||
{
|
||||
IOFile::IOFile(const std::string& filename, const char openmode[]) {
|
||||
Open(filename, openmode);
|
||||
}
|
||||
|
||||
IOFile::~IOFile()
|
||||
{
|
||||
IOFile::~IOFile() {
|
||||
Close();
|
||||
}
|
||||
|
||||
IOFile::IOFile(IOFile&& other)
|
||||
{
|
||||
IOFile::IOFile(IOFile&& other) {
|
||||
Swap(other);
|
||||
}
|
||||
|
||||
IOFile& IOFile::operator=(IOFile&& other)
|
||||
{
|
||||
IOFile& IOFile::operator=(IOFile&& other) {
|
||||
Swap(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void IOFile::Swap(IOFile& other)
|
||||
{
|
||||
void IOFile::Swap(IOFile& other) {
|
||||
std::swap(m_file, other.m_file);
|
||||
std::swap(m_good, other.m_good);
|
||||
}
|
||||
|
||||
bool IOFile::Open(const std::string& filename, const char openmode[])
|
||||
{
|
||||
bool IOFile::Open(const std::string& filename, const char openmode[]) {
|
||||
Close();
|
||||
#ifdef _WIN32
|
||||
_wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(), Common::UTF8ToUTF16W(openmode).c_str());
|
||||
_wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(),
|
||||
Common::UTF8ToUTF16W(openmode).c_str());
|
||||
#else
|
||||
m_file = fopen(filename.c_str(), openmode);
|
||||
#endif
|
||||
|
@ -930,8 +866,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
|
|||
return m_good;
|
||||
}
|
||||
|
||||
bool IOFile::Close()
|
||||
{
|
||||
bool IOFile::Close() {
|
||||
if (!IsOpen() || 0 != std::fclose(m_file))
|
||||
m_good = false;
|
||||
|
||||
|
@ -939,50 +874,46 @@ bool IOFile::Close()
|
|||
return m_good;
|
||||
}
|
||||
|
||||
u64 IOFile::GetSize() const
|
||||
{
|
||||
u64 IOFile::GetSize() const {
|
||||
if (IsOpen())
|
||||
return FileUtil::GetSize(m_file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IOFile::Seek(s64 off, int origin)
|
||||
{
|
||||
bool IOFile::Seek(s64 off, int origin) {
|
||||
if (!IsOpen() || 0 != fseeko(m_file, off, origin))
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
u64 IOFile::Tell() const
|
||||
{
|
||||
u64 IOFile::Tell() const {
|
||||
if (IsOpen())
|
||||
return ftello(m_file);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IOFile::Flush()
|
||||
{
|
||||
bool IOFile::Flush() {
|
||||
if (!IsOpen() || 0 != std::fflush(m_file))
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
}
|
||||
|
||||
bool IOFile::Resize(u64 size)
|
||||
{
|
||||
if (!IsOpen() || 0 !=
|
||||
bool IOFile::Resize(u64 size) {
|
||||
if (!IsOpen() ||
|
||||
0 !=
|
||||
#ifdef _WIN32
|
||||
// ector: _chsize sucks, not 64-bit safe
|
||||
// F|RES: changed to _chsize_s. i think it is 64-bit safe
|
||||
_chsize_s(_fileno(m_file), size)
|
||||
// ector: _chsize sucks, not 64-bit safe
|
||||
// F|RES: changed to _chsize_s. i think it is 64-bit safe
|
||||
_chsize_s(_fileno(m_file), size)
|
||||
#else
|
||||
// TODO: handle 64bit and growing
|
||||
ftruncate(fileno(m_file), size)
|
||||
// TODO: handle 64bit and growing
|
||||
ftruncate(fileno(m_file), size)
|
||||
#endif
|
||||
)
|
||||
)
|
||||
m_good = false;
|
||||
|
||||
return m_good;
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
@ -51,75 +51,75 @@ enum {
|
|||
NUM_PATH_INDICES
|
||||
};
|
||||
|
||||
namespace FileUtil
|
||||
{
|
||||
namespace FileUtil {
|
||||
|
||||
// FileSystem tree node/
|
||||
struct FSTEntry
|
||||
{
|
||||
struct FSTEntry {
|
||||
bool isDirectory;
|
||||
u64 size; // file length or number of entries from children
|
||||
std::string physicalName; // name on disk
|
||||
std::string virtualName; // name in FST names table
|
||||
u64 size; // file length or number of entries from children
|
||||
std::string physicalName; // name on disk
|
||||
std::string virtualName; // name in FST names table
|
||||
std::vector<FSTEntry> children;
|
||||
};
|
||||
|
||||
// Returns true if file filename exists
|
||||
bool Exists(const std::string &filename);
|
||||
bool Exists(const std::string& filename);
|
||||
|
||||
// Returns true if filename is a directory
|
||||
bool IsDirectory(const std::string &filename);
|
||||
bool IsDirectory(const std::string& filename);
|
||||
|
||||
// Returns the size of filename (64bit)
|
||||
u64 GetSize(const std::string &filename);
|
||||
u64 GetSize(const std::string& filename);
|
||||
|
||||
// Overloaded GetSize, accepts file descriptor
|
||||
u64 GetSize(const int fd);
|
||||
|
||||
// Overloaded GetSize, accepts FILE*
|
||||
u64 GetSize(FILE *f);
|
||||
u64 GetSize(FILE* f);
|
||||
|
||||
// Returns true if successful, or path already exists.
|
||||
bool CreateDir(const std::string &filename);
|
||||
bool CreateDir(const std::string& filename);
|
||||
|
||||
// Creates the full path of fullPath returns true on success
|
||||
bool CreateFullPath(const std::string &fullPath);
|
||||
bool CreateFullPath(const std::string& fullPath);
|
||||
|
||||
// Deletes a given filename, return true on success
|
||||
// Doesn't supports deleting a directory
|
||||
bool Delete(const std::string &filename);
|
||||
bool Delete(const std::string& filename);
|
||||
|
||||
// Deletes a directory filename, returns true on success
|
||||
bool DeleteDir(const std::string &filename);
|
||||
bool DeleteDir(const std::string& filename);
|
||||
|
||||
// renames file srcFilename to destFilename, returns true on success
|
||||
bool Rename(const std::string &srcFilename, const std::string &destFilename);
|
||||
bool Rename(const std::string& srcFilename, const std::string& destFilename);
|
||||
|
||||
// copies file srcFilename to destFilename, returns true on success
|
||||
bool Copy(const std::string &srcFilename, const std::string &destFilename);
|
||||
bool Copy(const std::string& srcFilename, const std::string& destFilename);
|
||||
|
||||
// creates an empty file filename, returns true on success
|
||||
bool CreateEmptyFile(const std::string &filename);
|
||||
bool CreateEmptyFile(const std::string& filename);
|
||||
|
||||
/**
|
||||
* @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null
|
||||
* @param num_entries_out to be assigned by the callable with the number of iterated directory
|
||||
* entries, never null
|
||||
* @param directory the path to the enclosing directory
|
||||
* @param virtual_name the entry name, without any preceding directory info
|
||||
* @return whether handling the entry succeeded
|
||||
*/
|
||||
using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out,
|
||||
const std::string& directory,
|
||||
const std::string& virtual_name)>;
|
||||
using DirectoryEntryCallable = std::function<bool(
|
||||
unsigned* num_entries_out, const std::string& directory, const std::string& virtual_name)>;
|
||||
|
||||
/**
|
||||
* Scans a directory, calling the callback for each file/directory contained within.
|
||||
* If the callback returns failure, scanning halts and this function returns failure as well
|
||||
* @param num_entries_out assigned by the function with the number of iterated directory entries, can be null
|
||||
* @param num_entries_out assigned by the function with the number of iterated directory entries,
|
||||
* can be null
|
||||
* @param directory the directory to scan
|
||||
* @param callback The callback which will be called for each entry
|
||||
* @return whether scanning the directory succeeded
|
||||
*/
|
||||
bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback);
|
||||
bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string& directory,
|
||||
DirectoryEntryCallable callback);
|
||||
|
||||
/**
|
||||
* Scans the directory tree, storing the results.
|
||||
|
@ -128,23 +128,24 @@ bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directo
|
|||
* @param recursion Number of children directories to read before giving up.
|
||||
* @return the total number of files/directories found
|
||||
*/
|
||||
unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry, unsigned int recursion = 0);
|
||||
unsigned ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
|
||||
unsigned int recursion = 0);
|
||||
|
||||
// deletes the given directory and anything under it. Returns true on success.
|
||||
bool DeleteDirRecursively(const std::string &directory, unsigned int recursion = 256);
|
||||
bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
|
||||
|
||||
// Returns the current directory
|
||||
std::string GetCurrentDir();
|
||||
|
||||
// Create directory and copy contents (does not overwrite existing files)
|
||||
void CopyDir(const std::string &source_path, const std::string &dest_path);
|
||||
void CopyDir(const std::string& source_path, const std::string& dest_path);
|
||||
|
||||
// Set the current directory to given directory
|
||||
bool SetCurrentDir(const std::string &directory);
|
||||
bool SetCurrentDir(const std::string& directory);
|
||||
|
||||
// Returns a pointer to a string with a Citra data dir in the user's home
|
||||
// directory. To be used in "multi-user" mode (that is, installed).
|
||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
|
||||
const std::string& GetUserPath(const unsigned int DirIDX, const std::string& newPath = "");
|
||||
|
||||
// Returns the path to where the sys file are
|
||||
std::string GetSysDirectory();
|
||||
|
@ -154,11 +155,11 @@ std::string GetBundleDirectory();
|
|||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string &GetExeDirectory();
|
||||
std::string& GetExeDirectory();
|
||||
#endif
|
||||
|
||||
size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename);
|
||||
size_t ReadFileToString(bool text_file, const char *filename, std::string &str);
|
||||
size_t WriteStringToFile(bool text_file, const std::string& str, const char* filename);
|
||||
size_t ReadFileToString(bool text_file, const char* filename, std::string& str);
|
||||
|
||||
/**
|
||||
* Splits the filename into 8.3 format
|
||||
|
@ -173,8 +174,7 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
|
|||
// simple wrapper for cstdlib file functions to
|
||||
// hopefully will make error checking easier
|
||||
// and make forgetting an fclose() harder
|
||||
class IOFile : public NonCopyable
|
||||
{
|
||||
class IOFile : public NonCopyable {
|
||||
public:
|
||||
IOFile();
|
||||
IOFile(const std::string& filename, const char openmode[]);
|
||||
|
@ -190,11 +190,12 @@ public:
|
|||
bool Close();
|
||||
|
||||
template <typename T>
|
||||
size_t ReadArray(T* data, size_t length)
|
||||
{
|
||||
static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects");
|
||||
size_t ReadArray(T* data, size_t length) {
|
||||
static_assert(std::is_standard_layout<T>(),
|
||||
"Given array does not consist of standard layout objects");
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects");
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"Given array does not consist of trivially copyable objects");
|
||||
#endif
|
||||
|
||||
if (!IsOpen()) {
|
||||
|
@ -210,11 +211,12 @@ public:
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
size_t WriteArray(const T* data, size_t length)
|
||||
{
|
||||
static_assert(std::is_standard_layout<T>(), "Given array does not consist of standard layout objects");
|
||||
size_t WriteArray(const T* data, size_t length) {
|
||||
static_assert(std::is_standard_layout<T>(),
|
||||
"Given array does not consist of standard layout objects");
|
||||
#if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER)
|
||||
static_assert(std::is_trivially_copyable<T>(), "Given array does not consist of trivially copyable objects");
|
||||
static_assert(std::is_trivially_copyable<T>(),
|
||||
"Given array does not consist of trivially copyable objects");
|
||||
#endif
|
||||
|
||||
if (!IsOpen()) {
|
||||
|
@ -229,27 +231,31 @@ public:
|
|||
return items_written;
|
||||
}
|
||||
|
||||
size_t ReadBytes(void* data, size_t length)
|
||||
{
|
||||
size_t ReadBytes(void* data, size_t length) {
|
||||
return ReadArray(reinterpret_cast<char*>(data), length);
|
||||
}
|
||||
|
||||
size_t WriteBytes(const void* data, size_t length)
|
||||
{
|
||||
size_t WriteBytes(const void* data, size_t length) {
|
||||
return WriteArray(reinterpret_cast<const char*>(data), length);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
size_t WriteObject(const T& object) {
|
||||
static_assert(!std::is_pointer<T>::value, "Given object is a pointer");
|
||||
return WriteArray(&object, 1);
|
||||
}
|
||||
|
||||
bool IsOpen() const { return nullptr != m_file; }
|
||||
bool IsOpen() const {
|
||||
return nullptr != m_file;
|
||||
}
|
||||
|
||||
// m_good is set to false when a read, write or other function fails
|
||||
bool IsGood() const { return m_good; }
|
||||
explicit operator bool() const { return IsGood(); }
|
||||
bool IsGood() const {
|
||||
return m_good;
|
||||
}
|
||||
explicit operator bool() const {
|
||||
return IsGood();
|
||||
}
|
||||
|
||||
bool Seek(s64 off, int origin);
|
||||
u64 Tell() const;
|
||||
|
@ -258,19 +264,21 @@ public:
|
|||
bool Flush();
|
||||
|
||||
// clear error state
|
||||
void Clear() { m_good = true; std::clearerr(m_file); }
|
||||
void Clear() {
|
||||
m_good = true;
|
||||
std::clearerr(m_file);
|
||||
}
|
||||
|
||||
private:
|
||||
std::FILE* m_file = nullptr;
|
||||
bool m_good = true;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
// To deal with Windows being dumb at unicode:
|
||||
template <typename T>
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode)
|
||||
{
|
||||
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) {
|
||||
#ifdef _MSC_VER
|
||||
fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode);
|
||||
#else
|
||||
|
|
|
@ -36,7 +36,7 @@ static FORCE_INLINE u64 fmix64(u64 k) {
|
|||
// platforms (MurmurHash3_x64_128). It was taken from:
|
||||
// https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
|
||||
void MurmurHash3_128(const void* key, int len, u32 seed, void* out) {
|
||||
const u8 * data = (const u8*)key;
|
||||
const u8* data = (const u8*)key;
|
||||
const int nblocks = len / 16;
|
||||
|
||||
u64 h1 = seed;
|
||||
|
@ -47,52 +47,84 @@ void MurmurHash3_128(const void* key, int len, u32 seed, void* out) {
|
|||
|
||||
// Body
|
||||
|
||||
const u64 * blocks = (const u64 *)(data);
|
||||
const u64* blocks = (const u64*)(data);
|
||||
|
||||
for (int i = 0; i < nblocks; i++) {
|
||||
u64 k1 = getblock64(blocks,i*2+0);
|
||||
u64 k2 = getblock64(blocks,i*2+1);
|
||||
u64 k1 = getblock64(blocks, i * 2 + 0);
|
||||
u64 k2 = getblock64(blocks, i * 2 + 1);
|
||||
|
||||
k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1;
|
||||
k1 *= c1;
|
||||
k1 = _rotl64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
|
||||
h1 = _rotl64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
|
||||
h1 = _rotl64(h1, 27);
|
||||
h1 += h2;
|
||||
h1 = h1 * 5 + 0x52dce729;
|
||||
|
||||
k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2;
|
||||
k2 *= c2;
|
||||
k2 = _rotl64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
h2 = _rotl64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
|
||||
h2 = _rotl64(h2, 31);
|
||||
h2 += h1;
|
||||
h2 = h2 * 5 + 0x38495ab5;
|
||||
}
|
||||
|
||||
// Tail
|
||||
|
||||
const u8 * tail = (const u8*)(data + nblocks*16);
|
||||
const u8* tail = (const u8*)(data + nblocks * 16);
|
||||
|
||||
u64 k1 = 0;
|
||||
u64 k2 = 0;
|
||||
|
||||
switch (len & 15) {
|
||||
case 15: k2 ^= ((u64)tail[14]) << 48;
|
||||
case 14: k2 ^= ((u64)tail[13]) << 40;
|
||||
case 13: k2 ^= ((u64)tail[12]) << 32;
|
||||
case 12: k2 ^= ((u64)tail[11]) << 24;
|
||||
case 11: k2 ^= ((u64)tail[10]) << 16;
|
||||
case 10: k2 ^= ((u64)tail[ 9]) << 8;
|
||||
case 9: k2 ^= ((u64)tail[ 8]) << 0;
|
||||
k2 *= c2; k2 = _rotl64(k2,33); k2 *= c1; h2 ^= k2;
|
||||
case 15:
|
||||
k2 ^= ((u64)tail[14]) << 48;
|
||||
case 14:
|
||||
k2 ^= ((u64)tail[13]) << 40;
|
||||
case 13:
|
||||
k2 ^= ((u64)tail[12]) << 32;
|
||||
case 12:
|
||||
k2 ^= ((u64)tail[11]) << 24;
|
||||
case 11:
|
||||
k2 ^= ((u64)tail[10]) << 16;
|
||||
case 10:
|
||||
k2 ^= ((u64)tail[9]) << 8;
|
||||
case 9:
|
||||
k2 ^= ((u64)tail[8]) << 0;
|
||||
k2 *= c2;
|
||||
k2 = _rotl64(k2, 33);
|
||||
k2 *= c1;
|
||||
h2 ^= k2;
|
||||
|
||||
case 8: k1 ^= ((u64)tail[ 7]) << 56;
|
||||
case 7: k1 ^= ((u64)tail[ 6]) << 48;
|
||||
case 6: k1 ^= ((u64)tail[ 5]) << 40;
|
||||
case 5: k1 ^= ((u64)tail[ 4]) << 32;
|
||||
case 4: k1 ^= ((u64)tail[ 3]) << 24;
|
||||
case 3: k1 ^= ((u64)tail[ 2]) << 16;
|
||||
case 2: k1 ^= ((u64)tail[ 1]) << 8;
|
||||
case 1: k1 ^= ((u64)tail[ 0]) << 0;
|
||||
k1 *= c1; k1 = _rotl64(k1,31); k1 *= c2; h1 ^= k1;
|
||||
case 8:
|
||||
k1 ^= ((u64)tail[7]) << 56;
|
||||
case 7:
|
||||
k1 ^= ((u64)tail[6]) << 48;
|
||||
case 6:
|
||||
k1 ^= ((u64)tail[5]) << 40;
|
||||
case 5:
|
||||
k1 ^= ((u64)tail[4]) << 32;
|
||||
case 4:
|
||||
k1 ^= ((u64)tail[3]) << 24;
|
||||
case 3:
|
||||
k1 ^= ((u64)tail[2]) << 16;
|
||||
case 2:
|
||||
k1 ^= ((u64)tail[1]) << 8;
|
||||
case 1:
|
||||
k1 ^= ((u64)tail[0]) << 0;
|
||||
k1 *= c1;
|
||||
k1 = _rotl64(k1, 31);
|
||||
k1 *= c2;
|
||||
h1 ^= k1;
|
||||
};
|
||||
|
||||
// Finalization
|
||||
|
||||
h1 ^= len; h2 ^= len;
|
||||
h1 ^= len;
|
||||
h2 ^= len;
|
||||
|
||||
h1 += h2;
|
||||
h2 += h1;
|
||||
|
|
|
@ -13,11 +13,25 @@ namespace KeyMap {
|
|||
// and map it directly to EmuWindow::ButtonPressed.
|
||||
// It should go the analog input way like circle pad does.
|
||||
const std::array<KeyTarget, Settings::NativeInput::NUM_INPUTS> mapping_targets = {{
|
||||
Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
|
||||
Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
|
||||
Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
|
||||
Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
|
||||
Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT,
|
||||
Service::HID::PAD_A,
|
||||
Service::HID::PAD_B,
|
||||
Service::HID::PAD_X,
|
||||
Service::HID::PAD_Y,
|
||||
Service::HID::PAD_L,
|
||||
Service::HID::PAD_R,
|
||||
Service::HID::PAD_ZL,
|
||||
Service::HID::PAD_ZR,
|
||||
Service::HID::PAD_START,
|
||||
Service::HID::PAD_SELECT,
|
||||
Service::HID::PAD_NONE,
|
||||
Service::HID::PAD_UP,
|
||||
Service::HID::PAD_DOWN,
|
||||
Service::HID::PAD_LEFT,
|
||||
Service::HID::PAD_RIGHT,
|
||||
Service::HID::PAD_C_UP,
|
||||
Service::HID::PAD_C_DOWN,
|
||||
Service::HID::PAD_C_LEFT,
|
||||
Service::HID::PAD_C_RIGHT,
|
||||
|
||||
IndirectTarget::CirclePadUp,
|
||||
IndirectTarget::CirclePadDown,
|
||||
|
@ -49,7 +63,8 @@ static void UpdateCirclePad(EmuWindow& emu_window) {
|
|||
--y;
|
||||
|
||||
float modifier = circle_pad_modifier ? Settings::values.pad_circle_modifier_scale : 1.0;
|
||||
emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF), y * modifier * (x == 0 ? 1.0 : SQRT_HALF));
|
||||
emu_window.CirclePadUpdated(x * modifier * (y == 0 ? 1.0 : SQRT_HALF),
|
||||
y * modifier * (x == 0 ? 1.0 : SQRT_HALF));
|
||||
}
|
||||
|
||||
int NewDeviceId() {
|
||||
|
@ -103,7 +118,7 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key) {
|
|||
}
|
||||
}
|
||||
|
||||
void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
|
||||
void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key) {
|
||||
auto target = key_map.find(key);
|
||||
if (target == key_map.end())
|
||||
return;
|
||||
|
@ -135,5 +150,4 @@ void ReleaseKey(EmuWindow& emu_window,HostDeviceKey key) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,14 +55,12 @@ struct HostDeviceKey {
|
|||
int key_code;
|
||||
int device_id; ///< Uniquely identifies a host device
|
||||
|
||||
bool operator<(const HostDeviceKey &other) const {
|
||||
return std::tie(key_code, device_id) <
|
||||
std::tie(other.key_code, other.device_id);
|
||||
bool operator<(const HostDeviceKey& other) const {
|
||||
return std::tie(key_code, device_id) < std::tie(other.key_code, other.device_id);
|
||||
}
|
||||
|
||||
bool operator==(const HostDeviceKey &other) const {
|
||||
return std::tie(key_code, device_id) ==
|
||||
std::tie(other.key_code, other.device_id);
|
||||
bool operator==(const HostDeviceKey& other) const {
|
||||
return std::tie(key_code, device_id) == std::tie(other.key_code, other.device_id);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -92,5 +90,4 @@ void PressKey(EmuWindow& emu_window, HostDeviceKey key);
|
|||
* Maps a key release action and call the corresponding function in EmuWindow
|
||||
*/
|
||||
void ReleaseKey(EmuWindow& emu_window, HostDeviceKey key);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,31 +4,30 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include <fstream>
|
||||
#include "common/common_types.h"
|
||||
|
||||
// defined in Version.cpp
|
||||
extern const char *scm_rev_git_str;
|
||||
extern const char* scm_rev_git_str;
|
||||
|
||||
// On disk format:
|
||||
//header{
|
||||
// header{
|
||||
// u32 'DCAC';
|
||||
// u32 version; // svn_rev
|
||||
// u16 sizeof(key_type);
|
||||
// u16 sizeof(value_type);
|
||||
//}
|
||||
|
||||
//key_value_pair{
|
||||
// key_value_pair{
|
||||
// u32 value_size;
|
||||
// key_type key;
|
||||
// value_type[value_size] value;
|
||||
//}
|
||||
|
||||
template <typename K, typename V>
|
||||
class LinearDiskCacheReader
|
||||
{
|
||||
class LinearDiskCacheReader {
|
||||
public:
|
||||
virtual void Read(const K &key, const V *value, u32 value_size) = 0;
|
||||
virtual void Read(const K& key, const V* value, u32 value_size) = 0;
|
||||
};
|
||||
|
||||
// Dead simple unsorted key-value store with append functionality.
|
||||
|
@ -44,12 +43,10 @@ public:
|
|||
// K : the key type
|
||||
// V : value array type
|
||||
template <typename K, typename V>
|
||||
class LinearDiskCache
|
||||
{
|
||||
class LinearDiskCache {
|
||||
public:
|
||||
// return number of read entries
|
||||
u32 OpenAndRead(const char *filename, LinearDiskCacheReader<K, V> &reader)
|
||||
{
|
||||
u32 OpenAndRead(const char* filename, LinearDiskCacheReader<K, V>& reader) {
|
||||
using std::ios_base;
|
||||
|
||||
// close any currently opened file
|
||||
|
@ -65,20 +62,19 @@ public:
|
|||
std::fstream::pos_type start_pos = m_file.tellg();
|
||||
std::streamoff file_size = end_pos - start_pos;
|
||||
|
||||
if (m_file.is_open() && ValidateHeader())
|
||||
{
|
||||
if (m_file.is_open() && ValidateHeader()) {
|
||||
// good header, read some key/value pairs
|
||||
K key;
|
||||
|
||||
V *value = nullptr;
|
||||
V* value = nullptr;
|
||||
u32 value_size;
|
||||
u32 entry_number;
|
||||
|
||||
std::fstream::pos_type last_pos = m_file.tellg();
|
||||
|
||||
while (Read(&value_size))
|
||||
{
|
||||
std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size;
|
||||
while (Read(&value_size)) {
|
||||
std::streamoff next_extent =
|
||||
(last_pos - start_pos) + sizeof(value_size) + value_size;
|
||||
if (next_extent > file_size)
|
||||
break;
|
||||
|
||||
|
@ -86,15 +82,10 @@ public:
|
|||
value = new V[value_size];
|
||||
|
||||
// read key/value and pass to reader
|
||||
if (Read(&key) &&
|
||||
Read(value, value_size) &&
|
||||
Read(&entry_number) &&
|
||||
entry_number == m_num_entries+1)
|
||||
{
|
||||
if (Read(&key) && Read(value, value_size) && Read(&entry_number) &&
|
||||
entry_number == m_num_entries + 1) {
|
||||
reader.Read(key, value, value_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -116,13 +107,11 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Sync()
|
||||
{
|
||||
void Sync() {
|
||||
m_file.flush();
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
void Close() {
|
||||
if (m_file.is_open())
|
||||
m_file.close();
|
||||
// clear any error flags
|
||||
|
@ -130,9 +119,9 @@ public:
|
|||
}
|
||||
|
||||
// Appends a key-value pair to the store.
|
||||
void Append(const K &key, const V *value, u32 value_size)
|
||||
{
|
||||
// TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
|
||||
void Append(const K& key, const V* value, u32 value_size) {
|
||||
// TODO: Should do a check that we don't already have "key"? (I think each caller does that
|
||||
// already.)
|
||||
Write(&value_size);
|
||||
Write(&key);
|
||||
Write(value, value_size);
|
||||
|
@ -141,38 +130,29 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void WriteHeader()
|
||||
{
|
||||
void WriteHeader() {
|
||||
Write(&m_header);
|
||||
}
|
||||
|
||||
bool ValidateHeader()
|
||||
{
|
||||
bool ValidateHeader() {
|
||||
char file_header[sizeof(Header)];
|
||||
|
||||
return (Read(file_header, sizeof(Header))
|
||||
&& !memcmp((const char*)&m_header, file_header, sizeof(Header)));
|
||||
return (Read(file_header, sizeof(Header)) &&
|
||||
!memcmp((const char*)&m_header, file_header, sizeof(Header)));
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
bool Write(const D *data, u32 count = 1)
|
||||
{
|
||||
bool Write(const D* data, u32 count = 1) {
|
||||
return m_file.write((const char*)data, count * sizeof(D)).good();
|
||||
}
|
||||
|
||||
template <typename D>
|
||||
bool Read(const D *data, u32 count = 1)
|
||||
{
|
||||
bool Read(const D* data, u32 count = 1) {
|
||||
return m_file.read((char*)data, count * sizeof(D)).good();
|
||||
}
|
||||
|
||||
struct Header
|
||||
{
|
||||
Header()
|
||||
: id(*(u32*)"DCAC")
|
||||
, key_t_size(sizeof(K))
|
||||
, value_t_size(sizeof(V))
|
||||
{
|
||||
struct Header {
|
||||
Header() : id(*(u32*)"DCAC"), key_t_size(sizeof(K)), value_t_size(sizeof(V)) {
|
||||
memcpy(ver, scm_rev_git_str, 40);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,73 +16,79 @@
|
|||
namespace Log {
|
||||
|
||||
/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
|
||||
#define ALL_LOG_CLASSES() \
|
||||
CLS(Log) \
|
||||
CLS(Common) \
|
||||
SUB(Common, Filesystem) \
|
||||
SUB(Common, Memory) \
|
||||
CLS(Core) \
|
||||
SUB(Core, ARM11) \
|
||||
SUB(Core, Timing) \
|
||||
CLS(Config) \
|
||||
CLS(Debug) \
|
||||
SUB(Debug, Emulated) \
|
||||
SUB(Debug, GPU) \
|
||||
SUB(Debug, Breakpoint) \
|
||||
SUB(Debug, GDBStub) \
|
||||
CLS(Kernel) \
|
||||
SUB(Kernel, SVC) \
|
||||
CLS(Service) \
|
||||
SUB(Service, SRV) \
|
||||
SUB(Service, FRD) \
|
||||
SUB(Service, FS) \
|
||||
SUB(Service, ERR) \
|
||||
SUB(Service, APT) \
|
||||
SUB(Service, GSP) \
|
||||
SUB(Service, AC) \
|
||||
SUB(Service, AM) \
|
||||
SUB(Service, PTM) \
|
||||
SUB(Service, LDR) \
|
||||
SUB(Service, NDM) \
|
||||
SUB(Service, NIM) \
|
||||
SUB(Service, NWM) \
|
||||
SUB(Service, CAM) \
|
||||
SUB(Service, CECD) \
|
||||
SUB(Service, CFG) \
|
||||
SUB(Service, DSP) \
|
||||
SUB(Service, DLP) \
|
||||
SUB(Service, HID) \
|
||||
SUB(Service, SOC) \
|
||||
SUB(Service, IR) \
|
||||
SUB(Service, Y2R) \
|
||||
CLS(HW) \
|
||||
SUB(HW, Memory) \
|
||||
SUB(HW, LCD) \
|
||||
SUB(HW, GPU) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Software) \
|
||||
SUB(Render, OpenGL) \
|
||||
CLS(Audio) \
|
||||
SUB(Audio, DSP) \
|
||||
SUB(Audio, Sink) \
|
||||
CLS(Loader)
|
||||
#define ALL_LOG_CLASSES() \
|
||||
CLS(Log) \
|
||||
CLS(Common) \
|
||||
SUB(Common, Filesystem) \
|
||||
SUB(Common, Memory) \
|
||||
CLS(Core) \
|
||||
SUB(Core, ARM11) \
|
||||
SUB(Core, Timing) \
|
||||
CLS(Config) \
|
||||
CLS(Debug) \
|
||||
SUB(Debug, Emulated) \
|
||||
SUB(Debug, GPU) \
|
||||
SUB(Debug, Breakpoint) \
|
||||
SUB(Debug, GDBStub) \
|
||||
CLS(Kernel) \
|
||||
SUB(Kernel, SVC) \
|
||||
CLS(Service) \
|
||||
SUB(Service, SRV) \
|
||||
SUB(Service, FRD) \
|
||||
SUB(Service, FS) \
|
||||
SUB(Service, ERR) \
|
||||
SUB(Service, APT) \
|
||||
SUB(Service, GSP) \
|
||||
SUB(Service, AC) \
|
||||
SUB(Service, AM) \
|
||||
SUB(Service, PTM) \
|
||||
SUB(Service, LDR) \
|
||||
SUB(Service, NDM) \
|
||||
SUB(Service, NIM) \
|
||||
SUB(Service, NWM) \
|
||||
SUB(Service, CAM) \
|
||||
SUB(Service, CECD) \
|
||||
SUB(Service, CFG) \
|
||||
SUB(Service, DSP) \
|
||||
SUB(Service, DLP) \
|
||||
SUB(Service, HID) \
|
||||
SUB(Service, SOC) \
|
||||
SUB(Service, IR) \
|
||||
SUB(Service, Y2R) \
|
||||
CLS(HW) \
|
||||
SUB(HW, Memory) \
|
||||
SUB(HW, LCD) \
|
||||
SUB(HW, GPU) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Software) \
|
||||
SUB(Render, OpenGL) \
|
||||
CLS(Audio) \
|
||||
SUB(Audio, DSP) \
|
||||
SUB(Audio, Sink) \
|
||||
CLS(Loader)
|
||||
|
||||
// GetClassName is a macro defined by Windows.h, grrr...
|
||||
const char* GetLogClassName(Class log_class) {
|
||||
switch (log_class) {
|
||||
#define CLS(x) case Class::x: return #x;
|
||||
#define SUB(x, y) case Class::x##_##y: return #x "." #y;
|
||||
#define CLS(x) \
|
||||
case Class::x: \
|
||||
return #x;
|
||||
#define SUB(x, y) \
|
||||
case Class::x##_##y: \
|
||||
return #x "." #y;
|
||||
ALL_LOG_CLASSES()
|
||||
#undef CLS
|
||||
#undef SUB
|
||||
case Class::Count:
|
||||
UNREACHABLE();
|
||||
case Class::Count:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
const char* GetLevelName(Level log_level) {
|
||||
#define LVL(x) case Level::x: return #x
|
||||
#define LVL(x) \
|
||||
case Level::x: \
|
||||
return #x
|
||||
switch (log_level) {
|
||||
LVL(Trace);
|
||||
LVL(Debug);
|
||||
|
@ -90,15 +96,14 @@ const char* GetLevelName(Level log_level) {
|
|||
LVL(Warning);
|
||||
LVL(Error);
|
||||
LVL(Critical);
|
||||
case Level::Count:
|
||||
UNREACHABLE();
|
||||
case Level::Count:
|
||||
UNREACHABLE();
|
||||
}
|
||||
#undef LVL
|
||||
}
|
||||
|
||||
Entry CreateEntry(Class log_class, Level log_level,
|
||||
const char* filename, unsigned int line_nr, const char* function,
|
||||
const char* format, va_list args) {
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, const char* format, va_list args) {
|
||||
using std::chrono::steady_clock;
|
||||
using std::chrono::duration_cast;
|
||||
|
||||
|
@ -111,7 +116,8 @@ Entry CreateEntry(Class log_class, Level log_level,
|
|||
entry.log_class = log_class;
|
||||
entry.log_level = log_level;
|
||||
|
||||
snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, line_nr);
|
||||
snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function,
|
||||
line_nr);
|
||||
entry.location = std::string(formatting_buffer.data());
|
||||
|
||||
vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
|
||||
|
@ -126,19 +132,16 @@ void SetFilter(Filter* new_filter) {
|
|||
filter = new_filter;
|
||||
}
|
||||
|
||||
void LogMessage(Class log_class, Level log_level,
|
||||
const char* filename, unsigned int line_nr, const char* function,
|
||||
const char* format, ...) {
|
||||
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, const char* format, ...) {
|
||||
if (filter != nullptr && !filter->CheckMessage(log_class, log_level))
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
Entry entry = CreateEntry(log_class, log_level,
|
||||
filename, line_nr, function, format, args);
|
||||
Entry entry = CreateEntry(log_class, log_level, filename, line_nr, function, format, args);
|
||||
va_end(args);
|
||||
|
||||
PrintColoredMessage(entry);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,10 +44,8 @@ const char* GetLogClassName(Class log_class);
|
|||
const char* GetLevelName(Level log_level);
|
||||
|
||||
/// Creates a log entry by formatting the given source location, and message.
|
||||
Entry CreateEntry(Class log_class, Level log_level,
|
||||
const char* filename, unsigned int line_nr, const char* function,
|
||||
const char* format, va_list args);
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, const char* format, va_list args);
|
||||
|
||||
void SetFilter(Filter* filter);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/logging/backend.h"
|
||||
#include "common/logging/filter.h"
|
||||
#include "common/string_util.h"
|
||||
|
||||
namespace Log {
|
||||
|
@ -63,11 +63,11 @@ static Class GetClassByName(const It begin, const It end) {
|
|||
}
|
||||
|
||||
bool Filter::ParseFilterRule(const std::string::const_iterator begin,
|
||||
const std::string::const_iterator end) {
|
||||
const std::string::const_iterator end) {
|
||||
auto level_separator = std::find(begin, end, ':');
|
||||
if (level_separator == end) {
|
||||
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
|
||||
std::string(begin, end).c_str());
|
||||
std::string(begin, end).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -95,5 +95,4 @@ bool Filter::ParseFilterRule(const std::string::const_iterator begin,
|
|||
bool Filter::CheckMessage(Class log_class, Level level) const {
|
||||
return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@ public:
|
|||
* - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace.
|
||||
*/
|
||||
void ParseFilterString(const std::string& filter_str);
|
||||
bool ParseFilterRule(const std::string::const_iterator start, const std::string::const_iterator end);
|
||||
bool ParseFilterRule(const std::string::const_iterator start,
|
||||
const std::string::const_iterator end);
|
||||
|
||||
/// Matches class/level combination against the filter, returning true if it passed.
|
||||
bool CheckMessage(Class log_class, Level level) const;
|
||||
|
@ -50,5 +51,4 @@ public:
|
|||
private:
|
||||
std::array<Level, (size_t)Class::Count> class_levels;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -28,71 +28,73 @@ typedef u8 ClassType;
|
|||
/**
|
||||
* Specifies the sub-system that generated the log message.
|
||||
*
|
||||
* @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in backend.cpp.
|
||||
* @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in
|
||||
* backend.cpp.
|
||||
*/
|
||||
enum class Class : ClassType {
|
||||
Log, ///< Messages about the log system itself
|
||||
Common, ///< Library routines
|
||||
Common_Filesystem, ///< Filesystem interface library
|
||||
Common_Memory, ///< Memory mapping and management functions
|
||||
Core, ///< LLE emulation core
|
||||
Core_ARM11, ///< ARM11 CPU core
|
||||
Core_Timing, ///< CoreTiming functions
|
||||
Config, ///< Emulator configuration (including commandline)
|
||||
Debug, ///< Debugging tools
|
||||
Debug_Emulated, ///< Debug messages from the emulated programs
|
||||
Debug_GPU, ///< GPU debugging tools
|
||||
Debug_Breakpoint, ///< Logging breakpoints and watchpoints
|
||||
Debug_GDBStub, ///< GDB Stub
|
||||
Kernel, ///< The HLE implementation of the CTR kernel
|
||||
Kernel_SVC, ///< Kernel system calls
|
||||
Service, ///< HLE implementation of system services. Each major service
|
||||
/// should have its own subclass.
|
||||
Service_SRV, ///< The SRV (Service Directory) implementation
|
||||
Service_FRD, ///< The FRD (Friends) service
|
||||
Service_FS, ///< The FS (Filesystem) service implementation
|
||||
Service_ERR, ///< The ERR (Error) port implementation
|
||||
Service_APT, ///< The APT (Applets) service
|
||||
Service_GSP, ///< The GSP (GPU control) service
|
||||
Service_AC, ///< The AC (WiFi status) service
|
||||
Service_AM, ///< The AM (Application manager) service
|
||||
Service_PTM, ///< The PTM (Power status & misc.) service
|
||||
Service_LDR, ///< The LDR (3ds dll loader) service
|
||||
Service_NDM, ///< The NDM (Network daemon manager) service
|
||||
Service_NIM, ///< The NIM (Network interface manager) service
|
||||
Service_NWM, ///< The NWM (Network wlan manager) service
|
||||
Service_CAM, ///< The CAM (Camera) service
|
||||
Service_CECD, ///< The CECD (StreetPass) service
|
||||
Service_CFG, ///< The CFG (Configuration) service
|
||||
Service_DSP, ///< The DSP (DSP control) service
|
||||
Service_DLP, ///< The DLP (Download Play) service
|
||||
Service_HID, ///< The HID (Human interface device) service
|
||||
Service_SOC, ///< The SOC (Socket) service
|
||||
Service_IR, ///< The IR service
|
||||
Service_Y2R, ///< The Y2R (YUV to RGB conversion) service
|
||||
HW, ///< Low-level hardware emulation
|
||||
HW_Memory, ///< Memory-map and address translation
|
||||
HW_LCD, ///< LCD register emulation
|
||||
HW_GPU, ///< GPU control emulation
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Emulator video output and hardware acceleration
|
||||
Render_Software, ///< Software renderer backend
|
||||
Render_OpenGL, ///< OpenGL backend
|
||||
Audio, ///< Audio emulation
|
||||
Audio_DSP, ///< The HLE implementation of the DSP
|
||||
Audio_Sink, ///< Emulator audio output backend
|
||||
Loader, ///< ROM loader
|
||||
Log, ///< Messages about the log system itself
|
||||
Common, ///< Library routines
|
||||
Common_Filesystem, ///< Filesystem interface library
|
||||
Common_Memory, ///< Memory mapping and management functions
|
||||
Core, ///< LLE emulation core
|
||||
Core_ARM11, ///< ARM11 CPU core
|
||||
Core_Timing, ///< CoreTiming functions
|
||||
Config, ///< Emulator configuration (including commandline)
|
||||
Debug, ///< Debugging tools
|
||||
Debug_Emulated, ///< Debug messages from the emulated programs
|
||||
Debug_GPU, ///< GPU debugging tools
|
||||
Debug_Breakpoint, ///< Logging breakpoints and watchpoints
|
||||
Debug_GDBStub, ///< GDB Stub
|
||||
Kernel, ///< The HLE implementation of the CTR kernel
|
||||
Kernel_SVC, ///< Kernel system calls
|
||||
Service, ///< HLE implementation of system services. Each major service
|
||||
/// should have its own subclass.
|
||||
Service_SRV, ///< The SRV (Service Directory) implementation
|
||||
Service_FRD, ///< The FRD (Friends) service
|
||||
Service_FS, ///< The FS (Filesystem) service implementation
|
||||
Service_ERR, ///< The ERR (Error) port implementation
|
||||
Service_APT, ///< The APT (Applets) service
|
||||
Service_GSP, ///< The GSP (GPU control) service
|
||||
Service_AC, ///< The AC (WiFi status) service
|
||||
Service_AM, ///< The AM (Application manager) service
|
||||
Service_PTM, ///< The PTM (Power status & misc.) service
|
||||
Service_LDR, ///< The LDR (3ds dll loader) service
|
||||
Service_NDM, ///< The NDM (Network daemon manager) service
|
||||
Service_NIM, ///< The NIM (Network interface manager) service
|
||||
Service_NWM, ///< The NWM (Network wlan manager) service
|
||||
Service_CAM, ///< The CAM (Camera) service
|
||||
Service_CECD, ///< The CECD (StreetPass) service
|
||||
Service_CFG, ///< The CFG (Configuration) service
|
||||
Service_DSP, ///< The DSP (DSP control) service
|
||||
Service_DLP, ///< The DLP (Download Play) service
|
||||
Service_HID, ///< The HID (Human interface device) service
|
||||
Service_SOC, ///< The SOC (Socket) service
|
||||
Service_IR, ///< The IR service
|
||||
Service_Y2R, ///< The Y2R (YUV to RGB conversion) service
|
||||
HW, ///< Low-level hardware emulation
|
||||
HW_Memory, ///< Memory-map and address translation
|
||||
HW_LCD, ///< LCD register emulation
|
||||
HW_GPU, ///< GPU control emulation
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Emulator video output and hardware acceleration
|
||||
Render_Software, ///< Software renderer backend
|
||||
Render_OpenGL, ///< OpenGL backend
|
||||
Audio, ///< Audio emulation
|
||||
Audio_DSP, ///< The HLE implementation of the DSP
|
||||
Audio_Sink, ///< Emulator audio output backend
|
||||
Loader, ///< ROM loader
|
||||
|
||||
Count ///< Total number of logging classes
|
||||
};
|
||||
|
||||
/// Logs a message to the global logger.
|
||||
void LogMessage(Class log_class, Level log_level,
|
||||
const char* filename, unsigned int line_nr, const char* function,
|
||||
void LogMessage(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function,
|
||||
#ifdef _MSC_VER
|
||||
_Printf_format_string_
|
||||
_Printf_format_string_
|
||||
#endif
|
||||
const char* format, ...)
|
||||
const char* format,
|
||||
...)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 6, 7)))
|
||||
#endif
|
||||
|
@ -100,17 +102,23 @@ void LogMessage(Class log_class, Level log_level,
|
|||
|
||||
} // namespace Log
|
||||
|
||||
#define LOG_GENERIC(log_class, log_level, ...) \
|
||||
#define LOG_GENERIC(log_class, log_level, ...) \
|
||||
::Log::LogMessage(log_class, log_level, __FILE__, __LINE__, __func__, __VA_ARGS__)
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define LOG_TRACE( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Trace, __VA_ARGS__)
|
||||
#define LOG_TRACE(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Trace, __VA_ARGS__)
|
||||
#else
|
||||
#define LOG_TRACE( log_class, ...) (void(0))
|
||||
#define LOG_TRACE(log_class, ...) (void(0))
|
||||
#endif
|
||||
|
||||
#define LOG_DEBUG( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Debug, __VA_ARGS__)
|
||||
#define LOG_INFO( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Info, __VA_ARGS__)
|
||||
#define LOG_WARNING( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Warning, __VA_ARGS__)
|
||||
#define LOG_ERROR( log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__)
|
||||
#define LOG_CRITICAL(log_class, ...) LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__)
|
||||
#define LOG_DEBUG(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Debug, __VA_ARGS__)
|
||||
#define LOG_INFO(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Info, __VA_ARGS__)
|
||||
#define LOG_WARNING(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Warning, __VA_ARGS__)
|
||||
#define LOG_ERROR(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Error, __VA_ARGS__)
|
||||
#define LOG_CRITICAL(log_class, ...) \
|
||||
LOG_GENERIC(::Log::Class::log_class, ::Log::Level::Critical, __VA_ARGS__)
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include <cstdio>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <Windows.h>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "common/logging/backend.h"
|
||||
|
@ -44,15 +44,14 @@ const char* TrimSourcePath(const char* path, const char* root) {
|
|||
}
|
||||
|
||||
void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) {
|
||||
unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
|
||||
unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
|
||||
unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000);
|
||||
|
||||
const char* class_name = GetLogClassName(entry.log_class);
|
||||
const char* level_name = GetLevelName(entry.log_level);
|
||||
|
||||
snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s",
|
||||
time_seconds, time_fractional, class_name, level_name,
|
||||
TrimSourcePath(entry.location.c_str()), entry.message.c_str());
|
||||
snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s", time_seconds, time_fractional,
|
||||
class_name, level_name, TrimSourcePath(entry.location.c_str()), entry.message.c_str());
|
||||
}
|
||||
|
||||
void PrintMessage(const Entry& entry) {
|
||||
|
@ -72,38 +71,50 @@ void PrintColoredMessage(const Entry& entry) {
|
|||
WORD color = 0;
|
||||
switch (entry.log_level) {
|
||||
case Level::Trace: // Grey
|
||||
color = FOREGROUND_INTENSITY; break;
|
||||
color = FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case Level::Debug: // Cyan
|
||||
color = FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
color = FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
break;
|
||||
case Level::Info: // Bright gray
|
||||
color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
|
||||
color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
||||
break;
|
||||
case Level::Warning: // Bright yellow
|
||||
color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;
|
||||
color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case Level::Error: // Bright red
|
||||
color = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
|
||||
color = FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case Level::Critical: // Bright magenta
|
||||
color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
|
||||
color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
|
||||
break;
|
||||
case Level::Count:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
SetConsoleTextAttribute(console_handle, color);
|
||||
#else
|
||||
# define ESC "\x1b"
|
||||
#define ESC "\x1b"
|
||||
const char* color = "";
|
||||
switch (entry.log_level) {
|
||||
case Level::Trace: // Grey
|
||||
color = ESC "[1;30m"; break;
|
||||
color = ESC "[1;30m";
|
||||
break;
|
||||
case Level::Debug: // Cyan
|
||||
color = ESC "[0;36m"; break;
|
||||
color = ESC "[0;36m";
|
||||
break;
|
||||
case Level::Info: // Bright gray
|
||||
color = ESC "[0;37m"; break;
|
||||
color = ESC "[0;37m";
|
||||
break;
|
||||
case Level::Warning: // Bright yellow
|
||||
color = ESC "[1;33m"; break;
|
||||
color = ESC "[1;33m";
|
||||
break;
|
||||
case Level::Error: // Bright red
|
||||
color = ESC "[1;31m"; break;
|
||||
color = ESC "[1;31m";
|
||||
break;
|
||||
case Level::Critical: // Bright magenta
|
||||
color = ESC "[1;35m"; break;
|
||||
color = ESC "[1;35m";
|
||||
break;
|
||||
case Level::Count:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -117,8 +128,7 @@ void PrintColoredMessage(const Entry& entry) {
|
|||
SetConsoleTextAttribute(console_handle, original_info.wAttributes);
|
||||
#else
|
||||
fputs(ESC "[0m", stderr);
|
||||
# undef ESC
|
||||
#undef ESC
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,5 +28,4 @@ void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len);
|
|||
void PrintMessage(const Entry& entry);
|
||||
/// Prints the same message as `PrintMessage`, but colored acoording to the severity level.
|
||||
void PrintColoredMessage(const Entry& entry);
|
||||
|
||||
}
|
||||
|
|
|
@ -8,33 +8,38 @@
|
|||
#include <cstdlib>
|
||||
#include <type_traits>
|
||||
|
||||
namespace MathUtil
|
||||
{
|
||||
namespace MathUtil {
|
||||
|
||||
inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) {
|
||||
inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1,
|
||||
unsigned length1) {
|
||||
return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T Clamp(const T val, const T& min, const T& max)
|
||||
{
|
||||
template <typename T>
|
||||
inline T Clamp(const T val, const T& min, const T& max) {
|
||||
return std::max(min, std::min(max, val));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
struct Rectangle
|
||||
{
|
||||
template <class T>
|
||||
struct Rectangle {
|
||||
T left;
|
||||
T top;
|
||||
T right;
|
||||
T bottom;
|
||||
|
||||
Rectangle() {}
|
||||
Rectangle() {
|
||||
}
|
||||
|
||||
Rectangle(T left, T top, T right, T bottom) : left(left), top(top), right(right), bottom(bottom) {}
|
||||
Rectangle(T left, T top, T right, T bottom)
|
||||
: left(left), top(top), right(right), bottom(bottom) {
|
||||
}
|
||||
|
||||
T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); }
|
||||
T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); }
|
||||
T GetWidth() const {
|
||||
return std::abs(static_cast<typename std::make_signed<T>::type>(right - left));
|
||||
}
|
||||
T GetHeight() const {
|
||||
return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace MathUtil
|
||||
} // namespace MathUtil
|
||||
|
|
|
@ -2,31 +2,29 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/memory_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/string_util.h"
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/string_util.h"
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#include <sys/mman.h>
|
||||
#include <cstdlib>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
|
||||
#include <unistd.h>
|
||||
#define PAGE_MASK (getpagesize() - 1)
|
||||
#define PAGE_MASK (getpagesize() - 1)
|
||||
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
|
||||
#endif
|
||||
|
||||
// This is purposely not a full wrapper for virtualalloc/mmap, but it
|
||||
// provides exactly the primitive operations that Dolphin needs.
|
||||
|
||||
void* AllocateExecutableMemory(size_t size, bool low)
|
||||
{
|
||||
void* AllocateExecutableMemory(size_t size, bool low) {
|
||||
#if defined(_WIN32)
|
||||
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#else
|
||||
|
@ -39,31 +37,27 @@ void* AllocateExecutableMemory(size_t size, bool low)
|
|||
// effect of discarding already mapped pages that happen to be in the
|
||||
// requested virtual memory range (such as the emulated RAM, sometimes).
|
||||
if (low && (!map_hint))
|
||||
map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */
|
||||
map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */
|
||||
#endif
|
||||
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANON | MAP_PRIVATE
|
||||
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE
|
||||
#if defined(ARCHITECTURE_X64) && defined(MAP_32BIT)
|
||||
| (low ? MAP_32BIT : 0)
|
||||
| (low ? MAP_32BIT : 0)
|
||||
#endif
|
||||
, -1, 0);
|
||||
,
|
||||
-1, 0);
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#ifdef _WIN32
|
||||
if (ptr == nullptr)
|
||||
{
|
||||
if (ptr == nullptr) {
|
||||
#else
|
||||
if (ptr == MAP_FAILED)
|
||||
{
|
||||
if (ptr == MAP_FAILED) {
|
||||
ptr = nullptr;
|
||||
#endif
|
||||
LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
|
||||
}
|
||||
#if !defined(_WIN32) && defined(ARCHITECTURE_X64) && !defined(MAP_32BIT)
|
||||
else
|
||||
{
|
||||
if (low)
|
||||
{
|
||||
else {
|
||||
if (low) {
|
||||
map_hint += size;
|
||||
map_hint = (char*)round_page(map_hint); /* round up to the next page */
|
||||
}
|
||||
|
@ -78,13 +72,11 @@ void* AllocateExecutableMemory(size_t size, bool low)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateMemoryPages(size_t size)
|
||||
{
|
||||
void* AllocateMemoryPages(size_t size) {
|
||||
#ifdef _WIN32
|
||||
void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
#else
|
||||
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
|
||||
if (ptr == MAP_FAILED)
|
||||
ptr = nullptr;
|
||||
|
@ -96,10 +88,9 @@ void* AllocateMemoryPages(size_t size)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void* AllocateAlignedMemory(size_t size,size_t alignment)
|
||||
{
|
||||
void* AllocateAlignedMemory(size_t size, size_t alignment) {
|
||||
#ifdef _WIN32
|
||||
void* ptr = _aligned_malloc(size,alignment);
|
||||
void* ptr = _aligned_malloc(size, alignment);
|
||||
#else
|
||||
void* ptr = nullptr;
|
||||
#ifdef ANDROID
|
||||
|
@ -116,10 +107,8 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
void FreeMemoryPages(void* ptr, size_t size)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
void FreeMemoryPages(void* ptr, size_t size) {
|
||||
if (ptr) {
|
||||
#ifdef _WIN32
|
||||
if (!VirtualFree(ptr, 0, MEM_RELEASE))
|
||||
LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n%s", GetLastErrorMsg());
|
||||
|
@ -129,20 +118,17 @@ void FreeMemoryPages(void* ptr, size_t size)
|
|||
}
|
||||
}
|
||||
|
||||
void FreeAlignedMemory(void* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
{
|
||||
void FreeAlignedMemory(void* ptr) {
|
||||
if (ptr) {
|
||||
#ifdef _WIN32
|
||||
_aligned_free(ptr);
|
||||
_aligned_free(ptr);
|
||||
#else
|
||||
free(ptr);
|
||||
free(ptr);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
|
||||
|
@ -152,19 +138,19 @@ void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
|||
#endif
|
||||
}
|
||||
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
|
||||
{
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) {
|
||||
#ifdef _WIN32
|
||||
DWORD oldValue;
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
|
||||
if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
|
||||
&oldValue))
|
||||
LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
|
||||
#else
|
||||
mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||
mprotect(ptr, size,
|
||||
allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string MemUsage()
|
||||
{
|
||||
std::string MemUsage() {
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "psapi")
|
||||
DWORD processID = GetCurrentProcessId();
|
||||
|
@ -175,10 +161,12 @@ std::string MemUsage()
|
|||
// Print information about the memory usage of the process.
|
||||
|
||||
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
|
||||
if (nullptr == hProcess) return "MemUsage Error";
|
||||
if (nullptr == hProcess)
|
||||
return "MemUsage Error";
|
||||
|
||||
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
|
||||
Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
|
||||
Ret = Common::StringFromFormat(
|
||||
"%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
|
||||
|
||||
CloseHandle(hProcess);
|
||||
return Ret;
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
void* AllocateExecutableMemory(size_t size, bool low = true);
|
||||
void* AllocateMemoryPages(size_t size);
|
||||
void FreeMemoryPages(void* ptr, size_t size);
|
||||
void* AllocateAlignedMemory(size_t size,size_t alignment);
|
||||
void* AllocateAlignedMemory(size_t size, size_t alignment);
|
||||
void FreeAlignedMemory(void* ptr);
|
||||
void WriteProtectMemory(void* ptr, size_t size, bool executable = false);
|
||||
void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute = false);
|
||||
std::string MemUsage();
|
||||
|
||||
inline int GetPageSize() { return 4096; }
|
||||
inline int GetPageSize() {
|
||||
return 4096;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#define MICROPROFILE_WEBSERVER 0
|
||||
#define MICROPROFILE_GPU_TIMERS 0 // TODO: Implement timer queries when we upgrade to OpenGL 3.3
|
||||
#define MICROPROFILE_CONTEXT_SWITCH_TRACE 0
|
||||
#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048<<13) // 16 MB
|
||||
#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048 << 13) // 16 MB
|
||||
|
||||
#ifdef _WIN32
|
||||
// This isn't defined by the standard library in MSVC2015
|
||||
|
|
|
@ -12,23 +12,21 @@
|
|||
#endif
|
||||
|
||||
// Neither Android nor OS X support TLS
|
||||
#if defined(__APPLE__) || (ANDROID && __clang__)
|
||||
#if defined(__APPLE__) || (ANDROID && __clang__)
|
||||
#define __thread
|
||||
#endif
|
||||
|
||||
// Generic function to get last error message.
|
||||
// Call directly after the command or use the error num.
|
||||
// This function might change the error code.
|
||||
const char* GetLastErrorMsg()
|
||||
{
|
||||
const char* GetLastErrorMsg() {
|
||||
static const size_t buff_size = 255;
|
||||
|
||||
#ifdef _WIN32
|
||||
static __declspec(thread) char err_str[buff_size] = {};
|
||||
|
||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
err_str, buff_size, nullptr);
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
|
||||
#else
|
||||
static __thread char err_str[buff_size] = {};
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
// Platform detection
|
||||
|
||||
#if defined(ARCHITECTURE_x86_64) || defined(__aarch64__)
|
||||
#define EMU_ARCH_BITS 64
|
||||
#define EMU_ARCH_BITS 64
|
||||
#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM)
|
||||
#define EMU_ARCH_BITS 32
|
||||
#define EMU_ARCH_BITS 32
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Common {
|
|||
namespace Profiling {
|
||||
|
||||
ProfilingManager::ProfilingManager()
|
||||
: last_frame_end(Clock::now()), this_frame_start(Clock::now()) {
|
||||
: last_frame_end(Clock::now()), this_frame_start(Clock::now()) {
|
||||
}
|
||||
|
||||
void ProfilingManager::BeginFrame() {
|
||||
|
@ -31,7 +31,7 @@ void ProfilingManager::FinishFrame() {
|
|||
}
|
||||
|
||||
TimingResultsAggregator::TimingResultsAggregator(size_t window_size)
|
||||
: max_window_size(window_size), window_size(0) {
|
||||
: max_window_size(window_size), window_size(0) {
|
||||
interframe_times.resize(window_size, Duration::zero());
|
||||
frame_times.resize(window_size, Duration::zero());
|
||||
}
|
||||
|
|
|
@ -4,20 +4,25 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_funcs.h"
|
||||
#include <utility>
|
||||
#include "common/common_funcs.h"
|
||||
|
||||
namespace detail {
|
||||
template <typename Func>
|
||||
struct ScopeExitHelper {
|
||||
explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {}
|
||||
~ScopeExitHelper() { func(); }
|
||||
template <typename Func>
|
||||
struct ScopeExitHelper {
|
||||
explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {
|
||||
}
|
||||
~ScopeExitHelper() {
|
||||
func();
|
||||
}
|
||||
|
||||
Func func;
|
||||
};
|
||||
Func func;
|
||||
};
|
||||
|
||||
template <typename Func>
|
||||
ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); }
|
||||
template <typename Func>
|
||||
ScopeExitHelper<Func> ScopeExit(Func&& func) {
|
||||
return ScopeExitHelper<Func>(std::move(func));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,11 +14,11 @@
|
|||
#include "common/string_util.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <Windows.h>
|
||||
#include <codecvt>
|
||||
#include "common/common_funcs.h"
|
||||
#include <Windows.h>
|
||||
#include <codecvt>
|
||||
#include "common/common_funcs.h"
|
||||
#else
|
||||
#include <iconv.h>
|
||||
#include <iconv.h>
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
@ -36,9 +36,8 @@ std::string ToUpper(std::string str) {
|
|||
}
|
||||
|
||||
// faster than sscanf
|
||||
bool AsciiToHex(const char* _szValue, u32& result)
|
||||
{
|
||||
char *endptr = nullptr;
|
||||
bool AsciiToHex(const char* _szValue, u32& result) {
|
||||
char* endptr = nullptr;
|
||||
const u32 value = strtoul(_szValue, &endptr, 16);
|
||||
|
||||
if (!endptr || *endptr)
|
||||
|
@ -48,8 +47,7 @@ bool AsciiToHex(const char* _szValue, u32& result)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
|
||||
{
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) {
|
||||
int writtenCount;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -84,22 +82,18 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
|
|||
writtenCount = vsnprintf(out, outsize, format, args);
|
||||
#endif
|
||||
|
||||
if (writtenCount > 0 && writtenCount < outsize)
|
||||
{
|
||||
if (writtenCount > 0 && writtenCount < outsize) {
|
||||
out[writtenCount] = '\0';
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
out[outsize - 1] = '\0';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string StringFromFormat(const char* format, ...)
|
||||
{
|
||||
std::string StringFromFormat(const char* format, ...) {
|
||||
va_list args;
|
||||
char *buf = nullptr;
|
||||
char* buf = nullptr;
|
||||
#ifdef _WIN32
|
||||
int required = 0;
|
||||
|
||||
|
@ -124,21 +118,17 @@ std::string StringFromFormat(const char* format, ...)
|
|||
}
|
||||
|
||||
// For Debugging. Read out an u8 array.
|
||||
std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces)
|
||||
{
|
||||
std::string ArrayToString(const u8* data, u32 size, int line_len, bool spaces) {
|
||||
std::ostringstream oss;
|
||||
oss << std::setfill('0') << std::hex;
|
||||
|
||||
for (int line = 0; size; ++data, --size)
|
||||
{
|
||||
for (int line = 0; size; ++data, --size) {
|
||||
oss << std::setw(2) << (int)*data;
|
||||
|
||||
if (line_len == ++line)
|
||||
{
|
||||
if (line_len == ++line) {
|
||||
oss << '\n';
|
||||
line = 0;
|
||||
}
|
||||
else if (spaces)
|
||||
} else if (spaces)
|
||||
oss << ' ';
|
||||
}
|
||||
|
||||
|
@ -146,8 +136,7 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces)
|
|||
}
|
||||
|
||||
// Turns " hej " into "hej". Also handles tabs.
|
||||
std::string StripSpaces(const std::string &str)
|
||||
{
|
||||
std::string StripSpaces(const std::string& str) {
|
||||
const size_t s = str.find_first_not_of(" \t\r\n");
|
||||
|
||||
if (str.npos != s)
|
||||
|
@ -159,17 +148,15 @@ std::string StripSpaces(const std::string &str)
|
|||
// "\"hello\"" is turned to "hello"
|
||||
// This one assumes that the string has already been space stripped in both
|
||||
// ends, as done by StripSpaces above, for example.
|
||||
std::string StripQuotes(const std::string& s)
|
||||
{
|
||||
std::string StripQuotes(const std::string& s) {
|
||||
if (s.size() && '\"' == s[0] && '\"' == *s.rbegin())
|
||||
return s.substr(1, s.size() - 2);
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
bool TryParse(const std::string &str, u32 *const output)
|
||||
{
|
||||
char *endptr = nullptr;
|
||||
bool TryParse(const std::string& str, u32* const output) {
|
||||
char* endptr = nullptr;
|
||||
|
||||
// Reset errno to a value other than ERANGE
|
||||
errno = 0;
|
||||
|
@ -183,8 +170,7 @@ bool TryParse(const std::string &str, u32 *const output)
|
|||
return false;
|
||||
|
||||
#if ULONG_MAX > UINT_MAX
|
||||
if (value >= 0x100000000ull
|
||||
&& value <= 0xFFFFFFFF00000000ull)
|
||||
if (value >= 0x100000000ull && value <= 0xFFFFFFFF00000000ull)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
|
@ -192,8 +178,7 @@ bool TryParse(const std::string &str, u32 *const output)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool TryParse(const std::string &str, bool *const output)
|
||||
{
|
||||
bool TryParse(const std::string& str, bool* const output) {
|
||||
if ("1" == str || "true" == ToLower(str))
|
||||
*output = true;
|
||||
else if ("0" == str || "false" == ToLower(str))
|
||||
|
@ -204,22 +189,21 @@ bool TryParse(const std::string &str, bool *const output)
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string StringFromBool(bool value)
|
||||
{
|
||||
std::string StringFromBool(bool value) {
|
||||
return value ? "True" : "False";
|
||||
}
|
||||
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension)
|
||||
{
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
|
||||
std::string* _pExtension) {
|
||||
if (full_path.empty())
|
||||
return false;
|
||||
|
||||
size_t dir_end = full_path.find_last_of("/"
|
||||
// windows needs the : included for something like just "C:" to be considered a directory
|
||||
// windows needs the : included for something like just "C:" to be considered a directory
|
||||
#ifdef _WIN32
|
||||
":"
|
||||
":"
|
||||
#endif
|
||||
);
|
||||
);
|
||||
if (std::string::npos == dir_end)
|
||||
dir_end = 0;
|
||||
else
|
||||
|
@ -241,8 +225,8 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
|
|||
return true;
|
||||
}
|
||||
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename)
|
||||
{
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
|
||||
const std::string& _Filename) {
|
||||
_CompleteFilename = _Path;
|
||||
|
||||
// check for seperator
|
||||
|
@ -253,8 +237,7 @@ void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _P
|
|||
_CompleteFilename += _Filename;
|
||||
}
|
||||
|
||||
void SplitString(const std::string& str, const char delim, std::vector<std::string>& output)
|
||||
{
|
||||
void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) {
|
||||
std::istringstream iss(str);
|
||||
output.resize(1);
|
||||
|
||||
|
@ -264,8 +247,7 @@ void SplitString(const std::string& str, const char delim, std::vector<std::stri
|
|||
output.pop_back();
|
||||
}
|
||||
|
||||
std::string TabsToSpaces(int tab_size, const std::string &in)
|
||||
{
|
||||
std::string TabsToSpaces(int tab_size, const std::string& in) {
|
||||
const std::string spaces(tab_size, ' ');
|
||||
std::string out(in);
|
||||
|
||||
|
@ -276,15 +258,13 @@ std::string TabsToSpaces(int tab_size, const std::string &in)
|
|||
return out;
|
||||
}
|
||||
|
||||
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest)
|
||||
{
|
||||
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
|
||||
size_t pos = 0;
|
||||
|
||||
if (src == dest)
|
||||
return result;
|
||||
|
||||
while ((pos = result.find(src, pos)) != std::string::npos)
|
||||
{
|
||||
while ((pos = result.find(src, pos)) != std::string::npos) {
|
||||
result.replace(pos, src.size(), dest);
|
||||
pos += dest.length();
|
||||
}
|
||||
|
@ -294,8 +274,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
|
|||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
std::string UTF16ToUTF8(const std::u16string& input)
|
||||
{
|
||||
std::string UTF16ToUTF8(const std::u16string& input) {
|
||||
#if _MSC_VER >= 1900
|
||||
// Workaround for missing char16_t/char32_t instantiations in MSVC2015
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
|
||||
|
@ -307,8 +286,7 @@ std::string UTF16ToUTF8(const std::u16string& input)
|
|||
#endif
|
||||
}
|
||||
|
||||
std::u16string UTF8ToUTF16(const std::string& input)
|
||||
{
|
||||
std::u16string UTF8ToUTF16(const std::string& input) {
|
||||
#if _MSC_VER >= 1900
|
||||
// Workaround for missing char16_t/char32_t instantiations in MSVC2015
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<__int16>, __int16> convert;
|
||||
|
@ -320,57 +298,56 @@ std::u16string UTF8ToUTF16(const std::string& input)
|
|||
#endif
|
||||
}
|
||||
|
||||
static std::wstring CPToUTF16(u32 code_page, const std::string& input)
|
||||
{
|
||||
auto const size = MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
|
||||
static std::wstring CPToUTF16(u32 code_page, const std::string& input) {
|
||||
auto const size =
|
||||
MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), nullptr, 0);
|
||||
|
||||
std::wstring output;
|
||||
output.resize(size);
|
||||
|
||||
if (size == 0 || size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size())))
|
||||
if (size == 0 ||
|
||||
size != MultiByteToWideChar(code_page, 0, input.data(), static_cast<int>(input.size()),
|
||||
&output[0], static_cast<int>(output.size())))
|
||||
output.clear();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string UTF16ToUTF8(const std::wstring& input)
|
||||
{
|
||||
auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), nullptr, 0, nullptr, nullptr);
|
||||
std::string UTF16ToUTF8(const std::wstring& input) {
|
||||
auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
|
||||
nullptr, 0, nullptr, nullptr);
|
||||
|
||||
std::string output;
|
||||
output.resize(size);
|
||||
|
||||
if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr))
|
||||
if (size == 0 ||
|
||||
size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()),
|
||||
&output[0], static_cast<int>(output.size()), nullptr, nullptr))
|
||||
output.clear();
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::wstring UTF8ToUTF16W(const std::string &input)
|
||||
{
|
||||
std::wstring UTF8ToUTF16W(const std::string& input) {
|
||||
return CPToUTF16(CP_UTF8, input);
|
||||
}
|
||||
|
||||
std::string SHIFTJISToUTF8(const std::string& input)
|
||||
{
|
||||
std::string SHIFTJISToUTF8(const std::string& input) {
|
||||
return UTF16ToUTF8(CPToUTF16(932, input));
|
||||
}
|
||||
|
||||
std::string CP1252ToUTF8(const std::string& input)
|
||||
{
|
||||
std::string CP1252ToUTF8(const std::string& input) {
|
||||
return UTF16ToUTF8(CPToUTF16(1252, input));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename T>
|
||||
static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
|
||||
{
|
||||
static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input) {
|
||||
std::string result;
|
||||
|
||||
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
|
||||
if ((iconv_t)(-1) == conv_desc)
|
||||
{
|
||||
if ((iconv_t)(-1) == conv_desc) {
|
||||
LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
|
||||
iconv_close(conv_desc);
|
||||
return {};
|
||||
|
@ -388,24 +365,18 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
|
|||
auto dst_buffer = &out_buffer[0];
|
||||
size_t dst_bytes = out_buffer.size();
|
||||
|
||||
while (0 != src_bytes)
|
||||
{
|
||||
size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
|
||||
&dst_buffer, &dst_bytes);
|
||||
while (0 != src_bytes) {
|
||||
size_t const iconv_result =
|
||||
iconv(conv_desc, (char**)(&src_buffer), &src_bytes, &dst_buffer, &dst_bytes);
|
||||
|
||||
if (static_cast<size_t>(-1) == iconv_result)
|
||||
{
|
||||
if (EILSEQ == errno || EINVAL == errno)
|
||||
{
|
||||
if (static_cast<size_t>(-1) == iconv_result) {
|
||||
if (EILSEQ == errno || EINVAL == errno) {
|
||||
// Try to skip the bad character
|
||||
if (0 != src_bytes)
|
||||
{
|
||||
if (0 != src_bytes) {
|
||||
--src_bytes;
|
||||
++src_buffer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
@ -420,13 +391,11 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
|
|||
return result;
|
||||
}
|
||||
|
||||
std::u16string UTF8ToUTF16(const std::string& input)
|
||||
{
|
||||
std::u16string UTF8ToUTF16(const std::string& input) {
|
||||
std::u16string result;
|
||||
|
||||
iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
|
||||
if ((iconv_t)(-1) == conv_desc)
|
||||
{
|
||||
if ((iconv_t)(-1) == conv_desc) {
|
||||
LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
|
||||
iconv_close(conv_desc);
|
||||
return {};
|
||||
|
@ -444,24 +413,18 @@ std::u16string UTF8ToUTF16(const std::string& input)
|
|||
char* dst_buffer = (char*)(&out_buffer[0]);
|
||||
size_t dst_bytes = out_buffer.size();
|
||||
|
||||
while (0 != src_bytes)
|
||||
{
|
||||
size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes,
|
||||
&dst_buffer, &dst_bytes);
|
||||
while (0 != src_bytes) {
|
||||
size_t const iconv_result =
|
||||
iconv(conv_desc, &src_buffer, &src_bytes, &dst_buffer, &dst_bytes);
|
||||
|
||||
if (static_cast<size_t>(-1) == iconv_result)
|
||||
{
|
||||
if (EILSEQ == errno || EINVAL == errno)
|
||||
{
|
||||
if (static_cast<size_t>(-1) == iconv_result) {
|
||||
if (EILSEQ == errno || EINVAL == errno) {
|
||||
// Try to skip the bad character
|
||||
if (0 != src_bytes)
|
||||
{
|
||||
if (0 != src_bytes) {
|
||||
--src_bytes;
|
||||
++src_buffer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
@ -476,32 +439,28 @@ std::u16string UTF8ToUTF16(const std::string& input)
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string UTF16ToUTF8(const std::u16string& input)
|
||||
{
|
||||
std::string UTF16ToUTF8(const std::u16string& input) {
|
||||
return CodeToUTF8("UTF-16LE", input);
|
||||
}
|
||||
|
||||
std::string CP1252ToUTF8(const std::string& input)
|
||||
{
|
||||
//return CodeToUTF8("CP1252//TRANSLIT", input);
|
||||
//return CodeToUTF8("CP1252//IGNORE", input);
|
||||
std::string CP1252ToUTF8(const std::string& input) {
|
||||
// return CodeToUTF8("CP1252//TRANSLIT", input);
|
||||
// return CodeToUTF8("CP1252//IGNORE", input);
|
||||
return CodeToUTF8("CP1252", input);
|
||||
}
|
||||
|
||||
std::string SHIFTJISToUTF8(const std::string& input)
|
||||
{
|
||||
//return CodeToUTF8("CP932", input);
|
||||
std::string SHIFTJISToUTF8(const std::string& input) {
|
||||
// return CodeToUTF8("CP932", input);
|
||||
return CodeToUTF8("SJIS", input);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
std::string StringFromFixedZeroTerminatedBuffer(const char * buffer, size_t max_len) {
|
||||
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len) {
|
||||
size_t len = 0;
|
||||
while (len < max_len && buffer[len] != '\0')
|
||||
++len;
|
||||
|
||||
return std::string(buffer, len);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,9 +25,8 @@ std::string StringFromFormat(const char* format, ...);
|
|||
// Cheap!
|
||||
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args);
|
||||
|
||||
template<size_t Count>
|
||||
inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...)
|
||||
{
|
||||
template <size_t Count>
|
||||
inline void CharArrayFromFormat(char (&out)[Count], const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
CharArrayFromFormatV(out, Count, format, args);
|
||||
|
@ -35,15 +34,14 @@ inline void CharArrayFromFormat(char (& out)[Count], const char* format, ...)
|
|||
}
|
||||
|
||||
// Good
|
||||
std::string ArrayToString(const u8 *data, u32 size, int line_len = 20, bool spaces = true);
|
||||
std::string ArrayToString(const u8* data, u32 size, int line_len = 20, bool spaces = true);
|
||||
|
||||
std::string StripSpaces(const std::string &s);
|
||||
std::string StripQuotes(const std::string &s);
|
||||
std::string StripSpaces(const std::string& s);
|
||||
std::string StripQuotes(const std::string& s);
|
||||
|
||||
// Thousand separator. Turns 12345678 into 12,345,678
|
||||
template <typename I>
|
||||
std::string ThousandSeparate(I value, int spaces = 0)
|
||||
{
|
||||
std::string ThousandSeparate(I value, int spaces = 0) {
|
||||
std::ostringstream oss;
|
||||
|
||||
// std::locale("") seems to be broken on many platforms
|
||||
|
@ -57,35 +55,34 @@ std::string ThousandSeparate(I value, int spaces = 0)
|
|||
|
||||
std::string StringFromBool(bool value);
|
||||
|
||||
bool TryParse(const std::string &str, bool *output);
|
||||
bool TryParse(const std::string &str, u32 *output);
|
||||
bool TryParse(const std::string& str, bool* output);
|
||||
bool TryParse(const std::string& str, u32* output);
|
||||
|
||||
template <typename N>
|
||||
static bool TryParse(const std::string &str, N *const output)
|
||||
{
|
||||
static bool TryParse(const std::string& str, N* const output) {
|
||||
std::istringstream iss(str);
|
||||
|
||||
N tmp = 0;
|
||||
if (iss >> tmp)
|
||||
{
|
||||
if (iss >> tmp) {
|
||||
*output = tmp;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: kill this
|
||||
bool AsciiToHex(const char* _szValue, u32& result);
|
||||
|
||||
std::string TabsToSpaces(int tab_size, const std::string &in);
|
||||
std::string TabsToSpaces(int tab_size, const std::string& in);
|
||||
|
||||
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
|
||||
|
||||
// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension);
|
||||
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
|
||||
std::string* _pExtension);
|
||||
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path, const std::string& _Filename);
|
||||
void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
|
||||
const std::string& _Filename);
|
||||
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
|
||||
|
||||
std::string UTF16ToUTF8(const std::u16string& input);
|
||||
|
@ -99,17 +96,21 @@ std::string UTF16ToUTF8(const std::wstring& input);
|
|||
std::wstring UTF8ToUTF16W(const std::string& str);
|
||||
|
||||
#ifdef _UNICODE
|
||||
inline std::string TStrToUTF8(const std::wstring& str)
|
||||
{ return UTF16ToUTF8(str); }
|
||||
inline std::string TStrToUTF8(const std::wstring& str) {
|
||||
return UTF16ToUTF8(str);
|
||||
}
|
||||
|
||||
inline std::wstring UTF8ToTStr(const std::string& str)
|
||||
{ return UTF8ToUTF16W(str); }
|
||||
inline std::wstring UTF8ToTStr(const std::string& str) {
|
||||
return UTF8ToUTF16W(str);
|
||||
}
|
||||
#else
|
||||
inline std::string TStrToUTF8(const std::string& str)
|
||||
{ return str; }
|
||||
inline std::string TStrToUTF8(const std::string& str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
inline std::string UTF8ToTStr(const std::string& str)
|
||||
{ return str; }
|
||||
inline std::string UTF8ToTStr(const std::string& str) {
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -134,5 +135,4 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
|
|||
* NUL-terminated then the string ends at max_len characters.
|
||||
*/
|
||||
std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, size_t max_len);
|
||||
|
||||
}
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <cstdlib>
|
||||
#include <cstdlib>
|
||||
#elif defined(__linux__)
|
||||
#include <byteswap.h>
|
||||
#include <byteswap.h>
|
||||
#elif defined(__FreeBSD__)
|
||||
#include <sys/endian.h>
|
||||
#include <sys/endian.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
|
@ -61,38 +61,73 @@
|
|||
namespace Common {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);}
|
||||
inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);}
|
||||
inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);}
|
||||
inline u16 swap16(u16 _data) {
|
||||
return _byteswap_ushort(_data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return _byteswap_ulong(_data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return _byteswap_uint64(_data);
|
||||
}
|
||||
#elif _M_ARM
|
||||
inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;}
|
||||
inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;}
|
||||
inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);}
|
||||
inline u16 swap16(u16 _data) {
|
||||
u32 data = _data;
|
||||
__asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data));
|
||||
return (u16)data;
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
__asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data));
|
||||
return _data;
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return ((u64)swap32(_data) << 32) | swap32(_data >> 32);
|
||||
}
|
||||
#elif __linux__
|
||||
inline u16 swap16(u16 _data) {return bswap_16(_data);}
|
||||
inline u32 swap32(u32 _data) {return bswap_32(_data);}
|
||||
inline u64 swap64(u64 _data) {return bswap_64(_data);}
|
||||
inline u16 swap16(u16 _data) {
|
||||
return bswap_16(_data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return bswap_32(_data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return bswap_64(_data);
|
||||
}
|
||||
#elif __APPLE__
|
||||
inline __attribute__((always_inline)) u16 swap16(u16 _data)
|
||||
{return (_data >> 8) | (_data << 8);}
|
||||
inline __attribute__((always_inline)) u32 swap32(u32 _data)
|
||||
{return __builtin_bswap32(_data);}
|
||||
inline __attribute__((always_inline)) u64 swap64(u64 _data)
|
||||
{return __builtin_bswap64(_data);}
|
||||
inline __attribute__((always_inline)) u16 swap16(u16 _data) {
|
||||
return (_data >> 8) | (_data << 8);
|
||||
}
|
||||
inline __attribute__((always_inline)) u32 swap32(u32 _data) {
|
||||
return __builtin_bswap32(_data);
|
||||
}
|
||||
inline __attribute__((always_inline)) u64 swap64(u64 _data) {
|
||||
return __builtin_bswap64(_data);
|
||||
}
|
||||
#elif __FreeBSD__
|
||||
inline u16 swap16(u16 _data) {return bswap16(_data);}
|
||||
inline u32 swap32(u32 _data) {return bswap32(_data);}
|
||||
inline u64 swap64(u64 _data) {return bswap64(_data);}
|
||||
inline u16 swap16(u16 _data) {
|
||||
return bswap16(_data);
|
||||
}
|
||||
inline u32 swap32(u32 _data) {
|
||||
return bswap32(_data);
|
||||
}
|
||||
inline u64 swap64(u64 _data) {
|
||||
return bswap64(_data);
|
||||
}
|
||||
#else
|
||||
// Slow generic implementation.
|
||||
inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);}
|
||||
inline u32 swap32(u32 data) {return (swap16(data) << 16) | swap16(data >> 16);}
|
||||
inline u64 swap64(u64 data) {return ((u64)swap32(data) << 32) | swap32(data >> 32);}
|
||||
inline u16 swap16(u16 data) {
|
||||
return (data >> 8) | (data << 8);
|
||||
}
|
||||
inline u32 swap32(u32 data) {
|
||||
return (swap16(data) << 16) | swap16(data >> 16);
|
||||
}
|
||||
inline u64 swap64(u64 data) {
|
||||
return ((u64)swap32(data) << 32) | swap32(data >> 32);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline float swapf(float f) {
|
||||
static_assert(sizeof(u32) == sizeof(float),
|
||||
"float must be the same size as uint32_t.");
|
||||
static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t.");
|
||||
|
||||
u32 value;
|
||||
std::memcpy(&value, &f, sizeof(u32));
|
||||
|
@ -104,8 +139,7 @@ inline float swapf(float f) {
|
|||
}
|
||||
|
||||
inline double swapd(double f) {
|
||||
static_assert(sizeof(u64) == sizeof(double),
|
||||
"double must be the same size as uint64_t.");
|
||||
static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t.");
|
||||
|
||||
u64 value;
|
||||
std::memcpy(&value, &f, sizeof(u64));
|
||||
|
@ -116,8 +150,7 @@ inline double swapd(double f) {
|
|||
return f;
|
||||
}
|
||||
|
||||
} // Namespace Common
|
||||
|
||||
} // Namespace Common
|
||||
|
||||
template <typename T, typename F>
|
||||
struct swap_struct_t {
|
||||
|
@ -129,251 +162,272 @@ protected:
|
|||
static T swap(T v) {
|
||||
return F::swap(v);
|
||||
}
|
||||
|
||||
public:
|
||||
T const swap() const {
|
||||
return swap(value);
|
||||
|
||||
}
|
||||
swap_struct_t() = default;
|
||||
swap_struct_t(const T &v): value(swap(v)) {}
|
||||
swap_struct_t(const T& v) : value(swap(v)) {
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
swapped_t& operator=(const S &source) {
|
||||
swapped_t& operator=(const S& source) {
|
||||
value = swap((T)source);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator s8() const { return (s8)swap(); }
|
||||
operator u8() const { return (u8)swap(); }
|
||||
operator s16() const { return (s16)swap(); }
|
||||
operator u16() const { return (u16)swap(); }
|
||||
operator s32() const { return (s32)swap(); }
|
||||
operator u32() const { return (u32)swap(); }
|
||||
operator s64() const { return (s64)swap(); }
|
||||
operator u64() const { return (u64)swap(); }
|
||||
operator float() const { return (float)swap(); }
|
||||
operator double() const { return (double)swap(); }
|
||||
operator s8() const {
|
||||
return (s8)swap();
|
||||
}
|
||||
operator u8() const {
|
||||
return (u8)swap();
|
||||
}
|
||||
operator s16() const {
|
||||
return (s16)swap();
|
||||
}
|
||||
operator u16() const {
|
||||
return (u16)swap();
|
||||
}
|
||||
operator s32() const {
|
||||
return (s32)swap();
|
||||
}
|
||||
operator u32() const {
|
||||
return (u32)swap();
|
||||
}
|
||||
operator s64() const {
|
||||
return (s64)swap();
|
||||
}
|
||||
operator u64() const {
|
||||
return (u64)swap();
|
||||
}
|
||||
operator float() const {
|
||||
return (float)swap();
|
||||
}
|
||||
operator double() const {
|
||||
return (double)swap();
|
||||
}
|
||||
|
||||
// +v
|
||||
swapped_t operator +() const {
|
||||
swapped_t operator+() const {
|
||||
return +swap();
|
||||
}
|
||||
// -v
|
||||
swapped_t operator -() const {
|
||||
swapped_t operator-() const {
|
||||
return -swap();
|
||||
}
|
||||
|
||||
// v / 5
|
||||
swapped_t operator/(const swapped_t &i) const {
|
||||
swapped_t operator/(const swapped_t& i) const {
|
||||
return swap() / i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator/(const S &i) const {
|
||||
swapped_t operator/(const S& i) const {
|
||||
return swap() / i;
|
||||
}
|
||||
|
||||
// v * 5
|
||||
swapped_t operator*(const swapped_t &i) const {
|
||||
swapped_t operator*(const swapped_t& i) const {
|
||||
return swap() * i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator*(const S &i) const {
|
||||
swapped_t operator*(const S& i) const {
|
||||
return swap() * i;
|
||||
}
|
||||
|
||||
// v + 5
|
||||
swapped_t operator+(const swapped_t &i) const {
|
||||
swapped_t operator+(const swapped_t& i) const {
|
||||
return swap() + i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator+(const S &i) const {
|
||||
swapped_t operator+(const S& i) const {
|
||||
return swap() + (T)i;
|
||||
}
|
||||
// v - 5
|
||||
swapped_t operator-(const swapped_t &i) const {
|
||||
swapped_t operator-(const swapped_t& i) const {
|
||||
return swap() - i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator-(const S &i) const {
|
||||
swapped_t operator-(const S& i) const {
|
||||
return swap() - (T)i;
|
||||
}
|
||||
|
||||
// v += 5
|
||||
swapped_t& operator+=(const swapped_t &i) {
|
||||
swapped_t& operator+=(const swapped_t& i) {
|
||||
value = swap(swap() + i.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator+=(const S &i) {
|
||||
swapped_t& operator+=(const S& i) {
|
||||
value = swap(swap() + (T)i);
|
||||
return *this;
|
||||
}
|
||||
// v -= 5
|
||||
swapped_t& operator-=(const swapped_t &i) {
|
||||
swapped_t& operator-=(const swapped_t& i) {
|
||||
value = swap(swap() - i.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator-=(const S &i) {
|
||||
swapped_t& operator-=(const S& i) {
|
||||
value = swap(swap() - (T)i);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ++v
|
||||
swapped_t& operator++() {
|
||||
value = swap(swap()+1);
|
||||
value = swap(swap() + 1);
|
||||
return *this;
|
||||
}
|
||||
// --v
|
||||
swapped_t& operator--() {
|
||||
value = swap(swap()-1);
|
||||
swapped_t& operator--() {
|
||||
value = swap(swap() - 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// v++
|
||||
swapped_t operator++(int) {
|
||||
swapped_t old = *this;
|
||||
value = swap(swap()+1);
|
||||
value = swap(swap() + 1);
|
||||
return old;
|
||||
}
|
||||
// v--
|
||||
swapped_t operator--(int) {
|
||||
swapped_t old = *this;
|
||||
value = swap(swap()-1);
|
||||
value = swap(swap() - 1);
|
||||
return old;
|
||||
}
|
||||
// Comparaison
|
||||
// v == i
|
||||
bool operator==(const swapped_t &i) const {
|
||||
bool operator==(const swapped_t& i) const {
|
||||
return swap() == i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
bool operator==(const S &i) const {
|
||||
bool operator==(const S& i) const {
|
||||
return swap() == i;
|
||||
}
|
||||
|
||||
// v != i
|
||||
bool operator!=(const swapped_t &i) const {
|
||||
bool operator!=(const swapped_t& i) const {
|
||||
return swap() != i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
bool operator!=(const S &i) const {
|
||||
bool operator!=(const S& i) const {
|
||||
return swap() != i;
|
||||
}
|
||||
|
||||
// v > i
|
||||
bool operator>(const swapped_t &i) const {
|
||||
bool operator>(const swapped_t& i) const {
|
||||
return swap() > i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
bool operator>(const S &i) const {
|
||||
bool operator>(const S& i) const {
|
||||
return swap() > i;
|
||||
}
|
||||
|
||||
// v < i
|
||||
bool operator<(const swapped_t &i) const {
|
||||
bool operator<(const swapped_t& i) const {
|
||||
return swap() < i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
bool operator<(const S &i) const {
|
||||
bool operator<(const S& i) const {
|
||||
return swap() < i;
|
||||
}
|
||||
|
||||
// v >= i
|
||||
bool operator>=(const swapped_t &i) const {
|
||||
bool operator>=(const swapped_t& i) const {
|
||||
return swap() >= i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
bool operator>=(const S &i) const {
|
||||
bool operator>=(const S& i) const {
|
||||
return swap() >= i;
|
||||
}
|
||||
|
||||
// v <= i
|
||||
bool operator<=(const swapped_t &i) const {
|
||||
bool operator<=(const swapped_t& i) const {
|
||||
return swap() <= i.swap();
|
||||
}
|
||||
template <typename S>
|
||||
bool operator<=(const S &i) const {
|
||||
bool operator<=(const S& i) const {
|
||||
return swap() <= i;
|
||||
}
|
||||
|
||||
// logical
|
||||
swapped_t operator !() const {
|
||||
swapped_t operator!() const {
|
||||
return !swap();
|
||||
}
|
||||
|
||||
// bitmath
|
||||
swapped_t operator ~() const {
|
||||
swapped_t operator~() const {
|
||||
return ~swap();
|
||||
}
|
||||
|
||||
swapped_t operator &(const swapped_t &b) const {
|
||||
swapped_t operator&(const swapped_t& b) const {
|
||||
return swap() & b.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator &(const S &b) const {
|
||||
swapped_t operator&(const S& b) const {
|
||||
return swap() & b;
|
||||
}
|
||||
swapped_t& operator &=(const swapped_t &b) {
|
||||
swapped_t& operator&=(const swapped_t& b) {
|
||||
value = swap(swap() & b.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator &=(const S b) {
|
||||
swapped_t& operator&=(const S b) {
|
||||
value = swap(swap() & b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
swapped_t operator |(const swapped_t &b) const {
|
||||
swapped_t operator|(const swapped_t& b) const {
|
||||
return swap() | b.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator |(const S &b) const {
|
||||
swapped_t operator|(const S& b) const {
|
||||
return swap() | b;
|
||||
}
|
||||
swapped_t& operator |=(const swapped_t &b) {
|
||||
swapped_t& operator|=(const swapped_t& b) {
|
||||
value = swap(swap() | b.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator |=(const S &b) {
|
||||
swapped_t& operator|=(const S& b) {
|
||||
value = swap(swap() | b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
swapped_t operator ^(const swapped_t &b) const {
|
||||
swapped_t operator^(const swapped_t& b) const {
|
||||
return swap() ^ b.swap();
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t operator ^(const S &b) const {
|
||||
swapped_t operator^(const S& b) const {
|
||||
return swap() ^ b;
|
||||
}
|
||||
swapped_t& operator ^=(const swapped_t &b) {
|
||||
swapped_t& operator^=(const swapped_t& b) {
|
||||
value = swap(swap() ^ b.swap());
|
||||
return *this;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator ^=(const S &b) {
|
||||
swapped_t& operator^=(const S& b) {
|
||||
value = swap(swap() ^ b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
swapped_t operator <<(const S &b) const {
|
||||
swapped_t operator<<(const S& b) const {
|
||||
return swap() << b;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator <<=(const S &b) const {
|
||||
swapped_t& operator<<=(const S& b) const {
|
||||
value = swap(swap() << b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
swapped_t operator >>(const S &b) const {
|
||||
swapped_t operator>>(const S& b) const {
|
||||
return swap() >> b;
|
||||
}
|
||||
template <typename S>
|
||||
swapped_t& operator >>=(const S &b) const {
|
||||
swapped_t& operator>>=(const S& b) const {
|
||||
value = swap(swap() >> b);
|
||||
return *this;
|
||||
}
|
||||
|
@ -381,129 +435,126 @@ public:
|
|||
// Member
|
||||
/** todo **/
|
||||
|
||||
|
||||
// Arithmetics
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator+(const S &p, const swapped_t v);
|
||||
friend S operator+(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator-(const S &p, const swapped_t v);
|
||||
friend S operator-(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator/(const S &p, const swapped_t v);
|
||||
friend S operator/(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator*(const S &p, const swapped_t v);
|
||||
friend S operator*(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator%(const S &p, const swapped_t v);
|
||||
friend S operator%(const S& p, const swapped_t v);
|
||||
|
||||
// Arithmetics + assignements
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator+=(const S &p, const swapped_t v);
|
||||
friend S operator+=(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator-=(const S &p, const swapped_t v);
|
||||
friend S operator-=(const S& p, const swapped_t v);
|
||||
|
||||
// Bitmath
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend S operator&(const S &p, const swapped_t v);
|
||||
friend S operator&(const S& p, const swapped_t v);
|
||||
|
||||
// Comparison
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator<(const S &p, const swapped_t v);
|
||||
friend bool operator<(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator>(const S &p, const swapped_t v);
|
||||
friend bool operator>(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator<=(const S &p, const swapped_t v);
|
||||
friend bool operator<=(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator>=(const S &p, const swapped_t v);
|
||||
friend bool operator>=(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator!=(const S &p, const swapped_t v);
|
||||
friend bool operator!=(const S& p, const swapped_t v);
|
||||
|
||||
template <typename S, typename T2, typename F2>
|
||||
friend bool operator==(const S &p, const swapped_t v);
|
||||
friend bool operator==(const S& p, const swapped_t v);
|
||||
};
|
||||
|
||||
|
||||
// Arithmetics
|
||||
template <typename S, typename T, typename F>
|
||||
S operator+(const S &i, const swap_struct_t<T, F> v) {
|
||||
S operator+(const S& i, const swap_struct_t<T, F> v) {
|
||||
return i + v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator-(const S &i, const swap_struct_t<T, F> v) {
|
||||
S operator-(const S& i, const swap_struct_t<T, F> v) {
|
||||
return i - v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator/(const S &i, const swap_struct_t<T, F> v) {
|
||||
S operator/(const S& i, const swap_struct_t<T, F> v) {
|
||||
return i / v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator*(const S &i, const swap_struct_t<T, F> v) {
|
||||
S operator*(const S& i, const swap_struct_t<T, F> v) {
|
||||
return i * v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator%(const S &i, const swap_struct_t<T, F> v) {
|
||||
S operator%(const S& i, const swap_struct_t<T, F> v) {
|
||||
return i % v.swap();
|
||||
}
|
||||
|
||||
// Arithmetics + assignements
|
||||
template <typename S, typename T, typename F>
|
||||
S &operator+=(S &i, const swap_struct_t<T, F> v) {
|
||||
S& operator+=(S& i, const swap_struct_t<T, F> v) {
|
||||
i += v.swap();
|
||||
return i;
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S &operator-=(S &i, const swap_struct_t<T, F> v) {
|
||||
S& operator-=(S& i, const swap_struct_t<T, F> v) {
|
||||
i -= v.swap();
|
||||
return i;
|
||||
}
|
||||
|
||||
// Logical
|
||||
template <typename S, typename T, typename F>
|
||||
S operator&(const S &i, const swap_struct_t<T, F> v) {
|
||||
S operator&(const S& i, const swap_struct_t<T, F> v) {
|
||||
return i & v.swap();
|
||||
}
|
||||
|
||||
template <typename S, typename T, typename F>
|
||||
S operator&(const swap_struct_t<T, F> v, const S &i) {
|
||||
S operator&(const swap_struct_t<T, F> v, const S& i) {
|
||||
return (S)(v.swap() & i);
|
||||
}
|
||||
|
||||
|
||||
// Comparaison
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator<(const S &p, const swap_struct_t<T, F> v) {
|
||||
bool operator<(const S& p, const swap_struct_t<T, F> v) {
|
||||
return p < v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator>(const S &p, const swap_struct_t<T, F> v) {
|
||||
bool operator>(const S& p, const swap_struct_t<T, F> v) {
|
||||
return p > v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator<=(const S &p, const swap_struct_t<T, F> v) {
|
||||
bool operator<=(const S& p, const swap_struct_t<T, F> v) {
|
||||
return p <= v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator>=(const S &p, const swap_struct_t<T, F> v) {
|
||||
bool operator>=(const S& p, const swap_struct_t<T, F> v) {
|
||||
return p >= v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator!=(const S &p, const swap_struct_t<T, F> v) {
|
||||
bool operator!=(const S& p, const swap_struct_t<T, F> v) {
|
||||
return p != v.swap();
|
||||
}
|
||||
template <typename S, typename T, typename F>
|
||||
bool operator==(const S &p, const swap_struct_t<T, F> v) {
|
||||
bool operator==(const S& p, const swap_struct_t<T, F> v) {
|
||||
return p == v.swap();
|
||||
}
|
||||
|
||||
|
@ -554,30 +605,30 @@ typedef s64 s64_le;
|
|||
typedef float float_le;
|
||||
typedef double double_le;
|
||||
|
||||
typedef swap_struct_t<u64, swap_64_t<u64> > u64_be;
|
||||
typedef swap_struct_t<s64, swap_64_t<s64> > s64_be;
|
||||
typedef swap_struct_t<u64, swap_64_t<u64>> u64_be;
|
||||
typedef swap_struct_t<s64, swap_64_t<s64>> s64_be;
|
||||
|
||||
typedef swap_struct_t<u32, swap_32_t<u32> > u32_be;
|
||||
typedef swap_struct_t<s32, swap_32_t<s32> > s32_be;
|
||||
typedef swap_struct_t<u32, swap_32_t<u32>> u32_be;
|
||||
typedef swap_struct_t<s32, swap_32_t<s32>> s32_be;
|
||||
|
||||
typedef swap_struct_t<u16, swap_16_t<u16> > u16_be;
|
||||
typedef swap_struct_t<s16, swap_16_t<s16> > s16_be;
|
||||
typedef swap_struct_t<u16, swap_16_t<u16>> u16_be;
|
||||
typedef swap_struct_t<s16, swap_16_t<s16>> s16_be;
|
||||
|
||||
typedef swap_struct_t<float, swap_float_t<float> > float_be;
|
||||
typedef swap_struct_t<double, swap_double_t<double> > double_be;
|
||||
typedef swap_struct_t<float, swap_float_t<float>> float_be;
|
||||
typedef swap_struct_t<double, swap_double_t<double>> double_be;
|
||||
#else
|
||||
|
||||
typedef swap_struct_t<u64, swap_64_t<u64> > u64_le;
|
||||
typedef swap_struct_t<s64, swap_64_t<s64> > s64_le;
|
||||
typedef swap_struct_t<u64, swap_64_t<u64>> u64_le;
|
||||
typedef swap_struct_t<s64, swap_64_t<s64>> s64_le;
|
||||
|
||||
typedef swap_struct_t<u32, swap_32_t<u32> > u32_le;
|
||||
typedef swap_struct_t<s32, swap_32_t<s32> > s32_le;
|
||||
typedef swap_struct_t<u32, swap_32_t<u32>> u32_le;
|
||||
typedef swap_struct_t<s32, swap_32_t<s32>> s32_le;
|
||||
|
||||
typedef swap_struct_t<u16, swap_16_t<u16> > u16_le;
|
||||
typedef swap_struct_t< s16, swap_16_t<s16> > s16_le;
|
||||
typedef swap_struct_t<u16, swap_16_t<u16>> u16_le;
|
||||
typedef swap_struct_t<s16, swap_16_t<s16>> s16_le;
|
||||
|
||||
typedef swap_struct_t<float, swap_float_t<float> > float_le;
|
||||
typedef swap_struct_t<double, swap_double_t<double> > double_le;
|
||||
typedef swap_struct_t<float, swap_float_t<float>> float_le;
|
||||
typedef swap_struct_t<double, swap_double_t<double>> double_le;
|
||||
|
||||
typedef u32 u32_be;
|
||||
typedef u16 u16_be;
|
||||
|
|
|
@ -6,49 +6,41 @@
|
|||
|
||||
TSymbolsMap g_symbols;
|
||||
|
||||
namespace Symbols
|
||||
{
|
||||
bool HasSymbol(u32 address)
|
||||
{
|
||||
return g_symbols.find(address) != g_symbols.end();
|
||||
}
|
||||
namespace Symbols {
|
||||
bool HasSymbol(u32 address) {
|
||||
return g_symbols.find(address) != g_symbols.end();
|
||||
}
|
||||
|
||||
void Add(u32 address, const std::string& name, u32 size, u32 type)
|
||||
{
|
||||
if (!HasSymbol(address))
|
||||
{
|
||||
TSymbol symbol;
|
||||
symbol.address = address;
|
||||
symbol.name = name;
|
||||
symbol.size = size;
|
||||
symbol.type = type;
|
||||
void Add(u32 address, const std::string& name, u32 size, u32 type) {
|
||||
if (!HasSymbol(address)) {
|
||||
TSymbol symbol;
|
||||
symbol.address = address;
|
||||
symbol.name = name;
|
||||
symbol.size = size;
|
||||
symbol.type = type;
|
||||
|
||||
g_symbols.emplace(address, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
TSymbol GetSymbol(u32 address)
|
||||
{
|
||||
const auto iter = g_symbols.find(address);
|
||||
|
||||
if (iter != g_symbols.end())
|
||||
return iter->second;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string GetName(u32 address)
|
||||
{
|
||||
return GetSymbol(address).name;
|
||||
}
|
||||
|
||||
void Remove(u32 address)
|
||||
{
|
||||
g_symbols.erase(address);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
g_symbols.clear();
|
||||
g_symbols.emplace(address, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
TSymbol GetSymbol(u32 address) {
|
||||
const auto iter = g_symbols.find(address);
|
||||
|
||||
if (iter != g_symbols.end())
|
||||
return iter->second;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::string GetName(u32 address) {
|
||||
return GetSymbol(address).name;
|
||||
}
|
||||
|
||||
void Remove(u32 address) {
|
||||
g_symbols.erase(address);
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
g_symbols.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,25 +10,22 @@
|
|||
|
||||
#include "common/common_types.h"
|
||||
|
||||
struct TSymbol
|
||||
{
|
||||
u32 address = 0;
|
||||
struct TSymbol {
|
||||
u32 address = 0;
|
||||
std::string name;
|
||||
u32 size = 0;
|
||||
u32 type = 0;
|
||||
u32 size = 0;
|
||||
u32 type = 0;
|
||||
};
|
||||
|
||||
typedef std::map<u32, TSymbol> TSymbolsMap;
|
||||
typedef std::pair<u32, TSymbol> TSymbolsPair;
|
||||
|
||||
namespace Symbols
|
||||
{
|
||||
bool HasSymbol(u32 address);
|
||||
namespace Symbols {
|
||||
bool HasSymbol(u32 address);
|
||||
|
||||
void Add(u32 address, const std::string& name, u32 size, u32 type);
|
||||
TSymbol GetSymbol(u32 address);
|
||||
const std::string GetName(u32 address);
|
||||
void Remove(u32 address);
|
||||
void Clear();
|
||||
void Add(u32 address, const std::string& name, u32 size, u32 type);
|
||||
TSymbol GetSymbol(u32 address);
|
||||
const std::string GetName(u32 address);
|
||||
void Remove(u32 address);
|
||||
void Clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,14 +12,14 @@ namespace Common {
|
|||
/**
|
||||
* Wraps an object, only allowing access to it via a locking reference wrapper. Good to ensure no
|
||||
* one forgets to lock a mutex before acessing an object. To access the wrapped object construct a
|
||||
* SyncronizedRef on this wrapper. Inspired by Rust's Mutex type (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
|
||||
* SyncronizedRef on this wrapper. Inspired by Rust's Mutex type
|
||||
* (http://doc.rust-lang.org/std/sync/struct.Mutex.html).
|
||||
*/
|
||||
template <typename T>
|
||||
class SynchronizedWrapper {
|
||||
public:
|
||||
template <typename... Args>
|
||||
SynchronizedWrapper(Args&&... args) :
|
||||
data(std::forward<Args>(args)...) {
|
||||
SynchronizedWrapper(Args&&... args) : data(std::forward<Args>(args)...) {
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -58,11 +58,19 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
T& operator*() { return wrapper->data; }
|
||||
const T& operator*() const { return wrapper->data; }
|
||||
T& operator*() {
|
||||
return wrapper->data;
|
||||
}
|
||||
const T& operator*() const {
|
||||
return wrapper->data;
|
||||
}
|
||||
|
||||
T* operator->() { return &wrapper->data; }
|
||||
const T* operator->() const { return &wrapper->data; }
|
||||
T* operator->() {
|
||||
return &wrapper->data;
|
||||
}
|
||||
const T* operator->() const {
|
||||
return &wrapper->data;
|
||||
}
|
||||
|
||||
private:
|
||||
SynchronizedWrapper<T>* wrapper;
|
||||
|
|
|
@ -5,27 +5,25 @@
|
|||
#include "common/thread.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach.h>
|
||||
#elif defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#if defined(BSD4_4) || defined(__OpenBSD__)
|
||||
#include <pthread_np.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <sched.h>
|
||||
#if defined(BSD4_4) || defined(__OpenBSD__)
|
||||
#include <pthread_np.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace Common
|
||||
{
|
||||
namespace Common {
|
||||
|
||||
int CurrentThreadId()
|
||||
{
|
||||
int CurrentThreadId() {
|
||||
#ifdef _MSC_VER
|
||||
return GetCurrentThreadId();
|
||||
#elif defined __APPLE__
|
||||
|
@ -37,26 +35,22 @@ int CurrentThreadId()
|
|||
|
||||
#ifdef _WIN32
|
||||
// Supporting functions
|
||||
void SleepCurrentThread(int ms)
|
||||
{
|
||||
void SleepCurrentThread(int ms) {
|
||||
Sleep(ms);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
{
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
|
||||
SetThreadAffinityMask(thread, mask);
|
||||
}
|
||||
|
||||
void SetCurrentThreadAffinity(u32 mask)
|
||||
{
|
||||
void SetCurrentThreadAffinity(u32 mask) {
|
||||
SetThreadAffinityMask(GetCurrentThread(), mask);
|
||||
}
|
||||
|
||||
void SwitchCurrentThread()
|
||||
{
|
||||
void SwitchCurrentThread() {
|
||||
SwitchToThread();
|
||||
}
|
||||
|
||||
|
@ -66,40 +60,34 @@ void SwitchCurrentThread()
|
|||
|
||||
// This is implemented much nicer in upcoming msvc++, see:
|
||||
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
|
||||
void SetCurrentThreadName(const char* szThreadName)
|
||||
{
|
||||
void SetCurrentThreadName(const char* szThreadName) {
|
||||
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||
|
||||
#pragma pack(push,8)
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
DWORD dwType; // must be 0x1000
|
||||
LPCSTR szName; // pointer to name (in user addr space)
|
||||
#pragma pack(push, 8)
|
||||
struct THREADNAME_INFO {
|
||||
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
|
||||
DWORD dwFlags; // reserved for future use, must be zero
|
||||
} info;
|
||||
#pragma pack(pop)
|
||||
#pragma pack(pop)
|
||||
|
||||
info.dwType = 0x1000;
|
||||
info.szName = szThreadName;
|
||||
info.dwThreadID = -1; //dwThreadID;
|
||||
info.dwThreadID = -1; // dwThreadID;
|
||||
info.dwFlags = 0;
|
||||
|
||||
__try
|
||||
{
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
__try {
|
||||
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
||||
} __except (EXCEPTION_CONTINUE_EXECUTION) {
|
||||
}
|
||||
__except(EXCEPTION_CONTINUE_EXECUTION)
|
||||
{}
|
||||
}
|
||||
|
||||
#else // !MSVC_VER, so must be POSIX threads
|
||||
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
||||
{
|
||||
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
|
||||
#ifdef __APPLE__
|
||||
thread_policy_set(pthread_mach_thread_np(thread),
|
||||
THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1);
|
||||
thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1);
|
||||
#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID)
|
||||
cpu_set_t cpu_set;
|
||||
CPU_ZERO(&cpu_set);
|
||||
|
@ -112,27 +100,23 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
|
|||
#endif
|
||||
}
|
||||
|
||||
void SetCurrentThreadAffinity(u32 mask)
|
||||
{
|
||||
void SetCurrentThreadAffinity(u32 mask) {
|
||||
SetThreadAffinity(pthread_self(), mask);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
void SleepCurrentThread(int ms)
|
||||
{
|
||||
void SleepCurrentThread(int ms) {
|
||||
usleep(1000 * ms);
|
||||
}
|
||||
|
||||
void SwitchCurrentThread()
|
||||
{
|
||||
void SwitchCurrentThread() {
|
||||
usleep(1000 * 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// MinGW with the POSIX threading model does not support pthread_setname_np
|
||||
#if !defined(_WIN32) || defined(_MSC_VER)
|
||||
void SetCurrentThreadName(const char* szThreadName)
|
||||
{
|
||||
void SetCurrentThreadName(const char* szThreadName) {
|
||||
#ifdef __APPLE__
|
||||
pthread_setname_np(szThreadName);
|
||||
#elif defined(__OpenBSD__)
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
|
@ -17,17 +17,17 @@
|
|||
// backwards compat support.
|
||||
// WARNING: This only works correctly with POD types.
|
||||
#if defined(__clang__)
|
||||
# if !__has_feature(cxx_thread_local)
|
||||
# define thread_local __thread
|
||||
# endif
|
||||
#if !__has_feature(cxx_thread_local)
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
||||
# define thread_local __thread
|
||||
# endif
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
# if _MSC_VER < 1900
|
||||
# define thread_local __declspec(thread)
|
||||
# endif
|
||||
#if _MSC_VER < 1900
|
||||
#define thread_local __declspec(thread)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
@ -39,7 +39,8 @@ void SetCurrentThreadAffinity(u32 mask);
|
|||
|
||||
class Event {
|
||||
public:
|
||||
Event() : is_set(false) {}
|
||||
Event() : is_set(false) {
|
||||
}
|
||||
|
||||
void Set() {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
|
@ -51,13 +52,14 @@ public:
|
|||
|
||||
void Wait() {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
condvar.wait(lk, [&]{ return is_set; });
|
||||
condvar.wait(lk, [&] { return is_set; });
|
||||
is_set = false;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
std::unique_lock<std::mutex> lk(mutex);
|
||||
// no other action required, since wait loops on the predicate and any lingering signal will get cleared on the first iteration
|
||||
// no other action required, since wait loops on the predicate and any lingering signal will
|
||||
// get cleared on the first iteration
|
||||
is_set = false;
|
||||
}
|
||||
|
||||
|
@ -69,7 +71,8 @@ private:
|
|||
|
||||
class Barrier {
|
||||
public:
|
||||
explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) {}
|
||||
explicit Barrier(size_t count_) : count(count_), waiting(0), generation(0) {
|
||||
}
|
||||
|
||||
/// Blocks until all "count" threads have called Sync()
|
||||
void Sync() {
|
||||
|
@ -81,7 +84,8 @@ public:
|
|||
waiting = 0;
|
||||
condvar.notify_all();
|
||||
} else {
|
||||
condvar.wait(lk, [this, current_generation]{ return current_generation != generation; });
|
||||
condvar.wait(lk,
|
||||
[this, current_generation] { return current_generation != generation; });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,7 +98,7 @@ private:
|
|||
};
|
||||
|
||||
void SleepCurrentThread(int ms);
|
||||
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
|
||||
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
|
||||
|
||||
// Use this function during a spin-wait to make the current thread
|
||||
// relax while another thread is working. This may be more efficient
|
||||
|
@ -103,6 +107,6 @@ inline void YieldCPU() {
|
|||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
void SetCurrentThreadName(const char *name);
|
||||
void SetCurrentThreadName(const char* name);
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
namespace Common {
|
||||
|
||||
template<class T, unsigned int N>
|
||||
template <class T, unsigned int N>
|
||||
struct ThreadQueueList {
|
||||
// TODO(yuriks): If performance proves to be a problem, the std::deques can be replaced with
|
||||
// (dynamically resizable) circular buffers to remove their overhead when
|
||||
|
@ -39,7 +39,7 @@ struct ThreadQueueList {
|
|||
}
|
||||
|
||||
T get_first() {
|
||||
Queue *cur = first;
|
||||
Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
if (!cur->data.empty()) {
|
||||
return cur->data.front();
|
||||
|
@ -51,7 +51,7 @@ struct ThreadQueueList {
|
|||
}
|
||||
|
||||
T pop_first() {
|
||||
Queue *cur = first;
|
||||
Queue* cur = first;
|
||||
while (cur != nullptr) {
|
||||
if (!cur->data.empty()) {
|
||||
auto tmp = std::move(cur->data.front());
|
||||
|
@ -65,8 +65,8 @@ struct ThreadQueueList {
|
|||
}
|
||||
|
||||
T pop_first_better(Priority priority) {
|
||||
Queue *cur = first;
|
||||
Queue *stop = &queues[priority];
|
||||
Queue* cur = first;
|
||||
Queue* stop = &queues[priority];
|
||||
while (cur < stop) {
|
||||
if (!cur->data.empty()) {
|
||||
auto tmp = std::move(cur->data.front());
|
||||
|
@ -80,12 +80,12 @@ struct ThreadQueueList {
|
|||
}
|
||||
|
||||
void push_front(Priority priority, const T& thread_id) {
|
||||
Queue *cur = &queues[priority];
|
||||
Queue* cur = &queues[priority];
|
||||
cur->data.push_front(thread_id);
|
||||
}
|
||||
|
||||
void push_back(Priority priority, const T& thread_id) {
|
||||
Queue *cur = &queues[priority];
|
||||
Queue* cur = &queues[priority];
|
||||
cur->data.push_back(thread_id);
|
||||
}
|
||||
|
||||
|
@ -96,12 +96,12 @@ struct ThreadQueueList {
|
|||
}
|
||||
|
||||
void remove(Priority priority, const T& thread_id) {
|
||||
Queue *cur = &queues[priority];
|
||||
Queue* cur = &queues[priority];
|
||||
boost::remove_erase(cur->data, thread_id);
|
||||
}
|
||||
|
||||
void rotate(Priority priority) {
|
||||
Queue *cur = &queues[priority];
|
||||
Queue* cur = &queues[priority];
|
||||
|
||||
if (cur->data.size() > 1) {
|
||||
cur->data.push_back(std::move(cur->data.front()));
|
||||
|
@ -115,7 +115,7 @@ struct ThreadQueueList {
|
|||
}
|
||||
|
||||
bool empty(Priority priority) const {
|
||||
const Queue *cur = &queues[priority];
|
||||
const Queue* cur = &queues[priority];
|
||||
return cur->data.empty();
|
||||
}
|
||||
|
||||
|
@ -139,7 +139,7 @@ private:
|
|||
}
|
||||
|
||||
void link(Priority priority) {
|
||||
Queue *cur = &queues[priority];
|
||||
Queue* cur = &queues[priority];
|
||||
|
||||
for (int i = priority - 1; i >= 0; --i) {
|
||||
if (queues[i].next_nonempty != UnlinkedTag()) {
|
||||
|
|
|
@ -16,11 +16,9 @@
|
|||
#include "common/string_util.h"
|
||||
#include "common/timer.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
namespace Common {
|
||||
|
||||
u32 Timer::GetTimeMs()
|
||||
{
|
||||
u32 Timer::GetTimeMs() {
|
||||
#ifdef _WIN32
|
||||
return timeGetTime();
|
||||
#else
|
||||
|
@ -35,32 +33,27 @@ u32 Timer::GetTimeMs()
|
|||
// --------------------------------------------
|
||||
|
||||
// Set initial values for the class
|
||||
Timer::Timer()
|
||||
: m_LastTime(0), m_StartTime(0), m_Running(false)
|
||||
{
|
||||
Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) {
|
||||
Update();
|
||||
}
|
||||
|
||||
// Write the starting time
|
||||
void Timer::Start()
|
||||
{
|
||||
void Timer::Start() {
|
||||
m_StartTime = GetTimeMs();
|
||||
m_Running = true;
|
||||
}
|
||||
|
||||
// Stop the timer
|
||||
void Timer::Stop()
|
||||
{
|
||||
void Timer::Stop() {
|
||||
// Write the final time
|
||||
m_LastTime = GetTimeMs();
|
||||
m_Running = false;
|
||||
}
|
||||
|
||||
// Update the last time variable
|
||||
void Timer::Update()
|
||||
{
|
||||
void Timer::Update() {
|
||||
m_LastTime = GetTimeMs();
|
||||
//TODO(ector) - QPF
|
||||
// TODO(ector) - QPF
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
@ -68,34 +61,32 @@ void Timer::Update()
|
|||
// -------------------------------------
|
||||
|
||||
// Get the number of milliseconds since the last Update()
|
||||
u64 Timer::GetTimeDifference()
|
||||
{
|
||||
u64 Timer::GetTimeDifference() {
|
||||
return GetTimeMs() - m_LastTime;
|
||||
}
|
||||
|
||||
// Add the time difference since the last Update() to the starting time.
|
||||
// This is used to compensate for a paused game.
|
||||
void Timer::AddTimeDifference()
|
||||
{
|
||||
void Timer::AddTimeDifference() {
|
||||
m_StartTime += GetTimeDifference();
|
||||
}
|
||||
|
||||
// Get the time elapsed since the Start()
|
||||
u64 Timer::GetTimeElapsed()
|
||||
{
|
||||
u64 Timer::GetTimeElapsed() {
|
||||
// If we have not started yet, return 1 (because then I don't
|
||||
// have to change the FPS calculation in CoreRerecording.cpp .
|
||||
if (m_StartTime == 0) return 1;
|
||||
if (m_StartTime == 0)
|
||||
return 1;
|
||||
|
||||
// Return the final timer time if the timer is stopped
|
||||
if (!m_Running) return (m_LastTime - m_StartTime);
|
||||
if (!m_Running)
|
||||
return (m_LastTime - m_StartTime);
|
||||
|
||||
return (GetTimeMs() - m_StartTime);
|
||||
}
|
||||
|
||||
// Get the formatted time elapsed since the Start()
|
||||
std::string Timer::GetTimeElapsedFormatted() const
|
||||
{
|
||||
std::string Timer::GetTimeElapsedFormatted() const {
|
||||
// If we have not started yet, return zero
|
||||
if (m_StartTime == 0)
|
||||
return "00:00:00:000";
|
||||
|
@ -114,50 +105,46 @@ std::string Timer::GetTimeElapsedFormatted() const
|
|||
// Hours
|
||||
u32 Hours = Minutes / 60;
|
||||
|
||||
std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i",
|
||||
Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000);
|
||||
std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", Hours, Minutes % 60, Seconds % 60,
|
||||
Milliseconds % 1000);
|
||||
return TmpStr;
|
||||
}
|
||||
|
||||
// Get current time
|
||||
void Timer::IncreaseResolution()
|
||||
{
|
||||
void Timer::IncreaseResolution() {
|
||||
#ifdef _WIN32
|
||||
timeBeginPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Timer::RestoreResolution()
|
||||
{
|
||||
void Timer::RestoreResolution() {
|
||||
#ifdef _WIN32
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the number of seconds since January 1 1970
|
||||
u64 Timer::GetTimeSinceJan1970()
|
||||
{
|
||||
u64 Timer::GetTimeSinceJan1970() {
|
||||
time_t ltime;
|
||||
time(<ime);
|
||||
return((u64)ltime);
|
||||
return ((u64)ltime);
|
||||
}
|
||||
|
||||
u64 Timer::GetLocalTimeSinceJan1970()
|
||||
{
|
||||
u64 Timer::GetLocalTimeSinceJan1970() {
|
||||
time_t sysTime, tzDiff, tzDST;
|
||||
struct tm * gmTime;
|
||||
struct tm* gmTime;
|
||||
|
||||
time(&sysTime);
|
||||
|
||||
// Account for DST where needed
|
||||
gmTime = localtime(&sysTime);
|
||||
if(gmTime->tm_isdst == 1)
|
||||
if (gmTime->tm_isdst == 1)
|
||||
tzDST = 3600;
|
||||
else
|
||||
tzDST = 0;
|
||||
|
||||
// Lazy way to get local time in sec
|
||||
gmTime = gmtime(&sysTime);
|
||||
gmTime = gmtime(&sysTime);
|
||||
tzDiff = sysTime - mktime(gmTime);
|
||||
|
||||
return (u64)(sysTime + tzDiff + tzDST);
|
||||
|
@ -165,10 +152,9 @@ u64 Timer::GetLocalTimeSinceJan1970()
|
|||
|
||||
// Return the current time formatted as Minutes:Seconds:Milliseconds
|
||||
// in the form 00:00:000.
|
||||
std::string Timer::GetTimeFormatted()
|
||||
{
|
||||
std::string Timer::GetTimeFormatted() {
|
||||
time_t sysTime;
|
||||
struct tm * gmTime;
|
||||
struct tm* gmTime;
|
||||
char tmp[13];
|
||||
|
||||
time(&sysTime);
|
||||
|
@ -176,7 +162,7 @@ std::string Timer::GetTimeFormatted()
|
|||
|
||||
strftime(tmp, 6, "%M:%S", gmTime);
|
||||
|
||||
// Now tack on the milliseconds
|
||||
// Now tack on the milliseconds
|
||||
#ifdef _WIN32
|
||||
struct timeb tp;
|
||||
(void)::ftime(&tp);
|
||||
|
@ -190,8 +176,7 @@ std::string Timer::GetTimeFormatted()
|
|||
|
||||
// Returns a timestamp with decimals for precise time comparisons
|
||||
// ----------------
|
||||
double Timer::GetDoubleTime()
|
||||
{
|
||||
double Timer::GetDoubleTime() {
|
||||
#ifdef _WIN32
|
||||
struct timeb tp;
|
||||
(void)::ftime(&tp);
|
||||
|
|
|
@ -4,13 +4,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Common
|
||||
{
|
||||
class Timer
|
||||
{
|
||||
namespace Common {
|
||||
class Timer {
|
||||
public:
|
||||
Timer();
|
||||
|
||||
|
@ -18,7 +16,8 @@ public:
|
|||
void Stop();
|
||||
void Update();
|
||||
|
||||
// The time difference is always returned in milliseconds, regardless of alternative internal representation
|
||||
// The time difference is always returned in milliseconds, regardless of alternative internal
|
||||
// representation
|
||||
u64 GetTimeDifference();
|
||||
void AddTimeDifference();
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
// Copyright 2014 Tony Wasserka
|
||||
// All rights reserved.
|
||||
//
|
||||
|
@ -36,158 +35,178 @@
|
|||
|
||||
namespace Math {
|
||||
|
||||
template<typename T> class Vec2;
|
||||
template<typename T> class Vec3;
|
||||
template<typename T> class Vec4;
|
||||
template <typename T>
|
||||
class Vec2;
|
||||
template <typename T>
|
||||
class Vec3;
|
||||
template <typename T>
|
||||
class Vec4;
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static inline Vec2<T> MakeVec(const T& x, const T& y);
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z);
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w);
|
||||
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
class Vec2 {
|
||||
public:
|
||||
T x;
|
||||
T y;
|
||||
|
||||
T* AsArray() { return &x; }
|
||||
T* AsArray() {
|
||||
return &x;
|
||||
}
|
||||
|
||||
Vec2() = default;
|
||||
Vec2(const T a[2]) : x(a[0]), y(a[1]) {}
|
||||
Vec2(const T& _x, const T& _y) : x(_x), y(_y) {}
|
||||
Vec2(const T a[2]) : x(a[0]), y(a[1]) {
|
||||
}
|
||||
Vec2(const T& _x, const T& _y) : x(_x), y(_y) {
|
||||
}
|
||||
|
||||
template<typename T2>
|
||||
template <typename T2>
|
||||
Vec2<T2> Cast() const {
|
||||
return Vec2<T2>((T2)x, (T2)y);
|
||||
}
|
||||
|
||||
static Vec2 AssignToAll(const T& f)
|
||||
{
|
||||
static Vec2 AssignToAll(const T& f) {
|
||||
return Vec2<T>(f, f);
|
||||
}
|
||||
|
||||
void Write(T a[2])
|
||||
{
|
||||
a[0] = x; a[1] = y;
|
||||
void Write(T a[2]) {
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
}
|
||||
|
||||
Vec2<decltype(T{}+T{})> operator +(const Vec2& other) const
|
||||
{
|
||||
return MakeVec(x+other.x, y+other.y);
|
||||
Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
|
||||
return MakeVec(x + other.x, y + other.y);
|
||||
}
|
||||
void operator += (const Vec2 &other)
|
||||
{
|
||||
x+=other.x; y+=other.y;
|
||||
void operator+=(const Vec2& other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
}
|
||||
Vec2<decltype(T{}-T{})> operator -(const Vec2& other) const
|
||||
{
|
||||
return MakeVec(x-other.x, y-other.y);
|
||||
Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
|
||||
return MakeVec(x - other.x, y - other.y);
|
||||
}
|
||||
void operator -= (const Vec2& other)
|
||||
{
|
||||
x-=other.x; y-=other.y;
|
||||
void operator-=(const Vec2& other) {
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
}
|
||||
template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type>
|
||||
Vec2<decltype(-T{})> operator -() const
|
||||
{
|
||||
return MakeVec(-x,-y);
|
||||
template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
|
||||
Vec2<decltype(-T{})> operator-() const {
|
||||
return MakeVec(-x, -y);
|
||||
}
|
||||
Vec2<decltype(T{}*T{})> operator * (const Vec2& other) const
|
||||
{
|
||||
return MakeVec(x*other.x, y*other.y);
|
||||
Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
|
||||
return MakeVec(x * other.x, y * other.y);
|
||||
}
|
||||
template<typename V>
|
||||
Vec2<decltype(T{}*V{})> operator * (const V& f) const
|
||||
{
|
||||
return MakeVec(x*f,y*f);
|
||||
template <typename V>
|
||||
Vec2<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return MakeVec(x * f, y * f);
|
||||
}
|
||||
template<typename V>
|
||||
void operator *= (const V& f)
|
||||
{
|
||||
x*=f; y*=f;
|
||||
template <typename V>
|
||||
void operator*=(const V& f) {
|
||||
x *= f;
|
||||
y *= f;
|
||||
}
|
||||
template<typename V>
|
||||
Vec2<decltype(T{}/V{})> operator / (const V& f) const
|
||||
{
|
||||
return MakeVec(x/f,y/f);
|
||||
template <typename V>
|
||||
Vec2<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return MakeVec(x / f, y / f);
|
||||
}
|
||||
template<typename V>
|
||||
void operator /= (const V& f)
|
||||
{
|
||||
template <typename V>
|
||||
void operator/=(const V& f) {
|
||||
*this = *this / f;
|
||||
}
|
||||
|
||||
T Length2() const
|
||||
{
|
||||
return x*x + y*y;
|
||||
T Length2() const {
|
||||
return x * x + y * y;
|
||||
}
|
||||
|
||||
// Only implemented for T=float
|
||||
float Length() const;
|
||||
void SetLength(const float l);
|
||||
Vec2 WithLength(const float l) const;
|
||||
float Distance2To(Vec2 &other);
|
||||
float Distance2To(Vec2& other);
|
||||
Vec2 Normalized() const;
|
||||
float Normalize(); // returns the previous length, which is often useful
|
||||
|
||||
T& operator [] (int i) //allow vector[1] = 3 (vector.y=3)
|
||||
T& operator[](int i) // allow vector[1] = 3 (vector.y=3)
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
T operator [] (const int i) const
|
||||
{
|
||||
T operator[](const int i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
void SetZero()
|
||||
{
|
||||
x=0; y=0;
|
||||
void SetZero() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
// Common aliases: UV (texel coordinates), ST (texture coordinates)
|
||||
T& u() { return x; }
|
||||
T& v() { return y; }
|
||||
T& s() { return x; }
|
||||
T& t() { return y; }
|
||||
T& u() {
|
||||
return x;
|
||||
}
|
||||
T& v() {
|
||||
return y;
|
||||
}
|
||||
T& s() {
|
||||
return x;
|
||||
}
|
||||
T& t() {
|
||||
return y;
|
||||
}
|
||||
|
||||
const T& u() const { return x; }
|
||||
const T& v() const { return y; }
|
||||
const T& s() const { return x; }
|
||||
const T& t() const { return y; }
|
||||
const T& u() const {
|
||||
return x;
|
||||
}
|
||||
const T& v() const {
|
||||
return y;
|
||||
}
|
||||
const T& s() const {
|
||||
return x;
|
||||
}
|
||||
const T& t() const {
|
||||
return y;
|
||||
}
|
||||
|
||||
// swizzlers - create a subvector of specific components
|
||||
const Vec2 yx() const { return Vec2(y, x); }
|
||||
const Vec2 vu() const { return Vec2(y, x); }
|
||||
const Vec2 ts() const { return Vec2(y, x); }
|
||||
const Vec2 yx() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
const Vec2 vu() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
const Vec2 ts() const {
|
||||
return Vec2(y, x);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename V>
|
||||
Vec2<T> operator * (const V& f, const Vec2<T>& vec)
|
||||
{
|
||||
return Vec2<T>(f*vec.x,f*vec.y);
|
||||
template <typename T, typename V>
|
||||
Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
|
||||
return Vec2<T>(f * vec.x, f * vec.y);
|
||||
}
|
||||
|
||||
typedef Vec2<float> Vec2f;
|
||||
|
||||
template<typename T>
|
||||
class Vec3
|
||||
{
|
||||
template <typename T>
|
||||
class Vec3 {
|
||||
public:
|
||||
T x;
|
||||
T y;
|
||||
T z;
|
||||
|
||||
T* AsArray() { return &x; }
|
||||
T* AsArray() {
|
||||
return &x;
|
||||
}
|
||||
|
||||
Vec3() = default;
|
||||
Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {}
|
||||
Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {}
|
||||
Vec3(const T a[3]) : x(a[0]), y(a[1]), z(a[2]) {
|
||||
}
|
||||
Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {
|
||||
}
|
||||
|
||||
template<typename T2>
|
||||
template <typename T2>
|
||||
Vec3<T2> Cast() const {
|
||||
return MakeVec<T2>((T2)x, (T2)y, (T2)z);
|
||||
}
|
||||
|
@ -196,126 +215,161 @@ public:
|
|||
static Vec3 FromRGB(unsigned int rgb);
|
||||
unsigned int ToRGB() const; // alpha bits set to zero
|
||||
|
||||
static Vec3 AssignToAll(const T& f)
|
||||
{
|
||||
static Vec3 AssignToAll(const T& f) {
|
||||
return MakeVec(f, f, f);
|
||||
}
|
||||
|
||||
void Write(T a[3])
|
||||
{
|
||||
a[0] = x; a[1] = y; a[2] = z;
|
||||
void Write(T a[3]) {
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
a[2] = z;
|
||||
}
|
||||
|
||||
Vec3<decltype(T{}+T{})> operator +(const Vec3 &other) const
|
||||
{
|
||||
return MakeVec(x+other.x, y+other.y, z+other.z);
|
||||
Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
|
||||
return MakeVec(x + other.x, y + other.y, z + other.z);
|
||||
}
|
||||
void operator += (const Vec3 &other)
|
||||
{
|
||||
x+=other.x; y+=other.y; z+=other.z;
|
||||
void operator+=(const Vec3& other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
}
|
||||
Vec3<decltype(T{}-T{})> operator -(const Vec3 &other) const
|
||||
{
|
||||
return MakeVec(x-other.x, y-other.y, z-other.z);
|
||||
Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
|
||||
return MakeVec(x - other.x, y - other.y, z - other.z);
|
||||
}
|
||||
void operator -= (const Vec3 &other)
|
||||
{
|
||||
x-=other.x; y-=other.y; z-=other.z;
|
||||
void operator-=(const Vec3& other) {
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
}
|
||||
template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type>
|
||||
Vec3<decltype(-T{})> operator -() const
|
||||
{
|
||||
return MakeVec(-x,-y,-z);
|
||||
template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
|
||||
Vec3<decltype(-T{})> operator-() const {
|
||||
return MakeVec(-x, -y, -z);
|
||||
}
|
||||
Vec3<decltype(T{}*T{})> operator * (const Vec3 &other) const
|
||||
{
|
||||
return MakeVec(x*other.x, y*other.y, z*other.z);
|
||||
Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
|
||||
return MakeVec(x * other.x, y * other.y, z * other.z);
|
||||
}
|
||||
template<typename V>
|
||||
Vec3<decltype(T{}*V{})> operator * (const V& f) const
|
||||
{
|
||||
return MakeVec(x*f,y*f,z*f);
|
||||
template <typename V>
|
||||
Vec3<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return MakeVec(x * f, y * f, z * f);
|
||||
}
|
||||
template<typename V>
|
||||
void operator *= (const V& f)
|
||||
{
|
||||
x*=f; y*=f; z*=f;
|
||||
template <typename V>
|
||||
void operator*=(const V& f) {
|
||||
x *= f;
|
||||
y *= f;
|
||||
z *= f;
|
||||
}
|
||||
template<typename V>
|
||||
Vec3<decltype(T{}/V{})> operator / (const V& f) const
|
||||
{
|
||||
return MakeVec(x/f,y/f,z/f);
|
||||
template <typename V>
|
||||
Vec3<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return MakeVec(x / f, y / f, z / f);
|
||||
}
|
||||
template<typename V>
|
||||
void operator /= (const V& f)
|
||||
{
|
||||
template <typename V>
|
||||
void operator/=(const V& f) {
|
||||
*this = *this / f;
|
||||
}
|
||||
|
||||
T Length2() const
|
||||
{
|
||||
return x*x + y*y + z*z;
|
||||
T Length2() const {
|
||||
return x * x + y * y + z * z;
|
||||
}
|
||||
|
||||
// Only implemented for T=float
|
||||
float Length() const;
|
||||
void SetLength(const float l);
|
||||
Vec3 WithLength(const float l) const;
|
||||
float Distance2To(Vec3 &other);
|
||||
float Distance2To(Vec3& other);
|
||||
Vec3 Normalized() const;
|
||||
float Normalize(); // returns the previous length, which is often useful
|
||||
|
||||
T& operator [] (int i) //allow vector[2] = 3 (vector.z=3)
|
||||
T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
T operator [] (const int i) const
|
||||
{
|
||||
T operator[](const int i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
void SetZero()
|
||||
{
|
||||
x=0; y=0; z=0;
|
||||
void SetZero() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
}
|
||||
|
||||
// Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
|
||||
T& u() { return x; }
|
||||
T& v() { return y; }
|
||||
T& w() { return z; }
|
||||
T& u() {
|
||||
return x;
|
||||
}
|
||||
T& v() {
|
||||
return y;
|
||||
}
|
||||
T& w() {
|
||||
return z;
|
||||
}
|
||||
|
||||
T& r() { return x; }
|
||||
T& g() { return y; }
|
||||
T& b() { return z; }
|
||||
T& r() {
|
||||
return x;
|
||||
}
|
||||
T& g() {
|
||||
return y;
|
||||
}
|
||||
T& b() {
|
||||
return z;
|
||||
}
|
||||
|
||||
T& s() { return x; }
|
||||
T& t() { return y; }
|
||||
T& q() { return z; }
|
||||
T& s() {
|
||||
return x;
|
||||
}
|
||||
T& t() {
|
||||
return y;
|
||||
}
|
||||
T& q() {
|
||||
return z;
|
||||
}
|
||||
|
||||
const T& u() const { return x; }
|
||||
const T& v() const { return y; }
|
||||
const T& w() const { return z; }
|
||||
const T& u() const {
|
||||
return x;
|
||||
}
|
||||
const T& v() const {
|
||||
return y;
|
||||
}
|
||||
const T& w() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
const T& r() const { return x; }
|
||||
const T& g() const { return y; }
|
||||
const T& b() const { return z; }
|
||||
const T& r() const {
|
||||
return x;
|
||||
}
|
||||
const T& g() const {
|
||||
return y;
|
||||
}
|
||||
const T& b() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
const T& s() const { return x; }
|
||||
const T& t() const { return y; }
|
||||
const T& q() const { return z; }
|
||||
const T& s() const {
|
||||
return x;
|
||||
}
|
||||
const T& t() const {
|
||||
return y;
|
||||
}
|
||||
const T& q() const {
|
||||
return z;
|
||||
}
|
||||
|
||||
// swizzlers - create a subvector of specific components
|
||||
// e.g. Vec2 uv() { return Vec2(x,y); }
|
||||
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all component names (x<->r) and permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); }
|
||||
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
|
||||
_DEFINE_SWIZZLER2(a, b, a##b); \
|
||||
_DEFINE_SWIZZLER2(a, b, a2##b2); \
|
||||
_DEFINE_SWIZZLER2(a, b, a3##b3); \
|
||||
_DEFINE_SWIZZLER2(a, b, a4##b4); \
|
||||
_DEFINE_SWIZZLER2(b, a, b##a); \
|
||||
_DEFINE_SWIZZLER2(b, a, b2##a2); \
|
||||
_DEFINE_SWIZZLER2(b, a, b3##a3); \
|
||||
// swizzlers - create a subvector of specific components
|
||||
// e.g. Vec2 uv() { return Vec2(x,y); }
|
||||
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
|
||||
// component names (x<->r) and permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) \
|
||||
const Vec2<T> name() const { \
|
||||
return Vec2<T>(a, b); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
|
||||
_DEFINE_SWIZZLER2(a, b, a##b); \
|
||||
_DEFINE_SWIZZLER2(a, b, a2##b2); \
|
||||
_DEFINE_SWIZZLER2(a, b, a3##b3); \
|
||||
_DEFINE_SWIZZLER2(a, b, a4##b4); \
|
||||
_DEFINE_SWIZZLER2(b, a, b##a); \
|
||||
_DEFINE_SWIZZLER2(b, a, b2##a2); \
|
||||
_DEFINE_SWIZZLER2(b, a, b3##a3); \
|
||||
_DEFINE_SWIZZLER2(b, a, b4##a4)
|
||||
|
||||
DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t);
|
||||
|
@ -325,41 +379,42 @@ public:
|
|||
#undef _DEFINE_SWIZZLER2
|
||||
};
|
||||
|
||||
template<typename T, typename V>
|
||||
Vec3<T> operator * (const V& f, const Vec3<T>& vec)
|
||||
{
|
||||
return Vec3<T>(f*vec.x,f*vec.y,f*vec.z);
|
||||
template <typename T, typename V>
|
||||
Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
|
||||
return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline float Vec3<float>::Length() const {
|
||||
return std::sqrt(x * x + y * y + z * z);
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
inline Vec3<float> Vec3<float>::Normalized() const {
|
||||
return *this / Length();
|
||||
}
|
||||
|
||||
|
||||
typedef Vec3<float> Vec3f;
|
||||
|
||||
template<typename T>
|
||||
class Vec4
|
||||
{
|
||||
template <typename T>
|
||||
class Vec4 {
|
||||
public:
|
||||
T x;
|
||||
T y;
|
||||
T z;
|
||||
T w;
|
||||
|
||||
T* AsArray() { return &x; }
|
||||
T* AsArray() {
|
||||
return &x;
|
||||
}
|
||||
|
||||
Vec4() = default;
|
||||
Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {}
|
||||
Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {}
|
||||
Vec4(const T a[4]) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {
|
||||
}
|
||||
Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {
|
||||
}
|
||||
|
||||
template<typename T2>
|
||||
template <typename T2>
|
||||
Vec4<T2> Cast() const {
|
||||
return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w);
|
||||
}
|
||||
|
@ -372,81 +427,79 @@ public:
|
|||
return Vec4<T>(f, f, f, f);
|
||||
}
|
||||
|
||||
void Write(T a[4])
|
||||
{
|
||||
a[0] = x; a[1] = y; a[2] = z; a[3] = w;
|
||||
void Write(T a[4]) {
|
||||
a[0] = x;
|
||||
a[1] = y;
|
||||
a[2] = z;
|
||||
a[3] = w;
|
||||
}
|
||||
|
||||
Vec4<decltype(T{}+T{})> operator +(const Vec4& other) const
|
||||
{
|
||||
return MakeVec(x+other.x, y+other.y, z+other.z, w+other.w);
|
||||
Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
|
||||
return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w);
|
||||
}
|
||||
void operator += (const Vec4& other)
|
||||
{
|
||||
x+=other.x; y+=other.y; z+=other.z; w+=other.w;
|
||||
void operator+=(const Vec4& other) {
|
||||
x += other.x;
|
||||
y += other.y;
|
||||
z += other.z;
|
||||
w += other.w;
|
||||
}
|
||||
Vec4<decltype(T{}-T{})> operator -(const Vec4 &other) const
|
||||
{
|
||||
return MakeVec(x-other.x, y-other.y, z-other.z, w-other.w);
|
||||
Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
|
||||
return MakeVec(x - other.x, y - other.y, z - other.z, w - other.w);
|
||||
}
|
||||
void operator -= (const Vec4 &other)
|
||||
{
|
||||
x-=other.x; y-=other.y; z-=other.z; w-=other.w;
|
||||
void operator-=(const Vec4& other) {
|
||||
x -= other.x;
|
||||
y -= other.y;
|
||||
z -= other.z;
|
||||
w -= other.w;
|
||||
}
|
||||
template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type>
|
||||
Vec4<decltype(-T{})> operator -() const
|
||||
{
|
||||
return MakeVec(-x,-y,-z,-w);
|
||||
template <typename Q = T, class = typename std::enable_if<std::is_signed<Q>::value>::type>
|
||||
Vec4<decltype(-T{})> operator-() const {
|
||||
return MakeVec(-x, -y, -z, -w);
|
||||
}
|
||||
Vec4<decltype(T{}*T{})> operator * (const Vec4 &other) const
|
||||
{
|
||||
return MakeVec(x*other.x, y*other.y, z*other.z, w*other.w);
|
||||
Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
|
||||
return MakeVec(x * other.x, y * other.y, z * other.z, w * other.w);
|
||||
}
|
||||
template<typename V>
|
||||
Vec4<decltype(T{}*V{})> operator * (const V& f) const
|
||||
{
|
||||
return MakeVec(x*f,y*f,z*f,w*f);
|
||||
template <typename V>
|
||||
Vec4<decltype(T{} * V{})> operator*(const V& f) const {
|
||||
return MakeVec(x * f, y * f, z * f, w * f);
|
||||
}
|
||||
template<typename V>
|
||||
void operator *= (const V& f)
|
||||
{
|
||||
x*=f; y*=f; z*=f; w*=f;
|
||||
template <typename V>
|
||||
void operator*=(const V& f) {
|
||||
x *= f;
|
||||
y *= f;
|
||||
z *= f;
|
||||
w *= f;
|
||||
}
|
||||
template<typename V>
|
||||
Vec4<decltype(T{}/V{})> operator / (const V& f) const
|
||||
{
|
||||
return MakeVec(x/f,y/f,z/f,w/f);
|
||||
template <typename V>
|
||||
Vec4<decltype(T{} / V{})> operator/(const V& f) const {
|
||||
return MakeVec(x / f, y / f, z / f, w / f);
|
||||
}
|
||||
template<typename V>
|
||||
void operator /= (const V& f)
|
||||
{
|
||||
template <typename V>
|
||||
void operator/=(const V& f) {
|
||||
*this = *this / f;
|
||||
}
|
||||
|
||||
T Length2() const
|
||||
{
|
||||
return x*x + y*y + z*z + w*w;
|
||||
T Length2() const {
|
||||
return x * x + y * y + z * z + w * w;
|
||||
}
|
||||
|
||||
// Only implemented for T=float
|
||||
float Length() const;
|
||||
void SetLength(const float l);
|
||||
Vec4 WithLength(const float l) const;
|
||||
float Distance2To(Vec4 &other);
|
||||
float Distance2To(Vec4& other);
|
||||
Vec4 Normalized() const;
|
||||
float Normalize(); // returns the previous length, which is often useful
|
||||
|
||||
T& operator [] (int i) //allow vector[2] = 3 (vector.z=3)
|
||||
T& operator[](int i) // allow vector[2] = 3 (vector.z=3)
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
T operator [] (const int i) const
|
||||
{
|
||||
T operator[](const int i) const {
|
||||
return *((&x) + i);
|
||||
}
|
||||
|
||||
void SetZero()
|
||||
{
|
||||
void SetZero() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
|
@ -454,30 +507,50 @@ public:
|
|||
}
|
||||
|
||||
// Common alias: RGBA (colors)
|
||||
T& r() { return x; }
|
||||
T& g() { return y; }
|
||||
T& b() { return z; }
|
||||
T& a() { return w; }
|
||||
T& r() {
|
||||
return x;
|
||||
}
|
||||
T& g() {
|
||||
return y;
|
||||
}
|
||||
T& b() {
|
||||
return z;
|
||||
}
|
||||
T& a() {
|
||||
return w;
|
||||
}
|
||||
|
||||
const T& r() const { return x; }
|
||||
const T& g() const { return y; }
|
||||
const T& b() const { return z; }
|
||||
const T& a() const { return w; }
|
||||
const T& r() const {
|
||||
return x;
|
||||
}
|
||||
const T& g() const {
|
||||
return y;
|
||||
}
|
||||
const T& b() const {
|
||||
return z;
|
||||
}
|
||||
const T& a() const {
|
||||
return w;
|
||||
}
|
||||
|
||||
// Swizzlers - Create a subvector of specific components
|
||||
// e.g. Vec2 uv() { return Vec2(x,y); }
|
||||
// Swizzlers - Create a subvector of specific components
|
||||
// e.g. Vec2 uv() { return Vec2(x,y); }
|
||||
|
||||
// _DEFINE_SWIZZLER2 defines a single such function
|
||||
// DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
|
||||
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); }
|
||||
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
|
||||
_DEFINE_SWIZZLER2(a, a, a##a); \
|
||||
// _DEFINE_SWIZZLER2 defines a single such function
|
||||
// DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
|
||||
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
|
||||
// permutations (xy<->yx)
|
||||
#define _DEFINE_SWIZZLER2(a, b, name) \
|
||||
const Vec2<T> name() const { \
|
||||
return Vec2<T>(a, b); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
|
||||
_DEFINE_SWIZZLER2(a, a, a##a); \
|
||||
_DEFINE_SWIZZLER2(a, a, a2##a2)
|
||||
#define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \
|
||||
_DEFINE_SWIZZLER2(a, b, a##b); \
|
||||
_DEFINE_SWIZZLER2(a, b, a2##b2); \
|
||||
_DEFINE_SWIZZLER2(b, a, b##a); \
|
||||
#define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \
|
||||
_DEFINE_SWIZZLER2(a, b, a##b); \
|
||||
_DEFINE_SWIZZLER2(a, b, a2##b2); \
|
||||
_DEFINE_SWIZZLER2(b, a, b##a); \
|
||||
_DEFINE_SWIZZLER2(b, a, b2##a2)
|
||||
|
||||
DEFINE_SWIZZLER2_COMP2(x, y, r, g);
|
||||
|
@ -494,22 +567,25 @@ public:
|
|||
#undef DEFINE_SWIZZLER2_COMP2
|
||||
#undef _DEFINE_SWIZZLER2
|
||||
|
||||
#define _DEFINE_SWIZZLER3(a, b, c, name) const Vec3<T> name() const { return Vec3<T>(a, b, c); }
|
||||
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
|
||||
_DEFINE_SWIZZLER3(a, a, a, a##a##a); \
|
||||
#define _DEFINE_SWIZZLER3(a, b, c, name) \
|
||||
const Vec3<T> name() const { \
|
||||
return Vec3<T>(a, b, c); \
|
||||
}
|
||||
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
|
||||
_DEFINE_SWIZZLER3(a, a, a, a##a##a); \
|
||||
_DEFINE_SWIZZLER3(a, a, a, a2##a2##a2)
|
||||
#define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \
|
||||
_DEFINE_SWIZZLER3(a, b, c, a##b##c); \
|
||||
_DEFINE_SWIZZLER3(a, c, b, a##c##b); \
|
||||
_DEFINE_SWIZZLER3(b, a, c, b##a##c); \
|
||||
_DEFINE_SWIZZLER3(b, c, a, b##c##a); \
|
||||
_DEFINE_SWIZZLER3(c, a, b, c##a##b); \
|
||||
_DEFINE_SWIZZLER3(c, b, a, c##b##a); \
|
||||
_DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \
|
||||
_DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \
|
||||
_DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \
|
||||
_DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \
|
||||
_DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \
|
||||
#define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \
|
||||
_DEFINE_SWIZZLER3(a, b, c, a##b##c); \
|
||||
_DEFINE_SWIZZLER3(a, c, b, a##c##b); \
|
||||
_DEFINE_SWIZZLER3(b, a, c, b##a##c); \
|
||||
_DEFINE_SWIZZLER3(b, c, a, b##c##a); \
|
||||
_DEFINE_SWIZZLER3(c, a, b, c##a##b); \
|
||||
_DEFINE_SWIZZLER3(c, b, a, c##b##a); \
|
||||
_DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \
|
||||
_DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \
|
||||
_DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \
|
||||
_DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \
|
||||
_DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \
|
||||
_DEFINE_SWIZZLER3(c, b, a, c2##b2##a2)
|
||||
|
||||
DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b);
|
||||
|
@ -525,123 +601,104 @@ public:
|
|||
#undef _DEFINE_SWIZZLER3
|
||||
};
|
||||
|
||||
|
||||
template<typename T, typename V>
|
||||
Vec4<decltype(V{}*T{})> operator * (const V& f, const Vec4<T>& vec)
|
||||
{
|
||||
return MakeVec(f*vec.x,f*vec.y,f*vec.z,f*vec.w);
|
||||
template <typename T, typename V>
|
||||
Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
|
||||
return MakeVec(f * vec.x, f * vec.y, f * vec.z, f * vec.w);
|
||||
}
|
||||
|
||||
typedef Vec4<float> Vec4f;
|
||||
|
||||
|
||||
template<typename T>
|
||||
static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec2<T>& a, const Vec2<T>& b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y;
|
||||
template <typename T>
|
||||
static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
|
||||
return a.x * b.x + a.y * b.y;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec3<T>& a, const Vec3<T>& b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||
template <typename T>
|
||||
static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline decltype(T{}*T{}+T{}*T{}) Dot(const Vec4<T>& a, const Vec4<T>& b)
|
||||
{
|
||||
return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
|
||||
template <typename T>
|
||||
static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec3<decltype(T{}*T{}-T{}*T{})> Cross(const Vec3<T>& a, const Vec3<T>& b)
|
||||
{
|
||||
return MakeVec(a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);
|
||||
template <typename T>
|
||||
static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
|
||||
return MakeVec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
|
||||
}
|
||||
|
||||
// linear interpolation via float: 0.0=begin, 1.0=end
|
||||
template<typename X>
|
||||
static inline decltype(X{}*float{}+X{}*float{}) Lerp(const X& begin, const X& end, const float t)
|
||||
{
|
||||
return begin*(1.f-t) + end*t;
|
||||
template <typename X>
|
||||
static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
|
||||
const float t) {
|
||||
return begin * (1.f - t) + end * t;
|
||||
}
|
||||
|
||||
// linear interpolation via int: 0=begin, base=end
|
||||
template<typename X, int base>
|
||||
static inline decltype((X{}*int{}+X{}*int{}) / base) LerpInt(const X& begin, const X& end, const int t)
|
||||
{
|
||||
return (begin*(base-t) + end*t) / base;
|
||||
template <typename X, int base>
|
||||
static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
|
||||
const int t) {
|
||||
return (begin * (base - t) + end * t) / base;
|
||||
}
|
||||
|
||||
// Utility vector factories
|
||||
template<typename T>
|
||||
static inline Vec2<T> MakeVec(const T& x, const T& y)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec2<T> MakeVec(const T& x, const T& y) {
|
||||
return Vec2<T>{x, y};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
|
||||
return Vec3<T>{x, y, z};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
|
||||
return MakeVec(x, y, zw[0], zw[1]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
|
||||
return MakeVec(xy[0], xy[1], z);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
|
||||
return MakeVec(x, yz[0], yz[1]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
|
||||
return Vec4<T>{x, y, z, w};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
|
||||
return MakeVec(xy[0], xy[1], z, w);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
|
||||
return MakeVec(x, yz[0], yz[1], w);
|
||||
}
|
||||
|
||||
// NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)".
|
||||
// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
|
||||
// out soon enough due to misuse of the returned structure.
|
||||
template<typename T>
|
||||
static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
|
||||
return MakeVec(xy[0], xy[1], zw[0], zw[1]);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
|
||||
return MakeVec(xyz[0], xyz[1], xyz[2], w);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw)
|
||||
{
|
||||
template <typename T>
|
||||
static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
|
||||
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
|
||||
}
|
||||
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -22,7 +22,8 @@ using namespace Gen;
|
|||
|
||||
// Shared code between Win64 and Unix64
|
||||
|
||||
void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) {
|
||||
void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size,
|
||||
size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp) {
|
||||
size_t shadow = 0;
|
||||
#if defined(_WIN32)
|
||||
shadow = 0x20;
|
||||
|
@ -49,17 +50,19 @@ void XEmitter::ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_
|
|||
*xmm_offsetp = subtraction - xmm_base_subtraction;
|
||||
}
|
||||
|
||||
size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) {
|
||||
size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
|
||||
size_t needed_frame_size) {
|
||||
size_t shadow, subtraction, xmm_offset;
|
||||
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset);
|
||||
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction,
|
||||
&xmm_offset);
|
||||
|
||||
for (int r : mask & ABI_ALL_GPRS)
|
||||
for (int r : mask& ABI_ALL_GPRS)
|
||||
PUSH((X64Reg)r);
|
||||
|
||||
if (subtraction)
|
||||
SUB(64, R(RSP), subtraction >= 0x80 ? Imm32((u32)subtraction) : Imm8((u8)subtraction));
|
||||
|
||||
for (int x : mask & ABI_ALL_FPRS) {
|
||||
for (int x : mask& ABI_ALL_FPRS) {
|
||||
MOVAPD(MDisp(RSP, (int)xmm_offset), (X64Reg)(x - 16));
|
||||
xmm_offset += 16;
|
||||
}
|
||||
|
@ -67,12 +70,14 @@ size_t XEmitter::ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_align
|
|||
return shadow;
|
||||
}
|
||||
|
||||
void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size) {
|
||||
void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
|
||||
size_t needed_frame_size) {
|
||||
size_t shadow, subtraction, xmm_offset;
|
||||
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction, &xmm_offset);
|
||||
ABI_CalculateFrameSize(mask, rsp_alignment, needed_frame_size, &shadow, &subtraction,
|
||||
&xmm_offset);
|
||||
|
||||
for (int x : mask & ABI_ALL_FPRS) {
|
||||
MOVAPD((X64Reg) (x - 16), MDisp(RSP, (int)xmm_offset));
|
||||
for (int x : mask& ABI_ALL_FPRS) {
|
||||
MOVAPD((X64Reg)(x - 16), MDisp(RSP, (int)xmm_offset));
|
||||
xmm_offset += 16;
|
||||
}
|
||||
|
||||
|
@ -86,10 +91,9 @@ void XEmitter::ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignmen
|
|||
}
|
||||
|
||||
// Common functions
|
||||
void XEmitter::ABI_CallFunction(const void *func) {
|
||||
void XEmitter::ABI_CallFunction(const void* func) {
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -98,11 +102,10 @@ void XEmitter::ABI_CallFunction(const void *func) {
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) {
|
||||
void XEmitter::ABI_CallFunctionC16(const void* func, u16 param1) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32((u32)param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -111,25 +114,11 @@ void XEmitter::ABI_CallFunctionC16(const void *func, u16 param1) {
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC16(const void *func, u32 param1, u16 param2) {
|
||||
void XEmitter::ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32((u32)param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -138,12 +127,23 @@ void XEmitter::ABI_CallFunctionC(const void *func, u32 param1) {
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) {
|
||||
void XEmitter::ABI_CallFunctionC(const void* func, u32 param1) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
} else {
|
||||
CALL(func);
|
||||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCC(const void* func, u32 param1, u32 param2) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -152,13 +152,12 @@ void XEmitter::ABI_CallFunctionCC(const void *func, u32 param1, u32 param2) {
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32 param3) {
|
||||
void XEmitter::ABI_CallFunctionCCC(const void* func, u32 param1, u32 param2, u32 param3) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -167,13 +166,12 @@ void XEmitter::ABI_CallFunctionCCC(const void *func, u32 param1, u32 param2, u32
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, void *param3) {
|
||||
void XEmitter::ABI_CallFunctionCCP(const void* func, u32 param1, u32 param2, void* param3) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(64, R(ABI_PARAM3), ImmPtr(param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -182,14 +180,14 @@ void XEmitter::ABI_CallFunctionCCP(const void *func, u32 param1, u32 param2, voi
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u32 param3, void *param4) {
|
||||
void XEmitter::ABI_CallFunctionCCCP(const void* func, u32 param1, u32 param2, u32 param3,
|
||||
void* param4) {
|
||||
MOV(32, R(ABI_PARAM1), Imm32(param1));
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
MOV(64, R(ABI_PARAM4), ImmPtr(param4));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -198,11 +196,10 @@ void XEmitter::ABI_CallFunctionCCCP(const void *func, u32 param1, u32 param2, u3
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionP(const void *func, void *param1) {
|
||||
void XEmitter::ABI_CallFunctionP(const void* func, void* param1) {
|
||||
MOV(64, R(ABI_PARAM1), ImmPtr(param1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -211,13 +208,12 @@ void XEmitter::ABI_CallFunctionP(const void *func, void *param1) {
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpArg &arg2) {
|
||||
void XEmitter::ABI_CallFunctionPA(const void* func, void* param1, const Gen::OpArg& arg2) {
|
||||
MOV(64, R(ABI_PARAM1), ImmPtr(param1));
|
||||
if (!arg2.IsSimpleReg(ABI_PARAM2))
|
||||
MOV(32, R(ABI_PARAM2), arg2);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -226,15 +222,15 @@ void XEmitter::ABI_CallFunctionPA(const void *func, void *param1, const Gen::OpA
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::OpArg &arg2, const Gen::OpArg &arg3) {
|
||||
void XEmitter::ABI_CallFunctionPAA(const void* func, void* param1, const Gen::OpArg& arg2,
|
||||
const Gen::OpArg& arg3) {
|
||||
MOV(64, R(ABI_PARAM1), ImmPtr(param1));
|
||||
if (!arg2.IsSimpleReg(ABI_PARAM2))
|
||||
MOV(32, R(ABI_PARAM2), arg2);
|
||||
if (!arg3.IsSimpleReg(ABI_PARAM3))
|
||||
MOV(32, R(ABI_PARAM3), arg3);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -243,13 +239,12 @@ void XEmitter::ABI_CallFunctionPAA(const void *func, void *param1, const Gen::Op
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2, u32 param3) {
|
||||
void XEmitter::ABI_CallFunctionPPC(const void* func, void* param1, void* param2, u32 param3) {
|
||||
MOV(64, R(ABI_PARAM1), ImmPtr(param1));
|
||||
MOV(64, R(ABI_PARAM2), ImmPtr(param2));
|
||||
MOV(32, R(ABI_PARAM3), Imm32(param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -259,12 +254,11 @@ void XEmitter::ABI_CallFunctionPPC(const void *func, void *param1, void *param2,
|
|||
}
|
||||
|
||||
// Pass a register as a parameter.
|
||||
void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) {
|
||||
void XEmitter::ABI_CallFunctionR(const void* func, X64Reg reg1) {
|
||||
if (reg1 != ABI_PARAM1)
|
||||
MOV(32, R(ABI_PARAM1), R(reg1));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -274,7 +268,7 @@ void XEmitter::ABI_CallFunctionR(const void *func, X64Reg reg1) {
|
|||
}
|
||||
|
||||
// Pass two registers as parameters.
|
||||
void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) {
|
||||
void XEmitter::ABI_CallFunctionRR(const void* func, X64Reg reg1, X64Reg reg2) {
|
||||
if (reg2 != ABI_PARAM1) {
|
||||
if (reg1 != ABI_PARAM1)
|
||||
MOV(64, R(ABI_PARAM1), R(reg1));
|
||||
|
@ -287,8 +281,7 @@ void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) {
|
|||
MOV(64, R(ABI_PARAM1), R(reg1));
|
||||
}
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -297,14 +290,12 @@ void XEmitter::ABI_CallFunctionRR(const void *func, X64Reg reg1, X64Reg reg2) {
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32 param2)
|
||||
{
|
||||
void XEmitter::ABI_CallFunctionAC(const void* func, const Gen::OpArg& arg1, u32 param2) {
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -313,15 +304,14 @@ void XEmitter::ABI_CallFunctionAC(const void *func, const Gen::OpArg &arg1, u32
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32 param2, u32 param3)
|
||||
{
|
||||
void XEmitter::ABI_CallFunctionACC(const void* func, const Gen::OpArg& arg1, u32 param2,
|
||||
u32 param3) {
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
MOV(32, R(ABI_PARAM2), Imm32(param2));
|
||||
MOV(64, R(ABI_PARAM3), Imm64(param3));
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -330,13 +320,11 @@ void XEmitter::ABI_CallFunctionACC(const void *func, const Gen::OpArg &arg1, u32
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1)
|
||||
{
|
||||
void XEmitter::ABI_CallFunctionA(const void* func, const Gen::OpArg& arg1) {
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
@ -345,15 +333,14 @@ void XEmitter::ABI_CallFunctionA(const void *func, const Gen::OpArg &arg1)
|
|||
}
|
||||
}
|
||||
|
||||
void XEmitter::ABI_CallFunctionAA(const void *func, const Gen::OpArg &arg1, const Gen::OpArg &arg2)
|
||||
{
|
||||
void XEmitter::ABI_CallFunctionAA(const void* func, const Gen::OpArg& arg1,
|
||||
const Gen::OpArg& arg2) {
|
||||
if (!arg1.IsSimpleReg(ABI_PARAM1))
|
||||
MOV(32, R(ABI_PARAM1), arg1);
|
||||
if (!arg2.IsSimpleReg(ABI_PARAM2))
|
||||
MOV(32, R(ABI_PARAM2), arg2);
|
||||
u64 distance = u64(func) - (u64(code) + 5);
|
||||
if (distance >= 0x0000000080000000ULL
|
||||
&& distance < 0xFFFFFFFF80000000ULL) {
|
||||
if (distance >= 0x0000000080000000ULL && distance < 0xFFFFFFFF80000000ULL) {
|
||||
// Far call
|
||||
MOV(64, R(RAX), ImmPtr(func));
|
||||
CALLptr(R(RAX));
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
|
||||
// Windows 64-bit
|
||||
// * 4-reg "fastcall" variant, very new-skool stack handling
|
||||
// * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself calls_
|
||||
// * Callee moves stack pointer, to make room for shadow regs for the biggest function _it itself
|
||||
// calls_
|
||||
// * Parameters passed in RCX, RDX, ... further parameters are MOVed into the allocated stack space.
|
||||
// Scratch: RAX RCX RDX R8 R9 R10 R11
|
||||
// Callee-save: RBX RSI RDI RBP R12 R13 R14 R15
|
||||
|
@ -35,10 +36,10 @@
|
|||
#define ABI_PARAM4 R9
|
||||
|
||||
// xmm0-xmm15 use the upper 16 bits in the functions that push/pop registers.
|
||||
#define ABI_ALL_CALLER_SAVED \
|
||||
(BitSet32 { RAX, RCX, RDX, R8, R9, R10, R11, \
|
||||
XMM0+16, XMM1+16, XMM2+16, XMM3+16, XMM4+16, XMM5+16 })
|
||||
#else //64-bit Unix / OS X
|
||||
#define ABI_ALL_CALLER_SAVED \
|
||||
(BitSet32{RAX, RCX, RDX, R8, R9, R10, R11, XMM0 + 16, XMM1 + 16, XMM2 + 16, XMM3 + 16, \
|
||||
XMM4 + 16, XMM5 + 16})
|
||||
#else // 64-bit Unix / OS X
|
||||
|
||||
#define ABI_PARAM1 RDI
|
||||
#define ABI_PARAM2 RSI
|
||||
|
@ -49,9 +50,7 @@
|
|||
|
||||
// TODO: Avoid pushing all 16 XMM registers when possible. Most functions we call probably
|
||||
// don't actually clobber them.
|
||||
#define ABI_ALL_CALLER_SAVED \
|
||||
(BitSet32 { RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11 } | \
|
||||
ABI_ALL_FPRS)
|
||||
#define ABI_ALL_CALLER_SAVED (BitSet32{RAX, RCX, RDX, RDI, RSI, R8, R9, R10, R11} | ABI_ALL_FPRS)
|
||||
#endif // WIN32
|
||||
|
||||
#define ABI_ALL_CALLEE_SAVED (~ABI_ALL_CALLER_SAVED)
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace Common {
|
|||
#ifndef _MSC_VER
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <sys/types.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
|
||||
|
@ -26,15 +26,9 @@ static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
|
|||
#else
|
||||
info[0] = function_id; // eax
|
||||
info[2] = subfunction_id; // ecx
|
||||
__asm__(
|
||||
"cpuid"
|
||||
: "=a" (info[0]),
|
||||
"=b" (info[1]),
|
||||
"=c" (info[2]),
|
||||
"=d" (info[3])
|
||||
: "a" (function_id),
|
||||
"c" (subfunction_id)
|
||||
);
|
||||
__asm__("cpuid"
|
||||
: "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
|
||||
: "a"(function_id), "c"(subfunction_id));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -88,14 +82,22 @@ static CPUCaps Detect() {
|
|||
if (max_std_fn >= 1) {
|
||||
__cpuid(cpu_id, 0x00000001);
|
||||
|
||||
if ((cpu_id[3] >> 25) & 1) caps.sse = true;
|
||||
if ((cpu_id[3] >> 26) & 1) caps.sse2 = true;
|
||||
if ((cpu_id[2]) & 1) caps.sse3 = true;
|
||||
if ((cpu_id[2] >> 9) & 1) caps.ssse3 = true;
|
||||
if ((cpu_id[2] >> 19) & 1) caps.sse4_1 = true;
|
||||
if ((cpu_id[2] >> 20) & 1) caps.sse4_2 = true;
|
||||
if ((cpu_id[2] >> 22) & 1) caps.movbe = true;
|
||||
if ((cpu_id[2] >> 25) & 1) caps.aes = true;
|
||||
if ((cpu_id[3] >> 25) & 1)
|
||||
caps.sse = true;
|
||||
if ((cpu_id[3] >> 26) & 1)
|
||||
caps.sse2 = true;
|
||||
if ((cpu_id[2]) & 1)
|
||||
caps.sse3 = true;
|
||||
if ((cpu_id[2] >> 9) & 1)
|
||||
caps.ssse3 = true;
|
||||
if ((cpu_id[2] >> 19) & 1)
|
||||
caps.sse4_1 = true;
|
||||
if ((cpu_id[2] >> 20) & 1)
|
||||
caps.sse4_2 = true;
|
||||
if ((cpu_id[2] >> 22) & 1)
|
||||
caps.movbe = true;
|
||||
if ((cpu_id[2] >> 25) & 1)
|
||||
caps.aes = true;
|
||||
|
||||
if ((cpu_id[3] >> 24) & 1) {
|
||||
caps.fxsave_fxrstor = true;
|
||||
|
@ -140,10 +142,14 @@ static CPUCaps Detect() {
|
|||
if (max_ex_fn >= 0x80000001) {
|
||||
// Check for more features
|
||||
__cpuid(cpu_id, 0x80000001);
|
||||
if (cpu_id[2] & 1) caps.lahf_sahf_64 = true;
|
||||
if ((cpu_id[2] >> 5) & 1) caps.lzcnt = true;
|
||||
if ((cpu_id[2] >> 16) & 1) caps.fma4 = true;
|
||||
if ((cpu_id[3] >> 29) & 1) caps.long_mode = true;
|
||||
if (cpu_id[2] & 1)
|
||||
caps.lahf_sahf_64 = true;
|
||||
if ((cpu_id[2] >> 5) & 1)
|
||||
caps.lzcnt = true;
|
||||
if ((cpu_id[2] >> 16) & 1)
|
||||
caps.fma4 = true;
|
||||
if ((cpu_id[3] >> 29) & 1)
|
||||
caps.long_mode = true;
|
||||
}
|
||||
|
||||
return caps;
|
||||
|
@ -162,24 +168,38 @@ std::string GetCPUCapsString() {
|
|||
sum += caps.brand_string;
|
||||
sum += ")";
|
||||
|
||||
if (caps.sse) sum += ", SSE";
|
||||
if (caps.sse)
|
||||
sum += ", SSE";
|
||||
if (caps.sse2) {
|
||||
sum += ", SSE2";
|
||||
if (!caps.flush_to_zero) sum += " (without DAZ)";
|
||||
if (!caps.flush_to_zero)
|
||||
sum += " (without DAZ)";
|
||||
}
|
||||
|
||||
if (caps.sse3) sum += ", SSE3";
|
||||
if (caps.ssse3) sum += ", SSSE3";
|
||||
if (caps.sse4_1) sum += ", SSE4.1";
|
||||
if (caps.sse4_2) sum += ", SSE4.2";
|
||||
if (caps.avx) sum += ", AVX";
|
||||
if (caps.avx2) sum += ", AVX2";
|
||||
if (caps.bmi1) sum += ", BMI1";
|
||||
if (caps.bmi2) sum += ", BMI2";
|
||||
if (caps.fma) sum += ", FMA";
|
||||
if (caps.aes) sum += ", AES";
|
||||
if (caps.movbe) sum += ", MOVBE";
|
||||
if (caps.long_mode) sum += ", 64-bit support";
|
||||
if (caps.sse3)
|
||||
sum += ", SSE3";
|
||||
if (caps.ssse3)
|
||||
sum += ", SSSE3";
|
||||
if (caps.sse4_1)
|
||||
sum += ", SSE4.1";
|
||||
if (caps.sse4_2)
|
||||
sum += ", SSE4.2";
|
||||
if (caps.avx)
|
||||
sum += ", AVX";
|
||||
if (caps.avx2)
|
||||
sum += ", AVX2";
|
||||
if (caps.bmi1)
|
||||
sum += ", BMI1";
|
||||
if (caps.bmi2)
|
||||
sum += ", BMI2";
|
||||
if (caps.fma)
|
||||
sum += ", FMA";
|
||||
if (caps.aes)
|
||||
sum += ", AES";
|
||||
if (caps.movbe)
|
||||
sum += ", MOVBE";
|
||||
if (caps.long_mode)
|
||||
sum += ", 64-bit support";
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -21,8 +21,8 @@
|
|||
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_set.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/code_block.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#if defined(ARCHITECTURE_x86_64) && !defined(_ARCH_64)
|
||||
#define _ARCH_64
|
||||
|
@ -34,75 +34,145 @@
|
|||
#define PTRBITS 32
|
||||
#endif
|
||||
|
||||
namespace Gen
|
||||
{
|
||||
namespace Gen {
|
||||
|
||||
enum X64Reg
|
||||
{
|
||||
EAX = 0, EBX = 3, ECX = 1, EDX = 2,
|
||||
ESI = 6, EDI = 7, EBP = 5, ESP = 4,
|
||||
enum X64Reg {
|
||||
EAX = 0,
|
||||
EBX = 3,
|
||||
ECX = 1,
|
||||
EDX = 2,
|
||||
ESI = 6,
|
||||
EDI = 7,
|
||||
EBP = 5,
|
||||
ESP = 4,
|
||||
|
||||
RAX = 0, RBX = 3, RCX = 1, RDX = 2,
|
||||
RSI = 6, RDI = 7, RBP = 5, RSP = 4,
|
||||
R8 = 8, R9 = 9, R10 = 10,R11 = 11,
|
||||
R12 = 12,R13 = 13,R14 = 14,R15 = 15,
|
||||
RAX = 0,
|
||||
RBX = 3,
|
||||
RCX = 1,
|
||||
RDX = 2,
|
||||
RSI = 6,
|
||||
RDI = 7,
|
||||
RBP = 5,
|
||||
RSP = 4,
|
||||
R8 = 8,
|
||||
R9 = 9,
|
||||
R10 = 10,
|
||||
R11 = 11,
|
||||
R12 = 12,
|
||||
R13 = 13,
|
||||
R14 = 14,
|
||||
R15 = 15,
|
||||
|
||||
AL = 0, BL = 3, CL = 1, DL = 2,
|
||||
SIL = 6, DIL = 7, BPL = 5, SPL = 4,
|
||||
AH = 0x104, BH = 0x107, CH = 0x105, DH = 0x106,
|
||||
AL = 0,
|
||||
BL = 3,
|
||||
CL = 1,
|
||||
DL = 2,
|
||||
SIL = 6,
|
||||
DIL = 7,
|
||||
BPL = 5,
|
||||
SPL = 4,
|
||||
AH = 0x104,
|
||||
BH = 0x107,
|
||||
CH = 0x105,
|
||||
DH = 0x106,
|
||||
|
||||
AX = 0, BX = 3, CX = 1, DX = 2,
|
||||
SI = 6, DI = 7, BP = 5, SP = 4,
|
||||
AX = 0,
|
||||
BX = 3,
|
||||
CX = 1,
|
||||
DX = 2,
|
||||
SI = 6,
|
||||
DI = 7,
|
||||
BP = 5,
|
||||
SP = 4,
|
||||
|
||||
XMM0=0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7,
|
||||
XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15,
|
||||
XMM0 = 0,
|
||||
XMM1,
|
||||
XMM2,
|
||||
XMM3,
|
||||
XMM4,
|
||||
XMM5,
|
||||
XMM6,
|
||||
XMM7,
|
||||
XMM8,
|
||||
XMM9,
|
||||
XMM10,
|
||||
XMM11,
|
||||
XMM12,
|
||||
XMM13,
|
||||
XMM14,
|
||||
XMM15,
|
||||
|
||||
YMM0=0, YMM1, YMM2, YMM3, YMM4, YMM5, YMM6, YMM7,
|
||||
YMM8, YMM9, YMM10, YMM11, YMM12, YMM13, YMM14, YMM15,
|
||||
YMM0 = 0,
|
||||
YMM1,
|
||||
YMM2,
|
||||
YMM3,
|
||||
YMM4,
|
||||
YMM5,
|
||||
YMM6,
|
||||
YMM7,
|
||||
YMM8,
|
||||
YMM9,
|
||||
YMM10,
|
||||
YMM11,
|
||||
YMM12,
|
||||
YMM13,
|
||||
YMM14,
|
||||
YMM15,
|
||||
|
||||
INVALID_REG = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
enum CCFlags
|
||||
{
|
||||
CC_O = 0,
|
||||
CC_NO = 1,
|
||||
CC_B = 2, CC_C = 2, CC_NAE = 2,
|
||||
CC_NB = 3, CC_NC = 3, CC_AE = 3,
|
||||
CC_Z = 4, CC_E = 4,
|
||||
CC_NZ = 5, CC_NE = 5,
|
||||
CC_BE = 6, CC_NA = 6,
|
||||
CC_NBE = 7, CC_A = 7,
|
||||
CC_S = 8,
|
||||
CC_NS = 9,
|
||||
CC_P = 0xA, CC_PE = 0xA,
|
||||
CC_NP = 0xB, CC_PO = 0xB,
|
||||
CC_L = 0xC, CC_NGE = 0xC,
|
||||
CC_NL = 0xD, CC_GE = 0xD,
|
||||
CC_LE = 0xE, CC_NG = 0xE,
|
||||
CC_NLE = 0xF, CC_G = 0xF
|
||||
enum CCFlags {
|
||||
CC_O = 0,
|
||||
CC_NO = 1,
|
||||
CC_B = 2,
|
||||
CC_C = 2,
|
||||
CC_NAE = 2,
|
||||
CC_NB = 3,
|
||||
CC_NC = 3,
|
||||
CC_AE = 3,
|
||||
CC_Z = 4,
|
||||
CC_E = 4,
|
||||
CC_NZ = 5,
|
||||
CC_NE = 5,
|
||||
CC_BE = 6,
|
||||
CC_NA = 6,
|
||||
CC_NBE = 7,
|
||||
CC_A = 7,
|
||||
CC_S = 8,
|
||||
CC_NS = 9,
|
||||
CC_P = 0xA,
|
||||
CC_PE = 0xA,
|
||||
CC_NP = 0xB,
|
||||
CC_PO = 0xB,
|
||||
CC_L = 0xC,
|
||||
CC_NGE = 0xC,
|
||||
CC_NL = 0xD,
|
||||
CC_GE = 0xD,
|
||||
CC_LE = 0xE,
|
||||
CC_NG = 0xE,
|
||||
CC_NLE = 0xF,
|
||||
CC_G = 0xF
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
NUMGPRs = 16,
|
||||
NUMXMMs = 16,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
SCALE_NONE = 0,
|
||||
SCALE_1 = 1,
|
||||
SCALE_2 = 2,
|
||||
SCALE_4 = 4,
|
||||
SCALE_8 = 8,
|
||||
SCALE_ATREG = 16,
|
||||
//SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG
|
||||
// SCALE_NOBASE_1 is not supported and can be replaced with SCALE_ATREG
|
||||
SCALE_NOBASE_2 = 34,
|
||||
SCALE_NOBASE_4 = 36,
|
||||
SCALE_NOBASE_8 = 40,
|
||||
SCALE_RIP = 0xFF,
|
||||
SCALE_IMM8 = 0xF0,
|
||||
SCALE_IMM8 = 0xF0,
|
||||
SCALE_IMM16 = 0xF1,
|
||||
SCALE_IMM32 = 0xF2,
|
||||
SCALE_IMM64 = 0xF3,
|
||||
|
@ -114,7 +184,7 @@ enum NormalOp {
|
|||
nrmSUB,
|
||||
nrmSBB,
|
||||
nrmAND,
|
||||
nrmOR ,
|
||||
nrmOR,
|
||||
nrmXOR,
|
||||
nrmMOV,
|
||||
nrmTEST,
|
||||
|
@ -157,68 +227,74 @@ enum FloatRound {
|
|||
class XEmitter;
|
||||
|
||||
// RIP addressing does not benefit from micro op fusion on Core arch
|
||||
struct OpArg
|
||||
{
|
||||
struct OpArg {
|
||||
friend class XEmitter;
|
||||
|
||||
constexpr OpArg() = default; // dummy op arg, used for storage
|
||||
constexpr OpArg() = default; // dummy op arg, used for storage
|
||||
constexpr OpArg(u64 offset_, int scale_, X64Reg rmReg = RAX, X64Reg scaledReg = RAX)
|
||||
: scale(static_cast<u8>(scale_))
|
||||
, offsetOrBaseReg(static_cast<u16>(rmReg))
|
||||
, indexReg(static_cast<u16>(scaledReg))
|
||||
, offset(offset_)
|
||||
{
|
||||
: scale(static_cast<u8>(scale_)), offsetOrBaseReg(static_cast<u16>(rmReg)),
|
||||
indexReg(static_cast<u16>(scaledReg)), offset(offset_) {
|
||||
}
|
||||
|
||||
constexpr bool operator==(const OpArg &b) const
|
||||
{
|
||||
return operandReg == b.operandReg &&
|
||||
scale == b.scale &&
|
||||
offsetOrBaseReg == b.offsetOrBaseReg &&
|
||||
indexReg == b.indexReg &&
|
||||
offset == b.offset;
|
||||
constexpr bool operator==(const OpArg& b) const {
|
||||
return operandReg == b.operandReg && scale == b.scale &&
|
||||
offsetOrBaseReg == b.offsetOrBaseReg && indexReg == b.indexReg && offset == b.offset;
|
||||
}
|
||||
|
||||
void WriteRex(XEmitter *emit, int opBits, int bits, int customOp = -1) const;
|
||||
void WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm, int W = 0) const;
|
||||
void WriteRest(XEmitter *emit, int extraBytes=0, X64Reg operandReg=INVALID_REG, bool warn_64bit_offset = true) const;
|
||||
void WriteSingleByteOp(XEmitter *emit, u8 op, X64Reg operandReg, int bits);
|
||||
void WriteNormalOp(XEmitter *emit, bool toRM, NormalOp op, const OpArg &operand, int bits) const;
|
||||
void WriteRex(XEmitter* emit, int opBits, int bits, int customOp = -1) const;
|
||||
void WriteVex(XEmitter* emit, X64Reg regOp1, X64Reg regOp2, int L, int pp, int mmmmm,
|
||||
int W = 0) const;
|
||||
void WriteRest(XEmitter* emit, int extraBytes = 0, X64Reg operandReg = INVALID_REG,
|
||||
bool warn_64bit_offset = true) const;
|
||||
void WriteSingleByteOp(XEmitter* emit, u8 op, X64Reg operandReg, int bits);
|
||||
void WriteNormalOp(XEmitter* emit, bool toRM, NormalOp op, const OpArg& operand,
|
||||
int bits) const;
|
||||
|
||||
constexpr bool IsImm() const { return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 || scale == SCALE_IMM64; }
|
||||
constexpr bool IsSimpleReg() const { return scale == SCALE_NONE; }
|
||||
constexpr bool IsSimpleReg(X64Reg reg) const
|
||||
{
|
||||
constexpr bool IsImm() const {
|
||||
return scale == SCALE_IMM8 || scale == SCALE_IMM16 || scale == SCALE_IMM32 ||
|
||||
scale == SCALE_IMM64;
|
||||
}
|
||||
constexpr bool IsSimpleReg() const {
|
||||
return scale == SCALE_NONE;
|
||||
}
|
||||
constexpr bool IsSimpleReg(X64Reg reg) const {
|
||||
return IsSimpleReg() && GetSimpleReg() == reg;
|
||||
}
|
||||
|
||||
int GetImmBits() const
|
||||
{
|
||||
switch (scale)
|
||||
{
|
||||
case SCALE_IMM8: return 8;
|
||||
case SCALE_IMM16: return 16;
|
||||
case SCALE_IMM32: return 32;
|
||||
case SCALE_IMM64: return 64;
|
||||
default: return -1;
|
||||
int GetImmBits() const {
|
||||
switch (scale) {
|
||||
case SCALE_IMM8:
|
||||
return 8;
|
||||
case SCALE_IMM16:
|
||||
return 16;
|
||||
case SCALE_IMM32:
|
||||
return 32;
|
||||
case SCALE_IMM64:
|
||||
return 64;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void SetImmBits(int bits) {
|
||||
switch (bits)
|
||||
{
|
||||
case 8: scale = SCALE_IMM8; break;
|
||||
case 16: scale = SCALE_IMM16; break;
|
||||
case 32: scale = SCALE_IMM32; break;
|
||||
case 64: scale = SCALE_IMM64; break;
|
||||
switch (bits) {
|
||||
case 8:
|
||||
scale = SCALE_IMM8;
|
||||
break;
|
||||
case 16:
|
||||
scale = SCALE_IMM16;
|
||||
break;
|
||||
case 32:
|
||||
scale = SCALE_IMM32;
|
||||
break;
|
||||
case 64:
|
||||
scale = SCALE_IMM64;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr X64Reg GetSimpleReg() const
|
||||
{
|
||||
return scale == SCALE_NONE
|
||||
? static_cast<X64Reg>(offsetOrBaseReg)
|
||||
: INVALID_REG;
|
||||
constexpr X64Reg GetSimpleReg() const {
|
||||
return scale == SCALE_NONE ? static_cast<X64Reg>(offsetOrBaseReg) : INVALID_REG;
|
||||
}
|
||||
|
||||
constexpr u32 GetImmValue() const {
|
||||
|
@ -234,41 +310,50 @@ private:
|
|||
u8 scale = 0;
|
||||
u16 offsetOrBaseReg = 0;
|
||||
u16 indexReg = 0;
|
||||
u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available.
|
||||
u64 offset = 0; // use RIP-relative as much as possible - 64-bit immediates are not available.
|
||||
u16 operandReg = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline OpArg M(const T *ptr) { return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP)); }
|
||||
constexpr OpArg R(X64Reg value) { return OpArg(0, SCALE_NONE, value); }
|
||||
constexpr OpArg MatR(X64Reg value) { return OpArg(0, SCALE_ATREG, value); }
|
||||
inline OpArg M(const T* ptr) {
|
||||
return OpArg(reinterpret_cast<u64>(ptr), static_cast<int>(SCALE_RIP));
|
||||
}
|
||||
constexpr OpArg R(X64Reg value) {
|
||||
return OpArg(0, SCALE_NONE, value);
|
||||
}
|
||||
constexpr OpArg MatR(X64Reg value) {
|
||||
return OpArg(0, SCALE_ATREG, value);
|
||||
}
|
||||
|
||||
constexpr OpArg MDisp(X64Reg value, int offset)
|
||||
{
|
||||
constexpr OpArg MDisp(X64Reg value, int offset) {
|
||||
return OpArg(static_cast<u32>(offset), SCALE_ATREG, value);
|
||||
}
|
||||
|
||||
constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset)
|
||||
{
|
||||
constexpr OpArg MComplex(X64Reg base, X64Reg scaled, int scale, int offset) {
|
||||
return OpArg(offset, scale, base, scaled);
|
||||
}
|
||||
|
||||
constexpr OpArg MScaled(X64Reg scaled, int scale, int offset)
|
||||
{
|
||||
return scale == SCALE_1
|
||||
? OpArg(offset, SCALE_ATREG, scaled)
|
||||
: OpArg(offset, scale | 0x20, RAX, scaled);
|
||||
constexpr OpArg MScaled(X64Reg scaled, int scale, int offset) {
|
||||
return scale == SCALE_1 ? OpArg(offset, SCALE_ATREG, scaled)
|
||||
: OpArg(offset, scale | 0x20, RAX, scaled);
|
||||
}
|
||||
|
||||
constexpr OpArg MRegSum(X64Reg base, X64Reg offset)
|
||||
{
|
||||
constexpr OpArg MRegSum(X64Reg base, X64Reg offset) {
|
||||
return MComplex(base, offset, 1, 0);
|
||||
}
|
||||
|
||||
constexpr OpArg Imm8 (u8 imm) { return OpArg(imm, SCALE_IMM8); }
|
||||
constexpr OpArg Imm16(u16 imm) { return OpArg(imm, SCALE_IMM16); } //rarely used
|
||||
constexpr OpArg Imm32(u32 imm) { return OpArg(imm, SCALE_IMM32); }
|
||||
constexpr OpArg Imm64(u64 imm) { return OpArg(imm, SCALE_IMM64); }
|
||||
constexpr OpArg Imm8(u8 imm) {
|
||||
return OpArg(imm, SCALE_IMM8);
|
||||
}
|
||||
constexpr OpArg Imm16(u16 imm) {
|
||||
return OpArg(imm, SCALE_IMM16);
|
||||
} // rarely used
|
||||
constexpr OpArg Imm32(u32 imm) {
|
||||
return OpArg(imm, SCALE_IMM32);
|
||||
}
|
||||
constexpr OpArg Imm64(u64 imm) {
|
||||
return OpArg(imm, SCALE_IMM64);
|
||||
}
|
||||
constexpr OpArg UImmAuto(u32 imm) {
|
||||
return OpArg(imm, imm >= 128 ? SCALE_IMM32 : SCALE_IMM8);
|
||||
}
|
||||
|
@ -277,8 +362,7 @@ constexpr OpArg SImmAuto(s32 imm) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
OpArg ImmPtr(const T* imm)
|
||||
{
|
||||
OpArg ImmPtr(const T* imm) {
|
||||
#ifdef _ARCH_64
|
||||
return Imm64(reinterpret_cast<u64>(imm));
|
||||
#else
|
||||
|
@ -286,36 +370,31 @@ OpArg ImmPtr(const T* imm)
|
|||
#endif
|
||||
}
|
||||
|
||||
inline u32 PtrOffset(const void* ptr, const void* base)
|
||||
{
|
||||
inline u32 PtrOffset(const void* ptr, const void* base) {
|
||||
#ifdef _ARCH_64
|
||||
s64 distance = (s64)ptr-(s64)base;
|
||||
if (distance >= 0x80000000LL ||
|
||||
distance < -0x80000000LL)
|
||||
{
|
||||
s64 distance = (s64)ptr - (s64)base;
|
||||
if (distance >= 0x80000000LL || distance < -0x80000000LL) {
|
||||
ASSERT_MSG(0, "pointer offset out of range");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (u32)distance;
|
||||
#else
|
||||
return (u32)ptr-(u32)base;
|
||||
return (u32)ptr - (u32)base;
|
||||
#endif
|
||||
}
|
||||
|
||||
//usage: int a[]; ARRAY_OFFSET(a,10)
|
||||
#define ARRAY_OFFSET(array,index) ((u32)((u64)&(array)[index]-(u64)&(array)[0]))
|
||||
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
|
||||
#define STRUCT_OFFSET(str,elem) ((u32)((u64)&(str).elem-(u64)&(str)))
|
||||
// usage: int a[]; ARRAY_OFFSET(a,10)
|
||||
#define ARRAY_OFFSET(array, index) ((u32)((u64) & (array)[index] - (u64) & (array)[0]))
|
||||
// usage: struct {int e;} s; STRUCT_OFFSET(s,e)
|
||||
#define STRUCT_OFFSET(str, elem) ((u32)((u64) & (str).elem - (u64) & (str)))
|
||||
|
||||
struct FixupBranch
|
||||
{
|
||||
u8 *ptr;
|
||||
int type; //0 = 8bit 1 = 32bit
|
||||
struct FixupBranch {
|
||||
u8* ptr;
|
||||
int type; // 0 = 8bit 1 = 32bit
|
||||
};
|
||||
|
||||
enum SSECompare
|
||||
{
|
||||
enum SSECompare {
|
||||
EQ = 0,
|
||||
LT,
|
||||
LE,
|
||||
|
@ -326,11 +405,10 @@ enum SSECompare
|
|||
ORD,
|
||||
};
|
||||
|
||||
class XEmitter
|
||||
{
|
||||
friend struct OpArg; // for Write8 etc
|
||||
class XEmitter {
|
||||
friend struct OpArg; // for Write8 etc
|
||||
private:
|
||||
u8 *code;
|
||||
u8* code;
|
||||
bool flags_locked;
|
||||
|
||||
void CheckFlags();
|
||||
|
@ -347,14 +425,19 @@ private:
|
|||
void WriteSSSE3Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0);
|
||||
void WriteSSE41Op(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0);
|
||||
void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp, const OpArg& arg, int extrabytes = 0);
|
||||
void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0);
|
||||
void WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0);
|
||||
void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0);
|
||||
void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg, int extrabytes = 0);
|
||||
void WriteAVXOp(u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
|
||||
int extrabytes = 0);
|
||||
void WriteVEXOp(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
|
||||
int extrabytes = 0);
|
||||
void WriteBMI1Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
|
||||
int extrabytes = 0);
|
||||
void WriteBMI2Op(int size, u8 opPrefix, u16 op, X64Reg regOp1, X64Reg regOp2, const OpArg& arg,
|
||||
int extrabytes = 0);
|
||||
void WriteFloatLoadStore(int bits, FloatOp op, FloatOp op_80b, const OpArg& arg);
|
||||
void WriteNormalOp(XEmitter *emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2);
|
||||
void WriteNormalOp(XEmitter* emit, int bits, NormalOp op, const OpArg& a1, const OpArg& a2);
|
||||
|
||||
void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size, size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp);
|
||||
void ABI_CalculateFrameSize(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size,
|
||||
size_t* shadowp, size_t* subtractionp, size_t* xmm_offsetp);
|
||||
|
||||
protected:
|
||||
void Write8(u8 value);
|
||||
|
@ -363,26 +446,38 @@ protected:
|
|||
void Write64(u64 value);
|
||||
|
||||
public:
|
||||
XEmitter() { code = nullptr; flags_locked = false; }
|
||||
XEmitter(u8 *code_ptr) { code = code_ptr; flags_locked = false; }
|
||||
virtual ~XEmitter() {}
|
||||
XEmitter() {
|
||||
code = nullptr;
|
||||
flags_locked = false;
|
||||
}
|
||||
XEmitter(u8* code_ptr) {
|
||||
code = code_ptr;
|
||||
flags_locked = false;
|
||||
}
|
||||
virtual ~XEmitter() {
|
||||
}
|
||||
|
||||
void WriteModRM(int mod, int rm, int reg);
|
||||
void WriteSIB(int scale, int index, int base);
|
||||
|
||||
void SetCodePtr(u8 *ptr);
|
||||
void SetCodePtr(u8* ptr);
|
||||
void ReserveCodeSpace(int bytes);
|
||||
const u8 *AlignCode4();
|
||||
const u8 *AlignCode16();
|
||||
const u8 *AlignCodePage();
|
||||
const u8 *GetCodePtr() const;
|
||||
u8 *GetWritableCodePtr();
|
||||
const u8* AlignCode4();
|
||||
const u8* AlignCode16();
|
||||
const u8* AlignCodePage();
|
||||
const u8* GetCodePtr() const;
|
||||
u8* GetWritableCodePtr();
|
||||
|
||||
void LockFlags() { flags_locked = true; }
|
||||
void UnlockFlags() { flags_locked = false; }
|
||||
void LockFlags() {
|
||||
flags_locked = true;
|
||||
}
|
||||
void UnlockFlags() {
|
||||
flags_locked = false;
|
||||
}
|
||||
|
||||
// Looking for one of these? It's BANNED!! Some instructions are slow on modern CPU
|
||||
// INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other string instr.,
|
||||
// INC, DEC, LOOP, LOOPNE, LOOPE, ENTER, LEAVE, XCHG, XLAT, REP MOVSB/MOVSD, REP SCASD + other
|
||||
// string instr.,
|
||||
// INC and DEC are slow on Intel Core, but not on AMD. They create a
|
||||
// false flag dependency because they only update a subset of the flags.
|
||||
// XCHG is SLOW and should be avoided.
|
||||
|
@ -401,11 +496,11 @@ public:
|
|||
void CLC();
|
||||
void CMC();
|
||||
|
||||
// These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and AMD!
|
||||
// These two can not be executed in 64-bit mode on early Intel 64-bit CPU:s, only on Core2 and
|
||||
// AMD!
|
||||
void LAHF(); // 3 cycle vector path
|
||||
void SAHF(); // direct path fast
|
||||
|
||||
|
||||
// Stack control
|
||||
void PUSH(X64Reg reg);
|
||||
void POP(X64Reg reg);
|
||||
|
@ -422,7 +517,7 @@ public:
|
|||
|
||||
void JMP(const u8* addr, bool force5Bytes = false);
|
||||
void JMPptr(const OpArg& arg);
|
||||
void JMPself(); //infinite loop!
|
||||
void JMPself(); // infinite loop!
|
||||
#ifdef CALL
|
||||
#undef CALL
|
||||
#endif
|
||||
|
@ -450,12 +545,11 @@ public:
|
|||
void BSR(int bits, X64Reg dest, const OpArg& src); // Top bit to bottom bit
|
||||
|
||||
// Cache control
|
||||
enum PrefetchLevel
|
||||
{
|
||||
PF_NTA, //Non-temporal (data used once and only once)
|
||||
PF_T0, //All cache levels
|
||||
PF_T1, //Levels 2+ (aliased to T0 on AMD)
|
||||
PF_T2, //Levels 3+ (aliased to T0 on AMD)
|
||||
enum PrefetchLevel {
|
||||
PF_NTA, // Non-temporal (data used once and only once)
|
||||
PF_T0, // All cache levels
|
||||
PF_T1, // Levels 2+ (aliased to T0 on AMD)
|
||||
PF_T2, // Levels 3+ (aliased to T0 on AMD)
|
||||
};
|
||||
void PREFETCH(PrefetchLevel level, OpArg arg);
|
||||
void MOVNTI(int bits, const OpArg& dest, X64Reg src);
|
||||
|
@ -464,8 +558,8 @@ public:
|
|||
void MOVNTPD(const OpArg& arg, X64Reg regOp);
|
||||
|
||||
// Multiplication / division
|
||||
void MUL(int bits, const OpArg& src); //UNSIGNED
|
||||
void IMUL(int bits, const OpArg& src); //SIGNED
|
||||
void MUL(int bits, const OpArg& src); // UNSIGNED
|
||||
void IMUL(int bits, const OpArg& src); // SIGNED
|
||||
void IMUL(int bits, X64Reg regOp, const OpArg& src);
|
||||
void IMUL(int bits, X64Reg regOp, const OpArg& src, const OpArg& imm);
|
||||
void DIV(int bits, const OpArg& src);
|
||||
|
@ -492,11 +586,19 @@ public:
|
|||
|
||||
// Extend EAX into EDX in various ways
|
||||
void CWD(int bits = 16);
|
||||
void CDQ() {CWD(32);}
|
||||
void CQO() {CWD(64);}
|
||||
void CDQ() {
|
||||
CWD(32);
|
||||
}
|
||||
void CQO() {
|
||||
CWD(64);
|
||||
}
|
||||
void CBW(int bits = 8);
|
||||
void CWDE() {CBW(16);}
|
||||
void CDQE() {CBW(32);}
|
||||
void CWDE() {
|
||||
CBW(16);
|
||||
}
|
||||
void CDQE() {
|
||||
CBW(32);
|
||||
}
|
||||
|
||||
// Load effective address
|
||||
void LEA(int bits, X64Reg dest, OpArg src);
|
||||
|
@ -511,7 +613,7 @@ public:
|
|||
void CMP(int bits, const OpArg& a1, const OpArg& a2);
|
||||
|
||||
// Bit operations
|
||||
void NOT (int bits, const OpArg& src);
|
||||
void NOT(int bits, const OpArg& src);
|
||||
void OR(int bits, const OpArg& a1, const OpArg& a2);
|
||||
void XOR(int bits, const OpArg& a1, const OpArg& a2);
|
||||
void MOV(int bits, const OpArg& a1, const OpArg& a2);
|
||||
|
@ -525,7 +627,8 @@ public:
|
|||
void BSWAP(int bits, X64Reg reg);
|
||||
|
||||
// Sign/zero extension
|
||||
void MOVSX(int dbits, int sbits, X64Reg dest, OpArg src); //automatically uses MOVSXD if necessary
|
||||
void MOVSX(int dbits, int sbits, X64Reg dest,
|
||||
OpArg src); // automatically uses MOVSXD if necessary
|
||||
void MOVZX(int dbits, int sbits, X64Reg dest, OpArg src);
|
||||
|
||||
// Available only on Atom or >= Haswell so far. Test with GetCPUCaps().movbe.
|
||||
|
@ -593,13 +696,27 @@ public:
|
|||
void CMPSS(X64Reg regOp, const OpArg& arg, u8 compare);
|
||||
void CMPSD(X64Reg regOp, const OpArg& arg, u8 compare);
|
||||
|
||||
void CMPEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_EQ); }
|
||||
void CMPLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LT); }
|
||||
void CMPLESS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_LE); }
|
||||
void CMPUNORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_UNORD); }
|
||||
void CMPNEQSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NEQ); }
|
||||
void CMPNLTSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_NLT); }
|
||||
void CMPORDSS(X64Reg regOp, const OpArg& arg) { CMPSS(regOp, arg, CMP_ORD); }
|
||||
void CMPEQSS(X64Reg regOp, const OpArg& arg) {
|
||||
CMPSS(regOp, arg, CMP_EQ);
|
||||
}
|
||||
void CMPLTSS(X64Reg regOp, const OpArg& arg) {
|
||||
CMPSS(regOp, arg, CMP_LT);
|
||||
}
|
||||
void CMPLESS(X64Reg regOp, const OpArg& arg) {
|
||||
CMPSS(regOp, arg, CMP_LE);
|
||||
}
|
||||
void CMPUNORDSS(X64Reg regOp, const OpArg& arg) {
|
||||
CMPSS(regOp, arg, CMP_UNORD);
|
||||
}
|
||||
void CMPNEQSS(X64Reg regOp, const OpArg& arg) {
|
||||
CMPSS(regOp, arg, CMP_NEQ);
|
||||
}
|
||||
void CMPNLTSS(X64Reg regOp, const OpArg& arg) {
|
||||
CMPSS(regOp, arg, CMP_NLT);
|
||||
}
|
||||
void CMPORDSS(X64Reg regOp, const OpArg& arg) {
|
||||
CMPSS(regOp, arg, CMP_ORD);
|
||||
}
|
||||
|
||||
// SSE/SSE2: Floating point packed arithmetic (x4 for float, x2 for double)
|
||||
void ADDPS(X64Reg regOp, const OpArg& arg);
|
||||
|
@ -638,10 +755,12 @@ public:
|
|||
// SSE/SSE2: Useful alternative to shuffle in some cases.
|
||||
void MOVDDUP(X64Reg regOp, const OpArg& arg);
|
||||
|
||||
// SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily on Ivy.
|
||||
// SSE3: Horizontal operations in SIMD registers. Very slow! shufps-based code beats it handily
|
||||
// on Ivy.
|
||||
void HADDPS(X64Reg dest, const OpArg& src);
|
||||
|
||||
// SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg contains both a read mask and a write "mask".
|
||||
// SSE4: Further horizontal operations - dot products. These are weirdly flexible, the arg
|
||||
// contains both a read mask and a write "mask".
|
||||
void DPPS(X64Reg dest, const OpArg& src, u8 arg);
|
||||
|
||||
void UNPCKLPS(X64Reg dest, const OpArg& src);
|
||||
|
@ -694,11 +813,13 @@ public:
|
|||
void MOVD_xmm(const OpArg& arg, X64Reg src);
|
||||
void MOVQ_xmm(OpArg arg, X64Reg src);
|
||||
|
||||
// SSE/SSE2: Generates a mask from the high bits of the components of the packed register in question.
|
||||
// SSE/SSE2: Generates a mask from the high bits of the components of the packed register in
|
||||
// question.
|
||||
void MOVMSKPS(X64Reg dest, const OpArg& arg);
|
||||
void MOVMSKPD(X64Reg dest, const OpArg& arg);
|
||||
|
||||
// SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a weird one.
|
||||
// SSE2: Selective byte store, mask in src register. EDI/RDI specifies store address. This is a
|
||||
// weird one.
|
||||
void MASKMOVDQU(X64Reg dest, X64Reg src);
|
||||
void LDDQU(X64Reg dest, const OpArg& src);
|
||||
|
||||
|
@ -729,10 +850,10 @@ public:
|
|||
void PACKUSDW(X64Reg dest, const OpArg& arg);
|
||||
void PACKUSWB(X64Reg dest, const OpArg& arg);
|
||||
|
||||
void PUNPCKLBW(X64Reg dest, const OpArg &arg);
|
||||
void PUNPCKLWD(X64Reg dest, const OpArg &arg);
|
||||
void PUNPCKLDQ(X64Reg dest, const OpArg &arg);
|
||||
void PUNPCKLQDQ(X64Reg dest, const OpArg &arg);
|
||||
void PUNPCKLBW(X64Reg dest, const OpArg& arg);
|
||||
void PUNPCKLWD(X64Reg dest, const OpArg& arg);
|
||||
void PUNPCKLDQ(X64Reg dest, const OpArg& arg);
|
||||
void PUNPCKLQDQ(X64Reg dest, const OpArg& arg);
|
||||
|
||||
void PTEST(X64Reg dest, const OpArg& arg);
|
||||
void PAND(X64Reg dest, const OpArg& arg);
|
||||
|
@ -839,25 +960,57 @@ public:
|
|||
void ROUNDPS(X64Reg dest, const OpArg& arg, u8 mode);
|
||||
void ROUNDPD(X64Reg dest, const OpArg& arg, u8 mode);
|
||||
|
||||
void ROUNDNEARSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_NEAREST); }
|
||||
void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_FLOOR); }
|
||||
void ROUNDCEILSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_CEIL); }
|
||||
void ROUNDZEROSS(X64Reg dest, const OpArg& arg) { ROUNDSS(dest, arg, FROUND_ZERO); }
|
||||
void ROUNDNEARSS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSS(dest, arg, FROUND_NEAREST);
|
||||
}
|
||||
void ROUNDFLOORSS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSS(dest, arg, FROUND_FLOOR);
|
||||
}
|
||||
void ROUNDCEILSS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSS(dest, arg, FROUND_CEIL);
|
||||
}
|
||||
void ROUNDZEROSS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSS(dest, arg, FROUND_ZERO);
|
||||
}
|
||||
|
||||
void ROUNDNEARSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_NEAREST); }
|
||||
void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_FLOOR); }
|
||||
void ROUNDCEILSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_CEIL); }
|
||||
void ROUNDZEROSD(X64Reg dest, const OpArg& arg) { ROUNDSD(dest, arg, FROUND_ZERO); }
|
||||
void ROUNDNEARSD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSD(dest, arg, FROUND_NEAREST);
|
||||
}
|
||||
void ROUNDFLOORSD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSD(dest, arg, FROUND_FLOOR);
|
||||
}
|
||||
void ROUNDCEILSD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSD(dest, arg, FROUND_CEIL);
|
||||
}
|
||||
void ROUNDZEROSD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDSD(dest, arg, FROUND_ZERO);
|
||||
}
|
||||
|
||||
void ROUNDNEARPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_NEAREST); }
|
||||
void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_FLOOR); }
|
||||
void ROUNDCEILPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_CEIL); }
|
||||
void ROUNDZEROPS(X64Reg dest, const OpArg& arg) { ROUNDPS(dest, arg, FROUND_ZERO); }
|
||||
void ROUNDNEARPS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPS(dest, arg, FROUND_NEAREST);
|
||||
}
|
||||
void ROUNDFLOORPS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPS(dest, arg, FROUND_FLOOR);
|
||||
}
|
||||
void ROUNDCEILPS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPS(dest, arg, FROUND_CEIL);
|
||||
}
|
||||
void ROUNDZEROPS(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPS(dest, arg, FROUND_ZERO);
|
||||
}
|
||||
|
||||
void ROUNDNEARPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_NEAREST); }
|
||||
void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_FLOOR); }
|
||||
void ROUNDCEILPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_CEIL); }
|
||||
void ROUNDZEROPD(X64Reg dest, const OpArg& arg) { ROUNDPD(dest, arg, FROUND_ZERO); }
|
||||
void ROUNDNEARPD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPD(dest, arg, FROUND_NEAREST);
|
||||
}
|
||||
void ROUNDFLOORPD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPD(dest, arg, FROUND_FLOOR);
|
||||
}
|
||||
void ROUNDCEILPD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPD(dest, arg, FROUND_CEIL);
|
||||
}
|
||||
void ROUNDZEROPD(X64Reg dest, const OpArg& arg) {
|
||||
ROUNDPD(dest, arg, FROUND_ZERO);
|
||||
}
|
||||
|
||||
// AVX
|
||||
void VADDSD(X64Reg regOp1, X64Reg regOp2, const OpArg& arg);
|
||||
|
@ -981,7 +1134,6 @@ public:
|
|||
void ABI_CallFunctionC16(const void* func, u16 param1);
|
||||
void ABI_CallFunctionCC16(const void* func, u32 param1, u16 param2);
|
||||
|
||||
|
||||
// These only support u32 parameters, but that's enough for a lot of uses.
|
||||
// These will destroy the 1 or 2 first "parameter regs".
|
||||
void ABI_CallFunctionC(const void* func, u32 param1);
|
||||
|
@ -1012,29 +1164,38 @@ public:
|
|||
*
|
||||
* @param mask Registers to push on the stack (high 16 bits are XMMs, low 16 bits are GPRs)
|
||||
* @param rsp_alignment Current alignment of the stack pointer, must be 0 or 8
|
||||
* @param needed_frame_size Additional space needed, e.g., for function arguments passed on the stack
|
||||
* @param needed_frame_size Additional space needed, e.g., for function arguments passed on the
|
||||
* stack
|
||||
* @return Size of the shadow space, i.e., offset of the frame
|
||||
*/
|
||||
size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0);
|
||||
size_t ABI_PushRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
|
||||
size_t needed_frame_size = 0);
|
||||
|
||||
/**
|
||||
* Restores specified registers and adjusts the stack to its original alignment, i.e., the alignment before
|
||||
* Restores specified registers and adjusts the stack to its original alignment, i.e., the
|
||||
* alignment before
|
||||
* the matching PushRegistersAndAdjustStack.
|
||||
*
|
||||
* @param mask Registers to restores from the stack (high 16 bits are XMMs, low 16 bits are GPRs)
|
||||
* @param rsp_alignment Original alignment before the matching PushRegistersAndAdjustStack, must be 0 or 8
|
||||
* @param mask Registers to restores from the stack (high 16 bits are XMMs, low 16 bits are
|
||||
* GPRs)
|
||||
* @param rsp_alignment Original alignment before the matching PushRegistersAndAdjustStack, must
|
||||
* be 0 or 8
|
||||
* @param needed_frame_size Additional space that was needed
|
||||
* @warning Stack must be currently 16-byte aligned
|
||||
*/
|
||||
void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment, size_t needed_frame_size = 0);
|
||||
|
||||
#ifdef _M_IX86
|
||||
static int ABI_GetNumXMMRegs() { return 8; }
|
||||
#else
|
||||
static int ABI_GetNumXMMRegs() { return 16; }
|
||||
#endif
|
||||
}; // class XEmitter
|
||||
void ABI_PopRegistersAndAdjustStack(BitSet32 mask, size_t rsp_alignment,
|
||||
size_t needed_frame_size = 0);
|
||||
|
||||
#ifdef _M_IX86
|
||||
static int ABI_GetNumXMMRegs() {
|
||||
return 8;
|
||||
}
|
||||
#else
|
||||
static int ABI_GetNumXMMRegs() {
|
||||
return 16;
|
||||
}
|
||||
#endif
|
||||
}; // class XEmitter
|
||||
|
||||
// Everything that needs to generate X86 code should inherit from this.
|
||||
// You get memory management for free, plus, you can use all the MOV etc functions without
|
||||
|
@ -1045,4 +1206,4 @@ public:
|
|||
void PoisonMemory() override;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue