GemStone indexing allows you to specify the optionPathTerms option, which allows you to add objects to an indexed collection that do not have the indexed path term.
Attempting to remove an object that did not have the indexed path term, however, could encounter an error.
File in the following as SystemUser, and commit.
run
GsOptionalPathTerm removeSelector: #'_nextObjectFor:'.
GsOptionalPathTerm removeSelector: #'_errorInvalidOffset:'.
%
method: GsOptionalPathTerm
_findAllValuesForIdenticalRootObject: rootObject
" if index directly on NSC elements or anObject is nil "
| ivOffset |
ivOffset := self _ivOffsetFor: rootObject.
ivOffset
ifNil: [
"no values in index for rootObject"
^ IdentityBag new ].
^ super _findAllValuesForIdenticalRootObject: rootObject
%
category: 'Accessing'
method: GsOptionalPathTerm
_nextObjectFor: anObject atInstVar: anIvOffset
"Returns the object at the instance variable that corresponds to the receiver"
| ivOffset |
ivOffset := self _ivOffsetFor: anObject.
ivOffset ifNil: [ ^ nil ].
^ super _nextObjectFor: anObject atInstVar: anIvOffset
%
category: 'Adding'
method: GsOptionalPathTerm
addMappingsForObject: anObject root: rootObject logging: aBoolean
"Add dependency list entries for anObject."
| ivOffset |
(nil == anObject or: [ self size == 0 ])
ifTrue: [ ^ self ].
(ivOffset := self _ivOffsetFor: anObject) == nil
ifTrue: [ ^ self recordNilOnPathForRoot: rootObject ].
^ super addMappingsForObject: anObject root: rootObject logging: aBoolean
%
category: 'Removing'
method: GsOptionalPathTerm
removeMappingsFor: anObject root: rootObject lastOne: aBoolean logging: doLogging
"Remove entries in the btree and dependency lists for anObject."
| ivOffset |
(nil == anObject or: [ self size == 0 ])
ifTrue: [ ^ self ].
(ivOffset := self _ivOffsetFor: anObject) == nil
ifTrue: [ ^ self removeNilOnPathForRoot: rootObject ].
^ super removeMappingsFor: anObject root: rootObject lastOne: aBoolean logging: doLogging
%
category: 'Private'
method: GsPathTerm
_findAllValuesForIdenticalRootObject: rootObject
" if index directly on NSC elements or anObject is nil "
| key tmpList |
(self indicatesIndexOnNscElements or: [ nil == rootObject ])
ifTrue: [ key := rootObject ]
ifFalse: [ key := self _nextObjectFor: rootObject ].
tmpList := IdentityBag new.
self updateBtree btreeRoot _findAllValuesForIdenticalKey: key into: tmpList.
^ (tmpList occurrencesOf: rootObject) <= 1
%
category: 'private'
method: PathTerm
_findAllValuesForIdenticalRootObject: rootObject
" if index directly on NSC elements or anObject is nil "
| key tmpList |
(self indicatesIndexOnNscElements or: [ nil == rootObject ])
ifTrue: [ key := rootObject ]
ifFalse: [ key := self _nextObjectFor: rootObject ].
tmpList := IdentityBag new.
self updateBtree btreeRoot _findAllValuesForIdenticalKey: key into: tmpList.
^ (tmpList occurrencesOf: rootObject) <= 1
%
category: 'Indexing Support'
method: UnorderedCollection
_isLastOccurrenceInIndexObjects: anObject
"Returns true if the given object is maintained in the indexing objects for one
occurrence."
| rootTerms pathTerm key val val2 num parentTerm |
rootTerms := self _indexedPaths rootTerms. " find a path term with a mapping in the index dictionary "
1 to: rootTerms size do: [ :i |
pathTerm := rootTerms at: i.
(pathTerm _isObsoletePathTerm)
ifFalse: [
pathTerm isRangeEqualityIndexLastPathTerm
ifTrue: [
pathTerm offset == 1
ifTrue: [ ^ pathTerm _findAllValuesForIdenticalRootObject: anObject ]
ifFalse: [
pathTerm hasIndexDictionary
ifTrue: [
pathTerm := pathTerm getParentTerm.
val := pathTerm updateDict
at: anObject
term: pathTerm
otherwise: nil.
(BucketValueBag _hasInstance: val)
ifTrue: [
" see if more than one mapping "
pathTerm indicatesNsc
ifTrue: [
num := val occurrencesOf: self.
num < val size
ifTrue: [
" if anObject is contained in other NSCs "
^ false ].
pathTerm := pathTerm getParentTerm. " get path term before this one "
val2 := pathTerm updateDict
at: self
term: pathTerm
otherwise: nil.
(BucketValueBag _hasInstance: val2)
ifTrue: [ ^ val2 size == num ]
ifFalse: [ ^ true ] ]
ifFalse: [ ^ (val occurrencesOf: self) <= 1 ] ]
ifFalse: [ ^ true ] ]
ifFalse: [ ^ (self occurrencesOf: anObject) <= 1] ] ]
ifFalse: [
pathTerm hasIndexDictionary
ifTrue: [
" get key to look up in index dictionary "
(pathTerm indicatesIndexOnNscElements or: [ nil == anObject ])
ifTrue: [ key := anObject ]
ifFalse: [
" see if a path with '*.*' in it "
pathTerm indicatesNsc
ifTrue: [
val := pathTerm updateDict
at: anObject
term: pathTerm getParentTerm
otherwise: nil.
^ (BucketValueBag _hasInstance: val) not ]
ifFalse: [ key := pathTerm _nextObjectFor: anObject ] ].
val := pathTerm updateDict at: key term: pathTerm otherwise: nil. " look up the mapping in the index dictionary "
(BucketValueBag _hasInstance: val)
ifTrue: [
" see if more than one mapping "
(num := val occurrencesOf: anObject) <= 1
ifTrue: [ ^ true ]
ifFalse: [
" see if multiple occurrences are due to more than one object
referencing self "
" if there is a parent term, it is a SetValuedPathTerm "
parentTerm := pathTerm getParentTerm.
parentTerm == nil
ifTrue: [ ^ false ].
val2 := pathTerm updateDict
at: anObject
term: parentTerm
otherwise: nil.
(BucketValueBag _hasInstance: val2)
ifTrue: [ ^ (val2 occurrencesOf: self) == num ]
ifFalse: [ ^ false ] ] ]
ifFalse: [ ^ true ] ]
ifFalse: [ ^ (self occurrencesOf: anObject) <= 1] ] ] ].
^ true " if we get this far, there are only incomplete indexes "
%
Last updated: 8/17/20