UdonLibrary 1.0.0
機械システム研究部 C++ ライブラリ
読み取り中…
検索中…
一致する文字列を見つけられません
Show.hpp
[詳解]
1//
2// 全プラットフォームで使用可能な表示関数
3//
4// Copyright (c) 2022-2024 udonrobo
5//
6
7#pragma once
8
13#include <utility>
14#include <string>
15
16#ifndef F
17# define F(x) (x)
18#endif
19
20#if (UDON_PLATFORM_OUTPUT_STREAM == UDON_PLATFORM_OUTPUT_CONSOLE) && UDON_PLATFORM_HAS_STL
21# include <iostream>
22#endif
23
24namespace Udon
25{
26
27 namespace Impl
28 {
29 using namespace Udon::Traits;
30
33 template <typename OutputStream>
35 {
36 using ResultType = bool;
37
38 template <typename... Args>
39 constexpr ResultType operator()(Args&&... args) const noexcept
40 {
41 return argsUnpack(std::forward<Args>(args)...);
42 }
43
44 private:
45 // 可変長引数展開
46 template <typename Head, typename... Tail>
47 constexpr ResultType argsUnpack(Head&& head, Tail&&... tail) const noexcept
48 {
49 // 全メンバが出力可能か判定し、論理積を得る
50 return Test<RemoveCVRefT<Head>>::test(*this, std::forward<Head>(head)) and argsUnpack(std::forward<Tail>(tail)...);
51 }
52
53 // 可変長引数展開 (終端)
54 constexpr ResultType argsUnpack() const noexcept { return true; }
55
56 public:
57 // T が出力可能な型か判定するテスト
58 // 部分特殊化を用いる
59 template <typename T, typename = void>
60 struct Test
61 {
62 static constexpr bool test(...)
63 {
64 // static_assert(AlwaysFalse<T>::value, "Udon::Print: T is not printable." __FUNCTION__);
65 return false;
66 }
67 };
68
69 // 列挙型は基底型が出力可能であるとき出力可能
70 template <typename Enum>
71 struct Test<Enum, EnableIfVoidT<IsEnum<Enum>::value>>
72 {
73 static constexpr bool test(...) { return true; }
74 };
75
76 // 配列型(文字配列除く)は要素が出力可能であるとき出力可能
77 template <typename Array>
78 struct Test<Array, EnableIfVoidT<
79 IsArray<Array>::value // 配列である
80 and not IsCString<Array>::value // C言語スタイル文字配列でない
81 and not IsOutputStreamable<OutputStream, Array>::value // ストリームへの出力が不可能
82 >>
83 {
84 template <typename T>
85 static constexpr bool test(const IsPrintableImpl& self, T&& array)
86 {
87 return Test<typename std::remove_extent<Array>::type>::test(self, *array); // 要素が出力可能である場合
88 }
89 };
90
91 //
92 // 以下、ユーザー定義型、もしくはストリームへ出力可能な型のオーバーロード解決を行う
93 //
94 // 出力用関数の使用優先度は
95 // 1. show 関数
96 // 2. ストリームへの出力
97 // 3. enumerate 関数
98
99 // show が存在、もしくはストリームへの出力が可能であれば出力可能
100 template <typename Printable>
101 struct Test<Printable, EnableIfVoidT<
102 HasMemberFunctionShow<Printable>::value // show 関数が存在する
103 or IsOutputStreamable<OutputStream, Printable>::value // ストリームへの出力が可能
104 >>
105 {
106 static constexpr bool test(...) { return true; }
107 };
108
109 // enumerate が存在すれば出力可能
110 template <typename Enumerable>
111 struct Test<Enumerable, EnableIfVoidT<
112 HasMemberFunctionEnumerate<Enumerable>::value // enumerate 関数が存在する
113 and not HasMemberFunctionShow<Enumerable>::value // show 関数が存在しない
114 and not IsOutputStreamable<OutputStream, Enumerable>::value // ストリームへの出力が不可能
115 >>
116 {
117 template <typename T>
118 static constexpr bool test(const IsPrintableImpl& tester, T&& e)
119 {
120 return e.enumerate(tester); // enumerate 関数が true を返した場合
121 }
122 };
123 };
124
129 template <typename OutputStream>
131 {
132 public:
133 constexpr Printer(OutputStream& stream, bool delimiterEnable)
134 : stream(stream)
135 , delimiterEnable(delimiterEnable)
136 {
137 }
138
139 using ResultType = void;
140
141 template <typename... Args>
142 constexpr ResultType operator()(Args&&... args) const
143 {
144 const_cast<Printer&>(*this).argsUnpack(std::forward<Args>(args)...);
145 }
146
147 private:
148 OutputStream& stream; // 出力先
149
150 bool delimiterEnable; // 区切り文字を出力するか
151
153 template <typename Head, typename... Tail>
154 ResultType argsUnpack(Head&& head, Tail&&... tail)
155 {
156 print(std::forward<Head>(head));
157 if (delimiterEnable and sizeof...(Tail) > 0)
158 stream << ", ";
159 argsUnpack(std::forward<Tail>(tail)...);
160 }
161
164 template <typename Head>
165 ResultType argsUnpack(Head&& head)
166 {
167 print(std::forward<Head>(head));
168 }
169
171 // ResultType argsUnpack() {}
172
173 private:
175 template <typename Enum, EnableIfNullptrT<IsEnum<RemoveCVRefT<Enum>>::value> = nullptr>
176 ResultType print(Enum&& e)
177 {
178 print(static_cast<typename std::underlying_type<RemoveCVRefT<Enum>>::type>(e));
179 }
180
183 template <typename Array, EnableIfNullptrT<
184 IsArray<RemoveCVRefT<Array>>::value // 配列である
185 and not IsCString<RemoveCVRefT<Array>>::value // C言語スタイル文字列は配列として扱わない
186 and not IsOutputStreamable<OutputStream, RemoveCVRefT<Array>>::value // ストリームへの出力が不可能
187 > = nullptr>
188 ResultType print(Array&& array)
189 {
190 stream << "{ ";
191 bool isFirst = true;
192 for (auto&& e : array)
193 {
194 if (isFirst)
195 isFirst = false;
196 else
197 stream << ", ";
198 print(e);
199 }
200 stream << " }";
201 }
202
203 // 出力用関数の優先度
204 // 1. show()
205 // 2. operator<<()
206 // 3. enumerate()
207
209 template <typename Printable, EnableIfNullptrT<HasMemberFunctionShow<RemoveCVRefT<Printable>>::value> = nullptr>
210 ResultType print(Printable&& printable)
211 {
212 printable.show();
213 }
214
216 template <typename OutputStreamable, EnableIfNullptrT<
217 IsOutputStreamable<OutputStream, RemoveCVRefT<OutputStreamable>>::value // ストリームへ出力可能
218 and not HasMemberFunctionShow<RemoveCVRefT<OutputStreamable>>::value // show が存在しない
219 > = nullptr>
220 ResultType print(OutputStreamable&& outputStreamable)
221 {
222 stream << std::forward<OutputStreamable>(outputStreamable);
223 }
224
226 template <typename Enumerable, EnableIfNullptrT<
227 HasMemberFunctionEnumerate<RemoveCVRefT<Enumerable>>::value // enumerate が存在
228 and not HasMemberFunctionShow<RemoveCVRefT<Enumerable>>::value // show が存在しない
229 and not IsOutputStreamable<OutputStream, RemoveCVRefT<Enumerable>>::value // ストリームへ出力可能でない
230 > = nullptr>
231 ResultType print(Enumerable&& enumerable)
232 {
233 stream << "{ ";
234 enumerable.enumerate(*this);
235 stream << " }";
236 }
237 };
238
239 } // namespace Impl
240
241 namespace Traits
242 {
253 template <typename OutputStream, typename... Args>
255 : std::integral_constant<bool, Impl::IsPrintableImpl<OutputStream>{}(RemoveReferenceT<Args>{}...)>
256 {
257 };
258 } // namespace Traits
259
260#ifdef ARDUINO
261
262 struct ArduinoStream
263 {
264 template <typename T>
265 auto operator<<(T&& rhs)
266 -> decltype(Serial.print(std::forward<T>(rhs)), std::declval<ArduinoStream&>())
267 {
268 Serial.print(std::forward<T>(rhs));
269 return *this;
270 }
271 };
272
273#endif
274
275#ifdef SIV3D_INCLUDED
276
277 struct Siv3DStream
278 {
279 template <typename T>
280 auto operator<<(T&& rhs)
281 -> decltype(s3d::Print.write(std::forward<T>(rhs)), std::declval<Siv3DStream&>())
282 {
283 s3d::Print.write(std::forward<T>(rhs));
284 return *this;
285 }
286
287 auto operator<<(const char* rhs)
288 {
289 s3d::Print.write(s3d::Unicode::Widen(rhs));
290 return *this;
291 }
292 };
293
294#endif
295
296 namespace Impl
297 {
298
300 {
303 };
304
305 template <typename... Args>
306 void ShowImpl(const ShowConfig& config, Args&&... args)
307 {
308
309#if defined(ARDUINO)
310
311 static_assert(Traits::IsPrintable<ArduinoStream, Args...>::value, "T is not printable");
312 ArduinoStream stream;
313 Impl::Printer<ArduinoStream> printer{ stream, config.delimiter };
314
315#elif defined(SIV3D_INCLUDED)
316
317 static_assert(Traits::IsPrintable<Siv3DStream, Args...>::value, "T is not printable");
318 Siv3DStream stream;
319 Impl::Printer<Siv3DStream> printer{ stream, config.delimiter };
320
321#elif UDON_PLATFORM_OUTPUT_STREAM == UDON_PLATFORM_OUTPUT_CONSOLE
322
323 static_assert(Traits::IsPrintable<std::ostream, Args...>::value, "T is not printable");
324 Impl::Printer<std::ostream> printer{ std::cout, config.delimiter };
325
326#endif
327
328 printer(std::forward<Args>(args)...);
329
330 if (config.newline)
331 {
332 printer('\n');
333 }
334 }
335 } // namespace Impl
336
338 template <typename... Args>
339 void Show(Args&&... args)
340 {
341 const Impl::ShowConfig config{
342 /* .delimiter = */ true,
343 /* .newline = */ false,
344 };
345
346 Impl::ShowImpl(config, std::forward<Args>(args)...);
347 }
348
350 template <typename... Args>
351 void Showln(Args&&... args)
352 {
353 const Impl::ShowConfig config{
354 /* .delimiter = */ true,
355 /* .newline = */ true,
356 };
357 Impl::ShowImpl(config, std::forward<Args>(args)...);
358 }
359
361 template <typename... Args>
362 void ShowRaw(Args&&... args)
363 {
364 const Impl::ShowConfig config{
365 /* .delimiter = */ false,
366 /* .newline = */ false,
367 };
368 Impl::ShowImpl(config, std::forward<Args>(args)...);
369 }
370} // namespace Udon
メンバ変数を列挙しストリームへ出力する
Definition Show.hpp:131
constexpr ResultType operator()(Args &&... args) const
Definition Show.hpp:142
void ResultType
Definition Show.hpp:139
constexpr Printer(OutputStream &stream, bool delimiterEnable)
Definition Show.hpp:133
void ShowImpl(const ShowConfig &config, Args &&... args)
Definition Show.hpp:306
Definition SerializerTraits.hpp:92
std::is_enum< T > IsEnum
Definition Typedef.hpp:49
EnableIfT< Test, std::nullptr_t > EnableIfNullptrT
Definition Typedef.hpp:81
EnableIfT< Test, void > EnableIfVoidT
Definition Typedef.hpp:69
std::is_same< DecayT< T >, const char * > IsCString
Definition Typedef.hpp:58
std::is_array< T > IsArray
Definition Typedef.hpp:52
Definition Bit.hpp:12
void Showln(Args &&... args)
改行、区切り文字ありで出力する
Definition Show.hpp:351
void Show(Args &&... args)
区切り文字ありで出力する
Definition Show.hpp:339
void ShowRaw(Args &&... args)
改行、区切り文字なしで出力する
Definition Show.hpp:362
Definition Show.hpp:61
static constexpr bool test(...)
Definition Show.hpp:62
オブジェクトが全て出力可能か判定する
Definition Show.hpp:35
bool ResultType
Definition Show.hpp:36
constexpr ResultType operator()(Args &&... args) const noexcept
Definition Show.hpp:39
Definition Show.hpp:300
bool newline
Definition Show.hpp:302
bool delimiter
Definition Show.hpp:301
T に enumerate(f) が存在するかどうかを判定する
Definition HasMemberFunction.hpp:135
T に T::show 関数が存在するか
Definition HasMemberFunction.hpp:48
Definition HasMemberFunction.hpp:148
オブジェクトが全て出力可能か判定する
Definition Show.hpp:256