diff --git a/ChangeLog b/ChangeLog index e45ce897..dcc221d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +2020-09-26 Markus Gans + * FData improvements + 2020-09-25 Markus Gans * std::clog now streams everything to the FLogger object * Added a unit test for the FData class diff --git a/src/include/final/fdata.h b/src/include/final/fdata.h index e108dcfd..f6b57f1a 100644 --- a/src/include/final/fdata.h +++ b/src/include/final/fdata.h @@ -47,154 +47,9 @@ namespace finalcut { -//---------------------------------------------------------------------- -// class FDataAccess -//---------------------------------------------------------------------- - template class FData; // Class forward declaration -class FDataAccess -{ - public: - // Constructor - FDataAccess(); - - // Destructor - virtual ~FDataAccess(); - - // Accessors - virtual const FString getClassName() const - { - return "FDataAccess"; - } - - template - const T& get() const - { - return static_cast&>(*this).get(); - } - - // Mutator - template - void set (const V& v) - { - static_cast&>(*this).set(v); - } -}; - - -//---------------------------------------------------------------------- -// class FData -//---------------------------------------------------------------------- - -template -class FData : public FDataAccess -{ - public: - // Constructors - explicit FData (T& v) // constructor - : value_ref{v} - { } - - explicit FData (T&& v) // constructor - : value{std::move(v)} - , value_ref{value} - { } - - // Destructor - ~FData() override - { } - - FData (const FData& d) // Copy constructor - : value{d.value} - , value_ref{value} - { } - - FData (FData&& d) noexcept // Move constructor - : value{std::move(d.value)} - , value_ref{value} - { } - - // Overloaded operators - FData& operator = (const FData& d) // Copy assignment operator (=) - { - value = d.value; - value_ref = value; - return *this; - } - - FData& operator = (FData&& d) noexcept // Move assignment operator (=) - { - value = std::move(d.value); - value_ref = value; - return *this; - } - - T operator () () const - { - return value_ref; - } - - template - T operator () (Args... args) const - { - return value_ref(args...); - } - - explicit operator T () const - { - return value_ref; - } - - FData& operator << (const T& v) - { - value_ref = v; - return *this; - } - - // Accessors - const FString getClassName() const override - { - return "FData"; - } - - T& get() - { - return value_ref; - } - - // Mutator - void set (const T& v) - { - value_ref = v; - } - - // Inquiries - bool isInitializedCopy() - { - return bool( &value == &value_ref ); - } - - bool isInitializedReference() - { - return ! isInitializedCopy(); - } - - // Friend Non-member operator functions - friend std::ostream& operator << (std::ostream &os, const FData& data) - { - os << data.value_ref; - return os; - } - - private: - // Data members - T value{}; - T& value_ref; -}; - // non-member functions //---------------------------------------------------------------------- namespace internal @@ -254,6 +109,162 @@ constexpr FData>* makeFData (T&& data) return new FData>(std::forward(data)); } + +//---------------------------------------------------------------------- +// class FDataAccess +//---------------------------------------------------------------------- + +class FDataAccess +{ + public: + // Constructor + FDataAccess(); + + // Destructor + virtual ~FDataAccess(); + + // Accessors + virtual const FString getClassName() const + { + return "FDataAccess"; + } + + template + clean_fdata_t& get() + { + return static_cast>&>(*this).get(); + } + + // Mutator + template + void set (V& data) + { + static_cast&>(*this).set(std::forward(data)); + } +}; + + +//---------------------------------------------------------------------- +// class FData +//---------------------------------------------------------------------- + +template +class FData : public FDataAccess +{ + public: + // Constructors + explicit FData (T& v) // constructor + : value_ref{v} + { } + + explicit FData (T&& v) // constructor + : value{std::move(v)} + , value_ref{value} + { } + + // Destructor + ~FData() override + { } + + FData (const FData& d) // Copy constructor + : value{d.value} + , value_ref{d.isInitializedCopy() ? std::ref(value) : d.value_ref} + { } + + FData (FData&& d) noexcept // Move constructor + : value{std::move(d.value)} + , value_ref{d.isInitializedCopy() ? std::ref(value) : std::move(d.value_ref)} + { } + + // Overloaded operators + FData& operator = (const FData& d) // Copy assignment operator (=) + { + if ( &d != this ) + { + value = d.value; + + if ( d.isInitializedCopy() ) + value_ref = value; + else + value_ref = d.value_ref; + } + + return *this; + } + + FData& operator = (FData&& d) noexcept // Move assignment operator (=) + { + if ( &d != this ) + { + value = std::move(d.value); + + if ( d.isInitializedCopy() ) + value_ref = value; + else + value_ref = std::move(d.value_ref); + } + + return *this; + } + + T operator () () const + { + return value_ref; + } + + explicit operator T () const + { + return value_ref; + } + + FData& operator << (const T& v) + { + value_ref.get() = v; + return *this; + } + + // Accessors + const FString getClassName() const override + { + return "FData"; + } + + T& get() const + { + return value_ref; + } + + // Mutator + void set (const T& v) + { + value_ref.get() = v; + } + + // Inquiries + bool isInitializedCopy() const + { + return bool( (void*)&value == (void*)&value_ref.get() ); + } + + bool isInitializedReference() const + { + return ! isInitializedCopy(); + } + + // Friend Non-member operator functions + friend std::ostream& operator << (std::ostream &os, const FData& data) + { + os << data.value_ref.get(); + return os; + } + + private: + // Data members + T value{}; + std::reference_wrapper value_ref; +}; + } // namespace finalcut #endif // FDATA_H diff --git a/test/fdata-test.cpp b/test/fdata-test.cpp index 858bc664..98e98ba0 100644 --- a/test/fdata-test.cpp +++ b/test/fdata-test.cpp @@ -46,6 +46,12 @@ long int my_function2 (long int i) return 2 * i; } +//---------------------------------------------------------------------- +long int my_function3 (long int i) +{ + return 3 * i; +} + //---------------------------------------------------------------------- // class FDataTest @@ -60,6 +66,10 @@ class FDataTest : public CPPUNIT_NS::TestFixture protected: void classNameTest(); void fdataTest(); + void copyConstructorTest(); + void moveConstructorTest(); + void copyAssignmentTest(); + void moveAssignmentTest(); void makeFDataTest(); private: @@ -69,6 +79,10 @@ class FDataTest : public CPPUNIT_NS::TestFixture // Add a methods to the test suite CPPUNIT_TEST (classNameTest); CPPUNIT_TEST (fdataTest); + CPPUNIT_TEST (copyConstructorTest); + CPPUNIT_TEST (moveConstructorTest); + CPPUNIT_TEST (copyAssignmentTest); + CPPUNIT_TEST (moveAssignmentTest); CPPUNIT_TEST (makeFDataTest); // End of test suite definition @@ -116,7 +130,7 @@ void FDataTest::fdataTest() // int value int integer_value = 10; - auto data2 = finalcut::FData(integer_value); + auto data2 = finalcut::FData(std::ref(integer_value)); CPPUNIT_ASSERT ( ! data2.isInitializedCopy() ); CPPUNIT_ASSERT ( data2.isInitializedReference() ); stream.clear(); @@ -203,11 +217,117 @@ void FDataTest::fdataTest() CPPUNIT_ASSERT ( data7.get() == "xyz" ); } +//---------------------------------------------------------------------- +void FDataTest::copyConstructorTest() +{ + // value copy + auto data1 = finalcut::FData(2); + CPPUNIT_ASSERT ( data1.isInitializedCopy() ); + CPPUNIT_ASSERT ( data1.get() == 2 ); + auto data2 = finalcut::FData(data1); + CPPUNIT_ASSERT ( data2.isInitializedCopy() ); + data1.get()++; + CPPUNIT_ASSERT ( data1.get() == 3 ); + CPPUNIT_ASSERT ( data2.get() == 2 ); + + // reference copy + uInt n = 100; + auto data3 = finalcut::FData(n); + CPPUNIT_ASSERT ( data3.isInitializedReference() ); + CPPUNIT_ASSERT ( data3.get() == 100 ); + auto data4 = finalcut::FData(data3); + CPPUNIT_ASSERT ( data4.isInitializedReference() ); + data3.get()--; + CPPUNIT_ASSERT ( data3.get() == 99 ); + CPPUNIT_ASSERT ( data4.get() == 99 ); +} + +//---------------------------------------------------------------------- +void FDataTest::moveConstructorTest() +{ + // value copy + auto data1 = finalcut::FData(-5); + CPPUNIT_ASSERT ( data1.isInitializedCopy() ); + CPPUNIT_ASSERT ( data1.get() == -5 ); + auto data2 = finalcut::FData(std::move(data1)); + CPPUNIT_ASSERT ( data2.isInitializedCopy() ); + data1.get() += 10; + CPPUNIT_ASSERT ( data1.get() == 5 ); + CPPUNIT_ASSERT ( data2.get() == -5 ); + + // reference copy + long int n = 0xfffffff; + auto data3 = finalcut::FData(n); + CPPUNIT_ASSERT ( data3.isInitializedReference() ); + CPPUNIT_ASSERT ( data3.get() == 0xfffffff ); + auto data4 = finalcut::FData(std::move(data3)); + CPPUNIT_ASSERT ( data4.isInitializedReference() ); + data3.get()++; + CPPUNIT_ASSERT ( data3.get() == 0x10000000 ); + CPPUNIT_ASSERT ( data4.get() == 0x10000000 ); +} + +//---------------------------------------------------------------------- +void FDataTest::copyAssignmentTest() +{ + // value copy + auto data1 = finalcut::FData(123); + CPPUNIT_ASSERT ( data1.isInitializedCopy() ); + CPPUNIT_ASSERT ( data1.get() == 123 ); + finalcut::FData data2{0}; + data2 = data1; + CPPUNIT_ASSERT ( data2.isInitializedCopy() ); + data1.get() -= 100; + CPPUNIT_ASSERT ( data1.get() == 23 ); + CPPUNIT_ASSERT ( data2.get() == 123 ); + + // reference copy + double c = 299792458.0; // Speed of light + auto data3 = finalcut::FData(c); + CPPUNIT_ASSERT ( data3.isInitializedReference() ); + CPPUNIT_ASSERT ( data3.get() == 299792458 ); + finalcut::FData data4{0.0}; + data4 = data3; + CPPUNIT_ASSERT ( data4.isInitializedReference() ); + data4.get() -= 343.2; // Speed of sound + + CPPUNIT_ASSERT ( data3.get() == 299792114.8 ); + CPPUNIT_ASSERT ( data4.get() == 299792114.8 ); +} + +//---------------------------------------------------------------------- +void FDataTest::moveAssignmentTest() +{ + // value copy + auto data1 = finalcut::FData(9.81F); + CPPUNIT_ASSERT ( data1.isInitializedCopy() ); + CPPUNIT_ASSERT ( data1.get() == 9.81F ); + finalcut::FData data2{0}; + data2 = std::move(data1); + CPPUNIT_ASSERT ( data2.isInitializedCopy() ); + data1.get() -= 0.81; + CPPUNIT_ASSERT ( data1.get() == 9.0F ); + CPPUNIT_ASSERT ( data2.get() == 9.81F ); + + // reference copy + auto au = 149597870700LL; // Astronomical unit + auto data3 = finalcut::FData(au); + CPPUNIT_ASSERT ( data3.isInitializedReference() ); + CPPUNIT_ASSERT ( data3.get() == 149597870700LL ); + finalcut::FData data4{0}; + data4 = std::move(data3); + CPPUNIT_ASSERT ( data4.isInitializedReference() ); + data4.get() /= 2LL; + CPPUNIT_ASSERT ( data3.get() == 74798935350LL ); + CPPUNIT_ASSERT ( data4.get() == 74798935350LL ); +} + //---------------------------------------------------------------------- void FDataTest::makeFDataTest() { finalcut::FDataAccess* data_pointer{nullptr}; + // Array using ThreeInts = int[3]; ThreeInts int_array{2, 1, 4}; data_pointer = finalcut::makeFData(std::move(int_array)); @@ -215,10 +335,12 @@ void FDataTest::makeFDataTest() CPPUNIT_ASSERT ( ints[0] == 2 ); CPPUNIT_ASSERT ( ints[1] == 1 ); CPPUNIT_ASSERT ( ints[2] == 4 ); + delete data_pointer; + // Integer int n = 9; data_pointer = finalcut::makeFData(std::move(n)); - auto data = static_cast&&>(*data_pointer); + auto& data = static_cast&>(*data_pointer); CPPUNIT_ASSERT ( data.isInitializedCopy() ); CPPUNIT_ASSERT ( ! data.isInitializedReference() ); auto& n2 = data.get(); @@ -226,10 +348,18 @@ void FDataTest::makeFDataTest() n2++; CPPUNIT_ASSERT ( n2 == 10 ); CPPUNIT_ASSERT ( data() == 10 ); + CPPUNIT_ASSERT ( data_pointer->get() == 10 ); + //data_pointer->set(33); + //CPPUNIT_ASSERT ( data_pointer->get() == 33 ); + delete data_pointer; - data_pointer = finalcut::makeFData(std::move(my_function2)); + // Function + data_pointer = finalcut::makeFData(my_function2); const auto& func = static_cast>&>(*data_pointer).get(); CPPUNIT_ASSERT ( func(128) == 256 ); + //data_pointer->set(&my_function3); + //PUNIT_ASSERT ( func(128) == 384 ); + delete data_pointer; } // Put the test suite in the registry