[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 | ||||
|  | ||||
| ### Bug fixes | ||||
|  | ||||
| - Fix incorrect behaviour in case of using standard iostream manipulators with fort::table. | ||||
|  | ||||
| ### Internal | ||||
|  | ||||
| - 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 | ||||
| #define LIBFORT_HPP | ||||
|  | ||||
| #include <iomanip> | ||||
| #include <sstream> | ||||
| #include <string> | ||||
| #include <stdexcept> | ||||
| #include <sstream> | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "fort.h" | ||||
|  | ||||
| @@ -150,6 +152,41 @@ const table_manipulator endr(1); | ||||
|  */ | ||||
| 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. | ||||
|  * | ||||
| @@ -534,8 +571,9 @@ public: | ||||
|     template <typename T> | ||||
|     table &operator<<(const T &arg) | ||||
|     { | ||||
|         constexpr bool is_manip = fort::is_stream_manipulator<typename std::decay<T>::type>(); | ||||
|         stream_ << arg; | ||||
|         if (stream_.tellp() >= 0) { | ||||
|         if (stream_.tellp() >= 0 && !is_manip) { | ||||
| #ifdef FT_HAVE_UTF8 | ||||
|             if (TT == table_type::character) { | ||||
|                 ft_nwrite(table_, 1, stream_.str().c_str()); | ||||
|   | ||||
							
								
								
									
										42
									
								
								src/fort.hpp
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								src/fort.hpp
									
									
									
									
									
								
							| @@ -34,9 +34,11 @@ SOFTWARE. | ||||
| #ifndef LIBFORT_HPP | ||||
| #define LIBFORT_HPP | ||||
|  | ||||
| #include <iomanip> | ||||
| #include <sstream> | ||||
| #include <string> | ||||
| #include <stdexcept> | ||||
| #include <sstream> | ||||
| #include <type_traits> | ||||
|  | ||||
| #include "fort.h" | ||||
|  | ||||
| @@ -150,6 +152,41 @@ const table_manipulator endr(1); | ||||
|  */ | ||||
| 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. | ||||
|  * | ||||
| @@ -534,8 +571,9 @@ public: | ||||
|     template <typename T> | ||||
|     table &operator<<(const T &arg) | ||||
|     { | ||||
|         constexpr bool is_manip = fort::is_stream_manipulator<typename std::decay<T>::type>(); | ||||
|         stream_ << arg; | ||||
|         if (stream_.tellp() >= 0) { | ||||
|         if (stream_.tellp() >= 0 && !is_manip) { | ||||
| #ifdef FT_HAVE_UTF8 | ||||
|             if (TT == table_type::character) { | ||||
|                 ft_nwrite(table_, 1, stream_.str().c_str()); | ||||
|   | ||||
| @@ -2,6 +2,16 @@ | ||||
| #include "fort.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) | ||||
| { | ||||
| @@ -97,6 +107,40 @@ void test_cpp_bug_fixes(void) | ||||
|             "+------+------+--------------------------------+\n"; | ||||
|         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) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 seleznevae
					seleznevae