[F] Fix incorrect behaviour in case of using standard iostream manipulators with fort::table.
This commit is contained in:
		| @@ -1,5 +1,9 @@ | |||||||
| ## v0.4.1 | ## v0.4.1 | ||||||
|  |  | ||||||
|  | ### Bug fixes | ||||||
|  |  | ||||||
|  | - Fix incorrect behaviour in case of using standard iostream manipulators with fort::table. | ||||||
|  |  | ||||||
| ### Internal | ### Internal | ||||||
|  |  | ||||||
| - Add alias `libfort::fort` for `fort` target that can be used via `add_subdirectory` in cmake. | - Add alias `libfort::fort` for `fort` target that can be used via `add_subdirectory` in cmake. | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								lib/fort.hpp
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								lib/fort.hpp
									
									
									
									
									
								
							| @@ -34,9 +34,11 @@ SOFTWARE. | |||||||
| #ifndef LIBFORT_HPP | #ifndef LIBFORT_HPP | ||||||
| #define LIBFORT_HPP | #define LIBFORT_HPP | ||||||
|  |  | ||||||
|  | #include <iomanip> | ||||||
|  | #include <sstream> | ||||||
| #include <string> | #include <string> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <sstream> | #include <type_traits> | ||||||
|  |  | ||||||
| #include "fort.h" | #include "fort.h" | ||||||
|  |  | ||||||
| @@ -150,6 +152,41 @@ const table_manipulator endr(1); | |||||||
|  */ |  */ | ||||||
| const table_manipulator separator(2); | const table_manipulator separator(2); | ||||||
|  |  | ||||||
|  | // Utility functions for internal library usage. | ||||||
|  | namespace detail | ||||||
|  | { | ||||||
|  | template <typename T> | ||||||
|  | constexpr bool is_stream_manipulator_impl() noexcept | ||||||
|  | { | ||||||
|  |     using Tdec = typename std::decay<T>::type; | ||||||
|  |     // Manipulators for integral types | ||||||
|  |     return std::is_same<Tdec, typename std::decay<decltype(std::dec)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::hex)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::oct)>::type>::value | ||||||
|  |            // Floating-point manipulators | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::fixed)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::scientific)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::hexfloat)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::defaultfloat)>::type>::value | ||||||
|  |            // Misc | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setbase(0))>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setfill('\0'))>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setprecision(0))>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setw(0))>::type>::value; | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Utility function that is used internally by the library to check if argument | ||||||
|  |  * passed to operator<< is a manipulator. In case default behaviour is not | ||||||
|  |  * enough write custom specialization of this function. | ||||||
|  |  */ | ||||||
|  | template <typename T> | ||||||
|  | constexpr bool is_stream_manipulator() noexcept | ||||||
|  | { | ||||||
|  |     return detail::is_stream_manipulator_impl<T>(); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Property owner. |  * Property owner. | ||||||
|  * |  * | ||||||
| @@ -534,8 +571,9 @@ public: | |||||||
|     template <typename T> |     template <typename T> | ||||||
|     table &operator<<(const T &arg) |     table &operator<<(const T &arg) | ||||||
|     { |     { | ||||||
|  |         constexpr bool is_manip = fort::is_stream_manipulator<typename std::decay<T>::type>(); | ||||||
|         stream_ << arg; |         stream_ << arg; | ||||||
|         if (stream_.tellp() >= 0) { |         if (stream_.tellp() >= 0 && !is_manip) { | ||||||
| #ifdef FT_HAVE_UTF8 | #ifdef FT_HAVE_UTF8 | ||||||
|             if (TT == table_type::character) { |             if (TT == table_type::character) { | ||||||
|                 ft_nwrite(table_, 1, stream_.str().c_str()); |                 ft_nwrite(table_, 1, stream_.str().c_str()); | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								src/fort.hpp
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								src/fort.hpp
									
									
									
									
									
								
							| @@ -34,9 +34,11 @@ SOFTWARE. | |||||||
| #ifndef LIBFORT_HPP | #ifndef LIBFORT_HPP | ||||||
| #define LIBFORT_HPP | #define LIBFORT_HPP | ||||||
|  |  | ||||||
|  | #include <iomanip> | ||||||
|  | #include <sstream> | ||||||
| #include <string> | #include <string> | ||||||
| #include <stdexcept> | #include <stdexcept> | ||||||
| #include <sstream> | #include <type_traits> | ||||||
|  |  | ||||||
| #include "fort.h" | #include "fort.h" | ||||||
|  |  | ||||||
| @@ -150,6 +152,41 @@ const table_manipulator endr(1); | |||||||
|  */ |  */ | ||||||
| const table_manipulator separator(2); | const table_manipulator separator(2); | ||||||
|  |  | ||||||
|  | // Utility functions for internal library usage. | ||||||
|  | namespace detail | ||||||
|  | { | ||||||
|  | template <typename T> | ||||||
|  | constexpr bool is_stream_manipulator_impl() noexcept | ||||||
|  | { | ||||||
|  |     using Tdec = typename std::decay<T>::type; | ||||||
|  |     // Manipulators for integral types | ||||||
|  |     return std::is_same<Tdec, typename std::decay<decltype(std::dec)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::hex)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::oct)>::type>::value | ||||||
|  |            // Floating-point manipulators | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::fixed)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::scientific)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::hexfloat)>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::defaultfloat)>::type>::value | ||||||
|  |            // Misc | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setbase(0))>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setfill('\0'))>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setprecision(0))>::type>::value | ||||||
|  |            || std::is_same<Tdec, typename std::decay<decltype(std::setw(0))>::type>::value; | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Utility function that is used internally by the library to check if argument | ||||||
|  |  * passed to operator<< is a manipulator. In case default behaviour is not | ||||||
|  |  * enough write custom specialization of this function. | ||||||
|  |  */ | ||||||
|  | template <typename T> | ||||||
|  | constexpr bool is_stream_manipulator() noexcept | ||||||
|  | { | ||||||
|  |     return detail::is_stream_manipulator_impl<T>(); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Property owner. |  * Property owner. | ||||||
|  * |  * | ||||||
| @@ -534,8 +571,9 @@ public: | |||||||
|     template <typename T> |     template <typename T> | ||||||
|     table &operator<<(const T &arg) |     table &operator<<(const T &arg) | ||||||
|     { |     { | ||||||
|  |         constexpr bool is_manip = fort::is_stream_manipulator<typename std::decay<T>::type>(); | ||||||
|         stream_ << arg; |         stream_ << arg; | ||||||
|         if (stream_.tellp() >= 0) { |         if (stream_.tellp() >= 0 && !is_manip) { | ||||||
| #ifdef FT_HAVE_UTF8 | #ifdef FT_HAVE_UTF8 | ||||||
|             if (TT == table_type::character) { |             if (TT == table_type::character) { | ||||||
|                 ft_nwrite(table_, 1, stream_.str().c_str()); |                 ft_nwrite(table_, 1, stream_.str().c_str()); | ||||||
|   | |||||||
| @@ -2,6 +2,16 @@ | |||||||
| #include "fort.hpp" | #include "fort.hpp" | ||||||
| #include "test_utils.hpp" | #include "test_utils.hpp" | ||||||
|  |  | ||||||
|  | namespace fort | ||||||
|  | { | ||||||
|  | // Write custom specialisation for testing purposes. | ||||||
|  | using setw_type = typename std::decay<decltype(std::setw(0))>::type; | ||||||
|  | template <> | ||||||
|  | constexpr bool is_stream_manipulator<setw_type>() noexcept | ||||||
|  | { | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | } | ||||||
|  |  | ||||||
| void test_cpp_bug_fixes(void) | void test_cpp_bug_fixes(void) | ||||||
| { | { | ||||||
| @@ -97,6 +107,40 @@ void test_cpp_bug_fixes(void) | |||||||
|             "+------+------+--------------------------------+\n"; |             "+------+------+--------------------------------+\n"; | ||||||
|         assert_string_equal(table_str, table_str_etalon); |         assert_string_equal(table_str, table_str_etalon); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     SCENARIO("Issue 49 - https://github.com/seleznevae/libfort/issues/49") { | ||||||
|  |         { | ||||||
|  |             fort::char_table table; | ||||||
|  |             table << std::setprecision(5) << 3.14 << std::hex << 256 << fort::endr | ||||||
|  |                   << std::fixed << std::setprecision(2) << 11.1234567; | ||||||
|  |             std::string table_str = table.to_string(); | ||||||
|  |             std::string table_str_etalon = | ||||||
|  |                 "+-------+-----+\n" | ||||||
|  |                 "|       |     |\n" | ||||||
|  |                 "|  3.14 | 100 |\n" | ||||||
|  |                 "|       |     |\n" | ||||||
|  |                 "+-------+-----+\n" | ||||||
|  |                 "|       |     |\n" | ||||||
|  |                 "| 11.12 |     |\n" | ||||||
|  |                 "|       |     |\n" | ||||||
|  |                 "+-------+-----+\n"; | ||||||
|  |             assert_string_equal(table_str, table_str_etalon); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         { | ||||||
|  |             fort::char_table table; | ||||||
|  |             table << std::setw(15) << 3.14000001; | ||||||
|  |             std::string table_str = table.to_string(); | ||||||
|  |             std::string table_str_etalon = | ||||||
|  |                 "+--+-----------------+\n" | ||||||
|  |                 "|  |                 |\n" | ||||||
|  |                 "|  |            3.14 |\n" | ||||||
|  |                 "|  |                 |\n" | ||||||
|  |                 "+--+-----------------+\n"; | ||||||
|  |             assert_string_equal(table_str, table_str_etalon); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void test_cpp_table_basic(void) | void test_cpp_table_basic(void) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 seleznevae
					seleznevae