[Seaside-dev] WADelayedMessageSend (issue 268)

Paolo Bonzini bonzini at gnu.org
Sun Jan 4 13:29:22 UTC 2009


Here is my try, together with testcases.  I suppose integrating it is
easier than rewriting it.

There's quite some duplication, but at the end you risk being slower
than the blocks you're trying to replace (though memory usage will be of
course lower, except on VW or other implementations with copying blocks).

Paolo
-------------- next part --------------
Object subclass: #WADelayedMessageSend
	instanceVariableNames: 'freeSlotsCount fixedSlotsCount receiver selector fixedArgs'
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Seaside-Core'!

!WADelayedMessageSend class methodsFor: 'instance creation'!

selector: aSymbol
	^self new selector: aSymbol fixedSlots: #()
!

receiver: anObject selector: aSymbol
	^self new selector: aSymbol fixedSlots: (Array with: anObject)
!

receiver: anObject selector: aSymbol argument: argObject
	^self new selector: aSymbol fixedSlots: (Array with: anObject with: argObject)
!

receiver: anObject selector: aSymbol arguments: anArray
	^self new selector: aSymbol fixedSlots: (Array with: anObject), anArray
! !

!WADelayedMessageSend methodsFor: 'instance creation'!

value
	freeSlotsCount = 0 ifFalse: [ ^self wrongArgCountError ].
	^receiver perform: selector withArguments: fixedArgs
!

value: anObject
	| actuals |
	freeSlotsCount = 1 ifFalse: [ ^self wrongArgCountError ].
	fixedSlotsCount = 0 ifTrue: [ ^anObject perform: selector ].
	fixedSlotsCount = 1 ifTrue: [ ^receiver perform: selector with: anObject ].
	fixedSlotsCount = 2 ifTrue: [ ^receiver perform: selector with: (fixedArgs at: 1) with: anObject ].

	actuals := Array new: fixedSlotsCount.
	actuals replaceFrom: 1 to: fixedSlotsCount - 1 with: fixedArgs startingAt: 1.
	actuals at: fixedSlotsCount put: anObject.
	^receiver perform: selector withArguments: actuals
!

value: obj1 value: obj2
	| actuals |
	freeSlotsCount = 2 ifFalse: [ ^self wrongArgCountError ].
	fixedSlotsCount = 0 ifTrue: [ ^obj1 perform: selector with: obj2 ].
	fixedSlotsCount = 1 ifTrue: [ ^receiver perform: selector with: obj1 with: obj2 ].
	fixedSlotsCount = 2 ifTrue: [ ^receiver perform: selector with: (fixedArgs at: 1) with: obj1 with: obj2 ].

	actuals := Array new: fixedSlotsCount + 1.
	actuals replaceFrom: 1 to: fixedSlotsCount - 1 with: fixedArgs startingAt: 1.
	actuals at: fixedSlotsCount put: obj1.
	actuals at: fixedSlotsCount + 1 put: obj2.
	^receiver perform: selector withArguments: actuals
!

value: obj1 value: obj2 value: obj3
	| actuals |
	freeSlotsCount = 3 ifFalse: [ ^self wrongArgCountError ].
	fixedSlotsCount = 0 ifTrue: [ ^obj1 perform: selector with: obj2 with: obj3 ].
	fixedSlotsCount = 1 ifTrue: [ ^receiver perform: selector with: obj1 with: obj2 with: obj3 ].

	actuals := Array new: fixedSlotsCount + 2.
	actuals replaceFrom: 1 to: fixedSlotsCount - 1 with: fixedArgs startingAt: 1.
	actuals at: fixedSlotsCount put: obj1.
	actuals at: fixedSlotsCount + 1 put: obj2.
	actuals at: fixedSlotsCount + 2 put: obj3.
	^receiver perform: selector withArguments: actuals
!

valueWithArguments: args
	| actuals totalSlots |
	freeSlotsCount = args size ifFalse: [ ^self wrongArgCountError ].
	freeSlotsCount = 0 ifTrue: [ ^receiver perform: selector withArguments: fixedArgs ].
	fixedSlotsCount = 0 ifTrue: [ ^(args at: 1) perform: selector withArguments: (args copyFrom: 2) ].
	fixedSlotsCount = 1 ifTrue: [ ^receiver perform: selector withArguments: args ].

	totalSlots := fixedSlotsCount + freeSlotsCount - 1.
	actuals := Array new: totalSlots.
	actuals replaceFrom: 1 to: fixedSlotsCount - 1 with: fixedArgs startingAt: 1.
	actuals replaceFrom: fixedSlotsCount to: totalSlots with: args startingAt: 1.
	^receiver perform: selector withArguments: actuals
!

!WADelayedMessageSend methodsFor: 'accessing'!

numArgs
	^freeSlotsCount
! !

!WADelayedMessageSend methodsFor: 'private'!

wrongArgCountError
	self error: 'invalid number of arguments'
! !

!WADelayedMessageSend methodsFor: 'initialization'!

selector: aSymbol fixedSlots: anArray
	selector := aSymbol.
	freeSlotsCount := (aSymbol numArgs + 1) - anArray size.
	fixedSlotsCount := anArray size.
	receiver := anArray at: 1 ifAbsent: [nil].
	fixedArgs := fixedSlotsCount = 0 ifTrue: [nil] ifFalse: [anArray allButFirst].
! !

TestCase subclass: #WADelayedMessageSendTest
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Seaside-Core-Tests'!

!WADelayedMessageSendTest methodsFor: 'helpers'!

assertValue: aDMS is: result
	self assert: aDMS value = result.
	self assert: (aDMS valueWithArguments: #()) = result
!

assert: aDMS value: arg is: result
	self assert: (aDMS value: arg) = result.
	self assert: (aDMS valueWithArguments: (Array with: arg)) = result
!

assert: aDMS value: arg value: arg2 is: result
	self assert: (aDMS value: arg value: arg2) = result.
	self assert: (aDMS valueWithArguments: (Array with: arg with: arg2)) = result
!

assert: aDMS value: arg value: arg2 value: arg3 is: result
	self assert: (aDMS value: arg value: arg2 value: arg3) = result.
	self assert: (aDMS valueWithArguments: (Array with: arg with: arg2 with: arg3)) = result
! !

!WADelayedMessageSendTest methodsFor: 'testcases'!

testSelector
	self
		assert: (WADelayedMessageSend selector: #abs)
		value: -15
		is: 15.
	self
		assert: (WADelayedMessageSend selector: #*)
		value: 5
		value: 3
		is: 15.
	self
		assert: (WADelayedMessageSend selector: #ifTrue:ifFalse:)
		value: true
		value: [15]
		value: [-15]
		is: 15.
!

testReceiverSelector
	self
		assertValue: (WADelayedMessageSend receiver: -15 selector: #abs)
		is: 15.
	self
		assert: (WADelayedMessageSend receiver: 5 selector: #*)
		value: 3 is: 15.
	self
		assert: (WADelayedMessageSend receiver: true selector: #ifTrue:ifFalse:)
		value: [15]
		value: [-15]
		is: 15.
!

testReceiverSelectorArgument
	self
		assertValue: (WADelayedMessageSend receiver: 5 selector: #* argument: 3)
		is: 15.
	self
		assert: (WADelayedMessageSend receiver: true selector: #ifTrue:ifFalse: argument: [15])
		value: [-15]
		is: 15.
!

testReceiverSelectorArguments
	self
		assertValue: (WADelayedMessageSend receiver: 5 selector: #* arguments: #(3))
		is: 15.
	self
		assertValue: (WADelayedMessageSend receiver: 10 selector: #between:and: arguments: #(-15 15))
		is: true.
	self
		assert: (WADelayedMessageSend receiver: 10 selector: #between:and: arguments: #(-15))
		value: 15
		is: true.
! !


More information about the seaside-dev mailing list