15 #ifndef PYTHON_TO_CPP_PRINT_HPP
16 #define PYTHON_TO_CPP_PRINT_HPP
26 #include <string_view>
27 #include <type_traits>
34 #ifndef PTC_DISABLE_STD_TYPES_PRINTING
41 #include <unordered_map>
52 using namespace std::literals::string_literals;
88 template <
class CharT>
89 std::conditional_t<std::is_same_v<CharT, char>,
const std::basic_string<CharT>&, std::basic_string<CharT>>
90 StringConverter(
const std::string& input_str )
92 if constexpr( std::is_same_v <CharT, char> )
96 else if constexpr( std::is_same_v <CharT, wchar_t> )
98 static std::wstring_convert <std::codecvt_utf8_utf16 <wchar_t>> converter_wchar_t;
99 return converter_wchar_t.from_bytes( input_str );
102 #if ( __cplusplus >= 202002L )
103 else if constexpr( std::is_same_v <CharT, char8_t> )
105 return reinterpret_cast <const char8_t*
>( input_str.c_str() );
108 else if constexpr( std::is_same_v <CharT, char16_t> )
110 static std::wstring_convert <std::codecvt_utf8_utf16 <char16_t>, char16_t> converter_16_t;
111 return converter_16_t.from_bytes( input_str );
113 else if constexpr( std::is_same_v <CharT, char32_t> )
115 static std::wstring_convert <std::codecvt_utf8_utf16 <char32_t>, char32_t> converter_32_t;
116 return converter_32_t.from_bytes( input_str );
121 return StringConverter<CharT>(
"" );
125 #ifndef PTC_DISABLE_STD_TYPES_PRINTING
133 template <
class T,
class T_str>
136 static std::false_type test( ... );
139 static auto test(
const U& u ) -> decltype( std::declval <std::basic_ostream<T_str>&>() << u, std::true_type{} );
141 static constexpr
bool value = decltype( test( std::declval <T>() ) )::value;
144 template<
class T,
class T_str>
145 inline constexpr
bool is_streamable_v = is_streamable<T, T_str>::value;
156 template <
class Container,
class T_str>
157 inline void print_adaptor( std::basic_ostream<T_str>& os,
const Container& container )
159 typename Container::const_iterator beg = container.begin();
160 std::basic_string<T_str> separator = StringConverter<T_str>(
""s );
162 while( beg != container.end() )
164 os << separator << *beg++;
165 separator = StringConverter<T_str>(
", "s );
178 template <
class Type,
class Container>
179 const Container& container_mod(
const std::stack<Type, Container>& stack )
181 struct HackedStack :
private std::stack<Type, Container>
183 static const Container& container(
const std::stack<Type, Container>& stack )
185 return stack.*&HackedStack::c;
189 return HackedStack::container( stack );
201 template <
class Type,
class Container >
202 const Container& container_mod(
const std::priority_queue<Type, Container>& priority_queue )
204 struct HackedQueue :
private std::priority_queue<Type, Container>
206 static const Container& container(
const std::priority_queue<Type, Container>& priority_queue )
208 return priority_queue.*&HackedQueue::c;
212 return HackedQueue::container( priority_queue );
219 #if defined( __GNUC__ ) && ( __GNUC___ <= 9 )
229 template <
class T_str>
230 inline std::basic_ostream<T_str>& operator << ( std::basic_ostream<T_str>& os, std::nullptr_t )
248 template <
class T_str,
class T_cmplx>
249 inline std::basic_ostream<T_str>& operator << ( std::basic_ostream<T_str>& os,
const std::complex<T_cmplx>& number )
251 os << number.real() <<
'+' << number.imag() <<
'j';
267 template <
class T_str,
class T,
class U>
268 inline std::basic_ostream<T_str>& operator <<( std::basic_ostream<T_str>& os,
const std::pair <T, U>& p )
270 os <<
'[' << p.first <<
", " << p.second <<
']';
287 template <
template <
typename,
typename...>
class ContainerType,
typename ValueType,
typename... Args,
class T_str>
288 std::enable_if_t< ! is_streamable_v <ContainerType <ValueType, Args...>, T_str>, std::basic_ostream<T_str>&>
289 operator <<( std::basic_ostream<T_str>& os,
const ContainerType<ValueType, Args...>& container )
291 static bool constexpr is_stack = std::is_same_v <ContainerType<ValueType, Args...>, std::stack<ValueType>>;
292 static bool constexpr is_pqueue = std::is_same_v <ContainerType<ValueType, Args...>, std::priority_queue<ValueType>>;
295 if constexpr ( ! is_stack && ! is_pqueue )
297 std::basic_string<T_str> separator = StringConverter<T_str>(
""s );
298 for (
const auto& elem: container )
302 separator = StringConverter<T_str>(
", "s );
307 print_adaptor( os, container_mod( container ) );
325 template <
class T_str,
class T,
size_t T_no>
326 std::basic_ostream<T_str>& operator <<( std::basic_ostream<T_str>& os,
const std::array<T, T_no>& container )
328 std::basic_string<T_str> separator = StringConverter<T_str>(
""s );
333 std::begin( container ),
334 std::prev( container.end() ),
335 std::ostream_iterator <T> { os,
", " }
337 os << container.back();
354 template <
class T_str,
class T1,
size_t arrSize,
355 typename = std::enable_if_t< ! std::is_same <T1,char>::value>>
356 std::basic_ostream<T_str>& operator <<( std::basic_ostream<T_str>& os,
const T1( & arr )[ arrSize ] )
361 std::basic_string<T_str> separator = StringConverter<T_str>(
""s );
362 for (
const auto& elem: arr )
366 separator = StringConverter<T_str>(
", "s );
385 template <
class T_str,
class T_time,
class int_type>
386 std::basic_ostream<T_str>& operator <<( std::basic_ostream<T_str>& os,
const std::chrono::duration<int_type, T_time>& val )
388 if constexpr( ! std::is_same_v<std::chrono::duration<int_type, T_time>, std::chrono::duration<int_type>> )
390 static std::unordered_map<std::type_index, std::basic_string_view<T_str>> time_map
392 {
typeid( std::nano ), StringConverter<T_str>(
"ns" ) },
393 {
typeid( std::micro ), StringConverter<T_str>(
"us" ) },
394 {
typeid( std::milli ), StringConverter<T_str>(
"ms" ) },
395 {
typeid( std::ratio<60> ), StringConverter<T_str>(
"min" ) },
396 {
typeid( std::ratio<3600> ), StringConverter<T_str>(
"h" ) }
399 #if ( __cplusplus >= 202002L )
400 time_map.insert( {
typeid( std::ratio<86400> ), StringConverter<T_str>(
"d" ) } );
401 time_map.insert( {
typeid( std::ratio<604800> ), StringConverter<T_str>(
"w" ) } );
402 time_map.insert( {
typeid( std::ratio<2629746> ), StringConverter<T_str>(
"mos" ) } );
403 time_map.insert( {
typeid( std::ratio<31556952> ), StringConverter<T_str>(
"y" ) } );
406 os << val.count() << time_map[
typeid( T_time ) ];
408 else if constexpr( std::is_same_v<std::chrono::duration<int_type, T_time>, std::chrono::duration<int_type>> )
410 os << val.count() <<
's';
426 template <
class T_str,
class T>
427 std::basic_ostream<T_str>& operator <<( std::basic_ostream<T_str>& os, std::optional<T>
const& opt )
429 if ( opt ) os << opt.value();
430 else os <<
"nullopt";
436 template<std::size_t...>
439 template<std::size_t N, std::size_t... Is>
440 struct gen_seq: gen_seq<N-1, N-1, Is...>{};
442 template<std::size_t... Is>
443 struct gen_seq<0, Is...> : seq<Is...>{};
445 template<
class T_str,
class Tuple, std::size_t... Is>
446 void print_tuple( std::basic_ostream<T_str>& os,
const Tuple& tup, seq<Is...> )
448 using swallow =
int[];
449 ( void )swallow{ 0, ( void( os << ( Is == 0 ?
"" :
", " ) << std::get<Is>( tup ) ), 0 )... };
452 template<
class T_str,
class... Args>
453 std::basic_ostream<T_str>& operator<<( std::basic_ostream<T_str>& os,
const std::tuple<Args...>& tup )
456 print_tuple( os, tup, gen_seq<
sizeof...( Args )>() );
477 template <
class T_str =
char,
class T>
478 std::basic_string<T_str> ptr( T* ptr )
480 static std::basic_ostringstream<T_str> oss;
481 oss.str( StringConverter<T_str>(
""s ) );
484 oss <<
"Value: " << ptr <<
"\n";
485 oss <<
"Address: " << &ptr;
499 template <
class T_str>
512 end( StringConverter<T_str>(
"\n"s ) ),
513 sep( StringConverter<T_str>(
" "s ) ),
516 #ifdef PTC_ENABLE_PERFORMANCE_IMPROVEMENTS
517 performance_options();
534 static std::basic_ostream<T> &
cout;
537 #ifdef PTC_ENABLE_PERFORMANCE_IMPROVEMENTS
548 static std::basic_istream<T> &cin;
604 pattern = pattern_val;
611 #ifdef PTC_ENABLE_GETTERS_FOR_UNIT_TESTS
619 inline const auto& getEnd()
const
630 inline const auto& getSep()
const
641 inline const bool& getFlush()
const
652 inline const auto& getPattern()
const
672 template <
class T,
class... Args>
675 if constexpr ( std::is_base_of_v <std::basic_ostream<T_str>, std::remove_reference_t<T>> )
677 print_backend( std::forward<T>(
first ), std::forward<Args>( args )... );
694 template <
class... Args>
697 if constexpr(
sizeof...( args ) > 0 )
703 static std::basic_ostringstream<T_str> oss;
704 oss.str( StringConverter<T_str>(
""s ) );
706 print_backend( oss, std::forward<Args>( args )... );
713 return StringConverter<T_str>(
"" );
725 if ( flush ) os << std::flush;
744 template <
typename T>
745 static constexpr
bool is_escape(
const T& str,
const ANSI& flag )
747 if constexpr( std::is_convertible_v <T, std::basic_string_view<T_str>> && ! std::is_same_v<T, std::nullptr_t> )
753 return ( std::basic_string_view<T_str>( str ).length() < 7 ) && (
str[0] ==
'\033' );
755 case( ANSI::generic ):
757 return ( std::basic_string_view<T_str>( str ).find(
'\033' ) != std::basic_string_view<T_str>::npos );
775 template <
class T_os,
class T,
class... Args>
776 void print_backend( T_os&& os, T&& first, Args&&... args )
const
778 std::lock_guard <std::mutex> lock{ mutex_ };
781 if( is_escape( first, ANSI::first ) || pattern.empty() ) os <<
first;
782 else os << pattern <<
first << pattern;
785 if constexpr(
sizeof...( args ) > 0 )
787 if ( is_escape( first, ANSI::first ) )
789 if( pattern.empty() ) ( ( os << args << sep ), ...);
790 else ( ( os << pattern << args << pattern << sep ), ...);
794 if( pattern.empty() ) ( ( os << sep << args ), ...);
795 else ( ( os << sep << pattern << args << pattern ), ...);
801 if constexpr(
sizeof...( args ) > 0 )
803 if ( is_escape( first, ANSI::generic ) || ( ( is_escape( args, ANSI::generic ) ) || ...) )
810 if ( is_escape( first, ANSI::generic ) )
817 if ( flush ) os << std::flush;
825 inline void performance_options()
const
827 std::lock_guard <std::mutex> lock{ mutex_ };
829 std::ios_base::sync_with_stdio(
false );
830 select_cout<T_str>::cout.tie(
nullptr );
832 #ifdef PTC_ENABLE_PERFORMANCE_IMPROVEMENTS
833 select_cin<T_str>::cin.tie(
nullptr );
840 std::basic_string<T_str> end, sep, pattern;
841 static std::mutex mutex_;
853 #ifdef PTC_ENABLE_PERFORMANCE_IMPROVEMENTS
865 #if ! defined( PTC_ENABLE_PERFORMANCE_IMPROVEMENTS ) && ! defined( __APPLE__ )
866 #if ( __cplusplus >= 202002L )
Print< wchar_t > wprint
Definition: print.hpp:863
mode
Enum class used to set up the "str" mode to pass a string with the content of the print function.
Definition: print.hpp:65
ANSI
Enum class used to switch among ANSI escape configurations in the "is_escape" function.
Definition: print.hpp:72
Print< char > print
Definition: print.hpp:862
Print< char32_t > print32
Definition: print.hpp:870
Print< char16_t > print16
Definition: print.hpp:869
Struct used to define a way to template the choice of the "std::cout" object in order to be "std::cou...
Definition: print.hpp:533
static std::basic_ostream< T > & cout
Definition: print.hpp:534
Class used to construct the print function.
Definition: print.hpp:501
Print()
Default constructor of the Print class. It initializes the basic class members and enable (if require...
Definition: print.hpp:511
void setEnd(const T &end_val)
Setter used to set the value of the "end" variable. Templated type is required in order to allow also...
Definition: print.hpp:565
void setSep(const T &sep_val)
Setter used to set the value of the "sep" variable. Templated type is required in order to allow also...
Definition: print.hpp:578
void setFlush(const bool &flush_val)
Setter used to set the value of the "flush" variable. Templated type is required in order to allow al...
Definition: print.hpp:589
void operator()(T &&first, Args &&... args) const
Frontend implementation of the () operator overload to print to the output stream....
Definition: print.hpp:673
const std::basic_string< T_str > operator()(mode &&first, Args &&... args) const
Frontend implementation of the () operator overload to initialize its content with an std::string obj...
Definition: print.hpp:695
void setPattern(const T &pattern_val)
Setter used to set the value of the "pattern" variable. Templated type is required in order to allow ...
Definition: print.hpp:602