diff --git a/include/pdi/array_datatype.h b/include/pdi/array_datatype.h index 3ef765cd6dd1792e4a71941573f4b47d9bd57684..78ba783c88161c825090127617bee632037bee6b 100644 --- a/include/pdi/array_datatype.h +++ b/include/pdi/array_datatype.h @@ -84,7 +84,9 @@ public: bool simple() const override; - void* data_dense_copy(void* to, const void* from) const override; + void* data_to_dense_copy(void* to, const void* from) const override; + + void* data_from_dense_copy(void* to, const void* from) const override; void destroy_data(void* ptr) const override; diff --git a/include/pdi/data_descriptor.h b/include/pdi/data_descriptor.h index 91fcaeea441a24e56a5cf2d2473a77f8f3bea783..2633cc95a80cfcbfd4645a1c9c81e62ac1e33dc8 100644 --- a/include/pdi/data_descriptor.h +++ b/include/pdi/data_descriptor.h @@ -64,7 +64,7 @@ public: */ virtual void metadata(bool metadata) = 0; - /** Access the name of the + /** Access the name of the descriptor */ virtual const std::string& name() const = 0; diff --git a/include/pdi/datatype.h b/include/pdi/datatype.h index d3df5237ebbf701759da9ab9c487e22387d24b4e..31324382444bb3cb522dfb393cd50e75b69e3a49 100644 --- a/include/pdi/datatype.h +++ b/include/pdi/datatype.h @@ -99,12 +99,22 @@ public: /** * Creates a dense deep copy of data * - * \param[in] to the pointer to the alocated memory to fill - * \param[in] from the pointer to the copied data + * \param[in] to the pointer to the allocated memory to fill (dense data) + * \param[in] from the pointer to the copied data (size of buffersize) * * \return updated `to' pointer */ - virtual void* data_dense_copy(void* to, const void* from) const = 0; + virtual void* data_to_dense_copy(void* to, const void* from) const = 0; + + /** + * Creates a sparse deep copy of dense data + * + * \param[in] to the pointer to the allocated memory to fill (size of buffersize) + * \param[in] from the pointer to the copied data (dense data) + * + * \return updated `to' pointer + */ + virtual void* data_from_dense_copy(void* to, const void* from) const = 0; /** * Function used to delete the data behind the datatype. This should not deallocate the memory. diff --git a/include/pdi/record_datatype.h b/include/pdi/record_datatype.h index 25bee81170e85e298ff2e23e65e8aec22080dfda..a16a80c8b1340052fa45cbc74dd511b420a3130a 100644 --- a/include/pdi/record_datatype.h +++ b/include/pdi/record_datatype.h @@ -99,7 +99,9 @@ public: bool simple() const override; - void* data_dense_copy(void* to, const void* from) const override; + void* data_to_dense_copy(void* to, const void* from) const override; + + void* data_from_dense_copy(void* to, const void* from) const override; void destroy_data(void* ptr) const override; diff --git a/include/pdi/scalar_datatype.h b/include/pdi/scalar_datatype.h index f0e31fae9bd44666c9372432b262d0e04158fbeb..db35c3522cc2cb8bc8b906e40b7b1e41e5919bd6 100644 --- a/include/pdi/scalar_datatype.h +++ b/include/pdi/scalar_datatype.h @@ -83,7 +83,9 @@ public: bool simple() const override; - void* data_dense_copy(void* to, const void* from) const override; + void* data_to_dense_copy(void* to, const void* from) const override; + + void* data_from_dense_copy(void* to, const void* from) const override; void destroy_data(void* ptr) const override; diff --git a/src/array_datatype.cxx b/src/array_datatype.cxx index fa7eccbc64ad05a76942633cc8b85fcf158fe777..693fcf4c421fb688a54014f9e36ac2ca9534b84b 100644 --- a/src/array_datatype.cxx +++ b/src/array_datatype.cxx @@ -129,7 +129,7 @@ bool Array_datatype::simple() const return m_subtype->simple(); } -void* Array_datatype::data_dense_copy(void* to, const void* from) const +void* Array_datatype::data_to_dense_copy(void* to, const void* from) const { size_t subtype_buffersize = subtype().buffersize(); from = static_cast<const uint8_t*>(from) + (start() * subtype_buffersize); @@ -147,12 +147,44 @@ void* Array_datatype::data_dense_copy(void* to, const void* from) const //size = 0, because we know that to points to allocated memory to = std::align(subtype_alignment, 0, to, space_to_align); - to = subtype().data_dense_copy(to, from); + to = subtype().data_to_dense_copy(to, from); from = reinterpret_cast<const uint8_t*>(from) + subtype_buffersize; } return to; } +void* Array_datatype::data_from_dense_copy(void* to, const void* from) const +{ + uint8_t* original_to = reinterpret_cast<uint8_t*>(to); + size_t subtype_buffersize = subtype().buffersize(); + to = static_cast<uint8_t*>(to) + (start() * subtype_buffersize); + + if (subtype().simple() && subtype().dense()) { + //dense copy + memcpy(to, from, datasize()); + to = original_to + buffersize(); + return to; + } + + size_t subtype_alignment = subtype().alignment(); + for (int subtype_no = 0; subtype_no < subsize(); subtype_no++) { + //space_to_align is set to alignment(), because we always find the alignment in the size of alignment + size_t space_to_align = subtype_alignment; + //size = 0, because we know that to points to allocated memory + to = std::align(subtype_alignment, 0, to, space_to_align); + + //cannot use std::aling, becasue `from' is const + auto subtype_align = subtype().alignment(); + int padding = (subtype_align - (reinterpret_cast<const uintptr_t>(from) % subtype_align)) % subtype_align; + from = reinterpret_cast<const uint8_t*>(from) + padding; + + to = subtype().data_from_dense_copy(to, from); + from = reinterpret_cast<const uint8_t*>(from) + subtype().datasize(); + } + to = original_to + buffersize(); + return to; +} + void Array_datatype::destroy_data(void* ptr) const { if (!subtype().simple()) { diff --git a/src/record_datatype.cxx b/src/record_datatype.cxx index d5d6d2b61f8b5da4fe55714c667819435e853f1d..c4a0a2503fd9b9e11e5628cfafbdd3528d345487 100644 --- a/src/record_datatype.cxx +++ b/src/record_datatype.cxx @@ -187,7 +187,7 @@ bool Record_datatype::simple() const return true; } -void* Record_datatype::data_dense_copy(void* to, const void* from) const +void* Record_datatype::data_to_dense_copy(void* to, const void* from) const { if (simple() && dense()) { //dense copy @@ -202,11 +202,35 @@ void* Record_datatype::data_dense_copy(void* to, const void* from) const //size = 0, because we know that to points to allocated memory to = std::align(member.type().alignment(), 0, to, space_to_align); const uint8_t* member_from = reinterpret_cast<const uint8_t*>(from) + member.displacement(); - to = member.type().data_dense_copy(to, member_from); + to = member.type().data_to_dense_copy(to, member_from); } return to; } +void* Record_datatype::data_from_dense_copy(void* to, const void* from) const +{ + uint8_t* original_to = reinterpret_cast<uint8_t*>(to); + + if (simple() && dense()) { + //dense copy + memcpy(to, from, datasize()); + to = original_to + buffersize(); + return to; + } + + for (auto&& member : members()) { + auto member_align = member.type().alignment(); + int padding = (member_align - (reinterpret_cast<const uintptr_t>(from) % member_align)) % member_align; + from = reinterpret_cast<const uint8_t*>(from) + padding; + to = original_to + member.displacement(); + + member.type().data_from_dense_copy(to, from); + from = reinterpret_cast<const uint8_t*>(from) + member.type().datasize(); + } + to = original_to + buffersize(); + return to; +} + void Record_datatype::destroy_data(void* ptr) const { if ( simple() ) return; diff --git a/src/ref_any.cxx b/src/ref_any.cxx index 0b9954c8ec6f05227b078eced6b0f86dc5fe7416..2c5ff93940f0e6756ddca40ac5bdfd47511867fa 100644 --- a/src/ref_any.cxx +++ b/src/ref_any.cxx @@ -50,7 +50,7 @@ Ref Ref_base::do_copy(Ref_r ref) void* buffer = operator new (size); void* data = std::align(densified_type->alignment(), densified_type->buffersize(), buffer, size); try { - ref.type().data_dense_copy(data, ref.get()); + ref.type().data_to_dense_copy(data, ref.get()); } catch (...) { ::operator delete (buffer); throw; diff --git a/src/scalar_datatype.cxx b/src/scalar_datatype.cxx index 75a82ba37658f30b5f3b08f21b82324e7b34fab7..6688b69f344604f11630d41df6a0e59818e01cb2 100644 --- a/src/scalar_datatype.cxx +++ b/src/scalar_datatype.cxx @@ -124,7 +124,7 @@ bool Scalar_datatype::simple() const return !m_copy && !m_destroy; } -void* Scalar_datatype::data_dense_copy(void* to, const void* from) const +void* Scalar_datatype::data_to_dense_copy(void* to, const void* from) const { if ( !m_copy ) { memcpy(to, from, datasize()); @@ -135,6 +135,11 @@ void* Scalar_datatype::data_dense_copy(void* to, const void* from) const return to; } +void* Scalar_datatype::data_from_dense_copy(void* to, const void* from) const +{ + return data_to_dense_copy(to, from); +} + void Scalar_datatype::destroy_data(void* ptr) const { if ( m_destroy ) { diff --git a/tests/PDI_array_datatype.cxx b/tests/PDI_array_datatype.cxx index e5af47b44ebb043817763ab75bfdb05a69e5f932..28a376edfb3abe349b0fc1efe4c34dd64e857780 100644 --- a/tests/PDI_array_datatype.cxx +++ b/tests/PDI_array_datatype.cxx @@ -25,6 +25,7 @@ #include <gtest/gtest.h> #include <pdi/array_datatype.h> +#include <pdi/scalar_datatype.h> #include "mocks/context_mock.h" #include "mocks/datatype_mock.h" @@ -265,3 +266,60 @@ TEST_F(ArrayDatatypeTest, check_alignment) EXPECT_CALL(*this->mockDatatype, alignment()).WillOnce(Return(subtype_alignment)); ASSERT_EQ(subtype_alignment, this->test_array.alignment()); } + + +/* + * Struct prepared for SparseArrayDeepCopyTest. + * + */ +struct SparseArrayDeepCopyTest : public ::testing::Test { + + int* sparse_array {new int[100]}; //buffer: 10 x 10; data: 4 x 4; start: (3, 3) + int* dense_array {new int[16]}; + + SparseArrayDeepCopyTest() + { + for (int i = 0; i < 100; i++) { + sparse_array[i] = 0; + } + for (int i = 0; i < 16; i++) { + dense_array[i] = i; + } + } + + Datatype_uptr datatype { + new Array_datatype + { + Datatype_uptr { + new Array_datatype + { + Datatype_uptr{new Scalar_datatype {Scalar_kind::SIGNED, sizeof(int)}}, + 10, + 3, + 4 + } + }, + 10, + 3, + 4 + } + }; +}; + +/* + * Name: SparseArrayDeepCopyTest.dense_to_sparse + * + * Tested functions: PDI::ArrayDatatypeTest::data_sparse_copy() + * + * Description: Test checks if correct copy is returned + * + */ +TEST_F(SparseArrayDeepCopyTest, dense_to_sparse) +{ + this->datatype->data_from_dense_copy(sparse_array, dense_array); + for (int i = 3; i < 7; i++) { + for (int j = 3; j < 7; j++) { + ASSERT_EQ(dense_array[(i-3)*4 + j-3], sparse_array[10*i + j]); + } + } +} \ No newline at end of file diff --git a/tests/PDI_record_datatype.cxx b/tests/PDI_record_datatype.cxx index db76e80e6e1e50859c7792bcdbeee932df81a143..c5eeea55c4c81726e1ce586ad0eca8e1bf5cdb58 100644 --- a/tests/PDI_record_datatype.cxx +++ b/tests/PDI_record_datatype.cxx @@ -135,3 +135,123 @@ TYPED_TEST(RecordDatatypeTest, check_clone_type) ASSERT_EQ(this->test_structure->test_record()->members().size(), newRecord->members().size()); } +/* + * Struct prepared for RecordDeepCopyTest. + * + */ +struct RecordDeepCopyTest : public ::testing::Test { + + struct Dense_record_t { + int my_int_array[9]; + char my_char; + long my_long_array[10]; + }; + struct Sparse_record_t { + int my_int_array[25]; + char my_char; + long my_long_array[100]; + }; + int copied_scalar; + + RecordDeepCopyTest() + { + for (int i = 0; i < 9; i++) { + dense_record.my_int_array[i] = i; + } + dense_record.my_char = 9; + for (int i = 0; i < 10; i++) { + dense_record.my_long_array[i] = i + 10; + } + + for (int i = 0; i < 25; i++) { + sparse_record.my_int_array[i] = 0; + } + sparse_record.my_char = 0; + for (int i = 0; i < 100; i++) { + sparse_record.my_long_array[i] = 0; + } + } + + Dense_record_t dense_record; + Sparse_record_t sparse_record; + + Datatype_uptr datatype { + new Record_datatype { + vector<Record_datatype::Member> { + Record_datatype::Member{ + 0, + unique_ptr<Datatype> { + new Array_datatype + { + unique_ptr<Datatype> { + new Array_datatype + { + unique_ptr<Datatype>{new Scalar_datatype {Scalar_kind::SIGNED, sizeof(int)}}, + 5, + 1, + 3 + } + }, + 5, + 1, + 3 + } + }, + "my_int_array" + }, + Record_datatype::Member{ + 100, + unique_ptr<Datatype> { new Scalar_datatype{Scalar_kind::UNSIGNED, sizeof(char)} }, + "my_char" + }, + Record_datatype::Member{ + 104, + unique_ptr<Datatype> { + new Array_datatype + { + unique_ptr<Datatype> { + new Array_datatype + { + unique_ptr<Datatype>{new Scalar_datatype {Scalar_kind::SIGNED, sizeof(long)}}, + 10, + 2, + 5 + } + }, + 10, + 5, + 2, + } + }, + "my_long_array" + } + }, + 908 + } + }; + +}; + +/* + * Name: RecordDeepCopyTest.dense_to_sparse + * + * Tested functions: PDI::ScalarDatatype::data_sparse_copy() + * + * Description: Test checks if correct copy is returned + * + */ +TEST_F(RecordDeepCopyTest, dense_to_sparse) +{ + this->datatype->data_from_dense_copy(&this->sparse_record, &this->dense_record); + for (int i = 1; i < 4; i++) { + for (int j = 1; j < 4; j++) { + ASSERT_EQ(this->dense_record.my_int_array[3*(i-1) + j-1], this->sparse_record.my_int_array[i*5 + j]); + } + } + ASSERT_EQ(this->dense_record.my_char, this->sparse_record.my_char); + for (int i = 5; i < 7; i++) { + for (int j = 2; j < 7; j++) { + ASSERT_EQ(this->dense_record.my_long_array[5*(i-5) + j-2], this->sparse_record.my_long_array[i*10 + j]); + } + } +} \ No newline at end of file diff --git a/tests/PDI_scalar_datatype.cxx b/tests/PDI_scalar_datatype.cxx index 36fd8cf38bcdd8176998e5c804416a99c6f1d6c7..4b158877f134b9acad97486479da7c9af73cc2ca 100644 --- a/tests/PDI_scalar_datatype.cxx +++ b/tests/PDI_scalar_datatype.cxx @@ -191,3 +191,36 @@ TYPED_TEST(ScalarDatatypeTest, check_evaluate) ASSERT_EQ(this->test_scalar->alignment(), cloned_scalar->alignment()); ASSERT_EQ(this->test_scalar->dense(), cloned_scalar->dense()); } + +/* + * Struct prepared for ScalarDeepCopyTest. + * + */ +struct ScalarDeepCopyTest : public ::testing::Test { + + int data_scalar; + int copied_scalar; + + ScalarDeepCopyTest() + { + data_scalar = 123; + copied_scalar = 0; + } + + Datatype_uptr datatype {new Scalar_datatype {Scalar_kind::SIGNED, sizeof(int)}}; + +}; + +/* + * Name: ScalarDeepCopyTest.dense_to_sparse + * + * Tested functions: PDI::ScalarDatatype::data_sparse_copy() + * + * Description: Test checks if correct copy is returned + * + */ +TEST_F(ScalarDeepCopyTest, dense_to_sparse) +{ + this->datatype->data_from_dense_copy(&copied_scalar, &data_scalar); + ASSERT_EQ(copied_scalar, data_scalar); +} \ No newline at end of file diff --git a/tests/mocks/datatype_mock.h b/tests/mocks/datatype_mock.h index 3486fc269bde89d5a90de1a966af463ec2705319..71c8051a18277c71fe01d818cae8221b9c9f8beb 100644 --- a/tests/mocks/datatype_mock.h +++ b/tests/mocks/datatype_mock.h @@ -68,7 +68,8 @@ struct MockDatatype : public PDI::Datatype { MOCK_CONST_METHOD0(evaluate_proxy, Datatype*()); MOCK_CONST_METHOD0(simple, bool()); - MOCK_CONST_METHOD2(data_dense_copy, void* (void* to, const void* from)); + MOCK_CONST_METHOD2(data_to_dense_copy, void* (void* to, const void* from)); + MOCK_CONST_METHOD2(data_from_dense_copy, void* (void* to, const void* from)); MOCK_CONST_METHOD1(destroy_data, void(void* ptr)); MOCK_CONST_METHOD1(equals, bool(const Datatype&)); MOCK_CONST_METHOD0(debug_string, std::string());