Caution
The libary is not ready for commercial use, bugs may still be present.
A modern C++ header-only formatting library that provides powerful string manipulation utilities and custom formatter creation capabilities for std::format.
- π Header-only library - just include and use
- π¦ Modern C++20 implementation
- π οΈ Rich string manipulation utilities
- π¨ Custom formatter creation with macros
- π§ Namespace and case formatting options
- πͺ Type-safe formatting with compile-time checks
Since EasyFMT is a header-only library, you just need to include the headers in your project:
#include <easy_fmt/easy_fmt.hpp>Make sure your compiler supports C++20 features, as this library uses modern C++ features like concepts and std::format.
The library provides a comprehensive set of string manipulation functions under the easy_fmt::string_utils namespace:
using namespace easy_fmt::string_utils;
// String trimming
auto trimmed = trim(" hello "); // "hello"
auto frontTrimmed = trimStart(" hello"); // "hello"
auto backTrimmed = trimEnd("hello "); // "hello"
// Case conversion
auto upper = toUpper("hello"); // "HELLO"
auto lower = toLower("HELLO"); // "hello"
auto cap = capitalize("hello"); // "Hello"
// String operations
auto parts = split("a,b,c", ','); // vector<string>{"a", "b", "c"}
auto joined = join({"a", "b", "c"}, ","); // "a,b,c"
auto repeated = repeat("ha", 3); // "hahaha"
// String checks
bool has = contains("hello", "ll"); // true
bool starts = startsWith("hello", "he"); // true
bool ends = endsWith("hello", "lo"); // trueEasyFMT makes it easy to create custom formatters for your types using macros. Here's an example:
namespace log {
enum class LogLevel { Debug, Info, Warning, Error };
}
CREATE_FORMATTER(
log::LogLevel,
"log::LogLevel::{}",
FORMATTER_MODULES(
FORMATTER_USING_NAMESPACE(log)
FORMATTER_CREATE_ENUM_MAP_MODULE(
LogLevel,
AS_STR,
static_cast<int>,
{
{ LogLevel::Debug, "DEBUG" },
{ LogLevel::Info, "INFO" },
{ LogLevel::Warning, "WARN" },
{ LogLevel::Error, "ERROR" }
}
)
),
AS_STR(OBJ)
);
// Usage:
LogLevel level = LogLevel::Warning;
std::cout << std::format("{}", level); // Outputs: log::LogLevel::WARN
std::cout << std::format("{:L}", level); // Outputs (Same as "{:fL}"): log::loglevel::warn
std::cout << std::format("{:U}", level); // Outputs (Same as "{:fU}"): LOG::LOGLEVEL::WARN
std::cout << std::format("{:sL}", level); // Outputs: warn
std::cout << std::format("{:sU}", level); // Outputs: WARN-
Namespace options (use with
:sor:f)::f- Full namespace (default):s- Short form (last part only)
-
Case options (use with
:Lor:U):- Default - No case modification
:L- Convert to lowercase:U- Convert to uppercase
- C++20 compatible compiler
- Standard library with std::format support
This section explains all the available functions and there uses.
enum class FormatterNamespaceOption : unsigned char {
eFull,
eShort
};enum class FormatterCaseOption : unsigned char
{
eDefault,
eLower,
eUpper
};Each formatter will have these types assigned to variables (NAMESPACE_OPTION & CASE_OPTION). Before the the formatting stage begins the options "s", "f", "L", "U" will be parsed and will update the respective NAMESPACE_OPTION and CASE_OPTION variables, which can be used by modules and the actual formatting process. (NOTE: Some expressions may not work, its adviced to at max simply use ternary operations e.g. (CASE_OPTION == easy_fmt::FormatterCaseOption::eFull ? "Formatting for full ns" ? "Formatting for short ns"))
This section explains all the available macros and how they work together to create custom formatters.
The main macro to create a formatter for your custom type.
Type: The type you want to create a formatter forStringFmt: The format string template (e.g., "{}", "MyType::{}") (treat this the same as a std::format string)Modules: Module definitions (use FORMATTER_MODULES to group them)...: Arguments to be passed to the std::format string
CREATE_FORMATTER(MyType, "{}", FORMATTER_NO_MODULES, toString(OBJ))This macro will also provide an variable called OBJ (const Type&) by which you can process.
Groups multiple module definitions together. (NOTE: Its important you do not seperate the items by ',')
FORMATTER_MODULES(
FORMATTER_USING_NAMESPACE(my_namespace)
FORMATTER_CREATE_MODULE(...)
)Used when no additional modules are needed for the formatter.
Creates a custom module with specified type and implementation.
FORMATTER_CREATE_MODULE(
FORMATTER_MODULE_TYPE(string, MyType),
CONVERT_TO_STRING,
[](MyType v) -> string { return v.toString(); }
)Establishes the function type for an module. (NOTE: The use of auto has not been tested and therefore adviced against)
Creates a module for enum-to-string conversion.
Type: The enum typeName: The name of the conversion functionAsUnderlying: Function to convert enum to a underlying type. (NOTE: Data returned from this will be used as a parameter for easy_fmt::toString)Map: Mapping of enum values to strings
FORMATTER_CREATE_ENUM_MAP_MODULE(
LogLevel,
LOG_STR,
static_cast<int>,
{
{LogLevel::Debug, "DEBUG"},
{LogLevel::Info, "INFO"}
}
)Creates a module using a switch statement for conversion.
FORMATTER_CREATE_SWITCH_MODULE(
LogLevel,
LOG_STR,
{
case LogLevel::Debug: return "DEBUG";
case LogLevel::Info: return "INFO";
default: return "UNKNOWN";
}
)FORMATTER_TRIM_MODULE: Adds TRIMFORMATTER_TRIM_START_MODULE: Adds TRIM_STARTFORMATTER_TRIM_END_MODULE: Adds TRIM_ENDFORMATTER_TRIMMING_MODULES: Adds all trimming functions (TRIM_START, TRIM_END, TRIM)FORMATTER_CASE_CONVERSION_MODULES: Adds case conversion functionsFORMATTER_SPLIT_JOIN_MODULES: Adds string splitting and joining functions
CREATE_FORMATTER(
MyType,
"{}",
FORMATTER_MODULES(
FORMATTER_CASE_CONVERSION_MODULES
FORMATTER_TRIMMING_MODULES
),
TO_LOWER(TRIM(toString(OBJ)))
)FORMATTER_CONTAINS_MODULE: String containment checkFORMATTER_STARTS_WITH_MODULE: Prefix checkFORMATTER_ENDS_WITH_MODULE: Suffix checkFORMATTER_REPLACE_MODULE: String replacementFORMATTER_REMOVE_MODULE: String removalFORMATTER_SUBSTR_MODULE: Substring extractionFORMATTER_REPEAT_MODULE: String repetition
You can combine multiple modules to create sophisticated formatters:
CREATE_FORMATTER(
ComplexType,
"{}.{}",
FORMATTER_MODULES(
FORMATTER_USING_NAMESPACE(my_namespace)
FORMATTER_CASE_CONVERSION_MODULES
FORMATTER_CREATE_MODULE(
FORMATTER_MODULE_TYPE(string, ComplexType),
GET_PREFIX,
[](const ComplexType& obj) { return obj.getPrefix(); }
)
FORMATTER_CREATE_MODULE(
FORMATTER_MODULE_TYPE(string, ComplexType),
GET_SUFFIX,
[](const ComplexType& obj) { return obj.getSuffix(); }
)
),
TO_UPPER(GET_PREFIX(OBJ)),
TO_LOWER(GET_SUFFIX(OBJ))
)This creates a formatter that:
- Uses a custom namespace
- Adds case conversion capabilities
- Creates two custom modules for prefix and suffix extraction
- Formats the output with uppercase prefix and lowercase suffix