diff --git a/src/Learning/KWDRRuleLibrary/KWDRBuildRelation.h b/src/Learning/KWDRRuleLibrary/KWDRBuildRelation.h index 187ba1e03..efc74a6d7 100644 --- a/src/Learning/KWDRRuleLibrary/KWDRBuildRelation.h +++ b/src/Learning/KWDRRuleLibrary/KWDRBuildRelation.h @@ -40,7 +40,7 @@ class KWDRBuildTableView : public KWDRTableCreationRule //////////////////////////////////////////////////////////////////////////// // Classe KWDRBuildTableAdvancedView -// Creation d'une vue sur une table, avec possibilite d'alimenter des attribut +// Creation d'une vue sur une table, avec possibilite d'alimenter des attributs // de la table en sortie directement via des des operandes en sortie et // des valeurs fournies par les operandes en entree corespondants class KWDRBuildTableAdvancedView : public KWDRTableCreationRule diff --git a/src/Learning/KWData/KWDatabase.cpp b/src/Learning/KWData/KWDatabase.cpp index dffdbb418..f0bb3d3e4 100644 --- a/src/Learning/KWData/KWDatabase.cpp +++ b/src/Learning/KWData/KWDatabase.cpp @@ -1213,6 +1213,7 @@ longint KWDatabase::GetUsedMemory() const lUsedMemory = sizeof(KWDatabase); // Memoire par attribut non elementaire + lUsedMemory += nkdMutationClasses.GetUsedMemory(); lUsedMemory += nkdUnusedNativeAttributesToKeep.GetUsedMemory(); lUsedMemory += oaAllObjects.GetUsedMemory(); lUsedMemory += sClassName.GetLength(); @@ -1595,12 +1596,22 @@ void KWDatabase::BuildPhysicalClass() oaClassNeededAttributes.RemoveAll(); } - // Collecte de toutes les logiques necessaires + // Collecte de toutes les logiques necessaires, et memorisation des classe de mutations + assert(nkdMutationClasses.GetCount() == 0); for (nClass = 0; nClass < oaAllNeededClasses.GetSize(); nClass++) { kwcCurrentPhysicalClass = cast(KWClass*, oaAllNeededClasses.GetAt(nClass)); + + // Recherche et memorisation de la classe logique correspondante kwcInitialClass = kwcClass->GetDomain()->LookupClass(kwcCurrentPhysicalClass->GetName()); nkdNeededLogicalClasses.SetAt(kwcInitialClass, kwcInitialClass); + + // Memorisation de la classe de mutation dans le cas ou une classe logique est explicitement utilisee + if (nkdNeededUsedClasses.Lookup(kwcCurrentPhysicalClass) != NULL) + nkdMutationClasses.SetAt(kwcCurrentPhysicalClass, kwcInitialClass); + // Sinon, on garde la classe physique, qui ne sera pas mutee + else + nkdMutationClasses.SetAt(kwcCurrentPhysicalClass, kwcCurrentPhysicalClass); } // Affichage des classes et attributs necessaires @@ -1614,10 +1625,10 @@ void KWDatabase::BuildPhysicalClass() { kwcCurrentPhysicalClass = cast(KWClass*, oaAllNeededClasses.GetAt(nClass)); cout << "\t" << kwcCurrentPhysicalClass->GetName(); - if (nkdNeededUsedClasses.Lookup(kwcCurrentPhysicalClass)) - cout << "\tLogical"; - else - cout << "\tPhysical"; + cout << "\tDomain=" + << cast(KWClass*, nkdMutationClasses.Lookup(kwcCurrentPhysicalClass)) + ->GetDomain() + ->GetName(); cout << endl; } @@ -2246,8 +2257,6 @@ void KWDatabase::ComputeUnusedNativeAttributesToKeepForRule(const NumericKeyDict attribute->GetAnyDerivationRule()); // Memorisation de l'attribut natif ou cree sinon, s'il n'est pas utilise - //DDD On prend en fait en compte toutes les classes, sinon cela fait planter z_TableCreationRules\BugDeleteSubTableOfView - //DDD le parametre nkdNeededClasses est donc a ignorer et inutile!!! if (not attribute->IsInBlock() and not attribute->GetReference() and not attribute->GetUsed() and nkdNeededClasses->Lookup(attribute->GetClass()) != NULL) @@ -2296,6 +2305,9 @@ void KWDatabase::DeletePhysicalClass() kwcCurrentClass->GetDatabaseTemporayDataItemsToComputeAndClean()->SetSize(0); } + // Nettoyage du dictionnaire des classes de mutation + nkdMutationClasses.RemoveAll(); + // Nettoyage du dictionnaire des attribut natif non utilises a detruire nkdUnusedNativeAttributesToKeep.RemoveAll(); } @@ -2340,7 +2352,7 @@ void KWDatabase::MutatePhysicalObject(KWObject* kwoPhysicalObject) const // Mutation si necessaire if (kwcPhysicalClass != kwcClass) - kwoPhysicalObject->Mutate(kwcClass, &nkdUnusedNativeAttributesToKeep); + kwoPhysicalObject->Mutate(kwcClass, &nkdMutationClasses, &nkdUnusedNativeAttributesToKeep); // Trace apres mutation if (bTrace) diff --git a/src/Learning/KWData/KWDatabase.h b/src/Learning/KWData/KWDatabase.h index 63dc49f15..0c681e937 100644 --- a/src/Learning/KWData/KWDatabase.h +++ b/src/Learning/KWData/KWDatabase.h @@ -440,7 +440,7 @@ class KWDatabase : public Object // Calcul du dictionnaire des attributs natifs inutilises a garder, en precisant les classes qui sont necessaires void ComputeUnusedNativeAttributesToKeep(const NumericKeyDictionary* nkdNeededClasses, NumericKeyDictionary* nkdAttributes); - void ComputeUnusedNativeAttributesToKeepForRule(const NumericKeyDictionary* nkdClassesToKeep, + void ComputeUnusedNativeAttributesToKeepForRule(const NumericKeyDictionary* nkdNeededClasses, NumericKeyDictionary* nkdAttributes, NumericKeyDictionary* nkdAnalysedRules, KWDerivationRule* rule); @@ -558,6 +558,24 @@ class KWDatabase : public Object // Meme remarque que pour kwcClass, mais uniquement en lecture. KWClass* kwcPhysicalClass; + // Dictionnaire des classes de mutation, avec en cle la classe physique des objets a muter + // et en valeur la classe suite a la mutation + // + // Dans la majorite des cas, la classe de mutation est la classe logique de meme nom, + // qui garde les attributs charges en memoire de la classe logique, alors que la classe physique + // a potentiellement plus d'attributs charges en memoire, en unused dans la classe logique, mais + // necessaires dans la classe physique pour le calcul des attribut derives + // + // Dans des cas a effet de bord, la classe de mutation peut rester la classe physique si la classe + // logique est en unused, mais est necessaire en tant qu'attribut de type relation non charge en + // memoire, mais a garder pour la destruction des objets (cf. UnloadedOwnedRelationAttribute dans KWClass) + // Exemple d'effet de bord: + // La classe Customer a des Services en Unused, ses services on des Usages, et la classe Customer + // a tous ses usages utilises via la regle TableSubUnion(Services, Usages) + // Dans ce cas, les Services physiques sont gardes dans leur classe physique pour gerer recursivement + // la destruction des Usages, mais ils ne sont pas mutes, car non utilises au niveau logique + NumericKeyDictionary nkdMutationClasses; + // Dictionnaire des attributs natifs Object ou ObjectArray a garder lors des mutations d'objet // Utile dans le cas multi-table, que ce soit dans le cas d'un schema multi-table "logique" // avec des fichiers mappes pour chaque table secondaire ou un schema multi-table "conceptuel" diff --git a/src/Learning/KWData/KWObject.cpp b/src/Learning/KWData/KWObject.cpp index 3ab5aecb3..f8323edeb 100644 --- a/src/Learning/KWData/KWObject.cpp +++ b/src/Learning/KWData/KWObject.cpp @@ -6,6 +6,8 @@ KWObject::KWObject(const KWClass* kwcNew, longint lIndex) { + const boolean bTrace = false; + require(kwcNew != NULL); require(kwcNew->IsCompiled()); require(lIndex > 0); @@ -20,6 +22,15 @@ KWObject::KWObject(const KWClass* kwcNew, longint lIndex) // Initialisation de l'objet Init(); + + // Trace de creation de l'objet + if (bTrace) + { + cout << "New KWObject " << GetClass()->GetDomain()->GetName() << " " << GetClass()->GetName() << " " + << GetCreationIndex(); + cout << " (" << kwcClass->GetLoadedDataItemNumber() << "," + << kwcClass->GetTotalInternallyLoadedDataItemNumber() << ") #" << this << "\n"; + } } KWObject::~KWObject() @@ -46,8 +57,8 @@ void KWObject::ComputeAllValues(KWDatabaseMemoryGuard* memoryGuard) // Trace de debut if (bTrace) - cout << "Begin KWObject::ComputeAllValues " << GetClass()->GetName() << " " << GetCreationIndex() - << "\n"; + cout << "Begin KWObject::ComputeAllValues " << GetClass()->GetDomain()->GetName() << " " + << GetClass()->GetName() << " " << GetCreationIndex() << " #" << this << "\n"; // Calcul de toutes les valeurs a transferer for (nAttribute = 0; nAttribute < kwcClass->GetConstDatabaseDataItemsToCompute()->GetSize(); nAttribute++) @@ -182,12 +193,13 @@ void KWObject::ComputeAllValues(KWDatabaseMemoryGuard* memoryGuard) // Trace de fin if (bTrace) - cout << "End KWObject::ComputeAllValues " << GetClass()->GetName() << " " << GetCreationIndex() << "\n"; + cout << "End KWObject::ComputeAllValues " << GetClass()->GetDomain()->GetName() << " " + << GetClass()->GetName() << " " << GetCreationIndex() << " #" << this << "\n"; } void KWObject::DeleteAttributes() { - boolean bTrace = false; + const boolean bTrace = false; int i; KWAttribute* attribute; SymbolVector* svTextList; @@ -206,7 +218,7 @@ void KWObject::DeleteAttributes() // Trace de debut if (bTrace) cout << " Begin KWObject::DeleteAttributes " << GetClass()->GetName() << " " << GetCreationIndex() - << "\n"; + << " #" << this << "\n"; // Recherche si usage de type view bIsViewTypeUse = GetViewTypeUse(); @@ -317,8 +329,8 @@ void KWObject::DeleteAttributes() { // Trace if (bTrace) - cout << " delete object " << attribute->GetName() - << kwoUsedObject << "\n"; + cout << " - delete object " << attribute->GetName() + << " #" << kwoUsedObject << "\n"; // Destruction delete kwoUsedObject; @@ -340,9 +352,10 @@ void KWObject::DeleteAttributes() { // Trace if (bTrace) - cout << " delete ObjectArray content " << attribute->GetName() - << " " - << "(size=" << oaUsedObjectArray->GetSize() << ") " + cout << " - delete ObjectArray content " + << attribute->GetName() + << " (needed=" << BooleanToString(bIsDeletionNeeded) + << ", size=" << oaUsedObjectArray->GetSize() << ") #" << oaUsedObjectArray << "\n"; // Destruction des objets contenus si necessaire @@ -370,7 +383,6 @@ void KWObject::DeleteAttributes() assert(not attribute->IsInBlock()); assert(not attribute->GetReference()); assert(attribute->GetLoaded() == false); - assert(not attribute->GetReference()); // Destruction necessaire si sous-objet natif, sauf dans le cas d'une vue // ou si sous-objet calcule, sauf s'il s'agit d'une reference @@ -391,7 +403,16 @@ void KWObject::DeleteAttributes() { kwoUsedObject = value.GetObject(); if (kwoUsedObject != NULL) + { + // Trace + if (bTrace) + cout << " - delete unloaded object " + << attribute->GetName() << " #" << kwoUsedObject + << "\n"; + + // Destruction delete kwoUsedObject; + } } } } @@ -407,6 +428,14 @@ void KWObject::DeleteAttributes() oaUsedObjectArray = value.GetObjectArray(); if (oaUsedObjectArray != NULL) { + // Trace + if (bTrace) + cout << " - delete unloaded ObjectArray content " + << attribute->GetName() + << " (needed=" << BooleanToString(bIsDeletionNeeded) + << ", size=" << oaUsedObjectArray->GetSize() << ") #" + << oaUsedObjectArray << "\n"; + // Destruction des objets contenus si necessaire if (bIsDeletionNeeded) oaUsedObjectArray->DeleteAll(); @@ -428,7 +457,7 @@ void KWObject::DeleteAttributes() // Trace de fin if (bTrace) cout << " End KWObject::DeleteAttributes " << GetClass()->GetName() << " " << GetCreationIndex() - << "\n"; + << " #" << this << "\n"; } void KWObject::CleanTemporayDataItemsToComputeAndClean() @@ -785,7 +814,7 @@ void KWObject::Init() SetSmallSize(nTotalInternallyLoadedDataItemNumber <= nBlockSize); // Initialisation des valeurs pour les attributs charges en memoire - // Les autres sont forcement natifs + // Les autres sont forcement natifs ou construits for (i = 0; i < nTotalLoadedDataItemNumber; i++) { dataItem = kwcClass->GetLoadedDataItemAt(i); @@ -926,6 +955,7 @@ void KWObject::Write(ostream& ost) const void KWObject::PrettyWrite(ostream& ost, const ALString& sIndent) const { + const boolean bTraceUnloadedRelationAttributes = true; const ALString sBasicIndent = " "; KWDataItem* dataItem; KWAttribute* attribute; @@ -945,8 +975,6 @@ void KWObject::PrettyWrite(ostream& ost, const ALString& sIndent) const require(sIndent.SpanIncluding(" ") == sIndent); // Impression de l'entete de l'objet - if (GetClass()->GetRoot()) - ost << GetClass()->GetName() << "\n"; ost << sIndent << "{" << GetClass()->GetName() << "[" << GetCreationIndex() << "]\n"; // Impression des attributs charges en memoire @@ -1155,6 +1183,75 @@ void KWObject::PrettyWrite(ostream& ost, const ALString& sIndent) const } } + // Affichage egalement des attributs relation non charges en memoire + if (bTraceUnloadedRelationAttributes) + { + // Commentaire pour preciser le type d'attributs + ost << sIndent << "// Internal unloaded relation attributes\n"; + + // Parcours des attributs + for (i = 0; i < GetClass()->GetUnloadedOwnedRelationAttributeNumber(); i++) + { + attribute = GetClass()->GetUnloadedOwnedRelationAttributeAt(i); + assert(KWType::IsRelation(attribute->GetType())); + + // Indentation + ost << sIndent; + + // Nom de l'attribut + ost << attribute->GetName() << ": "; + + // Value de type objet + if (attribute->GetType() == KWType::Object) + { + kwoUsedObject = GetAt(attribute->GetLoadIndex().GetDenseIndex()).GetObject(); + if (kwoUsedObject == NULL) + ost << "[NULL]\n"; + else + { + if (not attribute->GetReference()) + { + ost << "\n"; + kwoUsedObject->PrettyWrite(ost, sIndent + sBasicIndent); + } + else + ost << kwoUsedObject->GetClass()->GetName() << "[" + << kwoUsedObject->GetCreationIndex() << "]\n"; + } + } + else + { + assert(attribute->GetType() == KWType::ObjectArray); + oaUsedObjectArray = GetAt(attribute->GetLoadIndex().GetDenseIndex()).GetObjectArray(); + if (oaUsedObjectArray == NULL) + ost << "[NULL]\n"; + else + { + // Parcours des elements du tableau + ost << "\n" << sIndent + sBasicIndent << "{\n"; + for (j = 0; j < oaUsedObjectArray->GetSize(); j++) + { + kwoUsedObject = cast(KWObject*, oaUsedObjectArray->GetAt(j)); + + // Test si objet multi inclu ou multi reference + if (kwoUsedObject == NULL) + ost << sIndent + sBasicIndent << "[NULL]\n"; + else + { + if (not attribute->GetReference()) + kwoUsedObject->PrettyWrite(ost, sIndent + sBasicIndent + + sBasicIndent); + else + ost << sIndent + sBasicIndent << "[" + << kwoUsedObject->GetCreationIndex() << "]\n"; + } + } + ost << sIndent + sBasicIndent << "}\n"; + } + } + } + } + // Impression de la fin de l'objet ost << sIndent << "}\n"; } @@ -1485,9 +1582,11 @@ void KWObject::Test() KWClassDomain::DeleteAllDomains(); } -void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nkdUnusedNativeAttributesToKeep) +void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nkdMutationClasses, + const NumericKeyDictionary* nkdUnusedNativeAttributesToKeep) { const boolean bTrace = false; + const boolean bTraceObject = false; const KWClass* previousClass; const KWAttribute* previousAttribute; ObjectValues previousValues; @@ -1515,115 +1614,133 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk int nNewNumber; boolean bIsViewTypeUse; boolean bIsMutationNeeded; + boolean bIsAttributeMutationNeeded; debug(require(nObjectLoadedDataItemNumber == kwcClass->GetLoadedDataItemNumber())); debug(require(nFreshness == kwcClass->GetFreshness())); + require(nkdMutationClasses != NULL); + require(nkdUnusedNativeAttributesToKeep != NULL); require(GetClass()->IsCompiled()); require(kwcNewClass != NULL); require(kwcNewClass->IsCompiled()); require(kwcClass->GetName() == kwcNewClass->GetName()); - require(kwcNewClass->GetLoadedAttributeNumber() <= kwcClass->GetLoadedAttributeNumber()); - require(kwcNewClass->GetLoadedDataItemNumber() <= kwcClass->GetLoadedDataItemNumber()); - require(nkdUnusedNativeAttributesToKeep != NULL); - - // Aucune action si meme classe - if (kwcNewClass == kwcClass) - return; + require(nkdMutationClasses->Lookup(kwcClass) == kwcNewClass); + require(kwcNewClass == kwcClass or + kwcNewClass->GetLoadedAttributeNumber() <= kwcClass->GetLoadedAttributeNumber()); + require(kwcNewClass == kwcClass or + kwcNewClass->GetLoadedDataItemNumber() <= kwcClass->GetLoadedDataItemNumber()); // Trace de debut if (bTrace) - cout << "Begin Object::Mutate " << GetClass()->GetName() << " " << GetCreationIndex() << "\n"; + { + cout << "Begin Object::Mutate " << GetClass()->GetDomain()->GetName() << " " << GetClass()->GetName() + << " " << GetCreationIndex(); + cout << " (" << kwcClass->GetLoadedDataItemNumber() << "," + << kwcClass->GetTotalInternallyLoadedDataItemNumber() << ") -> "; + cout << kwcNewClass->GetDomain()->GetName() << "(" << kwcNewClass->GetLoadedDataItemNumber() << "," + << kwcNewClass->GetTotalInternallyLoadedDataItemNumber() << ") #" << this << "\n"; + if (bTraceObject) + PrettyWrite(cout, " "); + } + + // Recherche si la mutation est necessaire + // Attention, meme si la mutation n'est pas necessaire, il faut muter les attribut de type relation de l'objet + bIsMutationNeeded = (kwcNewClass != kwcClass); // Recherche si usage de type view bIsViewTypeUse = GetViewTypeUse(); - // Dereferencement des valeurs de type Symbol - // (pour assurer la gestion correcte du compteur de references des Symbol) - nNumber = kwcClass->GetLoadedDenseSymbolAttributeNumber(); - nNewNumber = kwcNewClass->GetLoadedDenseSymbolAttributeNumber(); - for (i = nNewNumber; i < nNumber; i++) + //////////////////////////////////////////////////////////////// + // Nettoyage du contenu en cours si la mutation est necessaire + if (bIsMutationNeeded) { - attribute = kwcClass->GetLoadedDenseSymbolAttributeAt(i); + // Dereferencement des valeurs de type Symbol + // (pour assurer la gestion correcte du compteur de references des Symbol) + nNumber = kwcClass->GetLoadedDenseSymbolAttributeNumber(); + nNewNumber = kwcNewClass->GetLoadedDenseSymbolAttributeNumber(); + for (i = nNewNumber; i < nNumber; i++) + { + attribute = kwcClass->GetLoadedDenseSymbolAttributeAt(i); - // Si attribut non garde - liLoadIndex = attribute->GetLoadIndex(); - assert(liLoadIndex.IsDense()); + // Si attribut non garde + liLoadIndex = attribute->GetLoadIndex(); + assert(liLoadIndex.IsDense()); - // Dereferencement sauf si valeur interdite - if (not GetAt(liLoadIndex.GetDenseIndex()).IsSymbolForbidenValue()) - GetAt(liLoadIndex.GetDenseIndex()).ResetSymbol(); - } + // Dereferencement sauf si valeur interdite + if (not GetAt(liLoadIndex.GetDenseIndex()).IsSymbolForbidenValue()) + GetAt(liLoadIndex.GetDenseIndex()).ResetSymbol(); + } - // Dereferencement des valeurs de type Text - // (pour assurer la gestion correcte du compteur de references des Text) - nNumber = kwcClass->GetLoadedTextAttributeNumber(); - nNewNumber = kwcNewClass->GetLoadedTextAttributeNumber(); - for (i = nNewNumber; i < nNumber; i++) - { - attribute = kwcClass->GetLoadedTextAttributeAt(i); + // Dereferencement des valeurs de type Text + // (pour assurer la gestion correcte du compteur de references des Text) + nNumber = kwcClass->GetLoadedTextAttributeNumber(); + nNewNumber = kwcNewClass->GetLoadedTextAttributeNumber(); + for (i = nNewNumber; i < nNumber; i++) + { + attribute = kwcClass->GetLoadedTextAttributeAt(i); - // Si attribut non garde - liLoadIndex = attribute->GetLoadIndex(); - assert(liLoadIndex.IsDense()); + // Si attribut non garde + liLoadIndex = attribute->GetLoadIndex(); + assert(liLoadIndex.IsDense()); - // Dereferencement sauf si valeur interdite - if (not GetAt(liLoadIndex.GetDenseIndex()).IsTextForbidenValue()) - GetAt(liLoadIndex.GetDenseIndex()).ResetText(); - } + // Dereferencement sauf si valeur interdite + if (not GetAt(liLoadIndex.GetDenseIndex()).IsTextForbidenValue()) + GetAt(liLoadIndex.GetDenseIndex()).ResetText(); + } - // Destruction des valeurs de type TextList - nNumber = kwcClass->GetLoadedTextListAttributeNumber(); - nNewNumber = kwcNewClass->GetLoadedTextListAttributeNumber(); - for (i = nNewNumber; i < nNumber; i++) - { - attribute = kwcClass->GetLoadedTextListAttributeAt(i); + // Destruction des valeurs de type TextList + nNumber = kwcClass->GetLoadedTextListAttributeNumber(); + nNewNumber = kwcNewClass->GetLoadedTextListAttributeNumber(); + for (i = nNewNumber; i < nNumber; i++) + { + attribute = kwcClass->GetLoadedTextListAttributeAt(i); - // Si attribut non garde - liLoadIndex = attribute->GetLoadIndex(); - assert(liLoadIndex.IsDense()); - assert(attribute->GetDerivationRule() != NULL); + // Si attribut non garde + liLoadIndex = attribute->GetLoadIndex(); + assert(liLoadIndex.IsDense()); + assert(attribute->GetDerivationRule() != NULL); - // Destruction sauf si valeur interdite - if (not GetAt(liLoadIndex.GetDenseIndex()).IsTextListForbidenValue()) - { - svTextList = GetAt(liLoadIndex.GetDenseIndex()).GetTextList(); - if (svTextList != NULL) - delete svTextList; + // Destruction sauf si valeur interdite + if (not GetAt(liLoadIndex.GetDenseIndex()).IsTextListForbidenValue()) + { + svTextList = GetAt(liLoadIndex.GetDenseIndex()).GetTextList(); + if (svTextList != NULL) + delete svTextList; + } } - } - - // Destruction des valeurs de type Object ou ObjectArray inclus non gardees - // On ne detruit en fait que les tableaux dans le cas d'objets references - // Les objets eux memes sont geres par les attributs de type Relation non charges en memoire - nNumber = kwcClass->GetLoadedRelationAttributeNumber(); - nNewNumber = kwcNewClass->GetLoadedRelationAttributeNumber(); - for (i = nNewNumber; i < nNumber; i++) - { - attribute = kwcClass->GetLoadedRelationAttributeAt(i); - liLoadIndex = attribute->GetLoadIndex(); - assert(liLoadIndex.IsDense()); - // Cas des ObjectArray - if (attribute->GetType() == KWType::ObjectArray) + // Destruction des valeurs de type Object ou ObjectArray inclus non gardees + // On ne detruit en fait que les tableaux dans le cas d'objets references + // Les objets eux memes sont geres par les attributs de type Relation non charges en memoire + nNumber = kwcClass->GetLoadedRelationAttributeNumber(); + nNewNumber = kwcNewClass->GetLoadedRelationAttributeNumber(); + for (i = nNewNumber; i < nNumber; i++) { - if (attribute->GetDerivationRule() != NULL) - { - assert(liLoadIndex.GetDenseIndex() >= kwcNewClass->GetLoadedDataItemNumber()); + attribute = kwcClass->GetLoadedRelationAttributeAt(i); + liLoadIndex = attribute->GetLoadIndex(); + assert(liLoadIndex.IsDense()); - // Destruction sauf si NULL ou derive mais non calcule - if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectArrayForbidenValue()) + // Cas des ObjectArray + if (attribute->GetType() == KWType::ObjectArray) + { + // Destruction du container si objets references + // Pas de destruction sinon, car on en aura besoin pour muter les objets contenus + // Les containers appartiennent a l'objet, qu'ils soient natifs ou + // proviennent d'une regle, auquel cas ils ont ete dupliques et + // doivent etre detruits, sans leur contenu + if (attribute->GetReference()) { - oaUsedObjectArray = GetAt(liLoadIndex.GetDenseIndex()).GetObjectArray(); - if (oaUsedObjectArray != NULL) + assert(liLoadIndex.GetDenseIndex() >= kwcNewClass->GetLoadedDataItemNumber()); + + // Destruction sauf si NULL ou derive mais non calcule + if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectArrayForbidenValue()) { - // Destruction du container si objets references - // Les containers appartiennent a l'objet, qu'ils soient natifs ou - // proviennent d'une regle, auquel cas ils ont ete dupliques - if (attribute->GetReference()) + oaUsedObjectArray = GetAt(liLoadIndex.GetDenseIndex()).GetObjectArray(); + if (oaUsedObjectArray != NULL) { // Trace if (bTrace) - cout << " delete ref ObjectArray " + cout << " - delete ref ObjectArray " << attribute->GetName() << " " << oaUsedObjectArray << "\n"; @@ -1634,170 +1751,176 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk } } } - } - // Pas de destruction des valeurs de type Structure non gardees + // Pas de destruction des valeurs de type Structure non gardees - // Destruction des blocs de valeurs non gardees - nNumber = kwcClass->GetLoadedAttributeBlockNumber(); - nNewNumber = kwcNewClass->GetLoadedAttributeBlockNumber(); - for (i = nNewNumber; i < nNumber; i++) - { - attributeBlock = kwcClass->GetLoadedAttributeBlockAt(i); - liLoadIndex = attributeBlock->GetLoadIndex(); - assert(liLoadIndex.IsDense()); - - // Destruction du bloc non garde - if (attributeBlock->GetType() == KWType::Continuous) + // Destruction des blocs de valeurs non gardees + nNumber = kwcClass->GetLoadedAttributeBlockNumber(); + nNewNumber = kwcNewClass->GetLoadedAttributeBlockNumber(); + for (i = nNewNumber; i < nNumber; i++) { - // Destruction sauf si non calcule - if (not GetAt(liLoadIndex.GetDenseIndex()).IsContinuousValueBlockForbidenValue()) - { - continuousValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetContinuousValueBlock(); - check(continuousValueBlock); - delete continuousValueBlock; - } - } - else if (attributeBlock->GetType() == KWType::Symbol) - { - // Destruction sauf si non calcule - if (not GetAt(liLoadIndex.GetDenseIndex()).IsSymbolValueBlockForbidenValue()) - { - symbolValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetSymbolValueBlock(); - check(symbolValueBlock); - delete symbolValueBlock; - } - } - else if (attributeBlock->GetType() == KWType::ObjectArray) - { - // Destruction sauf si non calcule - if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectArrayValueBlockForbidenValue()) - { - objectArrayValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetObjectArrayValueBlock(); - check(objectArrayValueBlock); - // Il ne faut pas detruire le contenu des ObjectArray du bloc, qui sont necessairement - // calcules - assert(attributeBlock->GetDerivationRule() != NULL); - assert(attributeBlock->GetDerivationRule()->GetReference()); - delete objectArrayValueBlock; - } - } - } - - // Nettoyage des blocs de valeurs gardes, potentiellement partiellement - for (i = 0; i < kwcNewClass->GetLoadedAttributeBlockNumber(); i++) - { - attributeBlock = kwcClass->GetLoadedAttributeBlockAt(i); - liLoadIndex = attributeBlock->GetLoadIndex(); - assert(liLoadIndex.IsDense()); - - // Acces au bloc dans la nouvelle classe - newAttributeBlock = kwcNewClass->GetLoadedAttributeBlockAt(i); - assert(liLoadIndex == newAttributeBlock->GetLoadIndex()); - assert(newAttributeBlock->GetLoadedAttributeNumber() <= attributeBlock->GetLoadedAttributeNumber()); - - // Nettoyage du bloc si necessaire - // Il faut eventuellement supprimer les variables surnumeraires, qui n'avaient ete chargees - // dans la classe physique que pour permettre le calcul des attributs derives - if (newAttributeBlock->GetLoadedAttributeNumber() < attributeBlock->GetLoadedAttributeNumber()) - { - assert(attributeBlock->GetLoadedAttributeMutationIndexes() != NULL); + attributeBlock = kwcClass->GetLoadedAttributeBlockAt(i); + liLoadIndex = attributeBlock->GetLoadIndex(); + assert(liLoadIndex.IsDense()); + // Destruction du bloc non garde if (attributeBlock->GetType() == KWType::Continuous) { - // Acces au bloc courant - continuousValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetContinuousValueBlock(); - check(continuousValueBlock); - - // Remplacement par un bloc extrait pour les nouveaux index - newContinuousValueBlock = KWContinuousValueBlock::ExtractBlockSubset( - continuousValueBlock, attributeBlock->GetLoadedAttributeMutationIndexes()); - GetAt(liLoadIndex.GetDenseIndex()).SetContinuousValueBlock(newContinuousValueBlock); - delete continuousValueBlock; + // Destruction sauf si non calcule + if (not GetAt(liLoadIndex.GetDenseIndex()).IsContinuousValueBlockForbidenValue()) + { + continuousValueBlock = + GetAt(liLoadIndex.GetDenseIndex()).GetContinuousValueBlock(); + check(continuousValueBlock); + delete continuousValueBlock; + } } else if (attributeBlock->GetType() == KWType::Symbol) { - // Acces au bloc courant - symbolValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetSymbolValueBlock(); - check(symbolValueBlock); - - // Remplacement par un bloc extrait pour les nouveaux index - newSymbolValueBlock = KWSymbolValueBlock::ExtractBlockSubset( - symbolValueBlock, attributeBlock->GetLoadedAttributeMutationIndexes()); - GetAt(liLoadIndex.GetDenseIndex()).SetSymbolValueBlock(newSymbolValueBlock); - delete symbolValueBlock; + // Destruction sauf si non calcule + if (not GetAt(liLoadIndex.GetDenseIndex()).IsSymbolValueBlockForbidenValue()) + { + symbolValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetSymbolValueBlock(); + check(symbolValueBlock); + delete symbolValueBlock; + } } else if (attributeBlock->GetType() == KWType::ObjectArray) { - // Acces au bloc courant - objectArrayValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetObjectArrayValueBlock(); - check(objectArrayValueBlock); - - // Remplacement par un bloc extrait pour les nouveaux index - newObjectArrayValueBlock = KWObjectArrayValueBlock::ExtractBlockSubset( - objectArrayValueBlock, attributeBlock->GetLoadedAttributeMutationIndexes()); - GetAt(liLoadIndex.GetDenseIndex()).SetObjectArrayValueBlock(newObjectArrayValueBlock); - // Il ne faut pas detruire le contenu des ObjectArray du bloc, qui sont necessairement - // calcules - assert(attributeBlock->GetDerivationRule() != NULL); - assert(attributeBlock->GetDerivationRule()->GetReference()); - delete objectArrayValueBlock; + // Destruction sauf si non calcule + if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectArrayValueBlockForbidenValue()) + { + objectArrayValueBlock = + GetAt(liLoadIndex.GetDenseIndex()).GetObjectArrayValueBlock(); + check(objectArrayValueBlock); + + // Il ne faut pas detruire le contenu des ObjectArray du bloc, qui sont necessairement calcules + assert(attributeBlock->GetDerivationRule() != NULL); + assert(attributeBlock->GetDerivationRule()->GetReference()); + delete objectArrayValueBlock; + } } } - } - // Memorisation des anciennes valeurs - previousClass = kwcClass; - previousValues = values; - bPreviousSmallSize = (previousClass->GetTotalInternallyLoadedDataItemNumber() <= nBlockSize); + // Nettoyage des blocs de valeurs gardes, potentiellement partiellement + for (i = 0; i < kwcNewClass->GetLoadedAttributeBlockNumber(); i++) + { + attributeBlock = kwcClass->GetLoadedAttributeBlockAt(i); + liLoadIndex = attributeBlock->GetLoadIndex(); + assert(liLoadIndex.IsDense()); - // Initialisation - kwcClass = kwcNewClass; - values.attributeValues = NULL; - debug(nObjectLoadedDataItemNumber = 0); - debug(nFreshness = 0); + // Acces au bloc dans la nouvelle classe + newAttributeBlock = kwcNewClass->GetLoadedAttributeBlockAt(i); + assert(liLoadIndex == newAttributeBlock->GetLoadIndex()); + assert(newAttributeBlock->GetLoadedAttributeNumber() <= + attributeBlock->GetLoadedAttributeNumber()); - // Creation du container d'attributs - nTotalInternallyLoadedDataItemNumber = kwcClass->GetTotalInternallyLoadedDataItemNumber(); - nLoadedDataItemNumber = kwcClass->GetLoadedDataItemNumber(); - if (nTotalInternallyLoadedDataItemNumber > 0) - { - // Trace - if (bTrace) - cout << " new ValueVector (size=" << nLoadedDataItemNumber - << " , internal size=" << nTotalInternallyLoadedDataItemNumber << ")\n"; + // Nettoyage du bloc si necessaire + // Il faut eventuellement supprimer les variables surnumeraires, qui n'avaient ete chargees + // dans la classe physique que pour permettre le calcul des attributs derives + if (newAttributeBlock->GetLoadedAttributeNumber() < attributeBlock->GetLoadedAttributeNumber()) + { + assert(attributeBlock->GetLoadedAttributeMutationIndexes() != NULL); - // Creation du vecteur de valeur et memorisation de son type de taille - values = NewValueVector(nTotalInternallyLoadedDataItemNumber); - SetSmallSize(nTotalInternallyLoadedDataItemNumber <= nBlockSize); + if (attributeBlock->GetType() == KWType::Continuous) + { + // Acces au bloc courant + continuousValueBlock = + GetAt(liLoadIndex.GetDenseIndex()).GetContinuousValueBlock(); + check(continuousValueBlock); + + // Remplacement par un bloc extrait pour les nouveaux index + newContinuousValueBlock = KWContinuousValueBlock::ExtractBlockSubset( + continuousValueBlock, attributeBlock->GetLoadedAttributeMutationIndexes()); + GetAt(liLoadIndex.GetDenseIndex()) + .SetContinuousValueBlock(newContinuousValueBlock); + delete continuousValueBlock; + } + else if (attributeBlock->GetType() == KWType::Symbol) + { + // Acces au bloc courant + symbolValueBlock = GetAt(liLoadIndex.GetDenseIndex()).GetSymbolValueBlock(); + check(symbolValueBlock); + + // Remplacement par un bloc extrait pour les nouveaux index + newSymbolValueBlock = KWSymbolValueBlock::ExtractBlockSubset( + symbolValueBlock, attributeBlock->GetLoadedAttributeMutationIndexes()); + GetAt(liLoadIndex.GetDenseIndex()).SetSymbolValueBlock(newSymbolValueBlock); + delete symbolValueBlock; + } + else if (attributeBlock->GetType() == KWType::ObjectArray) + { + // Acces au bloc courant + objectArrayValueBlock = + GetAt(liLoadIndex.GetDenseIndex()).GetObjectArrayValueBlock(); + check(objectArrayValueBlock); + + // Remplacement par un bloc extrait pour les nouveaux index + newObjectArrayValueBlock = KWObjectArrayValueBlock::ExtractBlockSubset( + objectArrayValueBlock, attributeBlock->GetLoadedAttributeMutationIndexes()); + GetAt(liLoadIndex.GetDenseIndex()) + .SetObjectArrayValueBlock(newObjectArrayValueBlock); + + // Il ne faut pas detruire le contenu des ObjectArray du bloc, qui sont necessairement calcules + assert(attributeBlock->GetDerivationRule() != NULL); + assert(attributeBlock->GetDerivationRule()->GetReference()); + delete objectArrayValueBlock; + } + } + } - // Transfert des valeurs chargees en memoire - for (i = 0; i < nLoadedDataItemNumber; i++) - GetAt(i) = GetValueAt(previousValues, bPreviousSmallSize, i); + // Memorisation des anciennes valeurs + previousClass = kwcClass; + previousValues = values; + bPreviousSmallSize = (previousClass->GetTotalInternallyLoadedDataItemNumber() <= nBlockSize); - // Transfert et mutation des Object et ObjectArray inclus natifs non charges en memoire - for (i = 0; i < kwcClass->GetUnloadedOwnedRelationAttributeNumber(); i++) + // Initialisation + kwcClass = kwcNewClass; + values.attributeValues = NULL; + debug(nObjectLoadedDataItemNumber = 0); + debug(nFreshness = 0); + + // Creation du container d'attributs + nTotalInternallyLoadedDataItemNumber = kwcClass->GetTotalInternallyLoadedDataItemNumber(); + nLoadedDataItemNumber = kwcClass->GetLoadedDataItemNumber(); + if (nTotalInternallyLoadedDataItemNumber > 0) { - attribute = kwcClass->GetUnloadedOwnedRelationAttributeAt(i); - liInternalLoadIndex = attribute->GetInternalLoadIndex(); - assert(liInternalLoadIndex.IsDense()); + // Trace + if (bTrace) + cout << " - new ValueVector (size=" << nLoadedDataItemNumber + << " , internal size=" << nTotalInternallyLoadedDataItemNumber << ")\n"; - // Verifications de coherence - assert(KWType::IsRelation(attribute->GetType())); - assert(not attribute->GetReference()); - assert(attribute->GetLoaded() == false); - assert(not attribute->GetReference()); + // Creation du vecteur de valeur et memorisation de son type de taille + values = NewValueVector(nTotalInternallyLoadedDataItemNumber); + SetSmallSize(nTotalInternallyLoadedDataItemNumber <= nBlockSize); - // Mutation necessaire si sous-objet natif, sauf dans le cas d'une vue - // ou si sous-objet calcule, sauf s'il s'agit d'une reference - if (attribute->GetDerivationRule() == NULL) - bIsMutationNeeded = not bIsViewTypeUse; - else - bIsMutationNeeded = not attribute->GetDerivationRule()->GetReference(); + // Transfert des valeurs chargees en memoire + for (i = 0; i < nLoadedDataItemNumber; i++) + { + // Verification de la coherence des attributs entre l'ancienne et la nouvelle classe + assert(kwcClass->GetLoadedDataItemAt(i)->GetName() == + previousClass->GetLoadedDataItemAt(i)->GetName()); + assert(kwcClass->GetLoadedDataItemAt(i)->IsAttribute() == + previousClass->GetLoadedDataItemAt(i)->IsAttribute()); + assert(kwcClass->GetLoadedDataItemAt(i)->IsAttribute() or + cast(KWAttributeBlock*, kwcClass->GetLoadedDataItemAt(i))->GetBlockType() == + cast(KWAttributeBlock*, kwcClass->GetLoadedDataItemAt(i))->GetBlockType()); + assert(kwcClass->GetLoadedDataItemAt(i)->IsAttributeBlock() or + cast(KWAttribute*, kwcClass->GetLoadedDataItemAt(i))->GetType() == + cast(KWAttribute*, kwcClass->GetLoadedDataItemAt(i))->GetType()); + + // Copie de la valeur + GetAt(i) = GetValueAt(previousValues, bPreviousSmallSize, i); + } - // Mutation si necessaire - if (bIsMutationNeeded) + // Transfert ou destruction des Object et ObjectArray inclus natifs non charges en memoire + for (i = 0; i < kwcClass->GetUnloadedOwnedRelationAttributeNumber(); i++) { + attribute = kwcClass->GetUnloadedOwnedRelationAttributeAt(i); + liInternalLoadIndex = attribute->GetInternalLoadIndex(); + assert(liInternalLoadIndex.IsDense()); + assert(not GetAt(liInternalLoadIndex.GetDenseIndex()).IsObjectForbidenValue()); + // Traitement si attribut precedent present dans la classe d'origine previousAttribute = previousClass->LookupAttribute(attribute->GetName()); if (previousAttribute != NULL) @@ -1813,7 +1936,7 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk liLoadIndex.GetDenseIndex()) .GetObject(); - // Transfert et mutation de l'objet si necessaire, destruction sinon + // Transfert de l'objet si necessaire, destruction sinon if (kwoUsedObject != NULL) { // Test de coherence @@ -1829,15 +1952,13 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk { GetAt(liInternalLoadIndex.GetDenseIndex()) .SetObject(kwoUsedObject); - kwoUsedObject->Mutate(attribute->GetClass(), - nkdUnusedNativeAttributesToKeep); } // Destruction sinon else { // Trace if (bTrace) - cout << " delete Object " + cout << " - delete Object " << attribute->GetName() << " " << kwoUsedObject << "\n"; @@ -1856,7 +1977,7 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk liLoadIndex.GetDenseIndex()) .GetObjectArray(); - // Transfert et mutation de l'objet si necessaire, destruction sinon + // Transfert des objets si necessaire, destruction sinon if (oaUsedObjectArray != NULL) { // Transfert si objet a garder @@ -1866,35 +1987,13 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk // Transfert du tableau GetAt(liInternalLoadIndex.GetDenseIndex()) .SetObjectArray(oaUsedObjectArray); - - // Parcours des objets du tableau pour mutation eventuelle - for (nObject = 0; - nObject < oaUsedObjectArray->GetSize(); nObject++) - { - kwoUsedObject = - cast(KWObject*, - oaUsedObjectArray->GetAt(nObject)); - - // Test de coherence - assert(kwoUsedObject->GetClass()->GetName() == - attribute->GetClass()->GetName()); - assert(kwoUsedObject->GetClass()->GetDomain() == - previousClass->GetDomain()); - assert(kwoUsedObject->GetClass() != - attribute->GetClass()); - - // Mutation - kwoUsedObject->Mutate( - attribute->GetClass(), - nkdUnusedNativeAttributesToKeep); - } } // Destruction sinon else { // Trace if (bTrace) - cout << " delete ObjectArray content " + cout << " - delete ObjectArray content " << attribute->GetName() << " " << "(size=" << oaUsedObjectArray->GetSize() << ") " << oaUsedObjectArray << "\n"; @@ -1909,107 +2008,89 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk } } - // Mutation des attributs Object ou ObjectArray transferres si necessaire - for (i = 0; i < kwcClass->GetLoadedRelationAttributeNumber(); i++) + // Destruction des valeurs precedentes, geree par la destruction de l'objet precedent memorise + if (previousValues.attributeValues != NULL) { - attribute = kwcClass->GetLoadedRelationAttributeAt(i); - liLoadIndex = attribute->GetLoadIndex(); - assert(liLoadIndex.IsDense()); + // Trace + if (bTrace) + cout << " - delete previous ValueVector (size=" + << previousClass->GetTotalInternallyLoadedDataItemNumber() << ")\n"; - // Mutation necessaire si sous-objet natif, sauf dans le cas d'une vue - // ou si sous-objet calcule, sauf s'il s'agit d'une reference - if (attribute->GetDerivationRule() == NULL) - bIsMutationNeeded = not bIsViewTypeUse; - else - bIsMutationNeeded = not attribute->GetDerivationRule()->GetReference(); + // Destruction + DeleteValueVector(previousValues, previousClass->GetTotalInternallyLoadedDataItemNumber()); + } + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + // Mutation des objets contenus, transferes ou non + + // Mutation des attributs Object ou ObjectArray transferres si necessaire + for (i = 0; i < kwcClass->GetLoadedRelationAttributeNumber(); i++) + { + attribute = kwcClass->GetLoadedRelationAttributeAt(i); + liLoadIndex = attribute->GetLoadIndex(); + assert(liLoadIndex.IsDense()); + + // Mutation necessaire si sous-objet natif, sauf dans le cas d'une vue + // ou si sous-objet calcule, sauf s'il s'agit d'une reference + if (attribute->GetDerivationRule() == NULL) + bIsAttributeMutationNeeded = not bIsViewTypeUse; + else + bIsAttributeMutationNeeded = not attribute->GetDerivationRule()->GetReference(); - // Mutation si necessaire - if (bIsMutationNeeded) + // Mutation si necessaire + if (bIsAttributeMutationNeeded) + { + // Cas des Object + if (attribute->GetType() == KWType::Object) { - // Cas des Object - if (attribute->GetType() == KWType::Object) + // Si attribut inclu: mutation + if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectForbidenValue()) { - // Si attribut inclu: mutation - if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectForbidenValue()) + kwoUsedObject = GetAt(liLoadIndex.GetDenseIndex()).GetObject(); + if (kwoUsedObject != NULL) { - kwoUsedObject = GetAt(liLoadIndex.GetDenseIndex()).GetObject(); - if (kwoUsedObject != NULL and - kwoUsedObject->GetClass()->GetDomain() != kwcClass->GetDomain()) - { - // Recherche de la classe destination - kwcMutationClass = kwcClass->GetDomain()->LookupClass( - kwoUsedObject->GetClass()->GetName()); - - // Si non trouve, supression - if (kwcMutationClass == NULL) - { - // Trace - if (bTrace) - cout << " delete unmutated Object " - << attribute->GetName() << " " - << kwoUsedObject << "\n"; - - // Supression - delete kwoUsedObject; - GetAt(liLoadIndex.GetDenseIndex()).SetObject(NULL); - } - // Sinon, mutation - else - kwoUsedObject->Mutate(kwcMutationClass, - nkdUnusedNativeAttributesToKeep); - } + // Recherche de la classe de mutation + kwcMutationClass = cast( + KWClass*, nkdMutationClasses->Lookup(kwoUsedObject->GetClass())); + assert(kwcMutationClass != NULL); + + // Mutation + kwoUsedObject->Mutate(kwcMutationClass, nkdMutationClasses, + nkdUnusedNativeAttributesToKeep); } } - // Cas des ObjectArray - else - { - assert(attribute->GetType() == KWType::ObjectArray); + } + // Cas des ObjectArray + else + { + assert(attribute->GetType() == KWType::ObjectArray); - // Si attribut multi-inclu: mutation - if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectArrayForbidenValue()) + // Si attribut multi-inclu: mutation + if (not GetAt(liLoadIndex.GetDenseIndex()).IsObjectArrayForbidenValue()) + { + oaUsedObjectArray = GetAt(liLoadIndex.GetDenseIndex()).GetObjectArray(); + if (oaUsedObjectArray != NULL) { - oaUsedObjectArray = GetAt(liLoadIndex.GetDenseIndex()).GetObjectArray(); - if (oaUsedObjectArray != NULL) + // Parcours des objets du tableau pour mutation eventuelle + kwcMutationClass = NULL; + for (nObject = 0; nObject < oaUsedObjectArray->GetSize(); nObject++) { - // Parcours des objets du tableau pour mutation eventuelle - kwcMutationClass = NULL; - for (nObject = 0; nObject < oaUsedObjectArray->GetSize(); - nObject++) + kwoUsedObject = + cast(KWObject*, oaUsedObjectArray->GetAt(nObject)); + if (kwoUsedObject != NULL) { - kwoUsedObject = - cast(KWObject*, oaUsedObjectArray->GetAt(nObject)); - if (kwoUsedObject != NULL and - kwoUsedObject->GetClass()->GetDomain() != - kwcClass->GetDomain()) - { - // Recherche de la classe destination - if (kwcMutationClass == NULL) - kwcMutationClass = - kwcClass->GetDomain()->LookupClass( - kwoUsedObject->GetClass() - ->GetName()); - - // Si non trouve, supression - if (kwcMutationClass == NULL) - { - // Trace - if (bTrace) - cout << " delete unmutated " - "Object in ObjectArray " - << attribute->GetName() - << " " << kwoUsedObject - << "\n"; - - // Supression - delete kwoUsedObject; - oaUsedObjectArray->SetAt(nObject, NULL); - } - // Sinon, mutation - else - kwoUsedObject->Mutate( - kwcMutationClass, - nkdUnusedNativeAttributesToKeep); - } + // Recherche de la classe de mutation + if (kwcMutationClass == NULL) + kwcMutationClass = cast( + KWClass*, nkdMutationClasses->Lookup( + kwoUsedObject->GetClass())); + assert(kwcMutationClass != NULL); + + // Mutation + kwoUsedObject->Mutate(kwcMutationClass, + nkdMutationClasses, + nkdUnusedNativeAttributesToKeep); } } } @@ -2018,25 +2099,96 @@ void KWObject::Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nk } } - // Destruction des valeurs precedentes, geree par la destruction de l'objet precedent memorise - if (previousValues.attributeValues != NULL) + // Mutation des Object et ObjectArray inclus natifs non charges en memoire + for (i = 0; i < kwcClass->GetUnloadedOwnedRelationAttributeNumber(); i++) { - // Trace - if (bTrace) - cout << " delete previous ValueVector (size=" - << previousClass->GetTotalInternallyLoadedDataItemNumber() << ")\n"; + attribute = kwcClass->GetUnloadedOwnedRelationAttributeAt(i); + liInternalLoadIndex = attribute->GetInternalLoadIndex(); + assert(liInternalLoadIndex.IsDense()); + assert(not GetAt(liInternalLoadIndex.GetDenseIndex()).IsObjectForbidenValue()); - // Destruction - DeleteValueVector(previousValues, previousClass->GetTotalInternallyLoadedDataItemNumber()); - } + // Verifications de coherence + assert(KWType::IsRelation(attribute->GetType())); + assert(not attribute->GetReference()); + assert(attribute->GetLoaded() == false); - // Trace de fin - if (bTrace) - cout << "End Object::Mutate " << GetClass()->GetName() << " " << GetCreationIndex() << "\n"; + // Mutation necessaire si sous-objet natif, sauf dans le cas d'une vue + // ou si sous-objet calcule, sauf s'il s'agit d'une reference + if (attribute->GetDerivationRule() == NULL) + bIsAttributeMutationNeeded = not bIsViewTypeUse; + else + { + assert(not attribute->GetDerivationRule()->GetReference()); + bIsAttributeMutationNeeded = true; + } + + // Mutation si necessaire + if (bIsAttributeMutationNeeded) + { + // Cas des Object + if (attribute->GetType() == KWType::Object) + { + kwoUsedObject = GetAt(liInternalLoadIndex.GetDenseIndex()).GetObject(); + + // Mutation de l'objet si necessaire + if (kwoUsedObject != NULL) + { + // Recherche de la classe de mutation + kwcMutationClass = + cast(KWClass*, nkdMutationClasses->Lookup(kwoUsedObject->GetClass())); + assert(kwcMutationClass != NULL); + + // Transfert + GetAt(liInternalLoadIndex.GetDenseIndex()).SetObject(kwoUsedObject); + kwoUsedObject->Mutate(kwcMutationClass, nkdMutationClasses, + nkdUnusedNativeAttributesToKeep); + } + } + // Cas des ObjectArray + else + { + assert(attribute->GetType() == KWType::ObjectArray); + + // Mutation des l'objet si necessaire + oaUsedObjectArray = GetAt(liInternalLoadIndex.GetDenseIndex()).GetObjectArray(); + if (oaUsedObjectArray != NULL) + { + // Parcours des objets du tableau pour mutation eventuelle + kwcMutationClass = NULL; + for (nObject = 0; nObject < oaUsedObjectArray->GetSize(); nObject++) + { + kwoUsedObject = cast(KWObject*, oaUsedObjectArray->GetAt(nObject)); + if (kwoUsedObject != NULL) + { + // Recherche de la classe de mutation + if (kwcMutationClass == NULL) + kwcMutationClass = + cast(KWClass*, nkdMutationClasses->Lookup( + kwoUsedObject->GetClass())); + assert(kwcMutationClass != NULL); + + // Mutation + kwoUsedObject->Mutate(kwcMutationClass, nkdMutationClasses, + nkdUnusedNativeAttributesToKeep); + } + } + } + } + } + } // Memorisation des informations de coherence debug(nObjectLoadedDataItemNumber = kwcClass->GetTotalInternallyLoadedDataItemNumber()); debug(nFreshness = kwcClass->GetFreshness()); + + // Trace de fin + if (bTrace) + { + if (bTraceObject) + PrettyWrite(cout, " "); + cout << "End Object::Mutate " << GetClass()->GetDomain()->GetName() << " " << GetClass()->GetName() + << " " << GetCreationIndex() << " #" << this << "\n"; + } } KWObject::ObjectValues KWObject::NewValueVector(int nSize) diff --git a/src/Learning/KWData/KWObject.h b/src/Learning/KWData/KWObject.h index 579c8a5ec..747dc0a40 100644 --- a/src/Learning/KWData/KWObject.h +++ b/src/Learning/KWData/KWObject.h @@ -233,24 +233,31 @@ class KWObject : public Object void CleanNativeRelationAttributes(); // Methode de mutation specifique a destination des classes KWDatabase et KWDataTableSliceSet - // La nouvelle classe doit avoir moins d'attributs Loaded que la classe - // precedente, et ces attributs doivent coincider (meme type, meme nom). - // Elle doit provenir d'un autre domaine, mais avoir meme nom. + // La nouvelle classe doit avoir le meme nom que celle de la classe en cours + // Dans certains cas particuliers, la nouvelle classe peut-etre la meme. Dans ce cas, + // l'objet est conserve tel quel, et seul son contenu est mute si necessaire + // Sinon, la nouvelle classe doit avoir moins d'attributs Loaded que la classe + // precedente, et ces attributs doivent coincider (meme type, meme nom) et etre en tete de + // classe dans le meme ordre. // // Lors de la mutation, on a les operations suivantes: - // attributs commun gardes - // attributs en trop detruits - // valeur derivees transferees telles quelles - // objets internes inclus ou multi-inclus soit mutes egalement si gardes - // (si possible, sinon detruits), soit detruits s'ils sont a supprimer - // objets references laisses tels quels (ni mutes, ni detruits) + // - attributs commun gardes + // - attributs en trop detruits + // - valeur derivees transferees telles quelles + // - objets internes inclus ou multi-inclus soit mutes egalement si gardes + // (si possible, sinon detruits), soit detruits s'ils sont a supprimer + // - objets references laisses tels quels (ni mutes, ni detruits) + // + // Le dictionnaire des classe de mutation specifie pour chaque classe initiale + // la classe a utiliser pour la mutation // // Le dictionnaire des attributs a garder (dans la nouvelle classe) indique // les attributs natifs non utilises object inclus ou multi-inclus a garder - // lors de la mutation, car referencable par de regles de derivation + // lors de la mutation, car referencable par des regles de derivation friend class KWDatabase; friend class KWDataTableSliceSet; - void Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nkdUnusedNativeAttributesToKeep); + void Mutate(const KWClass* kwcNewClass, const NumericKeyDictionary* nkdMutationClasses, + const NumericKeyDictionary* nkdUnusedNativeAttributesToKeep); // KWClass const KWClass* kwcClass; @@ -1324,10 +1331,11 @@ inline boolean KWObject::CheckAttributeObjectClass(KWAttribute* attribute, KWObj require(KWType::IsRelation(attribute->GetType())); if (kwoValue != NULL) { - if (not attribute->GetReference()) - return attribute->GetClass() == kwoValue->GetClass(); - else - return attribute->GetClass()->GetName() == kwoValue->GetClass()->GetName(); + // La classe doit etre de meme nom, mais ce n'est pas necessairement la meme + // En effet, lors d'une mutation d'objet par la methode Mutate, un objet du niveau + // logique peut etre un sous-objet d'un objet du niveau physique, gere par une classe + // du niveau physique + return attribute->GetClass()->GetName() == kwoValue->GetClass()->GetName(); } else return true; diff --git a/src/Learning/KWData/KWRelationCreationRule.h b/src/Learning/KWData/KWRelationCreationRule.h index 398aa03fd..fe74d1cda 100644 --- a/src/Learning/KWData/KWRelationCreationRule.h +++ b/src/Learning/KWData/KWRelationCreationRule.h @@ -28,7 +28,7 @@ class KWDRTableCreationRule; // - alimentation de type vue // - alimentation de type calcul // - le dictionnaire en sortie peut avoir ses variable utilisees ou non (Used), -// et des variable calculee si besoin +// et des variables calculees si besoin // - un dictionnaire en sortie n'est pas specifique aux regles de creation de Table: // a priori, un meme dictionnaire pourrait etre utilise pour une variable native alimentee // depuis un fichier, et pour une variable calculee alimentee par une regle de creation @@ -61,7 +61,7 @@ class KWDRTableCreationRule; // comme dans les fichier, ou de type Entity ou Table // - on peut avoir des variables calculees en sortie // - les variables calculees en sortie peuvent avoir le meme nom que des variables -// en entree, calculees ou non, meme avec des type differents; cela permet de creer +// en entree, calculees ou non, meme avec des types differents; cela permet de creer // de nouvelles variables independament en entree et en sortie // // Alimentation de type calcul @@ -71,7 +71,7 @@ class KWDRTableCreationRule; // - les operandes en sortie designent explicitement les noms des variables natives a alimenter dans // le dictionnaire en sortie // - cela ne concerne ques les variables natives en sortie du premier niveau dans le cas de variables -// de type relation: on ne peut pas specifier l'amilementation d'une variable secondaire d'une +// de type relation: on ne peut pas specifier l'alimentation d'une variable secondaire d'une // sous-table en sortie class KWDRRelationCreationRule : public KWDerivationRule { diff --git a/src/Learning/KWDataUtils/KWDataTableSliceSet.cpp b/src/Learning/KWDataUtils/KWDataTableSliceSet.cpp index c09a0e97e..a967e2e2c 100644 --- a/src/Learning/KWDataUtils/KWDataTableSliceSet.cpp +++ b/src/Learning/KWDataUtils/KWDataTableSliceSet.cpp @@ -2736,6 +2736,7 @@ KWObject* KWDataTableSliceSet::PhysicalRead() KWDataItem* dataItem; KWAttribute* attribute; KWAttributeBlock* attributeBlock; + NumericKeyDictionary nkdMutationClasses; NumericKeyDictionary nkdUnusedNativeAttributesToKeep; ALString sMessage; @@ -2820,8 +2821,10 @@ KWObject* KWDataTableSliceSet::PhysicalRead() // Mutation de l'objet if (bOk) { + assert(nkdMutationClasses.GetCount() == 0); assert(nkdUnusedNativeAttributesToKeep.GetCount() == 0); - kwoObject->Mutate(read_Class, &nkdUnusedNativeAttributesToKeep); + nkdMutationClasses.SetAt(kwoObject->GetClass(), cast(KWClass*, read_Class)); + kwoObject->Mutate(read_Class, &nkdMutationClasses, &nkdUnusedNativeAttributesToKeep); } // Destruction de l'objet en cas d'erreur diff --git a/src/Learning/MODL/MODL.cpp b/src/Learning/MODL/MODL.cpp index b87e5d6c8..9f8e55a7b 100644 --- a/src/Learning/MODL/MODL.cpp +++ b/src/Learning/MODL/MODL.cpp @@ -42,7 +42,7 @@ int main(int argc, char** argv) // SetWindowsDebugDir("Standard", "IrisLight"); // SetWindowsDebugDir("Standard", "IrisU2D"); // SetWindowsDebugDir("z_TableCreationRules", "NoKeyInCreatedSnowflake"); - // SetWindowsDebugDir("z_TableCreationRules", "TableNoKey"); + // SetWindowsDebugDir("z_TableCreationRules", "BUG_SnowflakeWithUnusedTable"); // Parametrage des logs memoires depuis les variables d'environnement, pris en compte dans KWLearningProject // KhiopsMemStatsLogFileName, KhiopsMemStatsLogFrequency, KhiopsMemStatsLogToCollect