diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | doc/src/index.rst | 6 | ||||
| -rw-r--r-- | include/newtype/new_type.hpp | 51 | ||||
| -rw-r--r-- | test/include/io_operators_suite.hpp | 11 | ||||
| -rw-r--r-- | test/src/driver.cpp | 2 | ||||
| -rw-r--r-- | test/src/io_operators_suite.cpp | 121 |
6 files changed, 185 insertions, 7 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f28c54..55d4da0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,6 +52,7 @@ if(BUILD_TESTING) "${PROJECT_SOURCE_DIR}/test/src/derivation_clause_suite.cpp" "${PROJECT_SOURCE_DIR}/test/src/conversion_suite.cpp" "${PROJECT_SOURCE_DIR}/test/src/equality_comparison_suite.cpp" + "${PROJECT_SOURCE_DIR}/test/src/io_operators_suite.cpp" "${PROJECT_SOURCE_DIR}/test/src/new_type_constructor_suite.cpp" "${PROJECT_SOURCE_DIR}/test/src/relational_operators_suite.cpp" ) diff --git a/doc/src/index.rst b/doc/src/index.rst index 907b58d..e0ebaad 100644 --- a/doc/src/index.rst +++ b/doc/src/index.rst @@ -169,7 +169,7 @@ Synopsis typename CharType, typename StreamTraits, typename = std::enable_if_t<DerivationClause(nt::Show)>> - auto operator<<(std::basic_ostream<CharType, StreamTraits> &&, + auto operator<<(std::basic_ostream<CharType, StreamTraits> &, new_type<BaseType, TagType, DerivationClause> const &) noexcept(/*see below*/) -> std::basic_ostream<CharType, StreamTraits> &; @@ -179,8 +179,8 @@ Synopsis typename CharType, typename StreamTraits, typename = std::enable_if_t<DerivationClause(nt::Read)>> - auto operator>>(std::basic_istream<CharType, StreamTraits> &&, - new_type<BaseType, TagType, DerivationClause> &&) noexcept(/*see below*/) + auto operator>>(std::basic_istream<CharType, StreamTraits> &, + new_type<BaseType, TagType, DerivationClause> &) noexcept(/*see below*/) -> std::basic_istream<CharType, StreamTraits> &; } diff --git a/include/newtype/new_type.hpp b/include/newtype/new_type.hpp index 17959ba..781c7a1 100644 --- a/include/newtype/new_type.hpp +++ b/include/newtype/new_type.hpp @@ -5,6 +5,8 @@ #include "newtype/deriving.hpp" #include "newtype/type.hpp" +#include <istream> +#include <ostream> #include <type_traits> namespace nt @@ -44,7 +46,7 @@ namespace nt return m_value; } - private: + protected: BaseType m_value{}; }; @@ -80,7 +82,7 @@ namespace nt return m_value; } - private: + protected: BaseType m_value; }; @@ -94,15 +96,29 @@ namespace nt template<typename BaseType, typename TagType, auto DerivationClause = deriving()> class new_type : public impl::new_type_storage<BaseType, TagType> { - using impl::new_type_storage<BaseType, TagType>::new_type_storage; + using storage = impl::new_type_storage<BaseType, TagType>; + + using storage::storage; using base_type = BaseType; using tag_type = TagType; auto constexpr static derivations = DerivationClause; + template<typename BaseTypeT, + typename TagTypeT, + auto DerivationClauseV, + typename CharType, + typename StreamTraits, + typename Enablement, + typename StreamType> + auto friend operator>>(std::basic_istream<CharType, StreamTraits> & input, + new_type<BaseTypeT, TagTypeT, DerivationClauseV> & target) noexcept(noexcept(std::declval<StreamType &>() >> + std::declval<BaseTypeT &>())) + -> std::basic_istream<CharType, StreamTraits> &; + public: - using impl::new_type_storage<BaseType, TagType>::decay; + using storage::decay; /** * Convert this instance into the equivalent base type value @@ -217,6 +233,33 @@ namespace nt return lhs.decay() >= rhs.decay(); } + template<typename BaseType, + typename TagType, + auto DerivationClause, + typename CharType, + typename StreamTraits, + typename = std::enable_if_t<DerivationClause(nt::Show)>, + typename StreamType = std::basic_ostream<CharType, StreamTraits>> + auto operator<<(std::basic_ostream<CharType, StreamTraits> & output, + new_type<BaseType, TagType, DerivationClause> const & source) noexcept(noexcept(std::declval<StreamType &>() + << std::declval<BaseType const &>())) + -> std::basic_ostream<CharType, StreamTraits> & + { + return output << source.decay(); + } + + template<typename BaseType, + typename TagType, + auto DerivationClause, + typename CharType, + typename StreamTraits, + typename = std::enable_if_t<DerivationClause(nt::Read)>, + typename StreamType = std::basic_istream<CharType, StreamTraits>> + auto operator>>(std::basic_istream<CharType, StreamTraits> & input, new_type<BaseType, TagType, DerivationClause> & target) noexcept( + noexcept(std::declval<StreamType &>() >> std::declval<BaseType &>())) -> std::basic_istream<CharType, StreamTraits> & + { + return input >> target.m_value; + } } // namespace nt #endif diff --git a/test/include/io_operators_suite.hpp b/test/include/io_operators_suite.hpp new file mode 100644 index 0000000..c7af2ee --- /dev/null +++ b/test/include/io_operators_suite.hpp @@ -0,0 +1,11 @@ +#ifndef NEWTYPE_TEST_IO_OPERATORS_SUITE_HPP +#define NEWTYPE_TEST_IO_OPERATORS_SUITE_HPP + +#include <cute/cute_suite.h> + +#include <string> +#include <utility> + +auto io_operators_suite() -> std::pair<cute::suite, std::string>; + +#endif
\ No newline at end of file diff --git a/test/src/driver.cpp b/test/src/driver.cpp index 1ba3d68..c650dda 100644 --- a/test/src/driver.cpp +++ b/test/src/driver.cpp @@ -1,6 +1,7 @@ #include "conversion_suite.hpp" #include "derivation_clause_suite.hpp" #include "equality_comparison_suite.hpp" +#include "io_operators_suite.hpp" #include "new_type_constructor_suite.hpp" #include "relational_operators_suite.hpp" @@ -55,6 +56,7 @@ int main(int argc, char ** argv) conversion_suite(), equality_comparison_suite(), relational_operators_suite(), + io_operators_suite(), }; auto selectors = get_test_selectors(suites); diff --git a/test/src/io_operators_suite.cpp b/test/src/io_operators_suite.cpp new file mode 100644 index 0000000..7f19963 --- /dev/null +++ b/test/src/io_operators_suite.cpp @@ -0,0 +1,121 @@ +#include "io_operators_suite.hpp" + +#include "kawaii.hpp" +#include "newtype/derivable.hpp" +#include "newtype/deriving.hpp" +#include "newtype/new_type.hpp" + +#include <cute/cute.h> + +#include <iosfwd> +#include <sstream> +#include <string> +#include <type_traits> +#include <utility> + +inline namespace traits_extensions +{ + + template<typename T, typename = void> + struct has_stream_input : std::false_type + { + }; + + template<typename T> + struct has_stream_input<T, std::void_t<decltype(std::declval<std::istream &>() >> std::declval<T &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr has_stream_input_v = has_stream_input<T>::value; + + template<typename T, typename = void> + struct has_stream_output : std::false_type + { + }; + + template<typename T> + struct has_stream_output<T, std::void_t<decltype(std::declval<std::ostream &>() << std::declval<T &>())>> : std::true_type + { + }; + + template<typename T> + auto constexpr has_stream_output_v = has_stream_output<T>::value; + +} // namespace traits_extensions + +inline namespace stream_input_operator_tests +{ + + auto a_new__type_has_the_stream_input_operator_if_the_derivation_clause_contains_read() -> void + { + using type_alias = nt::new_type<int, struct input_op_test_tag_1, deriving(nt::Read)>; + ASSERT(has_stream_input_v<type_alias>); + } + + auto a_new__type_does_not_have_the_stream_input_operator_if_the_derivation_clause_does_not_contain_read() -> void + { + using type_alias = nt::new_type<int, struct input_op_test_tag_2>; + ASSERT(!has_stream_input_v<type_alias>); + } + + auto a_instance_of_a_new__type_can_be_read_from_an_istream_if_the_base_type_can_be_read_from_an_istream() -> void + { + static_assert(has_stream_input_v<int>, "Sanity Check"); + using type_alias = nt::new_type<int, struct input_op_test_tag_3, deriving(nt::Read)>; + + auto obj = type_alias{}; + auto input = std::istringstream{"42"}; + + input >> obj; + + ASSERT_EQUAL(42, obj.decay()); + } + +} // namespace stream_input_operator_tests + +inline namespace stream_output_operator_tests +{ + + auto a_new__type_has_the_stream_output_operator_if_the_derivation_clause_contains_show() -> void + { + using type_alias = nt::new_type<int, struct output_op_test_tag_4, deriving(nt::Show)>; + ASSERT(has_stream_output_v<type_alias>); + } + + auto a_new__type_does_not_have_the_stream_output_operator_if_the_derivation_clause_does_not_contain_show() -> void + { + using type_alias = nt::new_type<int, struct output_op_test_tag_5>; + ASSERT(!has_stream_output_v<type_alias>); + } + + auto a_instance_of_a_new__type_can_be_written_to_an_ostream_if_the_base_type_can_be_written_to_an_ostream() -> void + { + static_assert(has_stream_output_v<int>, "Sanity Check"); + using type_alias = nt::new_type<int, struct output_op_test_tag_6, deriving(nt::Show)>; + + auto obj = type_alias{42}; + auto output = std::ostringstream{}; + + output << obj; + + ASSERT_EQUAL("42", output.str()); + } + +} // namespace stream_output_operator_tests + +auto io_operators_suite() -> std::pair<cute::suite, std::string> +{ + return {{ + // Stream Input Operator Tests + KAWAII(a_new__type_has_the_stream_input_operator_if_the_derivation_clause_contains_read), + KAWAII(a_new__type_does_not_have_the_stream_input_operator_if_the_derivation_clause_does_not_contain_read), + KAWAII(a_instance_of_a_new__type_can_be_read_from_an_istream_if_the_base_type_can_be_read_from_an_istream), + + // Stream Ouput Operator Tests + KAWAII(a_new__type_has_the_stream_output_operator_if_the_derivation_clause_contains_show), + KAWAII(a_new__type_does_not_have_the_stream_output_operator_if_the_derivation_clause_does_not_contain_show), + KAWAII(a_instance_of_a_new__type_can_be_written_to_an_ostream_if_the_base_type_can_be_written_to_an_ostream), + }, + "I/O Operators Tests"}; +}
\ No newline at end of file |
