aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@gmail.com>2019-12-28 19:35:55 +0100
committerFelix Morgner <felix.morgner@gmail.com>2019-12-28 19:35:55 +0100
commit2ebb5d337b085a4c7f21ffcd0e63f969272285ce (patch)
tree44b3a0a1b5acedf3406f0512c290f04237e1fbff
parentd8c5b02674d905f47f288b2fd20f88cb1f5fc792 (diff)
downloadnewtype-2ebb5d337b085a4c7f21ffcd0e63f969272285ce.tar.xz
newtype-2ebb5d337b085a4c7f21ffcd0e63f969272285ce.zip
new_type: implement stream io operators
-rw-r--r--CMakeLists.txt1
-rw-r--r--doc/src/index.rst6
-rw-r--r--include/newtype/new_type.hpp51
-rw-r--r--test/include/io_operators_suite.hpp11
-rw-r--r--test/src/driver.cpp2
-rw-r--r--test/src/io_operators_suite.cpp121
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