parselink-old/source/common/include/logging/traits.h
Kurt Sassenrath b0ed20369f Initial commit
* Logging ported from layover project with minor tweaks.
    * Logging test ported over.
    * Boost libraries are available.
2023-09-04 16:03:58 -07:00

116 lines
3.8 KiB
C++

//-----------------------------------------------------------------------------
// ___ __ _ _
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
// / ___/ (_| | | \__ \ __/ /__| | | | | <
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\
//
//-----------------------------------------------------------------------------
// Author: Kurt Sassenrath
// Module: Logging
//
// Type traits for massaging various types into something fmt-printable.
//
// Copyright (c) 2023 Kurt Sassenrath.
//
// License TBD.
//-----------------------------------------------------------------------------
#ifndef logging_traits_34e410874c0179c6
#define logging_traits_34e410874c0179c6
#include <type_traits>
#include <memory>
namespace parselink {
namespace logging {
// Customization point for printing out the enum name (value) and not the
// full type. The default prints the type name. An example is provided below.
//
// enum class Foo { Bar, Cat };
// Foo v{Foo::Bar};
// logger.log<...>("value: {}", v); // logs "value: Foo::Bar"
// logger.log<...>("value: {}", enum_name_only{v}); // logs "value: Bar"
template <typename E>
requires std::is_enum_v<E>
struct enum_name_only {
E v;
};
template <typename E>
enum_name_only(E) -> enum_name_only<E>;
// Wrapper for a string that will be colorized as if it's an error, instead of
// a normal string.
struct error_str {
template <std::convertible_to<std::string_view> T>
error_str(T&& t) : v(std::forward<T>(t)) {}
std::string_view v;
};
namespace detail {
// The following concepts aim to describe both raw and smart pointers in a
// way that the log formatter can deduce theme (color/format) as well as
// print the address without libformat's boilerplate (fmt::ptr).
template <typename T>
struct is_smart_pointer_type : std::false_type {};
template <typename T, typename D>
struct is_smart_pointer_type<std::unique_ptr<T, D>> : std::true_type {};
template <typename T>
struct is_smart_pointer_type<std::shared_ptr<T>> : std::true_type {};
template <typename T>
concept smart_pointer = is_smart_pointer_type<std::remove_cvref_t<T>>::value;
template <typename T>
using underlying_ptr_type = std::remove_cv_t<
std::remove_pointer_t<std::decay_t<std::remove_cvref_t<T>>>>;
template <typename T>
concept non_string_pointer =
std::is_pointer_v<std::decay_t<std::remove_cvref_t<T>>>
&& !std::is_same_v<underlying_ptr_type<T>, void>
&& !std::is_same_v<underlying_ptr_type<T>, char>;
template <typename T>
concept printable_pointer = smart_pointer<T> || non_string_pointer<T>;
// Some simple assertions to avoid breaking the code above.
static_assert(printable_pointer<int*>);
static_assert(printable_pointer<int*&>);
static_assert(printable_pointer<int const*&>);
static_assert(printable_pointer<int* const&>);
static_assert(printable_pointer<int (&)[4]>);
static_assert(printable_pointer<int const (&)[4]>);
static_assert(!printable_pointer<char*>);
static_assert(!printable_pointer<char*&>);
static_assert(!printable_pointer<char const*>);
static_assert(!printable_pointer<char const*&>);
static_assert(!printable_pointer<char (&)[4]>);
static_assert(!printable_pointer<char const (&)[4]>);
static_assert(!printable_pointer<void*>);
static_assert(!printable_pointer<void*&>);
static_assert(!printable_pointer<void const*>);
static_assert(!printable_pointer<void const*&>);
static_assert(printable_pointer<std::unique_ptr<int>>);
static_assert(printable_pointer<std::unique_ptr<int>&>);
static_assert(printable_pointer<std::unique_ptr<int> const&>);
static_assert(printable_pointer<std::unique_ptr<int const>>);
static_assert(printable_pointer<std::unique_ptr<int const>&>);
static_assert(printable_pointer<std::unique_ptr<int const> const&>);
} // namespace detail
} // namespace logging
} // namespace parselink
#endif // logging_traits_34e410874c0179c6