Skip to content

Commit 71832b6

Browse files
authored
std::format support (#1025)
1 parent d056690 commit 71832b6

File tree

12 files changed

+113
-5
lines changed

12 files changed

+113
-5
lines changed

cppwinrt/code_writers.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ namespace cppwinrt
115115
}
116116
}
117117

118+
[[nodiscard]] static finish_with wrap_ifdef(writer& w, std::string_view macro)
119+
{
120+
auto format = R"(#ifdef %
121+
)";
122+
123+
w.write(format, macro);
124+
125+
return { w, write_endif };
126+
}
127+
118128
static void write_parent_depends(writer& w, cache const& c, std::string_view const& type_namespace)
119129
{
120130
auto pos = type_namespace.rfind('.');
@@ -3216,6 +3226,18 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable<T, D, %>
32163226
type);
32173227
}
32183228

3229+
static void write_std_formatter(writer& w, TypeDef const& type)
3230+
{
3231+
if (implements_interface(type, "Windows.Foundation.IStringable"))
3232+
{
3233+
auto generics = type.GenericParam();
3234+
3235+
w.write(" template<%> struct formatter<%, wchar_t> : formatter<winrt::Windows::Foundation::IStringable, wchar_t> {};\n",
3236+
bind<write_generic_typenames>(generics),
3237+
type);
3238+
}
3239+
}
3240+
32193241
static void write_namespace_special(writer& w, std::string_view const& namespace_name)
32203242
{
32213243
if (namespace_name == "Windows.Foundation")
@@ -3259,6 +3281,7 @@ struct __declspec(empty_bases) produce_dispatch_to_overridable<T, D, %>
32593281
if (namespace_name == "Windows.Foundation")
32603282
{
32613283
w.write(strings::base_reference_produce_1);
3284+
w.write(strings::base_stringable_format);
32623285
}
32633286
}
32643287
}

cppwinrt/cppwinrt.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
<ClInclude Include="..\strings\base_string.h" />
8282
<ClInclude Include="..\strings\base_string_input.h" />
8383
<ClInclude Include="..\strings\base_string_operators.h" />
84+
<ClInclude Include="..\strings\base_stringable_format.h" />
8485
<ClInclude Include="..\strings\base_types.h" />
8586
<ClInclude Include="..\strings\base_version.h" />
8687
<ClInclude Include="..\strings\base_version_odr.h" />

cppwinrt/cppwinrt.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@
169169
<ClInclude Include="..\strings\base_iterator.h">
170170
<Filter>strings</Filter>
171171
</ClInclude>
172+
<ClInclude Include="..\strings\base_stringable_format.h">
173+
<Filter>strings</Filter>
174+
</ClInclude>
172175
</ItemGroup>
173176
<ItemGroup>
174177
<ResourceCompile Include="$(OutDir)version.rc" />

cppwinrt/file_writers.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,9 +197,17 @@ namespace cppwinrt
197197
}
198198
{
199199
auto wrap_std = wrap_std_namespace(w);
200-
auto wrap_lean = wrap_lean_and_mean(w);
201-
w.write_each<write_std_hash>(members.interfaces);
202-
w.write_each<write_std_hash>(members.classes);
200+
201+
{
202+
auto wrap_lean = wrap_lean_and_mean(w);
203+
w.write_each<write_std_hash>(members.interfaces);
204+
w.write_each<write_std_hash>(members.classes);
205+
}
206+
{
207+
auto wrap_format = wrap_ifdef(w, "__cpp_lib_format");
208+
w.write_each<write_std_formatter>(members.interfaces);
209+
w.write_each<write_std_formatter>(members.classes);
210+
}
203211
}
204212

205213
write_namespace_special(w, ns);

cppwinrt/helpers.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,27 @@ namespace cppwinrt
498498
return result;
499499
}
500500

501+
static bool implements_interface(TypeDef const& type, std::string_view const& name)
502+
{
503+
for (auto&& impl : type.InterfaceImpl())
504+
{
505+
const auto iface = impl.Interface();
506+
if (iface.type() != TypeDefOrRef::TypeSpec && type_name(iface) == name)
507+
{
508+
return true;
509+
}
510+
}
511+
512+
if (auto base = get_base_class(type))
513+
{
514+
return implements_interface(base, name);
515+
}
516+
else
517+
{
518+
return false;
519+
}
520+
}
521+
501522
bool has_fastabi_tearoffs(writer& w, TypeDef const& type)
502523
{
503524
for (auto&& [name, info] : get_interfaces(w, type))

strings/base_includes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
#include <directxmath.h>
2525
#endif
2626

27+
#ifdef __cpp_lib_format
28+
#include <format>
29+
#endif
30+
2731
#ifdef __cpp_lib_coroutine
2832

2933
#include <coroutine>

strings/base_string.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ WINRT_EXPORT namespace winrt
327327
return rend();
328328
}
329329

330-
#if __cpp_lib_starts_ends_with
330+
#ifdef __cpp_lib_starts_ends_with
331331
bool starts_with(wchar_t const value) const noexcept
332332
{
333333
return operator std::wstring_view().starts_with(value);
@@ -437,6 +437,11 @@ WINRT_EXPORT namespace winrt
437437
}
438438
}
439439

440+
#ifdef __cpp_lib_format
441+
template<>
442+
struct std::formatter<winrt::hstring, wchar_t> : std::formatter<std::wstring_view, wchar_t> {};
443+
#endif
444+
440445
namespace winrt::impl
441446
{
442447
template <> struct abi<hstring>

strings/base_stringable_format.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
#ifdef __cpp_lib_format
3+
template<>
4+
struct std::formatter<winrt::Windows::Foundation::IStringable, wchar_t> : std::formatter<winrt::hstring, wchar_t>
5+
{
6+
template<typename FormatContext>
7+
auto format(winrt::Windows::Foundation::IStringable const& obj, FormatContext& fc)
8+
{
9+
return std::formatter<winrt::hstring, wchar_t>::format(obj.ToString(), fc);
10+
}
11+
};
12+
#endif

test/test_cpp20/format.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#include "pch.h"
2+
#include <format>
3+
4+
struct stringable : winrt::implements<stringable, winrt::Windows::Foundation::IStringable>
5+
{
6+
winrt::hstring ToString()
7+
{
8+
return L"a stringable object";
9+
}
10+
};
11+
12+
TEST_CASE("format")
13+
{
14+
{
15+
winrt::hstring str = L"World";
16+
REQUIRE(std::format(L"Hello {}", str) == L"Hello World");
17+
}
18+
19+
{
20+
winrt::Windows::Foundation::IStringable obj = winrt::make<stringable>();
21+
REQUIRE(std::format(L"This is {}", obj) == L"This is a stringable object");
22+
}
23+
24+
{
25+
winrt::Windows::Data::Json::JsonArray jsonArray;
26+
REQUIRE(std::format(L"The contents of the array are: {}", jsonArray) == L"The contents of the array are: []");
27+
}
28+
}

test/test_cpp20/hstring.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ TEST_CASE("hstring")
1010
REQUIRE(text.ends_with(L"rocks!"));
1111
REQUIRE(textView.ends_with(L"rocks!"));
1212
REQUIRE(text.ends_with(L"rocks!") == textView.ends_with(L"rocks!"));
13-
}
13+
}

0 commit comments

Comments
 (0)