From ed102549f9264f782b3d33159c1368420ef20634 Mon Sep 17 00:00:00 2001 From: Sam Yates <halfflat@gmail.com> Date: Fri, 10 Jun 2016 15:11:46 +0200 Subject: [PATCH] Closer integration of optional type. * Move optionalm headers into src/util * Change namespace for optional classes to nest::mc::util * Include unit tests for optional and uninitialized classes * Simplify (dedoxygenate) comments in uninitialized.hpp --- external/optionalm/README | 1 - src/event_queue.hpp | 6 +- src/fvm.hpp | 2 - .../optionalm.h => src/util/optional.hpp | 27 +- .../util/uninitialized.hpp | 110 ++---- tests/CMakeLists.txt | 2 + tests/test_optional.cpp | 335 ++++++++++++++++++ tests/test_uninitialized.cpp | 200 +++++++++++ 8 files changed, 584 insertions(+), 99 deletions(-) delete mode 100644 external/optionalm/README rename external/optionalm/optionalm.h => src/util/optional.hpp (94%) rename external/optionalm/uninitialized.h => src/util/uninitialized.hpp (50%) create mode 100644 tests/test_optional.cpp create mode 100644 tests/test_uninitialized.cpp diff --git a/external/optionalm/README b/external/optionalm/README deleted file mode 100644 index 206f5968..00000000 --- a/external/optionalm/README +++ /dev/null @@ -1 +0,0 @@ -Adapted from github.com:halfflat/optionalm diff --git a/src/event_queue.hpp b/src/event_queue.hpp index 80b14a89..989e3487 100644 --- a/src/event_queue.hpp +++ b/src/event_queue.hpp @@ -4,7 +4,7 @@ #include <ostream> #include <queue> -#include <optionalm/optionalm.h> +#include "util/optional.hpp" namespace nest { namespace mc { @@ -46,14 +46,14 @@ public : } // pop until - hf::optionalm::optional<local_event> pop_if_before(float t_until) { + util::optional<local_event> pop_if_before(float t_until) { if (!queue_.empty() && queue_.top().time < t_until) { auto ev = queue_.top(); queue_.pop(); return ev; } else { - return hf::optionalm::nothing; + return util::nothing; } } diff --git a/src/fvm.hpp b/src/fvm.hpp index 49d0af7a..603196c0 100644 --- a/src/fvm.hpp +++ b/src/fvm.hpp @@ -19,8 +19,6 @@ #include <util.hpp> #include <vector/include/Vector.hpp> -#include <optionalm/optionalm.h> - #include <mechanisms/expsyn.hpp> namespace nest { diff --git a/external/optionalm/optionalm.h b/src/util/optional.hpp similarity index 94% rename from external/optionalm/optionalm.h rename to src/util/optional.hpp index d22c8ea2..7dd65a27 100644 --- a/external/optionalm/optionalm.h +++ b/src/util/optional.hpp @@ -1,4 +1,4 @@ -/*! \file optionalm.h +/*! \file optional.h * \brief An option class with a monadic interface. * * The std::option<T> class was proposed for inclusion into C++14, but was @@ -14,20 +14,18 @@ * is the lack of constexpr versions of the methods and constructors. */ -#ifndef HF_OPTIONALM_H_ -#define HF_OPTIONALM_H_ +#ifndef UTIL_OPTIONAL_H_ +#define UTIL_OPTIONAL_H_ #include <type_traits> #include <stdexcept> #include <utility> -#include <optionalm/uninitialized.h> +#include "util/uninitialized.hpp" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wlogical-op-parentheses" - -namespace hf { -namespace optionalm { +namespace nest { +namespace mc { +namespace util { template <typename X> struct optional; @@ -64,7 +62,7 @@ namespace detail { template <typename Y> friend struct optional; protected: - typedef hf::optionalm::uninitialized<X> D; + typedef util::uninitialized<X> D; public: typedef typename D::reference_type reference_type; @@ -281,7 +279,7 @@ struct optional<void>: detail::optional_base<void> { bool operator==(const Y &y) const { return false; } bool operator==(const optional<void> &o) const { - return set && o.set || !set && !o.set; + return (set && o.set) || (!set && !o.set); } }; @@ -292,7 +290,6 @@ typename std::enable_if< optional<typename std::common_type<typename detail::wrapped_type<A>::type,typename detail::wrapped_type<B>::type>::type> >::type operator|(A &&a,B &&b) { - typedef typename std::common_type<typename detail::wrapped_type<A>::type,typename detail::wrapped_type<B>::type>::type common; return a?a:b; } @@ -311,8 +308,6 @@ inline optional<void> provided(bool condition) { return condition?optional<void> template <typename X> optional<X> just(X &&x) { return optional<X>(std::forward<X>(x)); } -}} // namespace hf::optionalm - -#pragma clang diagnostic pop +}}} // namespace nest::mc::util -#endif // ndef HF_OPTIONALM_H_ +#endif // ndef UTIL_OPTIONALM_H_ diff --git a/external/optionalm/uninitialized.h b/src/util/uninitialized.hpp similarity index 50% rename from external/optionalm/uninitialized.h rename to src/util/uninitialized.hpp index 264e3844..17ab7d38 100644 --- a/external/optionalm/uninitialized.h +++ b/src/util/uninitialized.hpp @@ -1,34 +1,21 @@ -/*! \file uninitialized.h - * \brief Represent a possibly-uninitialized value, reference or void. +/* Represent a possibly-uninitialized value, reference or void. * - * The \c uninitialized\<X\> structure holds space for an item of - * type \c X, leaving its construction or destruction to the user. + * The uninitialized<X> structure holds space for an item of + * type X, leaving its construction or destruction to the user. + * + * Specialisations for reference types X & and for the void type + * allow for the handling of non-value types in a uniform manner. */ -#ifndef HF_UNINITIALIZED_H_ -#define HF_UNINITIALIZED_H_ - -namespace hf { -namespace optionalm { +#ifndef UTIL_UNINITIALIZED_H_ +#define UTIL_UNINITIALIZED_H_ -/*! \defgroup uninitialized The uninitialized<X> classes. - * \{ - * - * The \c uninitialized\<X\> structure holds space for an item of - * type \c X, which can then be explicitly constructed or - * deconstructed through the \c construct() and \c destruct() - * member functions. - * - * Specialisations for reference types <tt>X &</tt> and for the - * \c void type allow handling non-value types in a uniform - * manner. - */ +namespace nest { +namespace mc { +namespace util { -/*! \brief Maintains storage for a value of type X, with explicit - * construction and destruction. - * - * \tparam X - * The wrapped value type. +/* Maintains storage for a value of type X, with explicit + * construction and destruction. */ template <typename X> struct uninitialized { @@ -36,49 +23,40 @@ private: typename std::aligned_storage<sizeof(X),alignof(X)>::type data; public: - //! typedef X *pointer_type; - //! typedef const X *const_pointer_type; - //! typedef X &reference_type; - //! typedef const X &const_reference_type; - //! Return a pointer to the value. pointer_type ptr() { return reinterpret_cast<X *>(&data); } - //! Return a const pointer to the value. const_pointer_type cptr() const { return reinterpret_cast<const X *>(&data); } - //! Return a reference to the value. reference_type ref() { return *reinterpret_cast<X *>(&data); } - //! Return a const reference to the value. const_reference_type cref() const { return *reinterpret_cast<const X *>(&data); } - //! Copy construct the value. - template <typename Y=X,typename =typename std::enable_if<std::is_copy_constructible<Y>::value>::type> + // Copy construct the value. + template <typename Y=X, + typename =typename std::enable_if<std::is_copy_constructible<Y>::value>::type> void construct(const X &x) { new(&data) X(x); } - //! General constructor - template <typename... Y,typename =typename std::enable_if<std::is_constructible<X,Y...>::value>::type> + // General constructor for X, forwarding arguments. + template <typename... Y, + typename =typename std::enable_if<std::is_constructible<X,Y...>::value>::type> void construct(Y&& ...args) { new(&data) X(std::forward<Y>(args)...); } - //! Call the destructor of the value. void destruct() { ptr()->~X(); } - //! Apply the one-parameter functor F to the value by reference. + // Apply the one-parameter functor F to the value by reference. template <typename F> typename std::result_of<F(reference_type)>::type apply(F &&f) { return f(ref()); } - //! Apply the one-parameter functor F to the value by const reference. + + // Apply the one-parameter functor F to the value by const reference. template <typename F> typename std::result_of<F(const_reference_type)>::type apply(F &&f) const { return f(cref()); } }; -/*! \brief Maintains storage for a pointer of type X, representing - * a possibly uninitialized reference. - * - * \tparam X& - * Wrapped reference type. +/* Maintains storage for a pointer of type X, representing + * a possibly uninitialized reference. */ template <typename X> struct uninitialized<X&> { @@ -86,71 +64,51 @@ private: X *data; public: - //! typedef X *pointer_type; - //! typedef const X *const_pointer_type; - //! typedef X &reference_type; - //! typedef const X &const_reference_type; - //! Return a pointer to the value. pointer_type ptr() { return data; } - //! Return a const pointer to the value. const_pointer_type cptr() const { return data; } - //! Return a reference to the value. reference_type ref() { return *data; } - //! Return a const reference to the value. const_reference_type cref() const { return *data; } - //! Set the reference data. void construct(X &x) { data=&x; } - //! Destruct is a NOP for reference data. void destruct() {} - //! Apply the one-parameter functor F to the value by reference. + // Apply the one-parameter functor F to the value by reference. template <typename F> typename std::result_of<F(reference_type)>::type apply(F &&f) { return f(ref()); } - //! Apply the one-parameter functor F to the value by const reference. + // Apply the one-parameter functor F to the value by const reference. template <typename F> typename std::result_of<F(const_reference_type)>::type apply(F &&f) const { return f(cref()); } }; -/*! \brief Wrap a void type in an uninitialized template. +/* Wrap a void type in an uninitialized template. * - * Allows the use of <tt>uninitialized\<X\></tt> for void \c X, for generic - * applications. + * Allows the use of uninitialized<X> for void X, for generic applications. */ - template <> struct uninitialized<void> { - //! typedef void *pointer_type; - //! typedef const void *const_pointer_type; - //! typedef void reference_type; - //! typedef void const_reference_type; - //! pointer_type ptr() { return nullptr; } - //! const_pointer_type cptr() const { return nullptr; } - //! reference_type ref() {} - //! const_reference_type cref() const {} - //! No operation. + // No operation. void construct(...) {} - //! No operation. + // No operation. void destruct() {} - //! Equivalent to <tt>f()</tt> + // Equivalent to f() template <typename F> typename std::result_of<F()>::type apply(F &&f) const { return f(); } }; @@ -167,9 +125,7 @@ struct uninitialized_can_construct<X &,Y>: std::integral_constant<bool,std::is_c template <typename... Y> struct uninitialized_can_construct<void,Y...>: std::true_type {}; -/*! \} */ - -}} // namespace hf::optionalm +}}} // namespace nest::mc::util -#endif // ndef HF_UNINITIALIZED_H_ +#endif // ndef UTIL_UNINITIALIZED_H_ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9b612200..33e44398 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -20,6 +20,7 @@ set(TEST_SOURCES test_fvm.cpp test_matrix.cpp test_mechanisms.cpp + test_optional.cpp test_parameters.cpp test_point.cpp test_segment.cpp @@ -27,6 +28,7 @@ set(TEST_SOURCES test_swcio.cpp test_synapses.cpp test_tree.cpp + test_uninitialized.cpp # unit test driver test.cpp diff --git a/tests/test_optional.cpp b/tests/test_optional.cpp new file mode 100644 index 00000000..e3ca5ecb --- /dev/null +++ b/tests/test_optional.cpp @@ -0,0 +1,335 @@ +#include <typeinfo> +#include <array> +#include <algorithm> + +#include "gtest.h" +#include "util/optional.hpp" + +using namespace nest::mc::util; + +TEST(optionalm,ctors) { + optional<int> a,b(3),c=b,d=4; + + ASSERT_FALSE((bool)a); + ASSERT_TRUE((bool)b); + ASSERT_TRUE((bool)c); + ASSERT_TRUE((bool)d); + + EXPECT_EQ(3,b.get()); + EXPECT_EQ(3,c.get()); + EXPECT_EQ(4,d.get()); +} + +TEST(optionalm,unset_throw) { + optional<int> a; + int check=10; + + try { a.get(); } + catch(optional_unset_error &e) { + ++check; + } + EXPECT_EQ(11,check); + + check=20; + a=2; + try { a.get(); } + catch(optional_unset_error &e) { + ++check; + } + EXPECT_EQ(20,check); + + check=30; + a.reset(); + try { a.get(); } + catch(optional_unset_error &e) { + ++check; + } + EXPECT_EQ(31,check); +} + +TEST(optionalm,deref) { + struct foo { + int a; + explicit foo(int a_): a(a_) {} + double value() { return 3.0*a; } + }; + + optional<foo> f=foo(2); + EXPECT_EQ(6.0,f->value()); + EXPECT_EQ(2,(*f).a); +} + +TEST(optionalm,ctor_conv) { + optional<std::array<int,3>> x{{1,2,3}}; + EXPECT_EQ(3,x->size()); +} + +TEST(optionalm,ctor_ref) { + int v=10; + optional<int &> a(v); + + EXPECT_EQ(10,a.get()); + v=20; + EXPECT_EQ(20,a.get()); + + optional<int &> b(a),c=b,d=v; + EXPECT_EQ(&(a.get()),&(b.get())); + EXPECT_EQ(&(a.get()),&(c.get())); + EXPECT_EQ(&(a.get()),&(d.get())); +} + +TEST(optionalm,assign_returns) { + optional<int> a=3; + + auto b=(a=4); + EXPECT_EQ(typeid(optional<int>),typeid(b)); + + auto bp=&(a=4); + EXPECT_EQ(&a,bp); +} + +namespace { + struct nomove { + int value; + + nomove(): value(0) {} + nomove(int i): value(i) {} + nomove(const nomove &n): value(n.value) {} + nomove(nomove &&n) = delete; + + nomove &operator=(const nomove &n) { value=n.value; return *this; } + + bool operator==(const nomove &them) const { return them.value==value; } + bool operator!=(const nomove &them) const { return !(*this==them); } + }; +} + +TEST(optionalm,ctor_nomove) { + optional<nomove> a(nomove(3)); + EXPECT_EQ(nomove(3),a.get()); + + optional<nomove> b; + b=a; + EXPECT_EQ(nomove(3),b.get()); + + b=optional<nomove>(nomove(4)); + EXPECT_EQ(nomove(4),b.get()); +} + +namespace { + struct nocopy { + int value; + + nocopy(): value(0) {} + nocopy(int i): value(i) {} + nocopy(const nocopy &n) = delete; + nocopy(nocopy &&n) { + value=n.value; + n.value=0; + } + + nocopy &operator=(const nocopy &n) = delete; + nocopy &operator=(nocopy &&n) { + value=n.value; + n.value=-1; + return *this; + } + + bool operator==(const nocopy &them) const { return them.value==value; } + bool operator!=(const nocopy &them) const { return !(*this==them); } + }; +} + +TEST(optionalm,ctor_nocopy) { + optional<nocopy> a(nocopy(5)); + EXPECT_EQ(nocopy(5),a.get()); + + optional<nocopy> b(std::move(a)); + EXPECT_EQ(nocopy(5),b.get()); + EXPECT_EQ(0,a.get().value); + + b=optional<nocopy>(nocopy(6)); + EXPECT_EQ(nocopy(6),b.get()); +} + +namespace { + optional<double> odd_half(int n) { + optional<double> h; + if (n%2==1) h=n/2.0; + return h; + } +} + +TEST(optionalm,bind) { + optional<int> a; + auto b=a.bind(odd_half); + + EXPECT_EQ(typeid(optional<double>),typeid(b)); + + a=10; + b=a.bind(odd_half); + EXPECT_FALSE((bool)b); + + a=11; + b=a.bind(odd_half); + EXPECT_TRUE((bool)b); + EXPECT_EQ(5.5,b.get()); + + b=a >> odd_half >> [](double x) { return (int)x; } >> odd_half; + EXPECT_TRUE((bool)b); + EXPECT_EQ(2.5,b.get()); +} + +TEST(optionalm,void) { + optional<void> a,b(true),c(a),d=b,e(false); + + EXPECT_FALSE((bool)a); + EXPECT_TRUE((bool)b); + EXPECT_FALSE((bool)c); + EXPECT_TRUE((bool)d); + EXPECT_TRUE((bool)e); + + auto x=a >> []() { return 1; }; + EXPECT_FALSE((bool)x); + + x=b >> []() { return 1; }; + EXPECT_TRUE((bool)x); + EXPECT_EQ(1,x.get()); +} + +TEST(optionalm,bind_to_void) { + optional<int> a,b(3); + + int call_count=0; + auto vf=[&call_count](int i) -> void { ++call_count; }; + + auto x=a >> vf; + EXPECT_EQ(typeid(optional<void>),typeid(x)); + EXPECT_FALSE((bool)x); + EXPECT_EQ(0,call_count); + + call_count=0; + x=b >> vf; + EXPECT_TRUE((bool)x); + EXPECT_EQ(1,call_count); +} + +TEST(optionalm,bind_to_optional_void) { + optional<int> a,b(3),c(4); + + int count=0; + auto count_if_odd=[&count](int i) { return i%2?(++count,optional<void>(true)):optional<void>(); }; + + auto x=a >> count_if_odd; + EXPECT_EQ(typeid(optional<void>),typeid(x)); + EXPECT_FALSE((bool)x); + EXPECT_EQ(0,count); + + count=0; + x=b >> count_if_odd; + EXPECT_TRUE((bool)x); + EXPECT_EQ(1,count); + + count=0; + x=c >> count_if_odd; + EXPECT_FALSE((bool)x); + EXPECT_EQ(0,count); +} + +TEST(optionalm,bind_with_ref) { + optional<int> a=10; + a >> [](int &v) {++v; }; + EXPECT_EQ(11,*a); +} + +namespace { + struct check_cref { + int operator()(const int &) { return 10; } + int operator()(int &) { return 11; } + }; +} + +TEST(optionalm,bind_constness) { + check_cref checker; + optional<int> a=1; + int v=*(a >> checker); + EXPECT_EQ(11,v); + + const optional<int> b=1; + v=*(b >> checker); + EXPECT_EQ(10,v); +} + + +TEST(optionalm,conversion) { + optional<double> a(3),b=5; + EXPECT_TRUE((bool)a); + EXPECT_TRUE((bool)b); + EXPECT_EQ(3.0,a.get()); + EXPECT_EQ(5.0,b.get()); + + optional<int> x; + optional<double> c(x); + optional<double> d=optional<int>(); + EXPECT_FALSE((bool)c); + EXPECT_FALSE((bool)d); + + auto doubler=[](double x) { return x*2; }; + auto y=optional<int>(3) >> doubler; + EXPECT_TRUE((bool)y); + EXPECT_EQ(6.0,y.get()); +} + +TEST(optionalm,or_operator) { + optional<const char *> default_msg="default"; + auto x=nullptr | default_msg; + EXPECT_TRUE((bool)x); + EXPECT_STREQ("default",x.get()); + + auto y="something" | default_msg; + EXPECT_TRUE((bool)y); + EXPECT_STREQ("something",y.get()); + + optional<int> a(1),b,c(3); + EXPECT_EQ(1,*(a|b|c)); + EXPECT_EQ(1,*(a|c|b)); + EXPECT_EQ(1,*(b|a|c)); + EXPECT_EQ(3,*(b|c|a)); + EXPECT_EQ(3,*(c|a|b)); + EXPECT_EQ(3,*(c|b|a)); +} + +TEST(optionalm,and_operator) { + optional<int> a(1); + optional<double> b(2.0); + + auto ab=a&b; + auto ba=b&a; + + EXPECT_EQ(typeid(ab),typeid(b)); + EXPECT_EQ(typeid(ba),typeid(a)); + EXPECT_EQ(2.0,*ab); + EXPECT_EQ(1,*ba); + + auto zb=false & b; + EXPECT_EQ(typeid(zb),typeid(b)); + EXPECT_FALSE((bool)zb); + + auto b3=b & 3; + EXPECT_EQ(typeid(b3),typeid(optional<int>)); + EXPECT_TRUE((bool)b3); + EXPECT_EQ(3,*b3); +} + +TEST(optionalm,provided) { + std::array<int,3> qs={1,0,3}; + std::array<int,3> ps={14,14,14}; + std::array<int,3> rs; + + std::transform(ps.begin(),ps.end(),qs.begin(),rs.begin(), + [](int p,int q) { return *( provided(q!=0) >> [=]() { return p/q; } | -1 ); }); + + EXPECT_EQ(14,rs[0]); + EXPECT_EQ(-1,rs[1]); + EXPECT_EQ(4,rs[2]); +} diff --git a/tests/test_uninitialized.cpp b/tests/test_uninitialized.cpp new file mode 100644 index 00000000..dcc9e47c --- /dev/null +++ b/tests/test_uninitialized.cpp @@ -0,0 +1,200 @@ +#include "gtest.h" + +#include "util/uninitialized.hpp" + +using namespace nest::mc::util; + +namespace { + struct count_ops { + count_ops() {} + count_ops(const count_ops &n) { ++copy_ctor_count; } + count_ops(count_ops &&n) { ++move_ctor_count; } + + count_ops &operator=(const count_ops &n) { ++copy_assign_count; return *this; } + count_ops &operator=(count_ops &&n) { ++move_assign_count; return *this; } + + static int copy_ctor_count,copy_assign_count; + static int move_ctor_count,move_assign_count; + static void reset_counts() { + copy_ctor_count=copy_assign_count=0; + move_ctor_count=move_assign_count=0; + } + }; + + int count_ops::copy_ctor_count=0; + int count_ops::copy_assign_count=0; + int count_ops::move_ctor_count=0; + int count_ops::move_assign_count=0; +} + +TEST(uninitialized,ctor) { + count_ops::reset_counts(); + + uninitialized<count_ops> ua; + ua.construct(count_ops{}); + + count_ops b; + ua.construct(b); + + EXPECT_EQ(1,count_ops::copy_ctor_count); + EXPECT_EQ(0,count_ops::copy_assign_count); + EXPECT_EQ(1,count_ops::move_ctor_count); + EXPECT_EQ(0,count_ops::move_assign_count); + + ua.ref()=count_ops{}; + ua.ref()=b; + + EXPECT_EQ(1,count_ops::copy_ctor_count); + EXPECT_EQ(1,count_ops::copy_assign_count); + EXPECT_EQ(1,count_ops::move_ctor_count); + EXPECT_EQ(1,count_ops::move_assign_count); +} + +namespace { + struct nocopy { + nocopy() {} + nocopy(const nocopy &n) = delete; + nocopy(nocopy &&n) { ++move_ctor_count; } + + nocopy &operator=(const nocopy &n) = delete; + nocopy &operator=(nocopy &&n) { ++move_assign_count; return *this; } + + static int move_ctor_count,move_assign_count; + static void reset_counts() { move_ctor_count=move_assign_count=0; } + }; + + int nocopy::move_ctor_count=0; + int nocopy::move_assign_count=0; +} + +TEST(uninitialized,ctor_nocopy) { + nocopy::reset_counts(); + + uninitialized<nocopy> ua; + ua.construct(nocopy{}); + + EXPECT_EQ(1,nocopy::move_ctor_count); + EXPECT_EQ(0,nocopy::move_assign_count); + + ua.ref()=nocopy{}; + + EXPECT_EQ(1,nocopy::move_ctor_count); + EXPECT_EQ(1,nocopy::move_assign_count); +} + +namespace { + struct nomove { + nomove() {} + nomove(const nomove &n) { ++copy_ctor_count; } + nomove(nomove &&n) = delete; + + nomove &operator=(const nomove &n) { ++copy_assign_count; return *this; } + nomove &operator=(nomove &&n) = delete; + + static int copy_ctor_count,copy_assign_count; + static void reset_counts() { copy_ctor_count=copy_assign_count=0; } + }; + + int nomove::copy_ctor_count=0; + int nomove::copy_assign_count=0; +} + +TEST(uninitialized,ctor_nomove) { + nomove::reset_counts(); + + uninitialized<nomove> ua; + ua.construct(nomove{}); // check against rvalue + + nomove b; + ua.construct(b); // check against non-const lvalue + + const nomove c; + ua.construct(c); // check against const lvalue + + EXPECT_EQ(3,nomove::copy_ctor_count); + EXPECT_EQ(0,nomove::copy_assign_count); + + nomove a; + ua.ref()=a; + + EXPECT_EQ(3,nomove::copy_ctor_count); + EXPECT_EQ(1,nomove::copy_assign_count); +} + +TEST(uninitialized,void) { + uninitialized<void> a,b; + a=b; + + EXPECT_EQ(typeid(a.ref()),typeid(void)); +} + +TEST(uninitialized,ref) { + uninitialized<int &> x,y; + int a; + + x.construct(a); + y=x; + + x.ref()=2; + EXPECT_EQ(2,a); + + y.ref()=3; + EXPECT_EQ(3,a); + EXPECT_EQ(3,x.cref()); + + EXPECT_EQ(&a,x.ptr()); + EXPECT_EQ((const int *)&a,x.cptr()); +} + +namespace { + struct apply_tester { + mutable int op_count=0; + mutable int const_op_count=0; + + int operator()(const int &a) const { ++const_op_count; return a+1; } + int operator()(int &a) const { ++op_count; return ++a; } + }; +} + +TEST(uninitialized,apply) { + uninitialized<int> ua; + ua.construct(10); + + apply_tester A; + int r=ua.apply(A); + EXPECT_EQ(11,ua.cref()); + EXPECT_EQ(11,r); + + uninitialized<int &> ub; + ub.construct(ua.ref()); + + r=ub.apply(A); + EXPECT_EQ(12,ua.cref()); + EXPECT_EQ(12,r); + + uninitialized<const int &> uc; + uc.construct(ua.ref()); + + r=uc.apply(A); + EXPECT_EQ(12,ua.cref()); + EXPECT_EQ(13,r); + + const uninitialized<int> ud(ua); + + r=ud.apply(A); + EXPECT_EQ(12,ua.cref()); + EXPECT_EQ(12,ud.cref()); + EXPECT_EQ(13,r); + + EXPECT_EQ(2,A.op_count); + EXPECT_EQ(2,A.const_op_count); +} + +TEST(uninitialized,void_apply) { + uninitialized<void> uv; + + auto f=[]() { return 11; }; + EXPECT_EQ(11,uv.apply(f)); + + EXPECT_EQ(12.5,uv.apply([]() { return 12.5; })); +} -- GitLab