Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

時間型の fmt 対応 #894

Closed
Raclamusi opened this issue Sep 22, 2022 · 3 comments
Closed

時間型の fmt 対応 #894

Raclamusi opened this issue Sep 22, 2022 · 3 comments

Comments

@Raclamusi
Copy link
Member

時間型 ( std::chrono::duration ) を fmt に対応させることを提案します。

# include <Siv3D.hpp> // OpenSiv3D v0.6.5

void Main()
{
	Print << 1h + 3s;
	//Print << U"{}"_fmt(1h + 3s);  // error!

	while (System::Update());
}
実装案1
  • s3d::Format を使う
  • 実装が簡単
# include <Siv3D.hpp> // OpenSiv3D v0.6.5

template <class Rep, class Period>
struct SIV3D_HIDDEN fmt::formatter<std::chrono::duration<Rep, Period>, s3d::char32>
{
	std::u32string tag;

	auto parse(basic_format_parse_context<s3d::char32>& ctx)
	{
		return s3d::detail::GetFormatTag(tag, ctx);
	}

	template <class FormatContext>
	auto format(const std::chrono::duration<Rep, Period>& value, FormatContext& ctx)
	{
		const s3d::String s = s3d::Format(value);
		const basic_string_view<s3d::char32> sv(s.data(), s.size());

		if (tag.empty())
		{
			return format_to(ctx.out(), U"{}", sv);
		}
		else
		{
			const std::u32string format = (U"{:" + tag + U'}');
			return format_to(ctx.out(), format, sv);
		}
	}
};

void Main()
{
	Print << 1h + 3s;
	Print << U"{}"_fmt(1h + 3s);

	while (System::Update());
}
実装案2
  • fmt::format を使う
  • s3d::Literals::FormatLiterals::operator ""_fmt の結果は fmt::format と同じ方が自然?
  • 標準の出力と同じになるので、より多くの時間型に対応できる
  • s3d::Microseconds などの出力の単位が処理系定義になる ( μs or us )
# include <Siv3D.hpp> // OpenSiv3D v0.6.5

template <class Rep, class Period>
struct SIV3D_HIDDEN fmt::formatter<std::chrono::duration<Rep, Period>, s3d::char32>
{
	std::u32string tag;

	auto parse(basic_format_parse_context<s3d::char32>& ctx)
	{
		return s3d::detail::GetFormatTag(tag, ctx);
	}

	template <class FormatContext>
	auto format(const std::chrono::duration<Rep, Period>& value, FormatContext& ctx)
	{
		const s3d::String s = s3d::Unicode::Widen(fmt::format("{}", value));
		const basic_string_view<s3d::char32> sv(s.data(), s.size());

		if (tag.empty())
		{
			return format_to(ctx.out(), U"{}", sv);
		}
		else
		{
			const std::u32string format = (U"{:" + tag + U'}');
			return format_to(ctx.out(), format, sv);
		}
	}
};

void Main()
{
	using Picoseconds = std::chrono::duration<int64, std::pico>;
	using FemtosecondsF = std::chrono::duration<double, std::femto>;

	//Print << Picoseconds{ 42 };  // error!
	Print << U"{}"_fmt(Picoseconds{ 42 });
	Print << U"{}"_fmt(FemtosecondsF{ 42 });
	Print << U"{}"_fmt(std::chrono::years{ 42 });

	{
		// 標準の出力と同じ
		std::ostringstream oss;
		oss << Picoseconds{ 42 };
		assert(U"{}"_fmt(Picoseconds{ 42 }) == Unicode::Widen(oss.str()));
	}

	while (System::Update());
}
@Reputeless
Copy link
Member

Reputeless commented Sep 22, 2022

詳しい報告ありがとうございます!
μs/us の差異は好ましくない(Siv3D は μs us で統一したい)ので、v0.6 世代では実装案 1 が良いです。
pull-request と、コメントで assert で良いので簡単なテストを合わせて送っていただければマージします。

対応する時間型を増やせる件については、v0.8 世代で調査・検討したいと思います。

@Raclamusi
Copy link
Member Author

Siv3D って us じゃないですか?

void Formatter(FormatData& formatData, const Microseconds& microseconds)
{
detail::FormatDuration(formatData, microseconds, U"us");
}

@Reputeless
Copy link
Member

私の記憶違いでした。
us で一貫させたいです。

@Reputeless Reputeless moved this from ToDo to Done in v0.6 Roadmap Oct 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests

2 participants