mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	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