Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1955.mcz
==================== Summary ====================
Name: Morphic-mt.1955
Author: mt
Time: 31 March 2022, 9:26:46.023388 am
UUID: 905714e6-1f97-484f-8891-07064d9af418
Ancestors: Morphic-mt.1954
Make #disableDeferredUpdates an actual pragma-based preference. Users should be able to enable this when a VM's graphics backend is flickering on some platform or when dragging within Morphic is invisible.
Note that primitive 126 never fails (for boolean arguments) at the moment. So we cannot know if the graphics backend does actually support that extra display buffer.
You can observe the effect of this preference by inspecting "Project current world canvas" and on which kind of form it is drawing.
=============== Diff against Morphic-mt.1954 ===============
Item was changed:
+ ----- Method: WorldState class>>disableDeferredUpdates (in category 'preferences') -----
- ----- Method: WorldState class>>disableDeferredUpdates (in category 'accessing') -----
disableDeferredUpdates
+ <preference: 'Disable deferred updates (Morphic only)'
+ categoryList: #(Morphic Performance Graphics)
+ description: 'When enabled, use an extra image-side buffer for compositing screen contents.
+ When deferred updating is used, Morphic performs double-buffered screen updates by telling the VM to de-couple the Display from the hardware display buffer, drawing directly into the Display, and then forcing the changed regions of the Display to be copied to the screen. This saves both time (an extra BitBlt is avoided) and space (an extra display buffer is avoided). However, on platforms on which the Display points directly to the hardware screen buffer, deferred updating can''t be used. In this case, the drawing should be composited into an offscreen FormCanvas and then copied to the hardware display buffer.
+ Enable this preference when morphs become invisible while dragging them in the world or when you see ugly flashing while the layers of the drawing are assembled.'
+ type: #Boolean>
-
^DisableDeferredUpdates ifNil: [DisableDeferredUpdates := false]
!
Item was changed:
+ ----- Method: WorldState class>>disableDeferredUpdates: (in category 'preferences') -----
+ disableDeferredUpdates: aBooleanOrNil
+
+ DisableDeferredUpdates = aBooleanOrNil ifTrue: [^ self].
+ DisableDeferredUpdates := aBooleanOrNil ifNil: [false].
+ Project allMorphicProjects do: [:ea | ea world canvas: nil].!
- ----- Method: WorldState class>>disableDeferredUpdates: (in category 'accessing') -----
- disableDeferredUpdates: aBoolean
- "If the argument is true, disable deferred screen updating."
- "Details: When deferred updating is used, Morphic performs double-buffered screen updates by telling the VM to de-couple the Display from the hardware display buffer, drawing directly into the Display, and then forcing the changed regions of the Display to be copied to the screen. This saves both time (an extra BitBlt is avoided) and space (an extra display buffer is avoided). However, on platforms on which the Display points directly to the hardware screen buffer, deferred updating can't be used (you'd see ugly flashing as the layers of the drawing were assembled). In this case, the drawing is composited into an offscreen FormCanvas and then copied to the hardware display buffer."
-
- DisableDeferredUpdates := aBoolean.
- Project current isMorphic ifTrue: [Project currentWorld canvas: nil].!
Levente Uzonyi uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-ul.1002.mcz
==================== Summary ====================
Name: Collections-ul.1002
Author: ul
Time: 30 March 2022, 5:32:03.565112 pm
UUID: 7d079f04-98dd-49ea-a0d0-6aaff26ee090
Ancestors: Collections-ul.1001
- do not try to rehash and compact immutable hashed collections in #rehashAllInstances and #compactAllInstances, respectively
=============== Diff against Collections-ul.1001 ===============
Item was changed:
----- Method: HashedCollection class>>compactAllInstances (in category 'initialize-release') -----
compactAllInstances
+ "Do not use #allInstancesDo: because #compact may create new instances. Ignore immutable instances."
- "Do not use #allInstancesDo: because #compact may create new instances."
+ self allInstances do: [ :each |
+ each isReadOnlyObject ifFalse: [ each compact ] ]!
- self allInstances do: [ :each | each compact ]!
Item was changed:
----- Method: HashedCollection class>>rehashAllInstances (in category 'initialize-release') -----
rehashAllInstances
+ "Do not use #allInstancesDo: because #rehash may create new instances. Ignore immutable instances."
- "Do not use #allInstancesDo: because #rehash may create new instances."
+ self allInstances do: [ :each |
+ each isReadOnlyObject ifFalse: [
+ each rehash ] ]!
- self allInstances do: [ :each | each rehash ]!
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1954.mcz
==================== Summary ====================
Name: Morphic-mt.1954
Author: mt
Time: 30 March 2022, 2:07:43.932263 pm
UUID: bfd62696-7e09-d94a-b437-1ec22c999508
Ancestors: Morphic-mt.1953
Makes the preference #disableDeferredUpdates: functional by clearing the world's current canvas. See #assuredCanvas.
=============== Diff against Morphic-mt.1953 ===============
Item was changed:
----- Method: WorldState class>>disableDeferredUpdates: (in category 'accessing') -----
disableDeferredUpdates: aBoolean
"If the argument is true, disable deferred screen updating."
"Details: When deferred updating is used, Morphic performs double-buffered screen updates by telling the VM to de-couple the Display from the hardware display buffer, drawing directly into the Display, and then forcing the changed regions of the Display to be copied to the screen. This saves both time (an extra BitBlt is avoided) and space (an extra display buffer is avoided). However, on platforms on which the Display points directly to the hardware screen buffer, deferred updating can't be used (you'd see ugly flashing as the layers of the drawing were assembled). In this case, the drawing is composited into an offscreen FormCanvas and then copied to the hardware display buffer."
DisableDeferredUpdates := aBoolean.
+ Project current isMorphic ifTrue: [Project currentWorld canvas: nil].!
- !
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1953.mcz
==================== Summary ====================
Name: Morphic-mt.1953
Author: mt
Time: 30 March 2022, 12:53:51.805263 pm
UUID: d560c970-7e24-ac43-bfac-ca68c9e53541
Ancestors: Morphic-mt.1952
Tweak prior commentary bc. I just (re-)discovered the actual behavior of #deferUpdates: across platforms.
=============== Diff against Morphic-mt.1952 ===============
Item was changed:
----- Method: FormCanvas>>showAt:invalidRects: (in category 'other') -----
showAt: pt invalidRects: updateRects
+ "Show the receiver's bits (i.e, the form it is currently drawing on) on the screen, which is represented by the global Display form.
+
+ NOTE THAT #copyBits has the side effect of calling #primShowRectLeft:right:top:bottom: if the blitting target is that Display form. Thus, it is similar to calling #forceDamageToScreen: with updateRects after modifying Display directly but in deferred-drawing mode.
+
+ NOTE THAT not all platforms support deferred updates even though they are not failing in #deferUpdates:. Thus, this method has no practical benefit these days unless forced via #disableDeferredUpdates:."
- "Show the receiver's bits (i.e, the form it is currently drawing on) on the screen, which is represented by the global Display form. NOTE THAT #copyBits has the side effect of calling #primShowRectLeft:right:top:bottom: if the blitting target is that Display form. Thus, it is similar to calling #forceDamateToScreen: with updateRects after modifying Display directly but in deferred-drawing mode. Yet, not all platforms support #deferUpdates:, and that is why this method exists."
| blt |
blt := (BitBlt toForm: Display)
sourceForm: form;
combinationRule: Form over.
updateRects do:
[:rect |
blt sourceRect: rect;
destOrigin: rect topLeft + pt;
copyBits "...entails #primShowRect:... see above"]!
Marcel Taeumel uploaded a new version of Graphics to project The Trunk:
http://source.squeak.org/trunk/Graphics-mt.506.mcz
==================== Summary ====================
Name: Graphics-mt.506
Author: mt
Time: 30 March 2022, 10:14:23.797457 am
UUID: 1934ae70-75f2-9041-a4b6-aa12b4125cc3
Ancestors: Graphics-mt.505
Adds commentary about the side effects of #copyBits and #deferUpdates:.
=============== Diff against Graphics-mt.505 ===============
Item was changed:
----- Method: BitBlt>>copyBits (in category 'copying') -----
copyBits
"Primitive. Perform the movement of bits from the source form to the
destination form. Fail if any variables are not of the right type (Integer,
Float, or Form) or if the combination rule is not implemented.
+
+ NOTE THAT this method has the side effect of showing the copied bits on
+ screen if the destination form happens to be Display. The mechanism is
+ similar to calling #primShowRectLeft:right:top:bottom: manually.
+
In addition to the original 16 combination rules, this BitBlt supports
16 fail (to simulate paint)
17 fail (to simulate mask)
18 sourceWord + destinationWord
19 sourceWord - destinationWord
20 rgbAdd: sourceWord with: destinationWord
21 rgbSub: sourceWord with: destinationWord
22 rgbDiff: sourceWord with: destinationWord
23 tallyIntoMap: destinationWord
24 alphaBlend: sourceWord with: destinationWord
25 pixPaint: sourceWord with: destinationWord
26 pixMask: sourceWord with: destinationWord
27 rgbMax: sourceWord with: destinationWord
28 rgbMin: sourceWord with: destinationWord
29 rgbMin: sourceWord bitInvert32 with: destinationWord
"
<primitive: 'primitiveCopyBits' module: 'BitBltPlugin' error: ec>
(combinationRule >= 30 and: [combinationRule <= 31]) ifTrue:
["No alpha specified -- re-run with alpha = 1.0"
^ self copyBitsTranslucent: 255].
"Check for object movement during a surface callback, compressed source, destination or halftone forms.
Simply retry."
(ec == #'object moved'
or: [(sourceForm isForm and: [sourceForm unhibernate])
or: [(destForm isForm and: [destForm unhibernate])
or: [halftoneForm isForm and: [halftoneForm unhibernate]]]]) ifTrue:
[^self copyBits].
"Check for unimplmented rules"
combinationRule = Form oldPaint ifTrue: [^self paintBits].
combinationRule = Form oldErase1bitShape ifTrue: [^self eraseBits].
"Check if BitBlt doesn't support full color maps"
(colorMap notNil and: [colorMap isColormap]) ifTrue:
[colorMap := colorMap colors.
^self copyBits].
"Check if clipping got way out of range"
self clipRange.
"Convert all numeric parameters to integers and try again."
self roundVariables.
^self copyBitsAgain!
Item was changed:
----- Method: DisplayScreen>>deferUpdates: (in category 'other') -----
deferUpdates: aBoolean
+ "Set the deferUpdates flag in the virtual machine. When this flag is true, BitBlt operations on the Display are not automatically propagated to the screen. If this underlying platform does not support deferred updates, this primitive will fail. Answer whether updates were deferred before if the primitive succeeds, nil if it fails.
+
+ Note that when disabling deferred upates again after modifying the receiver, it is advisable to call #forceDisplayUpdate so that the deferred updates can actually be displayed on the screen."
- | wasDeferred |
- "Set the deferUpdates flag in the virtual machine. When this flag is true, BitBlt operations on the Display are not automatically propagated to the screen. If this underlying platform does not support deferred updates, this primitive will fail. Answer whether updates were deferred before if the primitive succeeds, nil if it fails."
+ | wasDeferred |
wasDeferred := DeferringUpdates == true.
DeferringUpdates := aBoolean.
^(self primitiveDeferUpdates: aBoolean) ifNotNil: [wasDeferred]!
Marcel Taeumel uploaded a new version of Morphic to project The Trunk:
http://source.squeak.org/trunk/Morphic-mt.1952.mcz
==================== Summary ====================
Name: Morphic-mt.1952
Author: mt
Time: 30 March 2022, 10:10:15.250457 am
UUID: 57eecf53-ca8b-6e42-b0cb-27c17f2c36fa
Ancestors: Morphic-mt.1951
Adds commentary about the double-buffering that happens in Morphic on platforms that do not support #deferUpdates: such as macOS.
=============== Diff against Morphic-mt.1951 ===============
Item was changed:
----- Method: FormCanvas>>showAt:invalidRects: (in category 'other') -----
showAt: pt invalidRects: updateRects
+ "Show the receiver's bits (i.e, the form it is currently drawing on) on the screen, which is represented by the global Display form. NOTE THAT #copyBits has the side effect of calling #primShowRectLeft:right:top:bottom: if the blitting target is that Display form. Thus, it is similar to calling #forceDamateToScreen: with updateRects after modifying Display directly but in deferred-drawing mode. Yet, not all platforms support #deferUpdates:, and that is why this method exists."
+
| blt |
blt := (BitBlt toForm: Display)
sourceForm: form;
combinationRule: Form over.
updateRects do:
[:rect |
blt sourceRect: rect;
destOrigin: rect topLeft + pt;
+ copyBits "...entails #primShowRect:... see above"]!
- copyBits]!
Levente Uzonyi uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-ul.1000.mcz
==================== Summary ====================
Name: Collections-ul.1000
Author: ul
Time: 28 March 2022, 8:25:48.093286 pm
UUID: 37ba296b-06e0-48f5-bdc8-2101110f360e
Ancestors: Collections-ct.998
Symbol changes:
- comment the symbol table implemented in a non-object-oriented fashion in the class comment
- both WeakSets of the symbol table are immutable (#beReadOnlyObject)
- #condenseNewSymbols does nothing if the tables are already empty and compact
- added a comment to all methods accessing the symbol table class variables
- use a loop instead of recursion in #rehash and #condenseNewSymbols
General:
- methods of the HashedCollection hierachy that update the tally and modify the array variable will update the tally first, so that immutable hashed collections raise an error before their non-immutable array variable is updated
- use #lookup: instead of #hasInterned:ifTrue:
- speed up WeakSet >> #postCopy
- added #isCompact to HashedCollection and Heap (thanks Christoph)
- avoid compaction of Heap if it is already compact
- updated the comment of various methods
=============== Diff against Collections-ct.998 ===============
Item was changed:
----- Method: Dictionary>>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) ifNil: [ ^aBlock value ].
+ tally := tally - 1. "Update tally first, so that read-only hashed collections raise an error before modifying array."
array at: index put: nil.
- tally := tally - 1.
self fixCollisionsFrom: index.
^association value!
Item was changed:
----- Method: HashedCollection>>atNewIndex:put: (in category 'private') -----
atNewIndex: index put: anObject
+ tally := tally + 1. "Update tally first, so that read-only hashed collections raise an error before modifying array."
array at: index put: anObject.
- tally := tally + 1.
"Keep array at least 1/4 free for decent hash behavior"
array size * 3 < (tally * 4) ifTrue: [ self grow ]!
Item was changed:
----- Method: HashedCollection>>growTo: (in category 'private') -----
growTo: anInteger
+ "Reallocate the elements array with the given size and reinsert the old elements. Do it even if the size of the array is the same as the argument because this method is also used to rehash the collection."
+
- "Grow the elements array and reinsert the old elements. Do it even if the size of the array is the same as the argument because this methods is also used to rehash the collection."
-
| oldElements |
oldElements := array.
array := self arrayType new: anInteger.
self noCheckNoGrowFillFrom: oldElements!
Item was added:
+ ----- Method: HashedCollection>>isCompact (in category 'testing') -----
+ isCompact
+ "Answer true if I have the smallest possible capacity to store the elements."
+
+ ^array size = (self class sizeFor: self slowSize)!
Item was changed:
----- Method: Heap>>compact (in category 'growing') -----
compact
"Remove any empty slots in the receiver."
+ self isCompact ifTrue: [ ^self ].
self growTo: self size.!
Item was added:
+ ----- Method: Heap>>isCompact (in category 'growing') -----
+ isCompact
+ "Answer true if I have the smallest possible capacity to store the elements."
+
+ ^array size = tally!
Item was changed:
----- Method: KeyedSet>>remove:ifAbsent: (in category 'removing') -----
remove: oldObject ifAbsent: aBlock
| index |
index := self scanFor: (keyBlock value: oldObject).
(array at: index) ifNil: [ ^ aBlock value ].
+ tally := tally - 1. "Update tally first, so that read-only hashed collections raise an error before modifying array."
array at: index put: nil.
- tally := tally - 1.
self fixCollisionsFrom: index.
^ oldObject!
Item was changed:
----- Method: KeyedSet>>removeKey:ifAbsent: (in category 'removing') -----
removeKey: key ifAbsent: aBlock
| index obj |
index := self scanFor: key.
obj := (array at: index) ifNil: [ ^ aBlock value ].
+ tally := tally - 1. "Update tally first, so that read-only hashed collections raise an error before modifying array."
array at: index put: nil.
- tally := tally - 1.
self fixCollisionsFrom: index.
^ obj enclosedSetElement!
Item was changed:
----- Method: Set>>remove:ifAbsent: (in category 'removing') -----
remove: oldObject ifAbsent: aBlock
| index |
index := self scanFor: oldObject.
(array at: index) ifNil: [ ^ aBlock value ].
+ tally := tally - 1. "Update tally first, so that read-only hashed collections raise an error before modifying array."
array at: index put: nil.
- tally := tally - 1.
self fixCollisionsFrom: index.
^ oldObject!
Item was changed:
String subclass: #Symbol
instanceVariableNames: ''
classVariableNames: 'NewSymbols SymbolTable'
poolDictionaries: ''
category: 'Collections-Strings'!
+ !Symbol commentStamp: 'ul 3/28/2022 19:53' prior: 0!
- !Symbol commentStamp: 'mt 4/13/2021 17:04' prior: 0!
I represent Strings that are created uniquely. Thus, someString asSymbol == someString asSymbol.
+ On my class-side, there is an implementation of a symbol table which provides concurrent access (both read and write) without using locks (Semaphore, Mutex, Monitor).
+ The state of the symbol table is stored in two immutable (see #beReadOnlyObject) WeakSets stored by the class variables SymbolTable and NewSymbols.
+ SymbolTable holds most of the interned symbols, while new symbols are always added to NewSymbols.
+ Once the size of NewSymbols exceeds a limit (1000 currently, see #intern:), its content is merged into SymbolTable (see #condenseNewSymbols).
+
+ To ensure a consistent view of the symbol table, all methods accessing it start with atomically creating a "snapshot" of the state, the two variables, by assigning them to two temporaries. Except for #intern:, which only accesses NewSymbols, hence it only creates a snapshot of that.
+ If the symbol table changes, NewSymbols will always be a different object, so it is enough to check whether NewSymbols is the same as before the operation to verify that the symbol table has not been modified.
+
+ There are three methods that can update the symbol table: #condenseNewSymbols, #rehash and #intern:. They create a snapshot first as described above, then create copies of the updated parts, and finally check whether NewSymbols is the same as before, and if it is, they apply their changes. That all happens atomically because #==, #ifTrue: and assignments are executed by the VM without suspension points, hence atomically. If NewSymbols is different, the methods are repeated until they succeed.
+ !
- ATTENTION!! To ensure consistency and thread safety without using a mutex, the two WeakSets which make up the symbol table are treated as if they were immutable. Removing from them without creating a copy just breaks that contract.!
Item was changed:
----- Method: Symbol class>>allSymbolTablesDo: (in category 'class initialization') -----
allSymbolTablesDo: aBlock
+ "See the class comment for details about the usage of the class variables before changing this method"
+
-
| originalNewSymbols originalSymbolTable |
originalNewSymbols := NewSymbols.
originalSymbolTable := SymbolTable.
originalNewSymbols do: aBlock.
originalSymbolTable do: aBlock.!
Item was changed:
----- Method: Symbol class>>allSymbolTablesDo:after: (in category 'class initialization') -----
allSymbolTablesDo: aBlock after: aSymbol
+ "See the class comment for details about the usage of the class variables before changing this method"
| originalNewSymbols originalSymbolTable |
originalNewSymbols := NewSymbols.
originalSymbolTable := SymbolTable.
(originalNewSymbols includes: aSymbol)
ifTrue: [
originalNewSymbols do: aBlock after: aSymbol.
originalSymbolTable do: aBlock after: aSymbol ]
ifFalse: [
originalSymbolTable do: aBlock after: aSymbol.
originalNewSymbols do: aBlock after: aSymbol ]
!
Item was changed:
----- Method: Symbol class>>allSymbols (in category 'accessing') -----
allSymbols
"Answer all interned symbols"
+ "See the class comment for details about the usage of the class variables before changing this method"
+
-
| originalNewSymbols originalSymbolTable |
originalNewSymbols := NewSymbols.
originalSymbolTable := SymbolTable.
^Array
new: originalNewSymbols slowSize + originalSymbolTable slowSize
+ streamContents: [ :stream |
- streamContents:[ :stream |
stream
nextPutAll: originalNewSymbols;
nextPutAll: originalSymbolTable ]
!
Item was changed:
----- Method: Symbol class>>condenseNewSymbols (in category 'private') -----
condenseNewSymbols
+ "Move all symbols from NewSymbols to SymbolTable, and compact SymbolTable if needed."
+ "See the class comment for details about the usage of the class variables before changing this method."
- "Move all symbols from NewSymbols to SymbolTable, and compact SymbolTable."
| originalNewSymbols originalSymbolTable newNewSymbols newSymbolTable |
+ [
+ originalNewSymbols := NewSymbols.
+ originalSymbolTable := SymbolTable.
+ (originalNewSymbols isEmpty and: [ originalSymbolTable isCompact ]) ifTrue: [
+ "Only recreate the sets if necessary"
+ ^self ].
+ (newNewSymbols := WeakSet new)
+ beReadOnlyObject.
+ (newSymbolTable := WeakSet new: originalNewSymbols slowSize + originalSymbolTable slowSize)
+ addAll: originalSymbolTable;
+ addAll: originalNewSymbols;
+ beReadOnlyObject.
+ originalNewSymbols == NewSymbols ifTrue: [
+ NewSymbols := newNewSymbols.
+ SymbolTable := newSymbolTable.
+ ^self ].
+ "Some other process has modified the symbol table. Try again." ] repeat!
- originalNewSymbols := NewSymbols.
- originalSymbolTable := SymbolTable.
- newNewSymbols := WeakSet new.
- newSymbolTable := originalSymbolTable copy
- addAll: originalNewSymbols;
- compact;
- yourself.
- originalNewSymbols == NewSymbols ifFalse: [
- "Some other process has modified the symbols. Try again."
- ^self condenseNewSymbols ].
- NewSymbols := newNewSymbols.
- SymbolTable := newSymbolTable!
Item was changed:
----- Method: Symbol class>>intern: (in category 'instance creation') -----
intern: aStringOrSymbol
"Answer the unique Symbol formed with given String.
If it does not exist yet, create it and intern it in the NewSymbols.
Interning a Symbol should return the Symbol itself, no Symbol should be duplicated"
+ "See the class comment for details about the usage of the class variables before changing this method"
| originalNewSymbols |
originalNewSymbols := NewSymbols.
^(self lookup: aStringOrSymbol) ifNil:[
| aSymbol newNewSymbols |
aStringOrSymbol isSymbol ifTrue:[
aSymbol := aStringOrSymbol.
] ifFalse:[
aSymbol := (aStringOrSymbol isOctetString ifTrue:[ByteSymbol] ifFalse:[WideSymbol])
new: aStringOrSymbol size.
aSymbol
copyFrom: aStringOrSymbol;
beReadOnlyObject.
].
newNewSymbols := originalNewSymbols copyWith: aSymbol.
+ newNewSymbols beReadOnlyObject.
originalNewSymbols == NewSymbols
ifTrue: [
NewSymbols := newNewSymbols.
newNewSymbols size > 1000 ifTrue: [ self condenseNewSymbols ].
aSymbol ]
ifFalse: [
"Some other process has modified the symbols. Try again."
self intern: aStringOrSymbol ] ]!
Item was changed:
----- Method: Symbol class>>lookup: (in category 'instance creation') -----
lookup: aStringOrSymbol
"Answer the unique Symbol formed with given String, if it exists.
Answer nil if no such Symbol does exist yet.
Looking up a Symbol should return the Symbol itself
- no Symbol should be duplicated
- every Symbol should be registered in one of the two Symbol tables"
+ "See the class comment for details about the usage of the class variables before changing this method"
| originalNewSymbols originalSymbolTable |
originalNewSymbols := NewSymbols.
originalSymbolTable := SymbolTable.
+ ^(originalSymbolTable like: aStringOrSymbol) ifNil: [ "Most symbols are in originalSymbolTable, so look for existing symbols in there first"
- ^(originalSymbolTable like: aStringOrSymbol) ifNil: [
originalNewSymbols like: aStringOrSymbol ]!
Item was changed:
----- Method: Symbol class>>possibleSelectorsFor: (in category 'private') -----
possibleSelectorsFor: misspelled
"Answer an ordered collection of possible corrections
for the misspelled selector in order of likelyhood"
| numArgs candidates lookupString best binary short long first |
lookupString := misspelled asLowercase. "correct uppercase selectors to lowercase"
numArgs := lookupString numArgs.
(numArgs < 0 or: [lookupString size < 2]) ifTrue: [^ OrderedCollection new: 0].
first := lookupString first.
short := lookupString size - (lookupString size // 4 max: 3) max: 2.
long := lookupString size + (lookupString size // 4 max: 3).
"First assemble candidates for detailed scoring"
candidates := OrderedCollection new.
self allSymbolTablesDo: [:s | | ss |
(((ss := s size) >= short "not too short"
and: [ss <= long "not too long"
or: [(s at: 1) = first]]) "well, any length OK if starts w/same letter"
and: [s numArgs = numArgs]) "and numArgs is the same"
ifTrue: [candidates add: s]].
"Then further prune these by correctAgainst:"
best := lookupString correctAgainst: candidates.
((misspelled last ~~ $:) and: [misspelled size > 1]) ifTrue: [
binary := misspelled, ':'. "try for missing colon"
+ (self lookup: binary) ifNotNil: [:him | best addFirst: him]].
- Symbol hasInterned: binary ifTrue: [:him | best addFirst: him]].
^ best!
Item was changed:
----- Method: Symbol class>>rehash (in category 'private') -----
rehash
"Rebuild the hash table, reclaiming unreferenced Symbols. This method will intern all symbols. You're probably looking for #condenseNewSymbols instead."
+ "See the class comment for details about the usage of the class variables before changing this method"
| originalNewSymbols originalSymbolTable newNewSymbols newSymbolTable |
+ [
+ originalNewSymbols := NewSymbols.
+ originalSymbolTable := SymbolTable.
+ newNewSymbols := WeakSet new.
+ newSymbolTable := WeakSet withAll: self allSubInstances.
+ newNewSymbols beReadOnlyObject.
+ newSymbolTable beReadOnlyObject.
+ originalNewSymbols == NewSymbols ifTrue: [
+ NewSymbols := newNewSymbols.
+ SymbolTable := newSymbolTable.
+ ^self ].
+ "Some other process has modified the symbol table. Try again." ] repeat
+ !
- originalNewSymbols := NewSymbols.
- originalSymbolTable := SymbolTable.
- newNewSymbols := WeakSet new.
- newSymbolTable := WeakSet withAll: self allSubInstances.
- originalNewSymbols == NewSymbols ifFalse: [
- "Some other process has modified the symbols. Try again."
- ^self rehash ].
- NewSymbols := newNewSymbols.
- SymbolTable := newSymbolTable!
Item was changed:
----- 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 ].
+ tally := tally - 1. "Update tally first, so that read-only hashed collections raise an error before modifying array."
array at: index put: vacuum.
- tally := tally - 1.
self fixCollisionsFrom: index.
^association value!
Item was changed:
----- Method: WeakSet>>postCopy (in category 'copying') -----
postCopy
+
| oldFlag |
super postCopy.
oldFlag := flag.
flag := Object new.
+ 1 to: array size do: [ :index |
+ (array at: index) == oldFlag ifTrue: [
+ array at: index put: flag ] ]!
- array replaceAll: oldFlag with: flag.!
Item was changed:
----- Method: WeakSet>>remove:ifAbsent: (in category 'removing') -----
remove: oldObject ifAbsent: aBlock
| index |
index := self scanFor: oldObject.
(array at: index) == flag ifTrue: [ ^ aBlock value ].
+ tally := tally - 1. "Update tally first, so that read-only hashed collections raise an error before modifying array."
array at: index put: flag.
- tally := tally - 1.
self fixCollisionsFrom: index.
^oldObject!
Item was changed:
+ (PackageInfo named: 'Collections') postscript: '"Make sure the symbol table consists of immutable sets"
+ #(SymbolTable NewSymbols) do: [ :variableName |
+ (Symbol classPool at: variableName) beReadOnlyObject ]'!
- (PackageInfo named: 'Collections') postscript: '"Definition of separators has been updated, update CharacterSet caches too"
- CharacterSet cleanUp: false.'!
Christoph Thiede uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-ct.999.mcz
==================== Summary ====================
Name: Collections-ct.999
Author: ct
Time: 28 March 2022, 10:08:58.886426 pm
UUID: d938acc0-5012-9649-960f-9b374a010b83
Ancestors: Collections-ct.998
Restores line breaks in Text codeSample that are required indeed for the FontImporterTool.
=============== Diff against Collections-ct.998 ===============
Item was changed:
----- Method: Text class>>codeSample (in category 'filler text') -----
codeSample
+ self flag: #linebreaks. "Samples are used in FontImporterTool and must contain manual linebreaks (visually stable example texts per line)."
^ 'exampleWithNumber: x
+ "A method that illustrates every part of Smalltalk method syntax
+ including primitives. It has unary, binary, and keyboard messages;
+ declares arguments and temporaries; accesses a global variable
+ (but not an instance variable); uses literals (array, nested array,
+ character, symbol, string, integer, float, scaled decimal, and byte
+ array); uses the pseudo variables nil, true, false, self, super, and
+ thisContext; shows that within a literal array nil, true, and false are
+ symbols not pseudo variables; and has sequence, assignment,
+ return, cascade, and tuple (array) creation. It has both zero
+ argument and one argument blocks, and has a block temporary."
- "A method that illustrates every part of Smalltalk method syntax including primitives. It has unary, binary, and keyboard messages; declares arguments and temporaries; accesses a global variable (but not an instance variable); uses literals (array, nested array, character, symbol, string, integer, float, scaled decimal, and byte array); uses the pseudo variables nil, true, false, self, super, and thisContext; shows that within a literal array nil, true, and false are symbols not pseudo variables; and has sequence, assignment, return, cascade, and tuple (array) creation. It has both zero argument and one argument blocks, and has a block temporary."
<primitive: ''primitiveCopyBits'' module: #BitBltPlugin error: ec>
| y |
true & false not & (nil isNil) ifFalse: [self halt].
y := self size + super size.
#($a #a ''a'' "a" (1 1.0 1.0s2) nil true false), { #[65]. thisContext. nil. true. false }
do: [ :each | | class |
class := each class.
Transcript
show: (class name);
show: '' ''].
^ x < y'!