5 # ifndef VCCC_LOG_STREAM_WRAPPER_HPP
6 # define VCCC_LOG_STREAM_WRAPPER_HPP
18 # include <type_traits>
33 # if __cplusplus >= 201703
34 # include <filesystem>
36 # include <string_view>
38 # include "boost/pfr.hpp"
44 template<
typename T,
typename =
void>
45 struct has_typename_key_type : std::false_type {};
48 struct has_typename_key_type<T,
void_t<typename T::key_type>> : std::true_type {};
50 template<
typename T,
typename =
void>
51 struct has_typename_mapped_type : std::false_type {};
54 struct has_typename_mapped_type<T,
void_t<typename T::mapped_type>> : std::true_type {};
57 struct is_mapped_range : std::false_type {};
60 struct is_mapped_range<T, true>
62 has_typename_key_type<T>,
63 has_typename_mapped_type<T>,
64 is_specialization<ranges::range_value_t<T>, std::pair>
67 #if __cplusplus >= 201703L
69 struct empty_aggregate : std::false_type {};
72 struct empty_aggregate<T, true> :
bool_constant<boost::pfr::tuple_size<T>::value == 0> {};
96 template<
typename String,
typename Stream>
183 template<
typename CharT,
184 typename String = std::basic_string<CharT>,
185 typename Stream = std::basic_stringstream<CharT>>
211 template<
typename T, std::enable_if_t<
212 std::is_base_of<StreamManipulator, remove_cvref_t<T>>
220 template<
typename T, std::enable_if_t<
221 !std::is_base_of<StreamManipulator, remove_cvref_t<T>>
255 using default_printable_t = std::true_type;
256 using not_default_printable_t = std::false_type;
260 void try_write(default_printable_t,
const T&
value) {
265 template<std::
size_t N>
266 void try_write(default_printable_t,
const char(&
str)[N]) {
271 template<
typename T, std::
size_t N>
272 void try_write(default_printable_t,
const T(&arr)[N]) {
285 for (std::size_t i = 1; i < N; ++i) {
293 void try_write(default_printable_t,
const std::string& s) {
295 stream_ <<
"\"" << s <<
"\"";
300 void try_write(default_printable_t,
const string_view& sv) {
302 stream_ <<
"\"" << sv <<
"\"";
307 #if __cplusplus >= 201703L
310 stream_ <<
"\"" << sv <<
"\"";
317 constexpr
void try_write(not_default_printable_t,
const T&
value) {
321 #if __cplusplus >= 201703
323 template<
typename T, std::enable_if_t<conjunction<
324 negation<ranges::range<T>>,
325 std::is_aggregate<T>,
326 negation<detail::empty_aggregate<T>>
328 void write(
const T& aggr) {
330 writeAggregate(aggr, std::make_index_sequence<boost::pfr::tuple_size_v<T>>{});
336 void writeAggregate(
const T& aggr, std::index_sequence<>) {
341 void writeAggregate(
const T& aggr, std::index_sequence<0>) {
343 (*this) << boost::pfr::get<0>(aggr);
347 template<
typename T, std::size_t ...I>
348 void writeAggregate(
const T& aggr, std::index_sequence<0, I...>) {
350 (*this) << boost::pfr::get<0>(aggr);
351 (((*this) <<
", " << boost::pfr::get<I>(aggr) ), ...);
356 #if __cplusplus < 201703L
359 template<
typename T, std::enable_if_t<conjunction<
360 negation<ranges::range<T>>,
362 negation<std::is_aggregate<T>>,
363 detail::empty_aggregate<T>
367 void write(
const T&
value) {
372 void writeAddress(
const T&
value) {
378 void write(
const T&
value) {
383 void writeRange(
const T&
value) {
385 auto last =
value.end();
402 void writeRangeElement(
const T&
value,
bool) {
406 template<
typename T1,
typename T2>
407 void writeRangeElement(
const std::pair<T1, T2>&
value,
bool as_map) {
409 (*this) <<
value.first <<
" => " <<
value.second;
411 (*
this) <<
"{" <<
value.first <<
", " <<
value.second <<
"}";
415 template<
typename Rep,
typename Period>
416 void write(
const std::chrono::duration<Rep, Period>& duration);
418 template<
typename Duration>
419 void write(
const std::chrono::time_point<std::chrono::system_clock, Duration>& time_point);
421 template<
typename Clock,
typename Duration>
422 void write(
const std::chrono::time_point<Clock, Duration>& time_point) {
424 write(time_point.time_since_epoch());
427 void write(
const std::time_t* tt);
430 template<
typename ...Ts>
431 void write(
const std::tuple<Ts...>&
value) {
432 writeTupleLike(
value, std::index_sequence_for<Ts...>{});
435 template<
typename T1,
typename T2>
436 void write(
const std::pair<T1, T2>&
value) {
437 writeTupleLike(
value, std::index_sequence_for<T1, T2>{});
441 void writeTupleLike(
const T&, std::index_sequence<>) {
446 void writeTupleLike(
const T&
value, std::index_sequence<0>) {
448 (*this) << std::get<0>(
value);
450 (*this) <<
"{ " << std::get<0>(
value) <<
" }";
453 template<
typename T, std::size_t... I>
454 void writeTupleLike(
const T&
value, std::index_sequence<0, I...>) {
456 (*this) << std::get<0>(
value);
458 int dummy[
sizeof...(I)] = {
459 (((*this) <<
", " << std::get<I>(
value)), 0)...
466 template<
typename T, T ...v>
467 void write(
const std::integer_sequence<T, v...>&) {
468 writeTupleLike(std::make_tuple(v...), std::make_index_sequence<
sizeof...(v)>{});
473 void write(
const optional<T>& op) {
477 stream_ <<
"nullopt";
481 template<
typename... T>
482 void write(
const variant<T...>& v) {
483 if (v.valueless_by_exception()) {
484 stream_ <<
"valueless_by_exception";
487 v.visit([
this](
const auto& elem) {
493 void write(
const std::integral_constant<bool, v>& t) {
494 stream_ << (v ?
"true_type" :
"false_type");
499 inline void write(
const std::unique_ptr<T>& p) {
500 stream_ <<
"std::unique_ptr -> ";
501 writePointer(p.get());
506 inline void write(
const std::shared_ptr<T>& p) {
507 stream_ <<
"std::shared_ptr -> ";
508 writePointer(p.get());
513 inline void write(
const std::weak_ptr<T>& p) {
514 stream_ <<
"std::weak_ptr -> ";
515 writePointer(p.get());
519 void writePointer(
const T* ptr) {
524 # if __cplusplus >= 201703L
525 void write(
const std::filesystem::directory_entry& d) {
531 void write(
const std::optional<T>& op) {
535 stream_ <<
"nullopt";
539 template<
typename... T>
540 void write(
const std::variant<T...>& v) {
541 if (v.valueless_by_exception()) {
542 stream_ <<
"valueless_by_exception";
555 template<
typename CharT,
typename String,
typename Stream>
556 template<
typename Rep,
typename Period>
557 void BasicStreamWrapper<CharT, String, Stream>::write(
const std::chrono::duration<Rep, Period>& duration_) {
558 IOSFlagsSaver<stream_type> saver(stream_);
561 duration_ >= std::chrono::duration<Rep, Period>::zero() ?
562 duration_ : -duration_;
564 if(duration < std::chrono::minutes(1)) {
565 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration);
566 stream_ << std::setprecision(5);
568 if(duration < std::chrono::milliseconds(1)) {
569 if(duration < std::chrono::nanoseconds(1'000))
570 stream_ << ns.count() <<
"ns";
572 stream_ << ns.count() / 1'000.L <<
"us";
575 if(duration < std::chrono::milliseconds(1'000))
576 stream_ << ns.count() / 1'000'000.L <<
"ms";
578 stream_ << ns.count() / 1'000'000'000.L <<
"s";
582 using days = std::chrono::duration<long, std::ratio< 86400>>;
583 using months = std::chrono::duration<long, std::ratio< 2629746>>;
584 using years = std::chrono::duration<long, std::ratio<31556952>>;
586 auto hh = std::chrono::duration_cast<std::chrono::hours >(duration % days (1)).count();
587 auto mm = std::chrono::duration_cast<std::chrono::minutes >(duration % std::chrono::hours (1)).count();
588 auto ss = std::chrono::duration_cast<std::chrono::seconds >(duration % std::chrono::minutes(1)).count();
589 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration % std::chrono::seconds(1)).count();
591 if(duration >= days(1)) {
592 auto DD = std::chrono::duration_cast<days >(duration % months(1)).count();
593 auto MM = std::chrono::duration_cast<months>(duration % years(1)).count();
594 auto YY = std::chrono::duration_cast<years >(duration).count();
596 if(YY) stream_ << YY <<
"Y ";
597 if(MM) stream_ << MM <<
"M ";
598 if(DD) stream_ << DD <<
"D ";
599 stream_ << std::setw(2) << std::setfill(
' ');
602 if(hh || mm || ss || ms) {
603 if (duration >= std::chrono::hours(1))
604 stream_ << hh <<
"h "
605 << std::setw(2) << std::setfill(
' ') << mm <<
"m ";
606 else if (duration >= std::chrono::minutes(1))
607 stream_ << mm <<
"m ";
609 stream_ << std::setw(2) << std::setfill(
' ') << ss;
610 if (ms) stream_ <<
'.' << std::setw(3) << std::setfill(
'0') << ms;
616 template<
typename CharT,
typename String,
typename Stream>
617 template<
typename Duration>
618 void BasicStreamWrapper<CharT, String, Stream>::write(
const std::chrono::time_point<std::chrono::system_clock, Duration>& time_point) {
619 static auto localtime_m =
new std::mutex();
621 std::time_t tt = std::chrono::system_clock::to_time_t(time_point);
623 std::unique_lock<std::mutex> lck(*localtime_m);
624 const std::tm* tm_obj = std::localtime(&tt);
626 if (tm_obj ==
nullptr) {
627 const auto unix_timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(time_point.time_since_epoch()).count();
628 stream_ << unix_timestamp;
632 stream_ << std::put_time(tm_obj,
"%Y-%m-%d %H:%M:%S.");
636 auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
637 time_point.time_since_epoch() % std::chrono::seconds(1)).count();
638 IOSFlagsSaver<stream_type> saver(stream_);
639 stream_ << std::setfill(
'0') << std::setw(3) << ms;
642 template<
typename CharT,
typename String,
typename Stream>
643 void BasicStreamWrapper<CharT, String, Stream>::write(
const std::time_t *tt) {
644 static std::mutex localtime_m;
645 std::lock_guard<std::mutex> lck(localtime_m);
647 #pragma warning( disable : 4996)
648 const std::tm* tm_obj = std::localtime(tt);
649 if(tm_obj ==
nullptr)
652 stream_ << std::put_time(tm_obj,
"%Y-%m-%d %H:%M:%S.");
stream wrapper that supports extended operator overloading
Definition: stream_wrapper.hpp:186
CharT char_type
Definition: stream_wrapper.hpp:189
const stream_type & stream() const
Definition: stream_wrapper.hpp:238
BasicStreamWrapper & operator<<(std::ostream &(*pf)(std::ostream &))
Definition: stream_wrapper.hpp:199
BasicStreamWrapper(stream_type &&stream)
Definition: stream_wrapper.hpp:196
stream_type & stream()
Return internal stream.
Definition: stream_wrapper.hpp:237
BasicStreamWrapper()=default
BasicStreamWrapper & operator<<(std::ios_base &(&io_manip)(std::ios_base &))
Definition: stream_wrapper.hpp:205
BasicStreamWrapper(string_type str)
Definition: stream_wrapper.hpp:195
typename base::stream_type stream_type
Definition: stream_wrapper.hpp:190
BasicStreamWrapper & operator<<(const T &value)
Definition: stream_wrapper.hpp:223
void str(string_type s)
Equals to stream().str(string_type)
Definition: stream_wrapper.hpp:250
typename base::traits_type traits_type
Definition: stream_wrapper.hpp:192
BasicStreamWrapper & operator<<(const T &manipulator)
Definition: stream_wrapper.hpp:214
typename base::string_type string_type
Definition: stream_wrapper.hpp:191
string_type str() const
Equals to stream().str()
Definition: stream_wrapper.hpp:244
static bool expand_aggregate()
Definition: global_stream_wrapper_settings.hpp:30
static bool expand_array()
Definition: global_stream_wrapper_settings.hpp:38
static bool quote_string()
Definition: global_stream_wrapper_settings.hpp:21
Manipulator for vccc::StreamWrapper.
Definition: stream_wrapper.hpp:84
~StreamManipulator()=default
StreamManipulator()=default
Definition: stream_wrapper.hpp:97
VCCC_NODISCARD bool quote_string() const noexcept
Definition: stream_wrapper.hpp:131
bool expand_aggregate_
Definition: stream_wrapper.hpp:160
static string_type & global_separator()
Get global separator.
Definition: stream_wrapper.hpp:108
VCCC_NODISCARD bool expand_aggregate() const noexcept
Definition: stream_wrapper.hpp:139
String string_type
Definition: stream_wrapper.hpp:100
string_type separator_
Definition: stream_wrapper.hpp:157
const string_type & separator() const
Get current separator.
Definition: stream_wrapper.hpp:118
bool quote_string_
Definition: stream_wrapper.hpp:159
void expand_aggregate(bool new_value) noexcept
Definition: stream_wrapper.hpp:143
typename stream_type::traits_type traits_type
Definition: stream_wrapper.hpp:101
void expand_array(bool new_value)
Definition: stream_wrapper.hpp:151
void quote_string(bool new_value) noexcept
Definition: stream_wrapper.hpp:135
bool expand_array_
Definition: stream_wrapper.hpp:161
bool first_
Definition: stream_wrapper.hpp:158
string_type separator(string_type new_separator)
Set current separator.
Definition: stream_wrapper.hpp:125
Stream stream_type
Definition: stream_wrapper.hpp:99
VCCC_NODISCARD bool expand_array()
Definition: stream_wrapper.hpp:147
constexpr VCCC_INLINE_OR_STATIC detail::prev_niebloid prev
Definition: prev.hpp:53
std::enable_if_t< std::is_object< T >::value, T * > addressof(T &t) noexcept
Definition: addressof.hpp:33
basic_string_view< char > string_view
Definition: string_view.hpp:794
std::integral_constant< bool, v > bool_constant
Definition: bool_constant.hpp:19
constexpr R visit(Visitor &&vis, Variants &&... vars)
Definition: visit.hpp:93
Definition: matrix.hpp:495
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 0 > first
Definition: key_value.hpp:34
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
#define VCCC_NODISCARD
Definition: nodiscard.hpp:14
Definition: is_printable.hpp:26