#std::vformat Logging + AZERTY conveniences

1 messages · Page 1 of 1 (latest)

steady pilot
#

@subtle jackal Improved with error catching on bad formats (no crash now 😄 ). Also this way exposes both styles so you can type AZERTY style or copy and paste standard style and just use the correct macro.

LOG(LogTemp, Warning, "{}", 42); // "42"
AZERTY_LOG(LogTemp, Warning, "§%", 42); // "42"
/**
 * Swaps brace characters for a std::format string.
 * Used to make it easier to type format strings on non-QWERTY keyboards.
 * Brace characters will swap to their substitute so that they are still available.
 *
 * FString Format = TEXT("§% {}"); 
 * FString ActualFormat = SwapFormatBraces(Format, L'§', L'%'); // "{} §%"
 * 
 * @param    Format                    std::format string
 * @param    LeftBraceSubstitute        Substitute for { in format
 * @param    RightBraceSubstitute    Substitute for } in format
 * @return    Swapped std::format string
 */
inline FString SwapFormatBraces(const FString& Format, const FString::ElementType LeftBraceSubstitute, const FString::ElementType RightBraceSubstitute)
{
    FString Result = Format;
    for(int32 i=0; i < Result.Len(); ++i)
    {
        if(LeftBraceSubstitute == Result[i]) {
            Result[i] = '{';
        }
        else if(RightBraceSubstitute == Result[i]) {
            Result[i] = '}'; 
        }
        else if('{' == Result[i]) {
            Result[i] = LeftBraceSubstitute; 
        }
        else if('}' == Result[i]) {
            Result[i] = RightBraceSubstitute; 
        }
    }
    return Result;
}

/**
 * Formats a string using std::vformat
 *
 * FString Format = TEXT("{}"); 
 * FString Formatted = FormatString(Format, 42); // "42"
 * 
 * @param    Format    std::format string
 * @param    Args    Arguments
 * @return    Formatted string
 */
template <typename ... TArgs>
FString FormatString(const FString& Format, TArgs... Args)
{
    try
    {
        return std::vformat(*Format, std::make_wformat_args(Args...)).c_str();
    }
    catch(std::format_error& FormatError)
    {
        return FString::Printf(TEXT("String Format Error: %s \"%s\""), *FString(FormatError.what()), *Format);
    }
}

/**
 * Formats a string using SwapFormatBraces and std::vformat 
 *
 * FString Format = TEXT("§%"); 
 * FString Formatted = FormatString_UsingSwappedFormatBraces(Format, L'§', L'%', 42); // "42"
 * 
 * @param    Format    std::format string
 * @param    LeftBraceSubstitute        Substitute for { in format
 * @param    RightBraceSubstitute    Substitute for } in format
 * @param    Args    Arguments
 * @return    Formatted string
 */
template <typename ... TArgs>
FString FormatString_UsingSwappedFormatBraces(const FString& Format, const FString::ElementType LeftBraceSubstitute, const FString::ElementType RightBraceSubstitute, TArgs... Args)
{
    const FString ActualFormat = SwapFormatBraces(Format, LeftBraceSubstitute, RightBraceSubstitute);
    try
    {
        return std::vformat(*ActualFormat, std::make_wformat_args(Args...)).c_str();
    }
    catch(std::format_error& FormatError)
    {
        return FString::Printf(TEXT("String Format Error: %s \"%s\" -> \"%s\""), *FString(FormatError.what()), *Format, *ActualFormat);
    }
}

/**
 * Log using std::vformat
 *
 * LOG(LogTemp, Warning, "{}", 42); // "42"
 */
#define LOG(CATEGORY, VERBOSITY, FORMAT, ...) UE_LOG(CATEGORY, VERBOSITY, TEXT("%s"), *FormatString(TEXT(FORMAT), ##__VA_ARGS__))

/**
 * Log using std::vformat and substitute braces for AZERTY keyboards
 *
 * AZERTY_LOG(LogTemp, Warning, "§%", 42); // "42"
 */
#define AZERTY_LOG(CATEGORY, VERBOSITY, FORMAT, ...) UE_LOG(CATEGORY, VERBOSITY, TEXT("%s"), *FormatString_UsingSwappedFormatBraces(TEXT(FORMAT), L'§', L'%', ##__VA_ARGS__))
subtle jackal
#

@steady pilot for some reasons i cant use strings as the args

#
0>format(3417): Error C2338 : static_assert failed: 'Cannot format an argument. To make type T formattable, provide a formatter<T> specialization. See N4928 [format.arg.store]/2 and [formatter.requirements].'
#

and

0>format(1782): Error C2665 : 'std::_Format_arg_traits<_Context>::_Phony_basic_format_arg_constructor': no overloaded function could convert all the argument types
steady pilot
subtle jackal
steady pilot
subtle jackal
#

sometimes i want to do a ternary with a string

steady pilot
#

but also why would you do that

subtle jackal
#

ig ill make a var

steady pilot
#

just put it in the format

#

if it's static text like that

#

but anyway

LOG(LogTemp, Warning, "{}", TEXT("some text"));

might work lemme check

subtle jackal
#

ill try later

subtle jackal
#

okay great

#

then this is fine

steady pilot
#

you just need the TEXT macro if you're gonna put in fixed text

subtle jackal
#

this works but this doesnt

// works
SL_INDVLOG("Inventory component slot change delegate got fired. Index: §%, Item Tag: §%", Index, Item ? 10 : 10);

// compile error
SL_INDVLOG("Inventory component slot change delegate got fired. Index: §%, Item Tag: §%", Index, Item ? Item->GetDebugName() : TEXT("Null"));
// or
const FString& Temp = "Null";
    SL_INDVLOG("Inventory component slot change delegate got fired. Index: §%, Item Tag: §%", Index, Item ? Item->GetDebugName() : Temp);

@steady pilot

#

#define SL_INDVLOG(FORMAT, ...) SL_LOG(LogLSInventorySystem, Display, GetWorld(), FORMAT, ##__VA_ARGS__)

#

and SL_LOG is
#define SL_SLOG(CATEGORY, VERBOSITY, FORMAT, ...) UE_LOG(CATEGORY, VERBOSITY, TEXT("%s %s"), __FUNCTIONW__, *FormatString_UsingSwappedFormatBraces(TEXT(FORMAT), L'§', L'%', ##__VA_ARGS__))

steady pilot
steady pilot
#

assuming FString GetDebugName()

subtle jackal
#

yes

#

okay

#

it worked, thanks

#

sorry for disturbing

steady pilot
#

np

#

we can expand this log system like Laura did to do some of this automatically for you

#

I'll help you with that later though

subtle jackal
#

i can type a * im not that lazy