Added formattable utility.
This commit is contained in:
parent
d3659f11f7
commit
933a36d992
122
source/mijin/util/formattable.hpp
Normal file
122
source/mijin/util/formattable.hpp
Normal file
@ -0,0 +1,122 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef MIJIN_UTIL_FORMATTABLE_HPP_INCLUDED
|
||||
#define MIJIN_UTIL_FORMATTABLE_HPP_INCLUDED 1
|
||||
|
||||
#include <format>
|
||||
#include "../container/boxed_object.hpp"
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
|
||||
//
|
||||
// public concepts
|
||||
//
|
||||
|
||||
template<typename T>
|
||||
concept parse_result_type = requires
|
||||
{
|
||||
typename T::parse_result_t;
|
||||
};
|
||||
|
||||
template<typename T, typename TParseContext>
|
||||
concept parseable_by_type = parse_result_type &&
|
||||
requires(const T& object, TParseContext& parseContext)
|
||||
{
|
||||
{ T::parseFormat(parseContext) } -> std::convertible_to<std::pair<typename TParseContext::iterator, typename T::parse_result_t>>;
|
||||
};
|
||||
|
||||
template<typename T, typename TFmtContext>
|
||||
concept simple_formattable_to_type = requires(const T& object, TFmtContext& formatContext)
|
||||
{
|
||||
{ object.format(formatContext) } -> std::convertible_to<typename TFmtContext::iterator>;
|
||||
};
|
||||
|
||||
template<typename T, typename TFmtContext, typename TParseContext>
|
||||
concept complex_formattable_to_type = parseable_by_type<T, TParseContext> &&
|
||||
requires(const T& object, TParseContext& parseContext, TFmtContext& formatContext, T::parse_result_t& parseResult)
|
||||
{
|
||||
{ object.format(formatContext, parseResult) } -> std::convertible_to<typename TFmtContext::iterator>;
|
||||
};
|
||||
|
||||
template<typename T, typename TFmtContext, typename TParseContext>
|
||||
concept formattable_to_type = simple_formattable_to_type<T, TFmtContext> || complex_formattable_to_type<T, TFmtContext, TParseContext>;
|
||||
|
||||
template<typename T>
|
||||
concept cformattable_type = formattable_to_type<T, std::format_context, std::format_parse_context>;
|
||||
|
||||
template<typename T>
|
||||
concept wformattable_type = formattable_to_type<T, std::wformat_context, std::wformat_parse_context>;
|
||||
|
||||
template<typename T>
|
||||
concept formattable_type = cformattable_type<T> && wformattable_type<T>;
|
||||
|
||||
template<typename T>
|
||||
concept any_formattable_type = cformattable_type<T> || wformattable_type<T>;
|
||||
|
||||
//
|
||||
// internal types
|
||||
//
|
||||
|
||||
namespace impl
|
||||
{
|
||||
template<typename T>
|
||||
struct ParseResult
|
||||
{
|
||||
};
|
||||
|
||||
template<parse_result_type T>
|
||||
struct ParseResult<T>
|
||||
{
|
||||
BoxedObject<typename T::parse_result_t> value;
|
||||
};
|
||||
}
|
||||
} // namespace mijin
|
||||
|
||||
template<mijin::any_formattable_type T>
|
||||
struct std::formatter<T>
|
||||
{
|
||||
[[no_unique_address]] [[maybe_unused]] mijin::impl::ParseResult<T> parseResult;
|
||||
|
||||
template<typename TContext>
|
||||
constexpr TContext::iterator parse(TContext& ctx)
|
||||
{
|
||||
if constexpr (mijin::parse_result_type<T>)
|
||||
{
|
||||
static_assert(mijin::parseable_by_type<T, TContext>, "Type does not support parsing by this context.");
|
||||
auto [it, result] = T::parseFormat(ctx);
|
||||
parseResult.value.construct(std::move(result));
|
||||
return it;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
|
||||
if (it != end && *it != '}')
|
||||
{
|
||||
throw std::format_error("invalid format");
|
||||
}
|
||||
|
||||
return it;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TContext>
|
||||
TContext::iterator format(const T& object, TContext& ctx) const
|
||||
{
|
||||
if constexpr (mijin::parse_result_type<T>)
|
||||
{
|
||||
auto it = object.format(ctx, std::move(*parseResult.value));
|
||||
parseResult.destroy();
|
||||
return it;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(mijin::simple_formattable_to_type<T, TContext>, "Type does not support formatting to this context.");
|
||||
return object.format(ctx);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // MIJIN_UTIL_FORMATTABLE_HPP_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user