From 7844a5068f0dd69216ca9863fe624c9b84d7bc32 Mon Sep 17 00:00:00 2001 From: seleznevae Date: Tue, 21 Apr 2020 20:27:32 +0300 Subject: [PATCH 1/3] [F] Fix incorrect behaviour in case of using standard iostream manipulators with fort::table. --- ChangeLog.md | 4 +++ lib/fort.hpp | 42 +++++++++++++++++++++-- src/fort.hpp | 42 +++++++++++++++++++++-- tests/bb_tests_cpp/test_table_basic.cpp | 44 +++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 4 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 79585e8..73ed4aa 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -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. diff --git a/lib/fort.hpp b/lib/fort.hpp index bcd5ea1..7933c65 100644 --- a/lib/fort.hpp +++ b/lib/fort.hpp @@ -34,9 +34,11 @@ SOFTWARE. #ifndef LIBFORT_HPP #define LIBFORT_HPP +#include +#include #include #include -#include +#include #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 +constexpr bool is_stream_manipulator_impl() noexcept +{ + using Tdec = typename std::decay::type; + // Manipulators for integral types + return std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + // Floating-point manipulators + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + // Misc + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::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 +constexpr bool is_stream_manipulator() noexcept +{ + return detail::is_stream_manipulator_impl(); +} + /** * Property owner. * @@ -534,8 +571,9 @@ public: template table &operator<<(const T &arg) { + constexpr bool is_manip = fort::is_stream_manipulator::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()); diff --git a/src/fort.hpp b/src/fort.hpp index bcd5ea1..7933c65 100644 --- a/src/fort.hpp +++ b/src/fort.hpp @@ -34,9 +34,11 @@ SOFTWARE. #ifndef LIBFORT_HPP #define LIBFORT_HPP +#include +#include #include #include -#include +#include #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 +constexpr bool is_stream_manipulator_impl() noexcept +{ + using Tdec = typename std::decay::type; + // Manipulators for integral types + return std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + // Floating-point manipulators + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + // Misc + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::type>::value + || std::is_same::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 +constexpr bool is_stream_manipulator() noexcept +{ + return detail::is_stream_manipulator_impl(); +} + /** * Property owner. * @@ -534,8 +571,9 @@ public: template table &operator<<(const T &arg) { + constexpr bool is_manip = fort::is_stream_manipulator::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()); diff --git a/tests/bb_tests_cpp/test_table_basic.cpp b/tests/bb_tests_cpp/test_table_basic.cpp index 4e52738..e45cae4 100644 --- a/tests/bb_tests_cpp/test_table_basic.cpp +++ b/tests/bb_tests_cpp/test_table_basic.cpp @@ -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::type; +template <> +constexpr bool is_stream_manipulator() 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) From 15c45271b8f1eba3f715c61a496137e70f574be4 Mon Sep 17 00:00:00 2001 From: seleznevae Date: Tue, 21 Apr 2020 20:38:31 +0300 Subject: [PATCH 2/3] [D] Delete some of the manipulators to improve support of old compilers --- lib/fort.hpp | 2 -- src/fort.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/lib/fort.hpp b/lib/fort.hpp index 7933c65..7e05e07 100644 --- a/lib/fort.hpp +++ b/lib/fort.hpp @@ -166,8 +166,6 @@ constexpr bool is_stream_manipulator_impl() noexcept // Floating-point manipulators || std::is_same::type>::value || std::is_same::type>::value - || std::is_same::type>::value - || std::is_same::type>::value // Misc || std::is_same::type>::value || std::is_same::type>::value diff --git a/src/fort.hpp b/src/fort.hpp index 7933c65..7e05e07 100644 --- a/src/fort.hpp +++ b/src/fort.hpp @@ -166,8 +166,6 @@ constexpr bool is_stream_manipulator_impl() noexcept // Floating-point manipulators || std::is_same::type>::value || std::is_same::type>::value - || std::is_same::type>::value - || std::is_same::type>::value // Misc || std::is_same::type>::value || std::is_same::type>::value From 3257aecaba0073eef484a3e6b096e717e66fbaaf Mon Sep 17 00:00:00 2001 From: seleznevae Date: Tue, 21 Apr 2020 21:08:06 +0300 Subject: [PATCH 3/3] [D] Remove specialization test --- tests/bb_tests_cpp/test_table_basic.cpp | 55 +++++++------------------ 1 file changed, 15 insertions(+), 40 deletions(-) diff --git a/tests/bb_tests_cpp/test_table_basic.cpp b/tests/bb_tests_cpp/test_table_basic.cpp index e45cae4..8ceaa9f 100644 --- a/tests/bb_tests_cpp/test_table_basic.cpp +++ b/tests/bb_tests_cpp/test_table_basic.cpp @@ -2,16 +2,6 @@ #include "fort.hpp" #include "test_utils.hpp" -namespace fort -{ -// Write custom specialisation for testing purposes. -using setw_type = typename std::decay::type; -template <> -constexpr bool is_stream_manipulator() noexcept -{ - return false; -} -} void test_cpp_bug_fixes(void) { @@ -110,36 +100,21 @@ void test_cpp_bug_fixes(void) 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); - } + 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); } }