diff --git a/Source/Vault.cpp b/Source/Vault.cpp index 3c26f00..92a9438 100644 --- a/Source/Vault.cpp +++ b/Source/Vault.cpp @@ -211,7 +211,7 @@ namespace mvlt } } - Vault& Vault::operator= (const Vault& other) noexcept + Vault& Vault::operator=(const Vault& other) noexcept { if (&other != this) { @@ -271,10 +271,12 @@ namespace mvlt RecordSetsSet = std::move(other.RecordSetsSet); } - Vault& Vault::operator= (Vault&& other) noexcept + Vault& Vault::operator=(Vault&& other) noexcept { if (this != &other) { + DropVault(); + ReadLock otherReadLock(other.RecursiveReadWriteMtx); VaultDerivedClass = VaultDerivedClasses::VaultBase; diff --git a/Source/Vault.h b/Source/Vault.h index 176edbb..c95f3f3 100644 --- a/Source/Vault.h +++ b/Source/Vault.h @@ -249,7 +249,7 @@ namespace mvlt \return reference to copied object */ - Vault& operator= (const Vault& other) noexcept; + Vault& operator=(const Vault& other) noexcept; /** \brief Move constructor @@ -265,7 +265,7 @@ namespace mvlt \return reference to moved object */ - Vault& operator= (Vault&& other) noexcept; + Vault& operator=(Vault&& other) noexcept; /** \brief Template method to add new key with default value to Vault diff --git a/Source/VaultRecordSet.cpp b/Source/VaultRecordSet.cpp index 08de1b7..4da3e11 100644 --- a/Source/VaultRecordSet.cpp +++ b/Source/VaultRecordSet.cpp @@ -34,6 +34,42 @@ namespace mvlt RecursiveReadWriteMtx.Disable(); } + void VaultRecordSet::MoveSet(VaultRecordSet& other) noexcept + { + WriteLock writeLock(other.ParentVault->RecursiveReadWriteMtx); + + VaultDerivedClass = VaultDerivedClasses::VaultRecordSetDerived; + + ParentVault = other.ParentVault; + other.ParentVault = nullptr; + + RecordTemplate = std::move(other.RecordTemplate); + VaultHashMapStructure = std::move(other.VaultHashMapStructure); + VaultMapStructure = std::move(other.VaultMapStructure); + KeysTypes = std::move(other.KeysTypes); + VaultRecordAdders = std::move(other.VaultRecordAdders); + VaultRecordClearers = std::move(other.VaultRecordClearers); + VaultRecordErasers = std::move(other.VaultRecordErasers); + VaultRecordSorters = std::move(other.VaultRecordSorters); + VaultKeyCopiers = std::move(other.VaultKeyCopiers); + KeysOrder = std::move(other.KeysOrder); + UniqueKeys = std::move(other.UniqueKeys); + InvalidFileRecords = std::move(other.InvalidFileRecords); + RecordsSet = std::move(other.RecordsSet); + RecordSetsSet = std::move(other.RecordSetsSet); + + ParentVault->RecordSetsSet.erase(&other); + ParentVault->RecordSetsSet.emplace(this); + + for (VaultRecord* record : other.RecordsSet) + { + record->EraseDependentSet(&other); + record->AddToDependentSets(this); + } + + RecursiveReadWriteMtx.Disable(); + } + VaultRecordSet::VaultRecordSet() noexcept { VaultDerivedClass = VaultDerivedClasses::VaultRecordSetDerived; @@ -42,7 +78,7 @@ namespace mvlt VaultRecordSet::VaultRecordSet(const VaultRecordSet& other) noexcept { - if (&other != this && other.GetIsParentVaultValid()) + if (other.GetIsParentVaultValid()) CopySet(other); } @@ -58,6 +94,25 @@ namespace mvlt return *this; } + VaultRecordSet::VaultRecordSet(VaultRecordSet&& other) noexcept + { + if (other.GetIsParentVaultValid()) + MoveSet(other); + } + + VaultRecordSet& VaultRecordSet::operator=(VaultRecordSet&& other) noexcept + { + if (&other != this) + { + if (other.GetIsParentVaultValid()) + MoveSet(other); + else + Reset(); + } + + return *this; + } + bool VaultRecordSet::GetIsParentVaultValid() const noexcept { return ParentVault != nullptr; diff --git a/Source/VaultRecordSet.h b/Source/VaultRecordSet.h index af22d35..2eecb13 100644 --- a/Source/VaultRecordSet.h +++ b/Source/VaultRecordSet.h @@ -59,6 +59,13 @@ namespace mvlt */ void CopySet(const VaultRecordSet& other) noexcept; + /** + \brief An internal method for moving objects + + \param [in] other object to move + */ + void MoveSet(VaultRecordSet& other) noexcept; + public: /// Make Vault class friend @@ -81,9 +88,27 @@ namespace mvlt \brief Operator assignment \param [in] other object to copy + + \return reference to copied object */ VaultRecordSet& operator=(const VaultRecordSet& other) noexcept; - + + /** + \brief Move constructor + + \param [in] other object to move + */ + VaultRecordSet(VaultRecordSet&& other) noexcept; + + /** + \brief Move assignment perator + + \param [in] other object to move + + \return reference to moveed object + */ + VaultRecordSet& operator=(VaultRecordSet&& other) noexcept; + /// Making operator comparison function friendly friend bool operator==(const VaultRecordSet& a, const VaultRecordSet& b); diff --git a/Tests/VaultRecordSetUnitTest.cpp b/Tests/VaultRecordSetUnitTest.cpp index 301c1ee..2ea1f70 100644 --- a/Tests/VaultRecordSetUnitTest.cpp +++ b/Tests/VaultRecordSetUnitTest.cpp @@ -45,6 +45,190 @@ void VaultRecordSet_OperatorAssignment_Test() TEST_ASSERT(vrs2 == vrs1, "Failed to assign vault record set"); } +void VaultRecordSet_MoveConstructor_Test() +{ + Vault* vlt = new Vault; + + vlt->AddKey("A", -1); + vlt->AddKey("B", "none"); + vlt->AddUniqueKey("C"); + + for (std::size_t i = 0; i < 10; ++i) + vlt->CreateRecord({{"A", static_cast(i * i * i)}, {"B", "test" + std::to_string(i)}, {"C", i}}); + + VaultRecordSet vrs1; + + vlt->RequestInterval("C", 2, 8, vrs1); + + std::vector vecA1; + std::vector vecB1; + std::vector vecC1; + std::vector pointers1; + + vrs1.SortBy("A", [&](const VaultRecordRef& ref) + { + int A; + std::string B; + std::size_t C; + + ref.GetData("A", A); + ref.GetData("B", B); + ref.GetData("C", C); + + vecA1.emplace_back(std::move(A)); + vecB1.emplace_back(std::move(B)); + vecC1.emplace_back(std::move(C)); + pointers1.emplace_back(ref.GetRecordUniqueId()); + + return true; + }); + + std::vector keys = vrs1.GetKeys(); + + VaultRecordSet vrs2(std::move(vrs1)); + + TEST_ASSERT(vrs1.Size() == 0,"Failed to move Vault"); + TEST_ASSERT(vrs1.GetKeys().empty(),"Failed to move Vault"); + + TEST_ASSERT(vrs2.Size() == 7,"Failed to move Vault"); + TEST_ASSERT(keys == vrs2.GetKeys(),"Failed to move Vault"); + + std::type_index keyType = typeid(void); + vrs2.GetKeyType("A", keyType); + TEST_ASSERT(keyType == typeid(int),"Failed to move Vault"); + vrs2.GetKeyType("B", keyType); + TEST_ASSERT(keyType == typeid(std::string),"Failed to move Vault"); + vrs2.GetKeyType("C", keyType); + TEST_ASSERT(keyType == typeid(std::size_t),"Failed to move Vault"); + + std::vector vecA2; + std::vector vecB2; + std::vector vecC2; + std::vector pointers2; + + vrs2.SortBy("A", [&](const VaultRecordRef& ref) + { + int A; + std::string B; + std::size_t C; + + ref.GetData("A", A); + ref.GetData("B", B); + ref.GetData("C", C); + + vecA2.emplace_back(std::move(A)); + vecB2.emplace_back(std::move(B)); + vecC2.emplace_back(std::move(C)); + pointers2.emplace_back(ref.GetRecordUniqueId()); + + return true; + }); + + TEST_ASSERT(vecA1 == vecA2, "Failed to move Vault"); + TEST_ASSERT(vecB1 == vecB2, "Failed to move Vault"); + TEST_ASSERT(vecC1 == vecC2, "Failed to move Vault"); + TEST_ASSERT(pointers1 == pointers2, "Failed to move Vault"); + + delete vlt; + + TEST_ASSERT(vrs2.GetParentVaultUniqueId() == "null", "Failed to move Vault"); +} + +void VaultRecordSet_MoveAssignment_Test() +{ + Vault* vlt = new Vault; + + vlt->AddKey("A", -1); + vlt->AddKey("B", "none"); + vlt->AddUniqueKey("C"); + + for (std::size_t i = 0; i < 10; ++i) + vlt->CreateRecord({{"A", static_cast(i * i * i)}, {"B", "test" + std::to_string(i)}, {"C", i}}); + + VaultRecordSet vrs1; + + vlt->RequestInterval("C", 2, 8, vrs1); + + std::vector vecA1; + std::vector vecB1; + std::vector vecC1; + std::vector pointers1; + + vrs1.SortBy("A", [&](const VaultRecordRef& ref) + { + int A; + std::string B; + std::size_t C; + + ref.GetData("A", A); + ref.GetData("B", B); + ref.GetData("C", C); + + vecA1.emplace_back(std::move(A)); + vecB1.emplace_back(std::move(B)); + vecC1.emplace_back(std::move(C)); + pointers1.emplace_back(ref.GetRecordUniqueId()); + + return true; + }); + + std::vector keys = vrs1.GetKeys(); + + VaultRecordSet vrs2 = std::move(vrs1); + + TEST_ASSERT(vrs1.Size() == 0,"Failed to move Vault"); + TEST_ASSERT(vrs1.GetKeys().empty(),"Failed to move Vault"); + + TEST_ASSERT(vrs2.Size() == 7,"Failed to move Vault"); + TEST_ASSERT(keys == vrs2.GetKeys(),"Failed to move Vault"); + + std::type_index keyType = typeid(void); + vrs2.GetKeyType("A", keyType); + TEST_ASSERT(keyType == typeid(int),"Failed to move Vault"); + vrs2.GetKeyType("B", keyType); + TEST_ASSERT(keyType == typeid(std::string),"Failed to move Vault"); + vrs2.GetKeyType("C", keyType); + TEST_ASSERT(keyType == typeid(std::size_t),"Failed to move Vault"); + + std::vector vecA2; + std::vector vecB2; + std::vector vecC2; + std::vector pointers2; + + vrs2.SortBy("A", [&](const VaultRecordRef& ref) + { + int A; + std::string B; + std::size_t C; + + ref.GetData("A", A); + ref.GetData("B", B); + ref.GetData("C", C); + + vecA2.emplace_back(std::move(A)); + vecB2.emplace_back(std::move(B)); + vecC2.emplace_back(std::move(C)); + pointers2.emplace_back(ref.GetRecordUniqueId()); + + return true; + }); + + TEST_ASSERT(vecA1 == vecA2, "Failed to move Vault"); + TEST_ASSERT(vecB1 == vecB2, "Failed to move Vault"); + TEST_ASSERT(vecC1 == vecC2, "Failed to move Vault"); + TEST_ASSERT(pointers1 == pointers2, "Failed to move Vault"); + + delete vlt; + + TEST_ASSERT(vrs2.GetParentVaultUniqueId() == "null", "Failed to move Vault"); + + // Check clearing old data + vrs2 = VaultRecordSet(); + + TEST_ASSERT(vrs2.Size() == 0,"Failed to move Vault"); + TEST_ASSERT(vrs2.GetKeys().empty(),"Failed to move Vault"); +} + void VaultRecordSet_OperatorComparison_Test() { Vault vlt; @@ -790,6 +974,8 @@ int main() { VaultRecordSet_CopyConstructor_Test(); VaultRecordSet_OperatorAssignment_Test(); + VaultRecordSet_MoveConstructor_Test(); + VaultRecordSet_MoveAssignment_Test(); VaultRecordSet_OperatorComparison_Test(); VaultRecordSet_GetIsParentVaultValid_Test(); VaultRecordSet_GetParentVaultUniqueId_Test(); diff --git a/Tests/VaultUnitTest.cpp b/Tests/VaultUnitTest.cpp index 35286de..05c3862 100644 --- a/Tests/VaultUnitTest.cpp +++ b/Tests/VaultUnitTest.cpp @@ -252,6 +252,12 @@ void Vault_MoveAssignment_Test() TEST_ASSERT(vecB1 == vecB2, "Failed to move Vault"); TEST_ASSERT(vecC1 == vecC2, "Failed to move Vault"); TEST_ASSERT(pointers1 == pointers2, "Failed to move Vault"); + + // Check clearing old data + vlt2 = Vault(); + + TEST_ASSERT(vlt2.Size() == 0,"Failed to move Vault"); + TEST_ASSERT(vlt2.GetKeys().empty(),"Failed to move Vault"); } void Vault_AddKey_Test()