format: add 'quoted' helper function that emulates std::quoted

This commit is contained in:
Danny Robson 2023-07-21 14:19:18 +10:00
parent fffd584c93
commit aaa00bc989
3 changed files with 119 additions and 0 deletions

View File

@ -352,6 +352,7 @@ list (
fixed_string.hpp
float.cpp
float.hpp
format/quoted.hpp
fourcc.cpp
fourcc.hpp
fs/scoped.cpp
@ -730,6 +731,7 @@ if (TESTS)
extent
fixed
float
format/quoted
fs/scoped
fs/tmp
geom/aabb

85
format/quoted.hpp Normal file
View File

@ -0,0 +1,85 @@
#pragma once
#include <fmt/format.h>
namespace cruft::format {
namespace detail {
/// A utility string container that is rendered enclosed in quotes when formatted.
template <typename string_type = std::string_view>
struct escaped_string {
/// The string that needs to be escaped
string_type source;
/// The character marking the beginning and end of the string that needs to be escaped
typename string_type::value_type delim;
/// The character that escapes other characters
typename string_type::value_type escape;
constexpr bool
escaped_character (char c) const
{
return delim == c or escape == c;
}
/// Copies the string characters to an output iterator, inserting
/// delim and escape characters as required.
template <typename OutputT>
constexpr
OutputT
copy (OutputT dst) const
{
*dst++ = delim;
for (const auto& c : source) {
if (escaped_character (c))
*dst++ = escape;
*dst++ = c;
}
*dst++ = delim;
return dst;
}
};
}
/// Returns an object that will be enclosed between delimiters. All
/// occurrences of this delimiter will be escaped with the supplied
/// character (as will occurences of this escape character).
constexpr
auto
quoted (
std::string_view source,
char delim = '"',
char escape = '\\'
) {
return cruft::format::detail::escaped_string<
std::string_view
> {
.source = source,
.delim = delim,
.escape = escape,
};
}
}
///////////////////////////////////////////////////////////////////////////////
template <typename string_type>
struct fmt::formatter<cruft::format::detail::escaped_string<string_type>> {
constexpr
format_parse_context::iterator
parse (fmt::format_parse_context ctx) const
{
return ctx.begin();
}
constexpr
format_context::iterator
format(
cruft::format::detail::escaped_string<string_type> const& val,
format_context & ctx
) const {
return val.copy (ctx.out());
}
};

32
test/format/quoted.cpp Normal file
View File

@ -0,0 +1,32 @@
#include <cruft/util/format/quoted.hpp>
#include <cruft/util/tap.hpp>
int main ()
{
static constexpr struct {
std::string_view format;
std::string_view inner;
std::string_view result;
std::string_view message;
} TESTS[] = {
{ "{}", "Foo", R"("Foo")", "Simple word" },
{ "{}", "F\"oo", R"("F\"oo")", "Embedded delim" },
{ "{}", "F\\oo", R"("F\\oo")", "Embedded escape" },
};
cruft::TAP::logger tap;
for (auto const &t: TESTS) {
auto const result = fmt::vformat (
t.format,
fmt::make_format_args (
cruft::format::quoted (t.inner)
)
);
tap.expect_eq (result, t.result, "quoted format: {}", t.message);
}
return tap.status ();
}