From 1cc98981cf559a83452ca4de3105fc648c93b190 Mon Sep 17 00:00:00 2001 From: CyrilFerlicot Date: Tue, 30 Jan 2024 12:11:19 +0100 Subject: [PATCH] Merge Moose storages My goal is to totally remove them but here is a first step by merging all storages. --- .../MooseAbstractGroupTest.class.st | 18 -- src/Moose-Core-Tests/MooseGroupTest.class.st | 5 - src/Moose-Core/MooseAbstractGroup.class.st | 2 +- .../MooseGroupRuntimeStorage.class.st | 167 ----------------- .../MooseGroupSetupStorage.class.st | 117 ------------ src/Moose-Core/MooseGroupStorage.class.st | 172 +++++++++++------- src/Moose-Core/MooseModel.class.st | 1 - .../InstallElementsOperator.class.st | 8 +- 8 files changed, 113 insertions(+), 377 deletions(-) delete mode 100644 src/Moose-Core/MooseGroupRuntimeStorage.class.st delete mode 100644 src/Moose-Core/MooseGroupSetupStorage.class.st diff --git a/src/Moose-Core-Tests/MooseAbstractGroupTest.class.st b/src/Moose-Core-Tests/MooseAbstractGroupTest.class.st index 32115617..3d1c412d 100644 --- a/src/Moose-Core-Tests/MooseAbstractGroupTest.class.st +++ b/src/Moose-Core-Tests/MooseAbstractGroupTest.class.st @@ -120,24 +120,6 @@ MooseAbstractGroupTest >> testAllWithType [ self assertEmpty: (group allWithType: Object) ] -{ #category : #tests } -MooseAbstractGroupTest >> testAllWithTypeAtRuntime [ - group addAll: {FamixTest3Class new . FamixTest3Method new}. - group entityStorage forRuntime. - self assert: (group allWithType: FamixTest3Class) size equals: 1. - self assert: (group allWithType: FamixTest3Method) size equals: 1. - self assertEmpty: (group allWithType: FamixTest3Invocation) -] - -{ #category : #tests } -MooseAbstractGroupTest >> testAllWithTypeAtSetup [ - group addAll: {FamixTest3Class new . FamixTest3Method new}. - group entityStorage forSetup. - self assert: (group allWithType: FamixTest3Class) size equals: 1. - self assert: (group allWithType: FamixTest3Method) size equals: 1. - self assertEmpty: (group allWithType: FamixTest3Invocation) -] - { #category : #tests } MooseAbstractGroupTest >> testAllWithTypeThenAllWithSubTypesOf [ group addAll: {FamixTest3Class new . FamixTest3Type new}. diff --git a/src/Moose-Core-Tests/MooseGroupTest.class.st b/src/Moose-Core-Tests/MooseGroupTest.class.st index 94d0fe5e..6417f7e0 100644 --- a/src/Moose-Core-Tests/MooseGroupTest.class.st +++ b/src/Moose-Core-Tests/MooseGroupTest.class.st @@ -30,11 +30,6 @@ MooseGroupTest >> testAsMooseGroupWithClasses [ self assert: group anyOne equals: Object ] -{ #category : #tests } -MooseGroupTest >> testDefaultStorage [ - self assert: (group entityStorage isKindOf: MooseGroupRuntimeStorage) -] - { #category : #tests } MooseGroupTest >> testDefaultStorageIterator [ self assert: group entityStorage iterator class equals: IteratorWithCollectionAPI diff --git a/src/Moose-Core/MooseAbstractGroup.class.st b/src/Moose-Core/MooseAbstractGroup.class.st index df2a1e39..c5a8f5c5 100644 --- a/src/Moose-Core/MooseAbstractGroup.class.st +++ b/src/Moose-Core/MooseAbstractGroup.class.st @@ -485,7 +485,7 @@ MooseAbstractGroup >> initialize [ MooseAbstractGroup >> initializeWithAll: aCollection [ self initialize. - storage := MooseGroupRuntimeStorage new: aCollection size. + storage := MooseGroupStorage new: aCollection size. self addAll: aCollection ] diff --git a/src/Moose-Core/MooseGroupRuntimeStorage.class.st b/src/Moose-Core/MooseGroupRuntimeStorage.class.st deleted file mode 100644 index f6b01dfe..00000000 --- a/src/Moose-Core/MooseGroupRuntimeStorage.class.st +++ /dev/null @@ -1,167 +0,0 @@ -" -I am storing the items of the group during the standard usage of moose entities. - -I store the entites for fast access byName and byType. I also contains the all the entities in elements which is not sorted. - -I am used by MooseAbstractGroup subclasses. - -Public API and Key Messages - -I am managed like a collection and my caches are autoupdated when an entity is added or removed. - -Internal Representation and Key Implementation Points. - - Instance Variables - byName: IdentityHashTable (key: mooseName) - byType: Dictionnary of OrderedCollection (key: FAMIXType) - the orderedCollection is sorted on access - elements: OrderedCollection - -Implementation Points -- On access by type, OrderedCollections in byType dictionary are sorted by MooseName to find its type faster. This sort is stored in sortedCollectionList and is invalidated on addition of a new element in the collection - -I am using an identity hash table to save the names because it is optimized for large collection. The possible loss of performances for small collection is negligeable compared to the gain for large collection. Creating a moose group of 2450080 entities took 6sec+ with anIdentityDictionary and now take 1.6sec+ with a IdentityHashTable. - - - -" -Class { - #name : #MooseGroupRuntimeStorage, - #superclass : #MooseGroupStorage, - #type : #variable, - #instVars : [ - 'byName', - 'elements', - 'byType' - ], - #category : #'Moose-Core' -} - -{ #category : #adding } -MooseGroupRuntimeStorage >> add: anElement [ - self privateAdd: anElement. - self updateCacheOnAddingOf: anElement. - ^anElement -] - -{ #category : #adding } -MooseGroupRuntimeStorage >> allEntityTypes [ - ^ byType keys -] - -{ #category : #accessing } -MooseGroupRuntimeStorage >> at: uniqueName ifAbsent: exceptionBlock [ - ^byName at: uniqueName asSymbol ifAbsent: exceptionBlock -] - -{ #category : #enumerating } -MooseGroupRuntimeStorage >> do: aBlock [ - - elements do: aBlock -] - -{ #category : #accessing } -MooseGroupRuntimeStorage >> elements [ - ^ elements -] - -{ #category : #initialization } -MooseGroupRuntimeStorage >> initialize: capacity [ - - super initialize: capacity. - byType := IdentityDictionary new: 24. - byName := IdentityHashTable new: capacity. - elements := self species new: capacity -] - -{ #category : #copying } -MooseGroupRuntimeStorage >> postCopy [ - super postCopy. - elements := elements copy. - byName := byName copy. - byType := byType copy -] - -{ #category : #adding } -MooseGroupRuntimeStorage >> privateAdd: anElement [ - ^elements add: anElement -] - -{ #category : #removing } -MooseGroupRuntimeStorage >> remove: anElement ifAbsent: exceptionBlock [ - self updateCacheOnRemovalOf: anElement. - elements remove: anElement. - ^ anElement -] - -{ #category : #removing } -MooseGroupRuntimeStorage >> removeAll [ - - self initialize: 10000 -] - -{ #category : #private } -MooseGroupRuntimeStorage >> resetMooseNameFor: anEntity [ - anEntity hasUniqueMooseNameInModel - ifTrue: [ - byName removeKey: anEntity mooseName asSymbol ifAbsent: [ ]. - super resetMooseNameFor: anEntity. - byName at: anEntity mooseName asSymbol put: anEntity ] - ifFalse: [ super resetMooseNameFor: anEntity ] -] - -{ #category : #enumerating } -MooseGroupRuntimeStorage >> selectAllWithType: aSmalltalkType [ - ^ byType - at: aSmalltalkType - ifAbsent: [ | result | - result := Set new. - byType keys - select: [ :aClass | aClass class = aSmalltalkType ] - thenDo: [ :aKey | (byType at: aKey) do: [ :anElement | result add: anElement ] ]. - OrderedCollection withAll: result ] -] - -{ #category : #accessing } -MooseGroupRuntimeStorage >> size [ - ^ elements size -] - -{ #category : #sorting } -MooseGroupRuntimeStorage >> sort: aBlock [ - - self elements sort: aBlock -] - -{ #category : #accessing } -MooseGroupRuntimeStorage >> species: anObject [ - - "WARNING: Changing the species of the inner collection might have unattempted consequences. - DO NOT EXECUTE THIS METHOD EXCEPT IF YOU ARE REALLY SURE OF YOUR NEED - - For instance, `model species: Set` would make indexed access to collection element impossible" - super species: anObject. - elements := self species withAll: elements -] - -{ #category : #private } -MooseGroupRuntimeStorage >> updateCacheOnAddingOf: anElement [ - (byType atOrOrederedCollection: anElement class) add: anElement. - anElement hasUniqueMooseNameInModel ifTrue: [ byName at: anElement mooseName put: anElement ]. - ^ anElement -] - -{ #category : #private } -MooseGroupRuntimeStorage >> updateCacheOnRemovalOf: anElement [ - byType at: anElement class ifPresent: [ :group | - group remove: anElement ifAbsent: [ self error: 'Internal storage inconsistency' ] ]. - - anElement hasUniqueMooseNameInModel ifFalse: [ ^ anElement ]. - - byName - at: anElement mooseName - ifAbsent: [ "In theory, objects are registered under their mooseName, - however some objects are still registered by their name - if #resetMooseName was not used when needed" self resetMooseNameFor: anElement ]. - byName removeKey: anElement mooseName ifAbsent: [ self error: 'Internal storage inconsistency' ]. - ^ anElement -] diff --git a/src/Moose-Core/MooseGroupSetupStorage.class.st b/src/Moose-Core/MooseGroupSetupStorage.class.st deleted file mode 100644 index 7662a60d..00000000 --- a/src/Moose-Core/MooseGroupSetupStorage.class.st +++ /dev/null @@ -1,117 +0,0 @@ -Class { - #name : #MooseGroupSetupStorage, - #superclass : #MooseGroupStorage, - #type : #variable, - #instVars : [ - 'elements' - ], - #category : #'Moose-Core' -} - -{ #category : #adding } -MooseGroupSetupStorage >> add: anElement [ - - ^elements add: anElement -] - -{ #category : #accessing } -MooseGroupSetupStorage >> allEntityTypes [ - ^ self collectAsSet: [ :each | each class ] -] - -{ #category : #accessing } -MooseGroupSetupStorage >> at: uniqueName ifAbsent: exceptionBlock [ - | s | - s := uniqueName asSymbol. - ^self - detect: [:each | s == each mooseName asSymbol] - ifNone: exceptionBlock -] - -{ #category : #'accessing-sequenceable' } -MooseGroupSetupStorage >> atIndex: index [ - - ^elements at: index -] - -{ #category : #enumerating } -MooseGroupSetupStorage >> do: aBlock [ - - ^elements do: aBlock -] - -{ #category : #accessing } -MooseGroupSetupStorage >> elements [ - - ^ self asArray -] - -{ #category : #'accessing-sequenceable' } -MooseGroupSetupStorage >> first [ - - ^elements first -] - -{ #category : #initialization } -MooseGroupSetupStorage >> initialize [ - super initialize. - - elements := self species new: 10000 -] - -{ #category : #initialization } -MooseGroupSetupStorage >> initialize: capacity [ - - super initialize: capacity. - elements := self species new: capacity -] - -{ #category : #'accessing-sequenceable' } -MooseGroupSetupStorage >> last [ - - ^elements last -] - -{ #category : #copying } -MooseGroupSetupStorage >> postCopy [ - super postCopy. - elements := elements copy -] - -{ #category : #removing } -MooseGroupSetupStorage >> remove: anElement ifAbsent: exceptionBlock [ - - ^elements remove: anElement ifAbsent: exceptionBlock -] - -{ #category : #removing } -MooseGroupSetupStorage >> removeAll [ - - self initialize -] - -{ #category : #enumerating } -MooseGroupSetupStorage >> selectAllWithType: aSmalltalkClass [ - ^ self select: - [ :each | - "-- select returns an ArrayList" - each class = aSmalltalkClass ] -] - -{ #category : #accessing } -MooseGroupSetupStorage >> size [ - - ^elements size -] - -{ #category : #accessing } -MooseGroupSetupStorage >> species: anObject [ - - "WARNING: Changing the species of the inner collection might have unattempted consequences. - DO NOT EXECUTE THIS METHOD EXCEPT IF YOU ARE REALLY SURE OF YOUR NEED - - For instance, `model species: Set` would make indexed access to collection element impossible" - - super species: anObject. - elements := self species withAll: elements -] diff --git a/src/Moose-Core/MooseGroupStorage.class.st b/src/Moose-Core/MooseGroupStorage.class.st index 0f6aa341..f861ee50 100644 --- a/src/Moose-Core/MooseGroupStorage.class.st +++ b/src/Moose-Core/MooseGroupStorage.class.st @@ -1,16 +1,44 @@ +" +I am storing the items of the group during the standard usage of moose entities. + +I store the entites for fast access byName and byType. I also contains the all the entities in elements which is not sorted. + +I am used by MooseAbstractGroup subclasses. + +Public API and Key Messages + +I am managed like a collection and my caches are autoupdated when an entity is added or removed. + +Internal Representation and Key Implementation Points. + + Instance Variables + byName: IdentityHashTable (key: mooseName) + byType: Dictionnary of OrderedCollection (key: FAMIXType) - the orderedCollection is sorted on access + elements: OrderedCollection + +Implementation Points +- On access by type, OrderedCollections in byType dictionary are sorted by MooseName to find its type faster. This sort is stored in sortedCollectionList and is invalidated on addition of a new element in the collection + +I am using an identity hash table to save the names because it is optimized for large collection. The possible loss of performances for small collection is negligeable compared to the gain for large collection. Creating a moose group of 2450080 entities took 6sec+ with anIdentityDictionary and now take 1.6sec+ with a IdentityHashTable. + + + +" Class { #name : #MooseGroupStorage, #superclass : #Collection, #type : #variable, #instVars : [ - 'species' + 'byName', + 'elements', + 'byType' ], #category : #'Moose-Core' } { #category : #'instance creation' } MooseGroupStorage class >> empty [ - ^ MooseGroupRuntimeStorage new + ^ MooseGroupStorage new ] { #category : #'instance creation' } @@ -38,13 +66,14 @@ MooseGroupStorage class >> withAll: aCollection [ { #category : #adding } MooseGroupStorage >> add: anElement [ - - ^self subclassResponsibility + self privateAdd: anElement. + self updateCacheOnAddingOf: anElement. + ^anElement ] -{ #category : #enumerating } +{ #category : #adding } MooseGroupStorage >> allEntityTypes [ - self subclassResponsibility + ^ byType keys ] { #category : #accessing } @@ -57,8 +86,7 @@ MooseGroupStorage >> at: uniqueName [ { #category : #accessing } MooseGroupStorage >> at: uniqueName ifAbsent: exceptionBlock [ - - ^self subclassResponsibility + ^byName at: uniqueName asSymbol ifAbsent: exceptionBlock ] { #category : #iterators } @@ -66,19 +94,6 @@ MooseGroupStorage >> basicIterator [ ^ self elements basicIterator ] -{ #category : #private } -MooseGroupStorage >> becomeKind: elementStorageClass [ - - self class = elementStorageClass ifTrue: [ ^ self ]. - - [ elementStorageClass includesBehavior: MooseGroupStorage ] assert. - - self do: [ :each | - each hasUniqueMooseNameInModel ifTrue: [ each privateClearMooseName ] ]. - - self become: (elementStorageClass withAll: self) -] - { #category : #enumerating } MooseGroupStorage >> collect: aBlock [ @@ -88,22 +103,15 @@ MooseGroupStorage >> collect: aBlock [ ^newCollection ] -{ #category : #accessing } -MooseGroupStorage >> elements [ - - ^self subclassResponsibility -] - -{ #category : #converting } -MooseGroupStorage >> forRuntime [ +{ #category : #enumerating } +MooseGroupStorage >> do: aBlock [ - self becomeKind: MooseGroupRuntimeStorage + elements do: aBlock ] -{ #category : #converting } -MooseGroupStorage >> forSetup [ - - self becomeKind: MooseGroupSetupStorage +{ #category : #accessing } +MooseGroupStorage >> elements [ + ^ elements ] { #category : #testing } @@ -113,16 +121,11 @@ MooseGroupStorage >> includesID: mooseID [ ] { #category : #initialization } -MooseGroupStorage >> initialize [ +MooseGroupStorage >> initialize: capacity [ - super initialize. - species := OrderedCollection -] - -{ #category : #initialization } -MooseGroupStorage >> initialize: aSize [ - - species := OrderedCollection + byType := IdentityDictionary new: 24. + byName := IdentityHashTable new: capacity. + elements := self species new: capacity ] { #category : #iterators } @@ -130,6 +133,19 @@ MooseGroupStorage >> iterator [ ^ self elements iterator ] +{ #category : #copying } +MooseGroupStorage >> postCopy [ + super postCopy. + elements := elements copy. + byName := byName copy. + byType := byType copy +] + +{ #category : #adding } +MooseGroupStorage >> privateAdd: anElement [ + ^elements add: anElement +] + { #category : #removing } MooseGroupStorage >> remove: anElement [ @@ -139,45 +155,77 @@ MooseGroupStorage >> remove: anElement [ ] { #category : #removing } -MooseGroupStorage >> remove: anElement ifAbsent: exceptionBlock [ - - ^self subclassResponsibility +MooseGroupStorage >> remove: anElement ifAbsent: exceptionBlock [ + self updateCacheOnRemovalOf: anElement. + elements remove: anElement. + ^ anElement ] { #category : #removing } MooseGroupStorage >> removeAll [ - ^self subclassResponsibility + self initialize: 10000 ] { #category : #private } MooseGroupStorage >> resetMooseNameFor: anEntity [ - anEntity privateClearMooseName + + anEntity hasUniqueMooseNameInModel + ifTrue: [ + byName removeKey: anEntity mooseName asSymbol ifAbsent: [ ]. + anEntity privateClearMooseName. + byName at: anEntity mooseName asSymbol put: anEntity ] + ifFalse: [ anEntity privateClearMooseName ] ] { #category : #enumerating } -MooseGroupStorage >> selectAllWithType: aSmalltalkClass [ - ^ self subclassResponsibility +MooseGroupStorage >> selectAllWithType: aSmalltalkType [ + ^ byType + at: aSmalltalkType + ifAbsent: [ | result | + result := Set new. + byType keys + select: [ :aClass | aClass class = aSmalltalkType ] + thenDo: [ :aKey | (byType at: aKey) do: [ :anElement | result add: anElement ] ]. + OrderedCollection withAll: result ] ] { #category : #accessing } MooseGroupStorage >> size [ - - ^self subclassResponsibility + ^ elements size +] + +{ #category : #sorting } +MooseGroupStorage >> sort: aBlock [ + + self elements sort: aBlock ] { #category : #private } -MooseGroupStorage >> species [ - - ^ species +MooseGroupStorage >> species [ + + ^ OrderedCollection ] -{ #category : #accessing } -MooseGroupStorage >> species: anObject [ +{ #category : #private } +MooseGroupStorage >> updateCacheOnAddingOf: anElement [ + (byType atOrOrederedCollection: anElement class) add: anElement. + anElement hasUniqueMooseNameInModel ifTrue: [ byName at: anElement mooseName put: anElement ]. + ^ anElement +] - "WARNING: Changing the species of the inner collection might have unattempted consequences. - DO NOT EXECUTE THIS METHOD EXCEPT IF YOU ARE REALLY SURE OF YOUR NEED - - For instance, `model species: Set` would make indexed access to collection element impossible" - species := anObject +{ #category : #private } +MooseGroupStorage >> updateCacheOnRemovalOf: anElement [ + byType at: anElement class ifPresent: [ :group | + group remove: anElement ifAbsent: [ self error: 'Internal storage inconsistency' ] ]. + + anElement hasUniqueMooseNameInModel ifFalse: [ ^ anElement ]. + + byName + at: anElement mooseName + ifAbsent: [ "In theory, objects are registered under their mooseName, + however some objects are still registered by their name + if #resetMooseName was not used when needed" self resetMooseNameFor: anElement ]. + byName removeKey: anElement mooseName ifAbsent: [ self error: 'Internal storage inconsistency' ]. + ^ anElement ] diff --git a/src/Moose-Core/MooseModel.class.st b/src/Moose-Core/MooseModel.class.st index c740d947..02091c1d 100644 --- a/src/Moose-Core/MooseModel.class.st +++ b/src/Moose-Core/MooseModel.class.st @@ -536,7 +536,6 @@ MooseModel >> flushPrivateState [ MooseModel >> importFrom: aFMModel named: aString [ self silentlyAddAll: aFMModel elements. - self entityStorage forRuntime. self name: aString ] diff --git a/src/Moose-SmalltalkImporter/InstallElementsOperator.class.st b/src/Moose-SmalltalkImporter/InstallElementsOperator.class.st index e7b0f930..15ad5fd2 100644 --- a/src/Moose-SmalltalkImporter/InstallElementsOperator.class.st +++ b/src/Moose-SmalltalkImporter/InstallElementsOperator.class.st @@ -39,13 +39,9 @@ InstallElementsOperator class >> with: elements runOn: aMooseModel [ { #category : #private } InstallElementsOperator >> basicRun [ - model entityStorage forSetup. - - self container do: [ :each | + self container do: [ :each | model add: each. - self increment ]. - - model entityStorage forRuntime + self increment ] ] { #category : #accessing }