Eliot Miranda uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-eem.736.mcz
==================== Summary ====================
Name: Tools-eem.736
Author: eem
Time: 16 December 2016, 11:28:21.691735 am
UUID: edf74efa-cdf2-4a15-8526-40f44f02273b
Ancestors: Tools-eem.735
Stop MessageSet>>initializeMessageList: from installng new MethodReferences when given a list of MethodReferences. The substitution breaks schemes such as constructing MessageSets for variants of MethodReference that hold edited versions of code, e.g. for viewing potential edits from the rewrite engine.
=============== Diff against Tools-eem.735 ===============
Item was changed:
----- Method: MessageSet>>initializeMessageList: (in category 'private') -----
initializeMessageList: anArray
+ "Initialize my messageList from the given list of MethodReference or string objects. NB: special handling for uniclasses.
+ Do /not/ replace the elements of anArray if they are already MethodReferences, so as to allow users to construct richer
+ systems, such as differencers between existing and edited versions of code."
- "Initialize my messageList from the given list of MethodReference or string objects. NB: special handling for uniclasses."
-
messageList := OrderedCollection new.
+ anArray do:
+ [:each |
+ each isMethodReference
+ ifTrue: [messageList addLast: each]
+ ifFalse:
+ [MessageSet
+ parse: each
+ toClassAndSelector: [ :class :sel | | s |
+ class ifNotNil:
+ [class isUniClass
+ ifTrue:
+ [s := class typicalInstanceName, ' ', sel]
+ ifFalse:
+ [s := class name , ' ' , sel , ' {' ,
+ ((class organization categoryOfElement: sel) ifNil: ['']) , '}' ,
+ ' {', class category, '}'].
+ messageList addLast: (
+ MethodReference new
+ setClass: class
+ methodSymbol: sel
+ stringVersion: s)]]]].
- anArray do: [ :each |
- MessageSet
- parse: each
- toClassAndSelector: [ :class :sel | | s |
- class ifNotNil:
- [class isUniClass
- ifTrue:
- [s := class typicalInstanceName, ' ', sel]
- ifFalse:
- [s := class name , ' ' , sel , ' {' ,
- ((class organization categoryOfElement: sel) ifNil: ['']) , '}' ,
- ' {', class category, '}'].
- messageList add: (
- MethodReference new
- setClass: class
- methodSymbol: sel
- stringVersion: s)]]].
messageListIndex := messageList isEmpty ifTrue: [0] ifFalse: [1].
contents := ''!
Nicolas Cellier uploaded a new version of Environments to project The Trunk:
http://source.squeak.org/trunk/Environments-nice.67.mcz
==================== Summary ====================
Name: Environments-nice.67
Author: nice
Time: 14 December 2016, 8:23:09.348821 pm
UUID: 0ba4d46a-6760-4902-b436-3fbb7b79a684
Ancestors: Environments-nice.66
Nuke the transition method and the transition postscript to make Undeclared Weak.
=============== Diff against Environments-nice.66 ===============
Item was removed:
- ----- Method: Environment>>makeUndeclaredWeak (in category 'private') -----
- makeUndeclaredWeak
- "This message is for transition only"
- | weakUndeclared |
- undeclared class = WeakIdentityDictionary ifTrue: [^self].
- weakUndeclared := WeakIdentityDictionary new: undeclared size.
- weakUndeclared addAll: undeclared associations.
- undeclared becomeForward: weakUndeclared!
Item was removed:
- (PackageInfo named: 'Environments') postscript: '"Undeclared should point weakly to its bindings
- so as to reduce namespace pollution."
-
- Environment allInstancesDo: [:e | e makeUndeclaredWeak].
- Smalltalk garbageCollect.
- '!
Nicolas Cellier uploaded a new version of Environments to project The Trunk:
http://source.squeak.org/trunk/Environments-nice.66.mcz
==================== Summary ====================
Name: Environments-nice.66
Author: nice
Time: 28 October 2016, 2:13:59.156947 pm
UUID: 93464b3f-60d7-d646-96a4-c7315b2cff73
Ancestors: Environments-nice.65
Make the undeclared dictionary point weakly to its bindings so as to reduce namespace pollution and minimize the impact of yet to be solved undeclared bugs.
This requires the WeakIdentityDictionary class defined in Collections-nice.723
=============== Diff against Environments-nice.65 ===============
Item was changed:
----- Method: Environment>>initialize (in category 'initialize-release') -----
initialize
declarations := IdentityDictionary new.
bindings := IdentityDictionary new.
+ undeclared := WeakIdentityDictionary new.
- undeclared := IdentityDictionary new.
policies := Array new.
observers := IdentitySet new.!
Item was added:
+ ----- Method: Environment>>makeUndeclaredWeak (in category 'private') -----
+ makeUndeclaredWeak
+ "This message is for transition only"
+ | weakUndeclared |
+ undeclared class = WeakIdentityDictionary ifTrue: [^self].
+ weakUndeclared := WeakIdentityDictionary new: undeclared size.
+ weakUndeclared addAll: undeclared associations.
+ undeclared becomeForward: weakUndeclared!
Item was changed:
+ (PackageInfo named: 'Environments') postscript: '"Undeclared should point weakly to its bindings
+ so as to reduce namespace pollution."
+
+ Environment allInstancesDo: [:e | e makeUndeclaredWeak].
+ Smalltalk garbageCollect.
- (PackageInfo named: 'Environments') postscript: '"It''s impossible to import a binding if not exported.
- There''s nothing secret in Smalltalk (nor private)."
- Smalltalk globals exportSelf.
'!
Nicolas Cellier uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-nice.728.mcz
==================== Summary ====================
Name: Collections-nice.728
Author: nice
Time: 14 December 2016, 8:01:20.748497 pm
UUID: fcb31400-a826-4642-8ad1-83c813998ba9
Ancestors: Collections-ul.727, Collections-nice.723
Merge Collections-nice.723 (WeakIdentityDictionary)
=============== Diff against Collections-ul.727 ===============
Item was changed:
----- Method: IdentityDictionary>>keyAtValue:ifAbsent: (in category 'accessing') -----
keyAtValue: value ifAbsent: exceptionBlock
"Answer the key that is the external name for the argument, value. If
there is none, answer the result of evaluating exceptionBlock."
+ ^self keyAtIdentityValue: value ifAbsent: exceptionBlock!
- ^super keyAtIdentityValue: value ifAbsent: exceptionBlock!
Item was added:
+ IdentityDictionary subclass: #WeakIdentityDictionary
+ instanceVariableNames: 'vacuum'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Collections-Weak'!
+
+ !WeakIdentityDictionary commentStamp: 'nice 10/27/2016 20:00' prior: 0!
+ I am a WeakIdentityDictionary, that is a dictionary pointing weakly to its associations of key->value pairs.
+ I am especially usefull for handling undeclared bindings that will be naturally garbage collected without having to scan all the CompiledMethods.
+
+ Instance variables:
+ vacuum <Object> a unique object used for marking empty slots
+
+ Due to usage of WeakArray for my own storage, reclaimed slots will be nilled out.
+ I cannot consider a nil slot as empty because of garbage collection does not fix collisions.
+ Thus I need to differentiate empty slots (vacuum) from garbaged collected slots (nil).
+
+ If I did not reclaim the nil slots and make them vacuum again, then my capacity would grow indefinitely.
+ My strategy to avoid such growth is to randomly cleanup the garbage collected slot encountered when scanning for a key.
+ It should mitigate the growth since this method is used when adding a new entry.
+
+ Due to those not yet cleaned-up nil slots I might over-estimate my size. Don't take it too literally.!
Item was added:
+ ----- Method: WeakIdentityDictionary class>>arrayType (in category 'private') -----
+ arrayType
+ ^ WeakArray!
Item was added:
+ ----- Method: WeakIdentityDictionary>>add: (in category 'accessing') -----
+ add: anAssociation
+
+ | index |
+ index := self scanFor: anAssociation key.
+ (array at: index)
+ ifNil: [ self atNewIndex: index put: anAssociation ]
+ ifNotNil: [ :element |
+ element == vacuum
+ ifTrue: [ self atNewIndex: index put: anAssociation ]
+ ifFalse: [ element value: anAssociation value ] ].
+ ^anAssociation!
Item was added:
+ ----- Method: WeakIdentityDictionary>>associationAt:ifAbsent: (in category 'accessing') -----
+ associationAt: key ifAbsent: aBlock
+ "Answer the association with the given key.
+ If key is not found, return the result of evaluating aBlock."
+
+ ^((array at: (self scanFor: key))
+ ifNil: [ aBlock value ]
+ ifNotNil: [:association |
+ association == vacuum
+ ifTrue: [ aBlock value ]
+ ifFalse: [ association ] ])!
Item was added:
+ ----- Method: WeakIdentityDictionary>>associationsDo: (in category 'enumerating') -----
+ associationsDo: aBlock
+ "Evaluate aBlock for each of the receiver's elements (key/value
+ associations)."
+
+ tally = 0 ifTrue: [ ^self].
+ 1 to: array size do: [ :index |
+ (array at: index) ifNotNil: [ :element |
+ element == vacuum ifFalse: [ aBlock value: element ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>at:ifAbsent: (in category 'accessing') -----
+ at: key ifAbsent: aBlock
+ "Answer the value associated with the key or, if key isn't found,
+ answer the result of evaluating aBlock."
+
+ ^((array at: (self scanFor: key))
+ ifNil: [ aBlock ]
+ ifNotNil: [:association |
+ association == vacuum
+ ifTrue: [ aBlock ]
+ ifFalse: [ association ] ]) value "Blocks and Associations expect #value"!
Item was added:
+ ----- Method: WeakIdentityDictionary>>at:ifPresent:ifAbsentPut: (in category 'accessing') -----
+ at: key ifPresent: oneArgBlock ifAbsentPut: absentBlock
+ "Lookup the given key in the receiver. If it is present, answer the value of
+ evaluating oneArgBlock with the value associated with the key. Otherwise
+ add the value of absentBlock under the key, and answer that value."
+
+ | index value |
+ index := self scanFor: key.
+ (array at: index) ifNotNil:
+ [:element|
+ element == vacuum ifFalse: [^oneArgBlock value: element value] ].
+ value := absentBlock value.
+ self atNewIndex: index put: (self associationClass key: key value: value).
+ ^value!
Item was added:
+ ----- Method: WeakIdentityDictionary>>at:put: (in category 'accessing') -----
+ at: key put: anObject
+ "Set the value at key to be anObject. If key is not found, create a
+ new entry for key and set is value to anObject. Answer anObject."
+
+ | index |
+ index := self scanFor: key.
+ (array at: index)
+ ifNil:
+ ["it's possible to get here if the association just died"
+ self atNewIndex: index put: (self associationClass key: key value: anObject) ]
+ ifNotNil: [ :association |
+ association == vacuum
+ ifTrue: [ self atNewIndex: index put: (self associationClass key: key value: anObject) ]
+ ifFalse: [association value: anObject ] ].
+ ^anObject!
Item was added:
+ ----- Method: WeakIdentityDictionary>>cleanupIndex: (in category 'private') -----
+ cleanupIndex: anInteger
+ array at: anInteger put: vacuum.
+ tally := tally - 1.
+ self fixCollisionsFrom: anInteger.!
Item was added:
+ ----- Method: WeakIdentityDictionary>>fixCollisionsFrom: (in category 'private') -----
+ fixCollisionsFrom: start
+ "The element at start has been removed and replaced by vacuum.
+ This method moves forward from there, relocating any entries
+ that had been placed below due to collisions with this one."
+
+ | element index |
+ index := start.
+ [ (element := array at: (index := index \\ array size + 1)) == vacuum ] whileFalse: [
+ element
+ ifNil:
+ [ "The binding at this slot was reclaimed - finish the cleanup"
+ array at: index put: vacuum.
+ tally := tally - 1 ]
+ ifNotNil:
+ [| newIndex |
+ (newIndex := self scanWithoutGarbagingFor: element key) = index ifFalse: [
+ array
+ at: newIndex put: element;
+ at: index put: vacuum ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>growTo: (in category 'private') -----
+ growTo: anInteger
+ "Grow the elements array and reinsert the old elements"
+
+ | oldElements |
+ oldElements := array.
+ array := self class arrayType new: anInteger withAll: vacuum.
+ self noCheckNoGrowFillFrom: oldElements!
Item was added:
+ ----- Method: WeakIdentityDictionary>>includesKey: (in category 'testing') -----
+ includesKey: key
+ "Answer whether the receiver has a key equal to the argument, key."
+
+ ^(array at: (self scanFor: key))
+ ifNil:
+ ["it just has been reclaimed"
+ false]
+ ifNotNil: [:element | element ~~ vacuum]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>initialize: (in category 'private') -----
+ initialize: n
+ vacuum := Object new.
+ array := self class arrayType new: n withAll: vacuum.
+ tally := 0!
Item was added:
+ ----- Method: WeakIdentityDictionary>>noCheckNoGrowFillFrom: (in category 'private') -----
+ noCheckNoGrowFillFrom: anArray
+ "Add the elements of anArray except nils to me assuming that I don't contain any of them, they are unique and I have more free space than they require."
+
+ 1 to: anArray size do: [ :index |
+ (anArray at: index) ifNotNil: [ :association |
+ association == vacuum
+ ifFalse: [array
+ at: (self scanForEmptySlotFor: association key)
+ put: association ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>postCopy (in category 'copying') -----
+ postCopy
+ "Beware: do share the bindings, so changing a binding value in the copy will also change it in the original.
+ Copying the bindings would not make sense: we hold weakly on them, so they would die at first garbage collection."
+
+ | oldVacuum |
+ super postCopy.
+ oldVacuum := vacuum.
+ vacuum := Object new.
+ array := array collect: [ :association |
+ association ifNotNil: [
+ association == oldVacuum
+ ifTrue: [ vacuum ]
+ ifFalse: [ association ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>removeKey:ifAbsent: (in category 'removing') -----
+ removeKey: key ifAbsent: aBlock
+ "Remove key (and its associated value) from the receiver. If key is not in
+ the receiver, answer the result of evaluating aBlock. Otherwise, answer
+ the value externally named by key."
+
+ | index association |
+ index := self scanFor: key.
+ (association := (array at: index)) == vacuum ifTrue: [ ^aBlock value ].
+ self cleanupIndex: index.
+ ^association value!
Item was added:
+ ----- Method: WeakIdentityDictionary>>scanFor: (in category 'private') -----
+ scanFor: anObject
+ "Scan the array for the first slot containing either
+ - a vacuum object indicating an empty slot
+ - or a binding whose key matches anObject.
+ Answer the index of that slot or raise an error if no slot is found.
+ When garbage collected slots are encountered, perform a clean-up."
+
+ | index start rescan |
+ [
+ rescan := false.
+ index := start := anObject scaledIdentityHash \\ array size + 1.
+ [
+ (array at: index)
+ ifNil:
+ ["Object at this slot has been garbage collected.
+ A rescan is necessary because fixing collisions
+ might have moved the target before current index."
+ self cleanupIndex: index.
+ rescan := true]
+ ifNotNil:
+ [:element | (element == vacuum or: [ element key == anObject ])
+ ifTrue: [ ^index ].
+ (index := index \\ array size + 1) = start ] ] whileFalse.
+ rescan ] whileTrue.
+ self errorNoFreeSpace!
Item was added:
+ ----- Method: WeakIdentityDictionary>>scanForEmptySlotFor: (in category 'private') -----
+ scanForEmptySlotFor: anObject
+ "Scan the array for the first empty slot marked by vacuum object.
+ Answer the index of that slot or raise an error if no slot is found.
+ Ignore the slots that have been garbage collected (those containing nil)."
+
+ | index start |
+ index := start := anObject scaledIdentityHash \\ array size + 1.
+ [
+ (array at: index)
+ ifNotNil:
+ [:element | element == vacuum ifTrue: [ ^index ] ].
+ (index := index \\ array size + 1) = start ] whileFalse.
+ self errorNoFreeSpace!
Item was added:
+ ----- Method: WeakIdentityDictionary>>scanWithoutGarbagingFor: (in category 'private') -----
+ scanWithoutGarbagingFor: anObject
+ "Scan the array for the first slot containing either
+ - a vacuum object indicating an empty slot
+ - or a binding whose key matches anObject.
+ Answer the index of that slot or raise an error if no slot is found.
+ Ignore the slots that have been garbage collected (those containing nil)"
+
+ | index start |
+ index := start := anObject scaledIdentityHash \\ array size + 1.
+ [
+ (array at: index)
+ ifNotNil:
+ [:element | (element == vacuum or: [ element key == anObject ])
+ ifTrue: [ ^index ] ].
+ (index := index \\ array size + 1) = start ] whileFalse.
+ self errorNoFreeSpace!
Item was changed:
+ ----- Method: WeakSet class>>arrayType (in category 'private') -----
- ----- Method: WeakSet class>>arrayType (in category 'as yet unclassified') -----
arrayType
^WeakArray!
Nicolas Cellier uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-nice.723.mcz
==================== Summary ====================
Name: Collections-nice.723
Author: nice
Time: 27 October 2016, 8:04:09.437881 pm
UUID: 0c01b091-06e9-694d-9415-56c62c06babc
Ancestors: Collections-nice.722
Provide a WeakIdentityDictionary - a good candidate for being used as environments undeclared pool.
=============== Diff against Collections-nice.722 ===============
Item was changed:
----- Method: IdentityDictionary>>keyAtValue:ifAbsent: (in category 'accessing') -----
keyAtValue: value ifAbsent: exceptionBlock
"Answer the key that is the external name for the argument, value. If
there is none, answer the result of evaluating exceptionBlock."
+ ^self keyAtIdentityValue: value ifAbsent: exceptionBlock!
- ^super keyAtIdentityValue: value ifAbsent: exceptionBlock!
Item was added:
+ IdentityDictionary subclass: #WeakIdentityDictionary
+ instanceVariableNames: 'vacuum'
+ classVariableNames: ''
+ poolDictionaries: ''
+ category: 'Collections-Weak'!
+
+ !WeakIdentityDictionary commentStamp: 'nice 10/27/2016 20:00' prior: 0!
+ I am a WeakIdentityDictionary, that is a dictionary pointing weakly to its associations of key->value pairs.
+ I am especially usefull for handling undeclared bindings that will be naturally garbage collected without having to scan all the CompiledMethods.
+
+ Instance variables:
+ vacuum <Object> a unique object used for marking empty slots
+
+ Due to usage of WeakArray for my own storage, reclaimed slots will be nilled out.
+ I cannot consider a nil slot as empty because of garbage collection does not fix collisions.
+ Thus I need to differentiate empty slots (vacuum) from garbaged collected slots (nil).
+
+ If I did not reclaim the nil slots and make them vacuum again, then my capacity would grow indefinitely.
+ My strategy to avoid such growth is to randomly cleanup the garbage collected slot encountered when scanning for a key.
+ It should mitigate the growth since this method is used when adding a new entry.
+
+ Due to those not yet cleaned-up nil slots I might over-estimate my size. Don't take it too literally.!
Item was added:
+ ----- Method: WeakIdentityDictionary class>>arrayType (in category 'private') -----
+ arrayType
+ ^ WeakArray!
Item was added:
+ ----- Method: WeakIdentityDictionary>>add: (in category 'accessing') -----
+ add: anAssociation
+
+ | index |
+ index := self scanFor: anAssociation key.
+ (array at: index)
+ ifNil: [ self atNewIndex: index put: anAssociation ]
+ ifNotNil: [ :element |
+ element == vacuum
+ ifTrue: [ self atNewIndex: index put: anAssociation ]
+ ifFalse: [ element value: anAssociation value ] ].
+ ^anAssociation!
Item was added:
+ ----- Method: WeakIdentityDictionary>>associationAt:ifAbsent: (in category 'accessing') -----
+ associationAt: key ifAbsent: aBlock
+ "Answer the association with the given key.
+ If key is not found, return the result of evaluating aBlock."
+
+ ^((array at: (self scanFor: key))
+ ifNil: [ aBlock value ]
+ ifNotNil: [:association |
+ association == vacuum
+ ifTrue: [ aBlock value ]
+ ifFalse: [ association ] ])!
Item was added:
+ ----- Method: WeakIdentityDictionary>>associationsDo: (in category 'enumerating') -----
+ associationsDo: aBlock
+ "Evaluate aBlock for each of the receiver's elements (key/value
+ associations)."
+
+ tally = 0 ifTrue: [ ^self].
+ 1 to: array size do: [ :index |
+ (array at: index) ifNotNil: [ :element |
+ element == vacuum ifFalse: [ aBlock value: element ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>at:ifAbsent: (in category 'accessing') -----
+ at: key ifAbsent: aBlock
+ "Answer the value associated with the key or, if key isn't found,
+ answer the result of evaluating aBlock."
+
+ ^((array at: (self scanFor: key))
+ ifNil: [ aBlock ]
+ ifNotNil: [:association |
+ association == vacuum
+ ifTrue: [ aBlock ]
+ ifFalse: [ association ] ]) value "Blocks and Associations expect #value"!
Item was added:
+ ----- Method: WeakIdentityDictionary>>at:ifPresent:ifAbsentPut: (in category 'accessing') -----
+ at: key ifPresent: oneArgBlock ifAbsentPut: absentBlock
+ "Lookup the given key in the receiver. If it is present, answer the value of
+ evaluating oneArgBlock with the value associated with the key. Otherwise
+ add the value of absentBlock under the key, and answer that value."
+
+ | index value |
+ index := self scanFor: key.
+ (array at: index) ifNotNil:
+ [:element|
+ element == vacuum ifFalse: [^oneArgBlock value: element value] ].
+ value := absentBlock value.
+ self atNewIndex: index put: (self associationClass key: key value: value).
+ ^value!
Item was added:
+ ----- Method: WeakIdentityDictionary>>at:put: (in category 'accessing') -----
+ at: key put: anObject
+ "Set the value at key to be anObject. If key is not found, create a
+ new entry for key and set is value to anObject. Answer anObject."
+
+ | index |
+ index := self scanFor: key.
+ (array at: index)
+ ifNil:
+ ["it's possible to get here if the association just died"
+ self atNewIndex: index put: (self associationClass key: key value: anObject) ]
+ ifNotNil: [ :association |
+ association == vacuum
+ ifTrue: [ self atNewIndex: index put: (self associationClass key: key value: anObject) ]
+ ifFalse: [association value: anObject ] ].
+ ^anObject!
Item was added:
+ ----- Method: WeakIdentityDictionary>>cleanupIndex: (in category 'private') -----
+ cleanupIndex: anInteger
+ array at: anInteger put: vacuum.
+ tally := tally - 1.
+ self fixCollisionsFrom: anInteger.!
Item was added:
+ ----- Method: WeakIdentityDictionary>>fixCollisionsFrom: (in category 'private') -----
+ fixCollisionsFrom: start
+ "The element at start has been removed and replaced by vacuum.
+ This method moves forward from there, relocating any entries
+ that had been placed below due to collisions with this one."
+
+ | element index |
+ index := start.
+ [ (element := array at: (index := index \\ array size + 1)) == vacuum ] whileFalse: [
+ element
+ ifNil:
+ [ "The binding at this slot was reclaimed - finish the cleanup"
+ array at: index put: vacuum.
+ tally := tally - 1 ]
+ ifNotNil:
+ [| newIndex |
+ (newIndex := self scanWithoutGarbagingFor: element key) = index ifFalse: [
+ array
+ at: newIndex put: element;
+ at: index put: vacuum ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>growTo: (in category 'private') -----
+ growTo: anInteger
+ "Grow the elements array and reinsert the old elements"
+
+ | oldElements |
+ oldElements := array.
+ array := self class arrayType new: anInteger withAll: vacuum.
+ self noCheckNoGrowFillFrom: oldElements!
Item was added:
+ ----- Method: WeakIdentityDictionary>>includesKey: (in category 'testing') -----
+ includesKey: key
+ "Answer whether the receiver has a key equal to the argument, key."
+
+ ^(array at: (self scanFor: key))
+ ifNil:
+ ["it just has been reclaimed"
+ false]
+ ifNotNil: [:element | element ~~ vacuum]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>initialize: (in category 'private') -----
+ initialize: n
+ vacuum := Object new.
+ array := self class arrayType new: n withAll: vacuum.
+ tally := 0!
Item was added:
+ ----- Method: WeakIdentityDictionary>>noCheckNoGrowFillFrom: (in category 'private') -----
+ noCheckNoGrowFillFrom: anArray
+ "Add the elements of anArray except nils to me assuming that I don't contain any of them, they are unique and I have more free space than they require."
+
+ 1 to: anArray size do: [ :index |
+ (anArray at: index) ifNotNil: [ :association |
+ association == vacuum
+ ifFalse: [array
+ at: (self scanForEmptySlotFor: association key)
+ put: association ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>postCopy (in category 'copying') -----
+ postCopy
+ "Beware: do share the bindings, so changing a binding value in the copy will also change it in the original.
+ Copying the bindings would not make sense: we hold weakly on them, so they would die at first garbage collection."
+
+ | oldVacuum |
+ super postCopy.
+ oldVacuum := vacuum.
+ vacuum := Object new.
+ array := array collect: [ :association |
+ association ifNotNil: [
+ association == oldVacuum
+ ifTrue: [ vacuum ]
+ ifFalse: [ association ] ] ]!
Item was added:
+ ----- Method: WeakIdentityDictionary>>removeKey:ifAbsent: (in category 'removing') -----
+ removeKey: key ifAbsent: aBlock
+ "Remove key (and its associated value) from the receiver. If key is not in
+ the receiver, answer the result of evaluating aBlock. Otherwise, answer
+ the value externally named by key."
+
+ | index association |
+ index := self scanFor: key.
+ (association := (array at: index)) == vacuum ifTrue: [ ^aBlock value ].
+ self cleanupIndex: index.
+ ^association value!
Item was added:
+ ----- Method: WeakIdentityDictionary>>scanFor: (in category 'private') -----
+ scanFor: anObject
+ "Scan the array for the first slot containing either
+ - a vacuum object indicating an empty slot
+ - or a binding whose key matches anObject.
+ Answer the index of that slot or raise an error if no slot is found.
+ When garbage collected slots are encountered, perform a clean-up."
+
+ | index start rescan |
+ [
+ rescan := false.
+ index := start := anObject scaledIdentityHash \\ array size + 1.
+ [
+ (array at: index)
+ ifNil:
+ ["Object at this slot has been garbage collected.
+ A rescan is necessary because fixing collisions
+ might have moved the target before current index."
+ self cleanupIndex: index.
+ rescan := true]
+ ifNotNil:
+ [:element | (element == vacuum or: [ element key == anObject ])
+ ifTrue: [ ^index ].
+ (index := index \\ array size + 1) = start ] ] whileFalse.
+ rescan ] whileTrue.
+ self errorNoFreeSpace!
Item was added:
+ ----- Method: WeakIdentityDictionary>>scanForEmptySlotFor: (in category 'private') -----
+ scanForEmptySlotFor: anObject
+ "Scan the array for the first empty slot marked by vacuum object.
+ Answer the index of that slot or raise an error if no slot is found.
+ Ignore the slots that have been garbage collected (those containing nil)."
+
+ | index start |
+ index := start := anObject scaledIdentityHash \\ array size + 1.
+ [
+ (array at: index)
+ ifNotNil:
+ [:element | element == vacuum ifTrue: [ ^index ] ].
+ (index := index \\ array size + 1) = start ] whileFalse.
+ self errorNoFreeSpace!
Item was added:
+ ----- Method: WeakIdentityDictionary>>scanWithoutGarbagingFor: (in category 'private') -----
+ scanWithoutGarbagingFor: anObject
+ "Scan the array for the first slot containing either
+ - a vacuum object indicating an empty slot
+ - or a binding whose key matches anObject.
+ Answer the index of that slot or raise an error if no slot is found.
+ Ignore the slots that have been garbage collected (those containing nil)"
+
+ | index start |
+ index := start := anObject scaledIdentityHash \\ array size + 1.
+ [
+ (array at: index)
+ ifNotNil:
+ [:element | (element == vacuum or: [ element key == anObject ])
+ ifTrue: [ ^index ] ].
+ (index := index \\ array size + 1) = start ] whileFalse.
+ self errorNoFreeSpace!
Item was changed:
+ ----- Method: WeakSet class>>arrayType (in category 'private') -----
- ----- Method: WeakSet class>>arrayType (in category 'as yet unclassified') -----
arrayType
^WeakArray!
Bernhard Pieber uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-bp.1316.mcz
==================== Summary ====================
Name: Morphic-bp.1316
Author: bp
Time: 8 December 2016, 4:51:49.905664 pm
UUID: 0bc98a49-1277-44f5-a127-3c3320c198a9
Ancestors: Morphic-ul.1315, Morphic-bp.1065
merged feature to snap and resize SystemWindows to halves and quadrants of the display when dragged to its edges, only works once the "Drag To Edges" preference is set and fastDragWindowForMorphic is turned off
=============== Diff against Morphic-ul.1315 ===============
Item was changed:
MorphicModel subclass: #SystemWindow
instanceVariableNames: 'labelString stripes label closeBox collapseBox paneMorphs paneRects collapsedFrame fullFrame isCollapsed isActive isLookingFocused menuBox mustNotClose labelWidgetAllowance updatablePanes allowReframeHandles labelArea expandBox'
+ classVariableNames: 'ClickOnLabelToEdit CloseBoxFrame CloseBoxImageFlat CloseBoxImageGradient CollapseBoxImageFlat CollapseBoxImageGradient DoubleClickOnLabelToExpand DragToEdges ExpandBoxFrame ExpandBoxImageFlat ExpandBoxImageGradient FocusFollowsMouse GradientWindow HideExpandButton MenuBoxFrame MenuBoxImageFlat MenuBoxImageGradient ResizeAlongEdges ReuseWindows RoundedWindowCorners TopWindow WindowTitleActiveOnFirstClick WindowsRaiseOnClick'
- classVariableNames: 'ClickOnLabelToEdit CloseBoxFrame CloseBoxImageFlat CloseBoxImageGradient CollapseBoxImageFlat CollapseBoxImageGradient DoubleClickOnLabelToExpand ExpandBoxFrame ExpandBoxImageFlat ExpandBoxImageGradient FocusFollowsMouse GradientWindow HideExpandButton MenuBoxFrame MenuBoxImageFlat MenuBoxImageGradient ResizeAlongEdges ReuseWindows RoundedWindowCorners TopWindow WindowTitleActiveOnFirstClick WindowsRaiseOnClick'
poolDictionaries: ''
category: 'Morphic-Windows'!
!SystemWindow commentStamp: '<historical>' prior: 0!
SystemWindow is the Morphic equivalent of StandardSystemView -- a labelled container for rectangular views, with iconic facilities for close, collapse/expand, and resizing.
The attribute onlyActiveOnTop, if set to true (and any call to activate will set this), determines that only the top member of a collection of such windows on the screen shall be active. To be not active means that a mouse click in any region will only result in bringing the window to the top and then making it active.!
Item was added:
+ ----- Method: SystemWindow class>>dragToEdges (in category 'preferences') -----
+ dragToEdges
+ <preference: 'Drag To Edges'
+ category: 'windows'
+ description: 'When true, windows snap and resize to corners and edges of the Display.'
+ type: #Boolean>
+ ^DragToEdges ifNil: [false]!
Item was added:
+ ----- Method: SystemWindow class>>dragToEdges: (in category 'preferences') -----
+ dragToEdges: aBoolean
+ DragToEdges := aBoolean!
Item was changed:
----- Method: SystemWindow>>doFastFrameDrag: (in category 'events') -----
doFastFrameDrag: grabPoint
"Do fast frame dragging from the given point"
+ | offset newBounds outerWorldBounds clearArea |
- | offset newBounds outerWorldBounds |
outerWorldBounds := self boundsIn: nil.
offset := outerWorldBounds origin - grabPoint.
+ clearArea := ActiveWorld clearArea.
+ newBounds := outerWorldBounds newRectFrom: [:f |
+ | p selector |
+ p := Sensor cursorPoint.
+ (self class dragToEdges and: [(selector := self dragToEdgesSelectorFor: p in: clearArea) notNil])
+ ifTrue: [clearArea perform: selector]
+ ifFalse: [p + offset extent: outerWorldBounds extent]].
+ self bounds: newBounds; comeToFront!
- newBounds := outerWorldBounds newRectFrom: [:f |
- Sensor cursorPoint + offset extent: outerWorldBounds extent].
- self position: (self globalPointToLocal: newBounds topLeft); comeToFront!
Item was added:
+ ----- Method: SystemWindow>>dragToEdgeDistance (in category 'resize/collapse') -----
+ dragToEdgeDistance
+ ^10!
Item was added:
+ ----- Method: SystemWindow>>dragToEdgesSelectorFor:in: (in category 'resize/collapse') -----
+ dragToEdgesSelectorFor: p in: a
+ "answer first matching drag resize selector, if none is found, answer nil"
+ #(isPoint:nearTopLeftOf: isPoint:nearTopRightOf: isPoint:nearBottomLeftOf: isPoint:nearBottomRightOf: isPoint:nearTopOf: isPoint:nearBottomOf: isPoint:nearLeftOf: isPoint:nearRightOf:)
+ with: #(topLeftQuadrant topRightQuadrant bottomLeftQuadrant bottomRightQuadrant topHalf bottomHalf leftHalf rightHalf)
+ do: [:predicate :selector |
+ (self perform: predicate with: p with: a) ifTrue: [^selector]].
+ ^nil!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearBottomLeftOf: (in category 'resize/collapse') -----
+ isPoint: p nearBottomLeftOf: a
+ ^(self isPoint: p nearBottomOf: a) and: [self isPoint: p nearLeftOf: a]!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearBottomOf: (in category 'resize/collapse') -----
+ isPoint: p nearBottomOf: a
+ ^p y > (a bottom - self dragToEdgeDistance)!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearBottomRightOf: (in category 'resize/collapse') -----
+ isPoint: p nearBottomRightOf: a
+ ^(self isPoint: p nearBottomOf: a) and: [self isPoint: p nearRightOf: a]!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearLeftOf: (in category 'resize/collapse') -----
+ isPoint: p nearLeftOf: a
+ ^p x < (a left + self dragToEdgeDistance)!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearRightOf: (in category 'resize/collapse') -----
+ isPoint: p nearRightOf: a
+ ^p x > (a right - self dragToEdgeDistance)!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearTopLeftOf: (in category 'resize/collapse') -----
+ isPoint: p nearTopLeftOf: a
+ ^(self isPoint: p nearTopOf: a) and: [self isPoint: p nearLeftOf: a]!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearTopOf: (in category 'resize/collapse') -----
+ isPoint: p nearTopOf: a
+ ^p y < (a top + self dragToEdgeDistance)!
Item was added:
+ ----- Method: SystemWindow>>isPoint:nearTopRightOf: (in category 'resize/collapse') -----
+ isPoint: p nearTopRightOf: a
+ ^(self isPoint: p nearTopOf: a) and: [self isPoint: p nearRightOf: a]!
Chris Muller uploaded a new version of Monticello to project The Trunk:
http://source.squeak.org/trunk/Monticello-cmm.659.mcz
==================== Summary ====================
Name: Monticello-cmm.659
Author: cmm
Time: 7 December 2016, 10:35:58.341395 pm
UUID: 0ac4585a-0c38-4f00-9d85-b0ee443b0631
Ancestors: Monticello-cmm.658
Fix menu activation on selected method or class which has no MC working copy defined.
=============== Diff against Monticello-cmm.658 ===============
Item was changed:
----- Method: Class>>workingCopy (in category '*monticello') -----
workingCopy
+ "Answer the MCWorkingCopy in which I am defined."
+ ^ self packageInfo ifNotNil: [ : pi | pi workingCopy ]!
- ^ self packageInfo workingCopy!
Item was changed:
----- Method: MCDefinition>>mcModel (in category 'private') -----
mcModel
"Find my WorkingCopy, use the first mcModel-capable repository in its reposigoryGroup."
+ self repositoryGroup ifNotNil:
+ [ : group | group repositoriesDo:
+ [ : each | each mcModel ifNotNilDo:
+ [ : mcModel | ^ mcModel ] ] ].
- self repositoryGroup repositoriesDo:
- [ : each | each mcModel ifNotNilDo:
- [ : mcModel | ^ mcModel ] ].
^ nil!
Item was changed:
----- Method: MCDefinition>>repositoryGroup (in category 'repositories') -----
repositoryGroup
"Answer the MCRepositoryGroup from which this this object was loaded."
+ ^ self workingCopy ifNotNil: [ : wc | wc repositoryGroup ]!
- ^ self workingCopy repositoryGroup!
Item was changed:
----- Method: MethodReference>>workingCopy (in category '*monticello') -----
workingCopy
"Answer the MCWorkingCopy in which I am defined."
+ ^ self packageInfo ifNotNil: [ : pi | pi workingCopy ]!
- ^ self packageInfo workingCopy!
Chris Muller uploaded a new version of Tools to project The Trunk:
http://source.squeak.org/trunk/Tools-cmm.733.mcz
==================== Summary ====================
Name: Tools-cmm.733
Author: cmm
Time: 6 December 2016, 3:50:06.783172 pm
UUID: 46663c9b-de5d-4b65-ae5e-def988146a88
Ancestors: Tools-nice.732
Smalltalk garbageCollect can sometimes take many minutes, and there's no need to do it when opening a ProcessBrowser.
=============== Diff against Tools-nice.732 ===============
Item was changed:
----- Method: ProcessBrowser class>>open (in category 'instance creation') -----
open
- "ProcessBrowser open"
- "Create and schedule a ProcessBrowser."
- Smalltalk garbageCollect.
^ToolBuilder open: self new!