Skip to content

Commit

Permalink
[io] Add more stdc++ types to IOStream formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Dec 30, 2024
1 parent e7fc5eb commit 3f2f647
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 44 deletions.
32 changes: 0 additions & 32 deletions src/modm/architecture/interface/clock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,35 +95,3 @@ using PreciseClock = chrono::micro_clock;
using namespace ::std::chrono_literals;

} // namespace modm

#if MODM_HAS_IOSTREAM
#include <modm/io/iostream.hpp>

namespace modm
{

/// @ingroup modm_architecture_clock
template<class C, class D>
modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::time_point<C, D>& m)
{
s << m.time_since_epoch();
return s;
}

/// @ingroup modm_architecture_clock
template<class T, class R>
modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::duration<T, R>& m)
{
s << m.count();
if constexpr (std::is_same_v<R, std::nano>) s << "ns";
if constexpr (std::is_same_v<R, std::micro>) s << "us";
if constexpr (std::is_same_v<R, std::milli>) s << "ms";
if constexpr (std::is_same_v<R, std::ratio<60>>) s << "min";
if constexpr (std::is_same_v<R, std::ratio<3600>>) s << 'h';
return s;
}

} // modm namespace
#endif
15 changes: 13 additions & 2 deletions src/modm/io/iostream.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@
#include <inttypes.h>
#include <type_traits>
#include <climits>
#include <chrono>
#include <string_view>

#include "iodevice.hpp"
#include "iodevice_wrapper.hpp" // convenience

%% if using_printf
%% if options.with_printf
/// @cond
extern "C"
{
Expand Down Expand Up @@ -214,6 +216,13 @@ public:
operator << (const char* s)
{ device->write(s); return *this; }

inline IOStream&
operator << (const std::string_view sv)
{
for (const auto c : sv) device->write(c);
return *this;
}

/// write the hex value of a pointer
inline IOStream&
operator << (const void* p)
Expand Down Expand Up @@ -290,7 +299,7 @@ private:
private:
IODevice* const device;
Mode mode = Mode::Ascii;
%% if using_printf
%% if options.with_printf
static void out_char(char c, void* arg)
{ if (c) reinterpret_cast<modm::IOStream*>(arg)->write(c); }
printf_output_gadget_t output_gadget{out_char, this, NULL, 0, INT_MAX};
Expand Down Expand Up @@ -363,4 +372,6 @@ white(IOStream& ios);

} // namespace modm

#include "iostream_chrono.hpp"

#endif // MODM_IOSTREAM_HPP
208 changes: 208 additions & 0 deletions src/modm/io/iostream_chrono.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/*
* Copyright (c) 2024 Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include <chrono>
#include <ctime>
%% if options.with_printf
#include <inttypes.h>
%% endif

namespace modm
{

/// @ingroup modm_io
/// @{

%% if not is_avr
inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::year year)
{
%% if options.with_printf
return s.printf("%04" PRIi16, int16_t(int(year)));
%% else
return s << int(year);
%% endif
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::month month)
{
static constexpr std::string_view map = "???JanFebMarAprMayJunJulAugSepOctNovDec";
return s << map.substr((unsigned(month) <= 12 ? unsigned(month) : 0u) * 3, 3);
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::day day)
{
%% if options.with_printf
return s.printf("%02" PRIu8, uint8_t(unsigned(day)));
%% else
return s << unsigned(day);
%% endif
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::weekday wd)
{
static constexpr std::string_view map = "SunMonTueWedThuFriSat???";
return s << map.substr((wd.c_encoding() < 7u ? wd.c_encoding() : 7u) * 3, 3);
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::weekday_indexed wdi)
{
s << wdi.weekday();
const auto index = wdi.index();
if (1 <= index and index <= 5) return s << '[' << index << ']';
return s << "[?]";
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::weekday_last wdl)
{
return s << wdl.weekday() << "[last]";
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::month_day md)
{
return s << md.month() << '/' << md.day();
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::month_day_last mdl)
{
return s << mdl.month() << "/last";
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::month_weekday mwd)
{
return s << mwd.month() << '/' << mwd.weekday_indexed();
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::month_weekday_last mwdl)
{
return s << mwdl.month() << '/' << mwdl.weekday_last();
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::year_month ym)
{
return s << ym.year() << '/' << ym.month();
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::year_month_day& ymd)
{
%% if options.with_printf
return s.printf("%04" PRIi16 "-%02" PRIu8 "-%02" PRIu8,
int16_t(int(ymd.year())), uint8_t(unsigned(ymd.month())), uint8_t(unsigned(ymd.day())));
%% else
return s << ymd.year() << '-' << unsigned(ymd.month()) << '-' << ymd.day();
%% endif
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::year_month_day_last& ymdl)
{
return s << ymdl.year() << '/' << ymdl.month_day_last();
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::year_month_weekday& ymwd)
{
return s << ymwd.year() << '/' << ymwd.month() << '/' << ymwd.weekday_indexed();
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::year_month_weekday_last& ymwdl)
{
return s << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last();
}

template< class Duration >
modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::hh_mm_ss<Duration>& hms)
{
%% if options.with_printf
s.printf("%02" PRIu8 ":%02" PRIu8 ":%02" PRIu8 ".%03" PRIu16,
uint8_t(hms.hours().count()), uint8_t(hms.minutes().count()), uint8_t(hms.seconds().count()),
uint16_t(std::chrono::duration_cast<std::chrono::milliseconds>(hms.subseconds()).count()));
%% else
s << uint8_t(hms.hours().count()) << ':' << uint8_t(hms.minutes().count()) << ':' << uint8_t(hms.seconds().count());
s << '.' << uint16_t(std::chrono::duration_cast<std::chrono::milliseconds>(hms.subseconds()).count());
%% endif
return s;
}
%% endif

template< class Rep, class Period >
inline modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::duration<Rep, Period>& d)
{
s << d.count();

if constexpr (std::is_same_v<typename Period::type, std::atto>) s << "as";
if constexpr (std::is_same_v<typename Period::type, std::femto>) s << "fs";
if constexpr (std::is_same_v<typename Period::type, std::pico>) s << "ps";
if constexpr (std::is_same_v<typename Period::type, std::nano>) s << "ns";
if constexpr (std::is_same_v<typename Period::type, std::micro>) s << "us";
if constexpr (std::is_same_v<typename Period::type, std::milli>) s << "ms";
if constexpr (std::is_same_v<typename Period::type, std::centi>) s << "cs";
if constexpr (std::is_same_v<typename Period::type, std::deci>) s << "ds";
if constexpr (std::is_same_v<typename Period::type, std::ratio<1>>) s << 's';
if constexpr (std::is_same_v<typename Period::type, std::deca>) s << "as";
if constexpr (std::is_same_v<typename Period::type, std::hecto>) s << "hs";
if constexpr (std::is_same_v<typename Period::type, std::kilo>) s << "ks";
if constexpr (std::is_same_v<typename Period::type, std::mega>) s << "Ms";
if constexpr (std::is_same_v<typename Period::type, std::giga>) s << "Gs";
if constexpr (std::is_same_v<typename Period::type, std::tera>) s << "Ts";
if constexpr (std::is_same_v<typename Period::type, std::peta>) s << "Ps";
if constexpr (std::is_same_v<typename Period::type, std::exa>) s << "Es";

if constexpr (std::is_same_v<typename Period::type, std::ratio<60>>) s << "min";
if constexpr (std::is_same_v<typename Period::type, std::ratio<3600>>) s << 'h';
if constexpr (std::is_same_v<typename Period::type, std::ratio<86400>>) s << 'd';

return s;
}

template< class Clock, class Duration >
modm::IOStream&
operator << (modm::IOStream& s, const std::chrono::time_point<Clock, Duration>& tp)
{
return s << tp.time_since_epoch();
}

inline modm::IOStream&
operator << (modm::IOStream& s, const std::tm& tm)
{
%% if options.with_printf
s.printf("%04" PRIu16 "-%02" PRIu8 "-%02" PRIu8 " %02" PRIu8 ":%02" PRIu8 ":%02" PRIu8,
uint16_t(tm.tm_year + 1900u), uint8_t(tm.tm_mon), uint8_t(tm.tm_mday),
uint8_t(tm.tm_hour), uint8_t(tm.tm_min), uint8_t(tm.tm_sec));
%% else
s << (tm.tm_year + 1900u) << '-' << tm.tm_mon << '-' << tm.tm_mday << ' ';
s << tm.tm_hour << ':' << tm.tm_min << ':' << tm.tm_sec;
%% endif
return s;
}

/// @}

}



12 changes: 6 additions & 6 deletions src/modm/io/iostream_printf.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <cmath>
#include "iostream.hpp"

%% if using_printf
%% if options.with_printf
#include <printf/printf.h>
#include <printf/printf_config.h>

Expand Down Expand Up @@ -76,7 +76,7 @@ IOStream::vprintf(const char *fmt, va_list ap)
void
IOStream::writeInteger(int16_t value)
{
%% if using_printf
%% if options.with_printf
print_integer(&output_gadget, uint16_t(value < 0 ? -value : value),
value < 0, 10, 0, 0, FLAGS_SHORT);
%% else
Expand All @@ -90,7 +90,7 @@ IOStream::writeInteger(int16_t value)
void
IOStream::writeInteger(uint16_t value)
{
%% if using_printf
%% if options.with_printf
print_integer(&output_gadget, value, false, 10, 0, 0, FLAGS_SHORT);
%% else
// hard coded for 32'768
Expand All @@ -103,7 +103,7 @@ IOStream::writeInteger(uint16_t value)
void
IOStream::writeInteger(int32_t value)
{
%% if using_printf
%% if options.with_printf
print_integer(&output_gadget, uint32_t(value < 0 ? -value : value),
value < 0, 10, 0, 0, FLAGS_LONG);
%% else
Expand All @@ -117,7 +117,7 @@ IOStream::writeInteger(int32_t value)
void
IOStream::writeInteger(uint32_t value)
{
%% if using_printf
%% if options.with_printf
print_integer(&output_gadget, value, false, 10, 0, 0, FLAGS_LONG);
%% else
// hard coded for 4294967295
Expand Down Expand Up @@ -146,7 +146,7 @@ IOStream::writeInteger(uint64_t value)
void
IOStream::writeDouble(const double& value)
{
%% if using_printf
%% if options.with_printf
print_floating_point(&output_gadget, value, 0, 0, 0, true);
%% else
if(!std::isfinite(value)) {
Expand Down
12 changes: 8 additions & 4 deletions src/modm/io/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,20 @@ def prepare(module, options):

def build(env):
core = env[":target"].get_driver("core")["type"]
target = env[":target"].identifier
env.substitutions = {
"is_hosted": env[":target"].identifier.platform == "hosted",
"family": env[":target"].identifier.family,
"is_hosted": target.platform == "hosted",
"is_avr": target.platform == "avr",
"family": target.family,
"core": core,
"using_printf": env.has_module(":printf"),
}
env.outbasepath = "modm/src/modm/io"
env.copy(".", ignore=env.ignore_files("io.hpp", "iostream_printf.cpp.in", "iostream.hpp.in"))
env.copy("iodevice.hpp")
env.copy("iodevice_wrapper.hpp")
env.template("iostream_printf.cpp.in")
env.template("iostream.hpp.in")
env.template("iostream_chrono.hpp.in")
env.copy("iostream.cpp")

env.outbasepath = "modm/src/modm"
env.copy("io.hpp")
Expand Down

0 comments on commit 3f2f647

Please sign in to comment.