Skip to content

Commit 3f2f647

Browse files
committed
[io] Add more stdc++ types to IOStream formatting
1 parent e7fc5eb commit 3f2f647

File tree

5 files changed

+235
-44
lines changed

5 files changed

+235
-44
lines changed

src/modm/architecture/interface/clock.hpp

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -95,35 +95,3 @@ using PreciseClock = chrono::micro_clock;
9595
using namespace ::std::chrono_literals;
9696

9797
} // namespace modm
98-
99-
#if MODM_HAS_IOSTREAM
100-
#include <modm/io/iostream.hpp>
101-
102-
namespace modm
103-
{
104-
105-
/// @ingroup modm_architecture_clock
106-
template<class C, class D>
107-
modm::IOStream&
108-
operator << (modm::IOStream& s, const std::chrono::time_point<C, D>& m)
109-
{
110-
s << m.time_since_epoch();
111-
return s;
112-
}
113-
114-
/// @ingroup modm_architecture_clock
115-
template<class T, class R>
116-
modm::IOStream&
117-
operator << (modm::IOStream& s, const std::chrono::duration<T, R>& m)
118-
{
119-
s << m.count();
120-
if constexpr (std::is_same_v<R, std::nano>) s << "ns";
121-
if constexpr (std::is_same_v<R, std::micro>) s << "us";
122-
if constexpr (std::is_same_v<R, std::milli>) s << "ms";
123-
if constexpr (std::is_same_v<R, std::ratio<60>>) s << "min";
124-
if constexpr (std::is_same_v<R, std::ratio<3600>>) s << 'h';
125-
return s;
126-
}
127-
128-
} // modm namespace
129-
#endif

src/modm/io/iostream.hpp.in

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
#include <inttypes.h>
2626
#include <type_traits>
2727
#include <climits>
28+
#include <chrono>
29+
#include <string_view>
2830

2931
#include "iodevice.hpp"
3032
#include "iodevice_wrapper.hpp" // convenience
3133

32-
%% if using_printf
34+
%% if options.with_printf
3335
/// @cond
3436
extern "C"
3537
{
@@ -214,6 +216,13 @@ public:
214216
operator << (const char* s)
215217
{ device->write(s); return *this; }
216218

219+
inline IOStream&
220+
operator << (const std::string_view sv)
221+
{
222+
for (const auto c : sv) device->write(c);
223+
return *this;
224+
}
225+
217226
/// write the hex value of a pointer
218227
inline IOStream&
219228
operator << (const void* p)
@@ -290,7 +299,7 @@ private:
290299
private:
291300
IODevice* const device;
292301
Mode mode = Mode::Ascii;
293-
%% if using_printf
302+
%% if options.with_printf
294303
static void out_char(char c, void* arg)
295304
{ if (c) reinterpret_cast<modm::IOStream*>(arg)->write(c); }
296305
printf_output_gadget_t output_gadget{out_char, this, NULL, 0, INT_MAX};
@@ -363,4 +372,6 @@ white(IOStream& ios);
363372

364373
} // namespace modm
365374

375+
#include "iostream_chrono.hpp"
376+
366377
#endif // MODM_IOSTREAM_HPP

src/modm/io/iostream_chrono.hpp.in

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* Copyright (c) 2024 Niklas Hauser
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#pragma once
13+
14+
#include <chrono>
15+
#include <ctime>
16+
%% if options.with_printf
17+
#include <inttypes.h>
18+
%% endif
19+
20+
namespace modm
21+
{
22+
23+
/// @ingroup modm_io
24+
/// @{
25+
26+
%% if not is_avr
27+
inline modm::IOStream&
28+
operator << (modm::IOStream& s, const std::chrono::year year)
29+
{
30+
%% if options.with_printf
31+
return s.printf("%04" PRIi16, int16_t(int(year)));
32+
%% else
33+
return s << int(year);
34+
%% endif
35+
}
36+
37+
inline modm::IOStream&
38+
operator << (modm::IOStream& s, const std::chrono::month month)
39+
{
40+
static constexpr std::string_view map = "???JanFebMarAprMayJunJulAugSepOctNovDec";
41+
return s << map.substr((unsigned(month) <= 12 ? unsigned(month) : 0u) * 3, 3);
42+
}
43+
44+
inline modm::IOStream&
45+
operator << (modm::IOStream& s, const std::chrono::day day)
46+
{
47+
%% if options.with_printf
48+
return s.printf("%02" PRIu8, uint8_t(unsigned(day)));
49+
%% else
50+
return s << unsigned(day);
51+
%% endif
52+
}
53+
54+
inline modm::IOStream&
55+
operator << (modm::IOStream& s, const std::chrono::weekday wd)
56+
{
57+
static constexpr std::string_view map = "SunMonTueWedThuFriSat???";
58+
return s << map.substr((wd.c_encoding() < 7u ? wd.c_encoding() : 7u) * 3, 3);
59+
}
60+
61+
inline modm::IOStream&
62+
operator << (modm::IOStream& s, const std::chrono::weekday_indexed wdi)
63+
{
64+
s << wdi.weekday();
65+
const auto index = wdi.index();
66+
if (1 <= index and index <= 5) return s << '[' << index << ']';
67+
return s << "[?]";
68+
}
69+
70+
inline modm::IOStream&
71+
operator << (modm::IOStream& s, const std::chrono::weekday_last wdl)
72+
{
73+
return s << wdl.weekday() << "[last]";
74+
}
75+
76+
inline modm::IOStream&
77+
operator << (modm::IOStream& s, const std::chrono::month_day md)
78+
{
79+
return s << md.month() << '/' << md.day();
80+
}
81+
82+
inline modm::IOStream&
83+
operator << (modm::IOStream& s, const std::chrono::month_day_last mdl)
84+
{
85+
return s << mdl.month() << "/last";
86+
}
87+
88+
inline modm::IOStream&
89+
operator << (modm::IOStream& s, const std::chrono::month_weekday mwd)
90+
{
91+
return s << mwd.month() << '/' << mwd.weekday_indexed();
92+
}
93+
94+
inline modm::IOStream&
95+
operator << (modm::IOStream& s, const std::chrono::month_weekday_last mwdl)
96+
{
97+
return s << mwdl.month() << '/' << mwdl.weekday_last();
98+
}
99+
100+
inline modm::IOStream&
101+
operator << (modm::IOStream& s, const std::chrono::year_month ym)
102+
{
103+
return s << ym.year() << '/' << ym.month();
104+
}
105+
106+
inline modm::IOStream&
107+
operator << (modm::IOStream& s, const std::chrono::year_month_day& ymd)
108+
{
109+
%% if options.with_printf
110+
return s.printf("%04" PRIi16 "-%02" PRIu8 "-%02" PRIu8,
111+
int16_t(int(ymd.year())), uint8_t(unsigned(ymd.month())), uint8_t(unsigned(ymd.day())));
112+
%% else
113+
return s << ymd.year() << '-' << unsigned(ymd.month()) << '-' << ymd.day();
114+
%% endif
115+
}
116+
117+
inline modm::IOStream&
118+
operator << (modm::IOStream& s, const std::chrono::year_month_day_last& ymdl)
119+
{
120+
return s << ymdl.year() << '/' << ymdl.month_day_last();
121+
}
122+
123+
inline modm::IOStream&
124+
operator << (modm::IOStream& s, const std::chrono::year_month_weekday& ymwd)
125+
{
126+
return s << ymwd.year() << '/' << ymwd.month() << '/' << ymwd.weekday_indexed();
127+
}
128+
129+
inline modm::IOStream&
130+
operator << (modm::IOStream& s, const std::chrono::year_month_weekday_last& ymwdl)
131+
{
132+
return s << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last();
133+
}
134+
135+
template< class Duration >
136+
modm::IOStream&
137+
operator << (modm::IOStream& s, const std::chrono::hh_mm_ss<Duration>& hms)
138+
{
139+
%% if options.with_printf
140+
s.printf("%02" PRIu8 ":%02" PRIu8 ":%02" PRIu8 ".%03" PRIu16,
141+
uint8_t(hms.hours().count()), uint8_t(hms.minutes().count()), uint8_t(hms.seconds().count()),
142+
uint16_t(std::chrono::duration_cast<std::chrono::milliseconds>(hms.subseconds()).count()));
143+
%% else
144+
s << uint8_t(hms.hours().count()) << ':' << uint8_t(hms.minutes().count()) << ':' << uint8_t(hms.seconds().count());
145+
s << '.' << uint16_t(std::chrono::duration_cast<std::chrono::milliseconds>(hms.subseconds()).count());
146+
%% endif
147+
return s;
148+
}
149+
%% endif
150+
151+
template< class Rep, class Period >
152+
inline modm::IOStream&
153+
operator << (modm::IOStream& s, const std::chrono::duration<Rep, Period>& d)
154+
{
155+
s << d.count();
156+
157+
if constexpr (std::is_same_v<typename Period::type, std::atto>) s << "as";
158+
if constexpr (std::is_same_v<typename Period::type, std::femto>) s << "fs";
159+
if constexpr (std::is_same_v<typename Period::type, std::pico>) s << "ps";
160+
if constexpr (std::is_same_v<typename Period::type, std::nano>) s << "ns";
161+
if constexpr (std::is_same_v<typename Period::type, std::micro>) s << "us";
162+
if constexpr (std::is_same_v<typename Period::type, std::milli>) s << "ms";
163+
if constexpr (std::is_same_v<typename Period::type, std::centi>) s << "cs";
164+
if constexpr (std::is_same_v<typename Period::type, std::deci>) s << "ds";
165+
if constexpr (std::is_same_v<typename Period::type, std::ratio<1>>) s << 's';
166+
if constexpr (std::is_same_v<typename Period::type, std::deca>) s << "as";
167+
if constexpr (std::is_same_v<typename Period::type, std::hecto>) s << "hs";
168+
if constexpr (std::is_same_v<typename Period::type, std::kilo>) s << "ks";
169+
if constexpr (std::is_same_v<typename Period::type, std::mega>) s << "Ms";
170+
if constexpr (std::is_same_v<typename Period::type, std::giga>) s << "Gs";
171+
if constexpr (std::is_same_v<typename Period::type, std::tera>) s << "Ts";
172+
if constexpr (std::is_same_v<typename Period::type, std::peta>) s << "Ps";
173+
if constexpr (std::is_same_v<typename Period::type, std::exa>) s << "Es";
174+
175+
if constexpr (std::is_same_v<typename Period::type, std::ratio<60>>) s << "min";
176+
if constexpr (std::is_same_v<typename Period::type, std::ratio<3600>>) s << 'h';
177+
if constexpr (std::is_same_v<typename Period::type, std::ratio<86400>>) s << 'd';
178+
179+
return s;
180+
}
181+
182+
template< class Clock, class Duration >
183+
modm::IOStream&
184+
operator << (modm::IOStream& s, const std::chrono::time_point<Clock, Duration>& tp)
185+
{
186+
return s << tp.time_since_epoch();
187+
}
188+
189+
inline modm::IOStream&
190+
operator << (modm::IOStream& s, const std::tm& tm)
191+
{
192+
%% if options.with_printf
193+
s.printf("%04" PRIu16 "-%02" PRIu8 "-%02" PRIu8 " %02" PRIu8 ":%02" PRIu8 ":%02" PRIu8,
194+
uint16_t(tm.tm_year + 1900u), uint8_t(tm.tm_mon), uint8_t(tm.tm_mday),
195+
uint8_t(tm.tm_hour), uint8_t(tm.tm_min), uint8_t(tm.tm_sec));
196+
%% else
197+
s << (tm.tm_year + 1900u) << '-' << tm.tm_mon << '-' << tm.tm_mday << ' ';
198+
s << tm.tm_hour << ':' << tm.tm_min << ':' << tm.tm_sec;
199+
%% endif
200+
return s;
201+
}
202+
203+
/// @}
204+
205+
}
206+
207+
208+

src/modm/io/iostream_printf.cpp.in

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
#include <cmath>
2323
#include "iostream.hpp"
2424

25-
%% if using_printf
25+
%% if options.with_printf
2626
#include <printf/printf.h>
2727
#include <printf/printf_config.h>
2828

@@ -76,7 +76,7 @@ IOStream::vprintf(const char *fmt, va_list ap)
7676
void
7777
IOStream::writeInteger(int16_t value)
7878
{
79-
%% if using_printf
79+
%% if options.with_printf
8080
print_integer(&output_gadget, uint16_t(value < 0 ? -value : value),
8181
value < 0, 10, 0, 0, FLAGS_SHORT);
8282
%% else
@@ -90,7 +90,7 @@ IOStream::writeInteger(int16_t value)
9090
void
9191
IOStream::writeInteger(uint16_t value)
9292
{
93-
%% if using_printf
93+
%% if options.with_printf
9494
print_integer(&output_gadget, value, false, 10, 0, 0, FLAGS_SHORT);
9595
%% else
9696
// hard coded for 32'768
@@ -103,7 +103,7 @@ IOStream::writeInteger(uint16_t value)
103103
void
104104
IOStream::writeInteger(int32_t value)
105105
{
106-
%% if using_printf
106+
%% if options.with_printf
107107
print_integer(&output_gadget, uint32_t(value < 0 ? -value : value),
108108
value < 0, 10, 0, 0, FLAGS_LONG);
109109
%% else
@@ -117,7 +117,7 @@ IOStream::writeInteger(int32_t value)
117117
void
118118
IOStream::writeInteger(uint32_t value)
119119
{
120-
%% if using_printf
120+
%% if options.with_printf
121121
print_integer(&output_gadget, value, false, 10, 0, 0, FLAGS_LONG);
122122
%% else
123123
// hard coded for 4294967295
@@ -146,7 +146,7 @@ IOStream::writeInteger(uint64_t value)
146146
void
147147
IOStream::writeDouble(const double& value)
148148
{
149-
%% if using_printf
149+
%% if options.with_printf
150150
print_floating_point(&output_gadget, value, 0, 0, 0, true);
151151
%% else
152152
if(!std::isfinite(value)) {

src/modm/io/module.lb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,20 @@ def prepare(module, options):
4141

4242
def build(env):
4343
core = env[":target"].get_driver("core")["type"]
44+
target = env[":target"].identifier
4445
env.substitutions = {
45-
"is_hosted": env[":target"].identifier.platform == "hosted",
46-
"family": env[":target"].identifier.family,
46+
"is_hosted": target.platform == "hosted",
47+
"is_avr": target.platform == "avr",
48+
"family": target.family,
4749
"core": core,
48-
"using_printf": env.has_module(":printf"),
4950
}
5051
env.outbasepath = "modm/src/modm/io"
51-
env.copy(".", ignore=env.ignore_files("io.hpp", "iostream_printf.cpp.in", "iostream.hpp.in"))
52+
env.copy("iodevice.hpp")
53+
env.copy("iodevice_wrapper.hpp")
5254
env.template("iostream_printf.cpp.in")
5355
env.template("iostream.hpp.in")
56+
env.template("iostream_chrono.hpp.in")
57+
env.copy("iostream.cpp")
5458

5559
env.outbasepath = "modm/src/modm"
5660
env.copy("io.hpp")

0 commit comments

Comments
 (0)