mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
304 lines
5.7 KiB
C++
304 lines
5.7 KiB
C++
#pragma once
|
|
|
|
#include <fstream>
|
|
#include <functional>
|
|
#include <ostream>
|
|
#include <type_traits>
|
|
|
|
#include <Windows.h>
|
|
|
|
#include <Common/ScopedCriticalSection.h>
|
|
#include <DDraw/Log.h>
|
|
#include <Win32/Log.h>
|
|
|
|
#define LOG_FUNC(...) Compat::LogFunc logFunc(__VA_ARGS__)
|
|
#define LOG_RESULT(...) logFunc.setResult(__VA_ARGS__)
|
|
|
|
#define LOG_ONCE(msg) \
|
|
{ \
|
|
static bool isAlreadyLogged = false; \
|
|
if (!isAlreadyLogged) \
|
|
{ \
|
|
Compat::Log() << msg; \
|
|
isAlreadyLogged = true; \
|
|
} \
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, std::nullptr_t);
|
|
std::ostream& operator<<(std::ostream& os, const char* str);
|
|
std::ostream& operator<<(std::ostream& os, const unsigned char* data);
|
|
std::ostream& operator<<(std::ostream& os, const WCHAR* wstr);
|
|
|
|
namespace Compat
|
|
{
|
|
using ::operator<<;
|
|
|
|
namespace detail
|
|
{
|
|
template <typename T>
|
|
struct Hex
|
|
{
|
|
explicit Hex(T val) : val(val) {}
|
|
T val;
|
|
};
|
|
|
|
template <typename Elem>
|
|
struct Array
|
|
{
|
|
Array(const Elem* elem, const unsigned long size) : elem(elem), size(size) {}
|
|
const Elem* elem;
|
|
const unsigned long size;
|
|
};
|
|
|
|
template <typename T>
|
|
struct Out
|
|
{
|
|
explicit Out(T val) : val(val) {}
|
|
T val;
|
|
};
|
|
|
|
class LogParams;
|
|
|
|
class LogFirstParam
|
|
{
|
|
public:
|
|
LogFirstParam(std::ostream& os) : m_os(os) {}
|
|
template <typename T> LogParams operator<<(const T& val) { m_os << val; return LogParams(m_os); }
|
|
|
|
protected:
|
|
std::ostream& m_os;
|
|
};
|
|
|
|
class LogParams
|
|
{
|
|
public:
|
|
LogParams(std::ostream& os) : m_os(os) {}
|
|
template <typename T> LogParams& operator<<(const T& val) { m_os << ',' << val; return *this; }
|
|
|
|
operator std::ostream&() { return m_os; }
|
|
|
|
private:
|
|
std::ostream& m_os;
|
|
};
|
|
|
|
template <typename T>
|
|
std::ostream& operator<<(std::ostream& os, Hex<T> hex)
|
|
{
|
|
os << "0x" << std::hex << hex.val << std::dec;
|
|
return os;
|
|
}
|
|
|
|
template <typename Elem>
|
|
std::ostream& operator<<(std::ostream& os, Array<Elem> array)
|
|
{
|
|
os << '[';
|
|
if (Log::isPointerDereferencingAllowed())
|
|
{
|
|
if (0 != array.size)
|
|
{
|
|
os << array.elem[0];
|
|
}
|
|
for (unsigned long i = 1; i < array.size; ++i)
|
|
{
|
|
os << ',' << array.elem[i];
|
|
}
|
|
}
|
|
return os << ']';
|
|
}
|
|
|
|
template <typename T>
|
|
std::ostream& operator<<(std::ostream& os, Out<T> out)
|
|
{
|
|
++Log::s_outParamDepth;
|
|
os << out.val;
|
|
--Log::s_outParamDepth;
|
|
return os;
|
|
}
|
|
}
|
|
|
|
template <typename T> detail::Hex<T> hex(T val)
|
|
{
|
|
return detail::Hex<T>(val);
|
|
}
|
|
|
|
template <typename Elem>
|
|
detail::Array<Elem> array(const Elem* elem, const unsigned long size)
|
|
{
|
|
return detail::Array<Elem>(elem, size);
|
|
}
|
|
|
|
template <typename T> detail::Out<T> out(const T& val)
|
|
{
|
|
return detail::Out<T>(val);
|
|
}
|
|
|
|
class Log
|
|
{
|
|
public:
|
|
Log();
|
|
~Log();
|
|
|
|
template <typename T>
|
|
Log& operator<<(const T& t)
|
|
{
|
|
s_logFile << t;
|
|
return *this;
|
|
}
|
|
|
|
static bool isPointerDereferencingAllowed() { return s_isLeaveLog || 0 == s_outParamDepth; }
|
|
|
|
protected:
|
|
template <typename... Params>
|
|
Log(const char* prefix, const char* funcName, Params... params) : Log()
|
|
{
|
|
s_logFile << prefix << ' ' << funcName << '(';
|
|
toList(params...);
|
|
s_logFile << ')';
|
|
}
|
|
|
|
private:
|
|
friend class LogFunc;
|
|
template <typename T> friend std::ostream& detail::operator<<(std::ostream& os, detail::Out<T> out);
|
|
|
|
void toList()
|
|
{
|
|
}
|
|
|
|
template <typename Param>
|
|
void toList(Param param)
|
|
{
|
|
s_logFile << param;
|
|
}
|
|
|
|
template <typename Param, typename... Params>
|
|
void toList(Param firstParam, Params... remainingParams)
|
|
{
|
|
s_logFile << firstParam << ", ";
|
|
toList(remainingParams...);
|
|
}
|
|
|
|
ScopedCriticalSection m_lock;
|
|
|
|
static thread_local DWORD s_indent;
|
|
static thread_local DWORD s_outParamDepth;
|
|
static thread_local bool s_isLeaveLog;
|
|
|
|
static std::ofstream s_logFile;
|
|
};
|
|
|
|
class LogStruct : public detail::LogFirstParam
|
|
{
|
|
public:
|
|
LogStruct(std::ostream& os) : detail::LogFirstParam(os) { m_os << '{'; }
|
|
~LogStruct() { m_os << '}'; }
|
|
};
|
|
|
|
#ifdef DEBUGLOGS
|
|
typedef Log LogDebug;
|
|
|
|
class LogFunc
|
|
{
|
|
public:
|
|
template <typename... Params>
|
|
LogFunc(const char* funcName, Params... params)
|
|
: m_printCall([=](Log& log) { log << funcName << '('; log.toList(params...); log << ')'; })
|
|
{
|
|
Log log;
|
|
log << "> ";
|
|
m_printCall(log);
|
|
Log::s_indent += 2;
|
|
}
|
|
|
|
~LogFunc()
|
|
{
|
|
Log::s_isLeaveLog = true;
|
|
Log::s_indent -= 2;
|
|
Log log;
|
|
log << "< ";
|
|
m_printCall(log);
|
|
|
|
if (m_printResult)
|
|
{
|
|
log << " = ";
|
|
m_printResult(log);
|
|
}
|
|
Log::s_isLeaveLog = false;
|
|
}
|
|
|
|
template <typename T>
|
|
T setResult(T result)
|
|
{
|
|
m_printResult = [=](Log& log) { log << std::hex << result << std::dec; };
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
std::function<void(Log&)> m_printCall;
|
|
std::function<void(Log&)> m_printResult;
|
|
};
|
|
#else
|
|
class LogDebug
|
|
{
|
|
public:
|
|
template <typename T> LogDebug& operator<<(const T&) { return *this; }
|
|
};
|
|
|
|
class LogFunc
|
|
{
|
|
public:
|
|
template <typename... Params>
|
|
LogFunc(const char* /*funcName*/, Params...)
|
|
{
|
|
}
|
|
|
|
template <typename T>
|
|
T setResult(T result)
|
|
{
|
|
return result;
|
|
}
|
|
};
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
typename std::enable_if<std::is_class<T>::value && !std::is_same<T, std::string>::value, std::ostream&>::type
|
|
operator<<(std::ostream& os, const T& t)
|
|
{
|
|
return os << static_cast<const void*>(&t);
|
|
}
|
|
|
|
template <typename T>
|
|
typename std::enable_if<std::is_class<T>::value, std::ostream&>::type
|
|
operator<<(std::ostream& os, T* t)
|
|
{
|
|
if (!t)
|
|
{
|
|
return os << "null";
|
|
}
|
|
|
|
if (!Compat::Log::isPointerDereferencingAllowed())
|
|
{
|
|
return os << static_cast<const void*>(t);
|
|
}
|
|
|
|
return os << *t;
|
|
}
|
|
|
|
template <typename T>
|
|
std::ostream& operator<<(std::ostream& os, T** t)
|
|
{
|
|
if (!t)
|
|
{
|
|
return os << "null";
|
|
}
|
|
|
|
os << static_cast<const void*>(t);
|
|
|
|
if (Compat::Log::isPointerDereferencingAllowed())
|
|
{
|
|
os << '=' << *t;
|
|
}
|
|
|
|
return os;
|
|
}
|