Skip to content
Permalink
Browse files
Merge pull request #10182 from Pokechu22/log-enum-class
Convert LOG_TYPE and LOG_LEVELS to enum class
  • Loading branch information
leoetlino committed Oct 24, 2021
2 parents 23159da + 04d8cdf commit 85bbc0d
Show file tree
Hide file tree
Showing 52 changed files with 376 additions and 258 deletions.
@@ -1336,7 +1336,7 @@ private void addExtensionTypeSettings(ArrayList<SettingsItem> sl, int wiimoteNum

private static int getLogVerbosityEntries()
{
// Value obtained from LOG_LEVELS in Common/Logging/Log.h
// Value obtained from LogLevel in Common/Logging/Log.h
if (NativeLibrary.GetMaxLogLevel() == 5)
{
return R.array.logVerbosityEntriesMaxLevelDebug;
@@ -1349,7 +1349,7 @@ private static int getLogVerbosityEntries()

private static int getLogVerbosityValues()
{
// Value obtained from LOG_LEVELS in Common/Logging/Log.h
// Value obtained from LogLevel in Common/Logging/Log.h
if (NativeLibrary.GetMaxLogLevel() == 5)
{
return R.array.logVerbosityValuesMaxLevelDebug;
@@ -145,7 +145,7 @@
<item>0</item>
</integer-array>

<!-- Log Verbosity selection based on LOG_LEVELS in Common/Logging/Log.h -->
<!-- Log Verbosity selection based on LogLevel in Common/Logging/Log.h -->
<string-array name="logVerbosityEntriesMaxLevelInfo" translatable="false">
<item>Notice</item>
<item>Error</item>
@@ -29,7 +29,8 @@ static void LogCallback(const char* format, ...)
const std::string message = StringFromFormatV(adapted_format.c_str(), args);
va_end(args);

instance->Log(Common::Log::LNOTICE, Common::Log::AUDIO, filename, lineno, message.c_str());
instance->Log(Common::Log::LogLevel::LNOTICE, Common::Log::LogType::AUDIO, filename, lineno,
message.c_str());
}

static void DestroyContext(cubeb* ctx)
@@ -21,7 +21,7 @@
#define DEBUG_ASSERT_MSG(_t_, _a_, _msg_, ...) \
do \
{ \
if constexpr (Common::Log::MAX_LOGLEVEL >= Common::Log::LOG_LEVELS::LDEBUG) \
if constexpr (Common::Log::MAX_LOGLEVEL >= Common::Log::LogLevel::LDEBUG) \
{ \
if (!(_a_)) \
{ \
@@ -43,6 +43,6 @@
#define DEBUG_ASSERT(_a_) \
do \
{ \
if constexpr (Common::Log::MAX_LOGLEVEL >= Common::Log::LOG_LEVELS::LDEBUG) \
if constexpr (Common::Log::MAX_LOGLEVEL >= Common::Log::LogLevel::LDEBUG) \
ASSERT(_a_); \
} while (0)
@@ -42,6 +42,7 @@ add_library(common
ENetUtil.cpp
ENetUtil.h
EnumFormatter.h
EnumMap.h
Event.h
FileSearch.cpp
FileSearch.h
@@ -27,6 +27,7 @@

#include "Common/Assert.h"
#include "Common/CommonTypes.h"
#include "Common/EnumMap.h"
#include "Common/Flag.h"
#include "Common/Inline.h"
#include "Common/Logging/Log.h"
@@ -175,6 +176,12 @@ class PointerWrap
DoArray(x.data(), static_cast<u32>(x.size()));
}

template <typename V, auto last_member, typename = decltype(last_member)>
void DoArray(Common::EnumMap<V, last_member>& x)
{
DoArray(x.data(), static_cast<u32>(x.size()));
}

template <typename T, typename std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
void DoArray(T* x, u32 count)
{
@@ -3,7 +3,8 @@

#pragma once

#include <array>
#include "Common/EnumMap.h"

#include <fmt/format.h>
#include <type_traits>

@@ -41,11 +42,15 @@
* formatter() : EnumFormatter(names) {}
* };
*/
template <auto last_member, typename T = decltype(last_member),
size_t size = static_cast<size_t>(last_member) + 1,
std::enable_if_t<std::is_enum_v<T>, bool> = true>
template <auto last_member, typename = decltype(last_member)>
class EnumFormatter
{
// The second template argument is needed to avoid compile errors from ambiguity with multiple
// enums with the same number of members in GCC prior to 8. See https://godbolt.org/z/xcKaW1seW
// and https://godbolt.org/z/hz7Yqq1P5
using T = decltype(last_member);
static_assert(std::is_enum_v<T>);

public:
constexpr auto parse(fmt::format_parse_context& ctx)
{
@@ -61,27 +66,27 @@ class EnumFormatter
{
const auto value_s = static_cast<std::underlying_type_t<T>>(e); // Possibly signed
const auto value_u = static_cast<std::make_unsigned_t<T>>(value_s); // Always unsigned
const bool has_name = value_s >= 0 && value_u < size && m_names[value_u] != nullptr;
const bool has_name = m_names.InBounds(e) && m_names[e] != nullptr;

if (!formatting_for_shader)
{
if (has_name)
return fmt::format_to(ctx.out(), "{} ({})", m_names[value_u], value_s);
return fmt::format_to(ctx.out(), "{} ({})", m_names[e], value_s);
else
return fmt::format_to(ctx.out(), "Invalid ({})", value_s);
}
else
{
if (has_name)
return fmt::format_to(ctx.out(), "{:#x}u /* {} */", value_u, m_names[value_u]);
return fmt::format_to(ctx.out(), "{:#x}u /* {} */", value_u, m_names[e]);
else
return fmt::format_to(ctx.out(), "{:#x}u /* Invalid */", value_u);
}
}

protected:
// This is needed because std::array deduces incorrectly if nullptr is included in the list
using array_type = std::array<const char*, size>;
using array_type = Common::EnumMap<const char*, last_member>;

constexpr explicit EnumFormatter(const array_type names) : m_names(std::move(names)) {}

@@ -0,0 +1,83 @@
// Copyright 2021 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <type_traits>

#include "Common/TypeUtils.h"

template <std::size_t position, std::size_t bits, typename T, typename StorageType>
struct BitField;

namespace Common
{
// A type that allows lookup of values associated with an enum as the key.
// Designed for enums whose numeric values start at 0 and increment continuously with few gaps.
template <typename V, auto last_member, typename = decltype(last_member)>
class EnumMap final
{
// The third template argument is needed to avoid compile errors from ambiguity with multiple
// enums with the same number of members in GCC prior to 8. See https://godbolt.org/z/xcKaW1seW
// and https://godbolt.org/z/hz7Yqq1P5
using T = decltype(last_member);
static_assert(std::is_enum_v<T>);
static constexpr size_t s_size = static_cast<size_t>(last_member) + 1;

using array_type = std::array<V, s_size>;
using iterator = typename array_type::iterator;
using const_iterator = typename array_type::const_iterator;

public:
constexpr EnumMap() = default;
constexpr EnumMap(const EnumMap& other) = default;
constexpr EnumMap& operator=(const EnumMap& other) = default;
constexpr EnumMap(EnumMap&& other) = default;
constexpr EnumMap& operator=(EnumMap&& other) = default;

// Constructor that accepts exactly size Vs (enforcing that all must be specified).
template <typename... T, typename = std::enable_if_t<Common::IsNOf<V, s_size, T...>::value>>
constexpr EnumMap(T... values) : m_array{static_cast<V>(values)...}
{
}

constexpr const V& operator[](T key) const { return m_array[static_cast<std::size_t>(key)]; }
constexpr V& operator[](T key) { return m_array[static_cast<std::size_t>(key)]; }

// These only exist to perform the safety check; without them, BitField's implicit conversion
// would work (but since BitField is used for game-generated data, we need to be careful about
// bounds-checking)
template <std::size_t position, std::size_t bits, typename StorageType>
constexpr const V& operator[](BitField<position, bits, T, StorageType> key) const
{
static_assert(1 << bits == s_size, "Unsafe indexing into EnumMap (may go out of bounds)");
return m_array[static_cast<std::size_t>(key.Value())];
}
template <std::size_t position, std::size_t bits, typename StorageType>
constexpr V& operator[](BitField<position, bits, T, StorageType> key)
{
static_assert(1 << bits == s_size, "Unsafe indexing into EnumMap (may go out of bounds)");
return m_array[static_cast<std::size_t>(key.value())];
}

constexpr bool InBounds(T key) const { return static_cast<std::size_t>(key) < s_size; }

constexpr size_t size() const noexcept { return s_size; }

constexpr V* data() { return m_array.data(); }
constexpr const V* data() const { return m_array.data(); }

constexpr iterator begin() { return m_array.begin(); }
constexpr iterator end() { return m_array.end(); }
constexpr const_iterator begin() const { return m_array.begin(); }
constexpr const_iterator end() const { return m_array.end(); }
constexpr const_iterator cbegin() const { return m_array.cbegin(); }
constexpr const_iterator cend() const { return m_array.cend(); }

constexpr void fill(const V& v) { m_array.fill(v); }

private:
array_type m_array{};
};
} // namespace Common
@@ -11,7 +11,7 @@ class ConsoleListener : public Common::Log::LogListener
ConsoleListener();
~ConsoleListener();

void Log(Common::Log::LOG_LEVELS level, const char* text) override;
void Log(Common::Log::LogLevel level, const char* text) override;

private:
bool m_use_color = false;
@@ -13,26 +13,26 @@ ConsoleListener::~ConsoleListener()
{
}

void ConsoleListener::Log(Common::Log::LOG_LEVELS level, const char* text)
void ConsoleListener::Log(Common::Log::LogLevel level, const char* text)
{
android_LogPriority logLevel = ANDROID_LOG_UNKNOWN;

// Map dolphin's log levels to android's
switch (level)
{
case Common::Log::LOG_LEVELS::LDEBUG:
case Common::Log::LogLevel::LDEBUG:
logLevel = ANDROID_LOG_DEBUG;
break;
case Common::Log::LOG_LEVELS::LINFO:
case Common::Log::LogLevel::LINFO:
logLevel = ANDROID_LOG_INFO;
break;
case Common::Log::LOG_LEVELS::LWARNING:
case Common::Log::LogLevel::LWARNING:
logLevel = ANDROID_LOG_WARN;
break;
case Common::Log::LOG_LEVELS::LERROR:
case Common::Log::LogLevel::LERROR:
logLevel = ANDROID_LOG_ERROR;
break;
case Common::Log::LOG_LEVELS::LNOTICE:
case Common::Log::LogLevel::LNOTICE:
logLevel = ANDROID_LOG_INFO;
break;
}
@@ -21,7 +21,7 @@ ConsoleListener::~ConsoleListener()
fflush(nullptr);
}

void ConsoleListener::Log(Common::Log::LOG_LEVELS level, const char* text)
void ConsoleListener::Log(Common::Log::LogLevel level, const char* text)
{
char color_attr[16] = "";
char reset_attr[16] = "";
@@ -31,15 +31,15 @@ void ConsoleListener::Log(Common::Log::LOG_LEVELS level, const char* text)
strcpy(reset_attr, "\x1b[0m");
switch (level)
{
case Common::Log::LOG_LEVELS::LNOTICE:
case Common::Log::LogLevel::LNOTICE:
// light green
strcpy(color_attr, "\x1b[92m");
break;
case Common::Log::LOG_LEVELS::LERROR:
case Common::Log::LogLevel::LERROR:
// light red
strcpy(color_attr, "\x1b[91m");
break;
case Common::Log::LOG_LEVELS::LWARNING:
case Common::Log::LogLevel::LWARNING:
// light yellow
strcpy(color_attr, "\x1b[93m");
break;
@@ -14,7 +14,7 @@ ConsoleListener::~ConsoleListener()
{
}

void ConsoleListener::Log([[maybe_unused]] Common::Log::LOG_LEVELS level, const char* text)
void ConsoleListener::Log([[maybe_unused]] Common::Log::LogLevel level, const char* text)
{
::OutputDebugStringW(UTF8ToWString(text).c_str());
}

0 comments on commit 85bbc0d

Please sign in to comment.