Browse Source

Eliminated concurrent modifcation exception for list, stack.

Mark Sibly 9 years ago
parent
commit
b20ffbe5fc

+ 26 - 14
modules/std/collections/container.monkey2

@@ -7,14 +7,12 @@ IContainer does not actually declare any members, but a class that implements IC
 
 `Method All:IteratorType()` - Gets an iterator to all values in the container.
 
-...where 'IteratorType' is a class or struct type that implements the following properties and methods:
+...where `IteratorType` is a class or struct type that implements the following properties and methods:
 
 `Property Current:ValueType()` - The current value pointed to by the iterator.
 
 `Property AtEnd:bool()` - true if iterator is at end of container.
 
-`Method Erase()` - Erases the value pointed to by the iterator.
-
 `Method Bump()` - Bumps the iterator so it points to the next value in the container.
 
 ...where 'ValueType' is the type of the values contained in the container.
@@ -31,6 +29,7 @@ Next
 
 ...to this...
 
+
 ```
 Local iterator:=container.All()
 
@@ -44,9 +43,15 @@ While Not iterator.AtEnd
 Wend
 ```
 
-Containers should not be modified while eachin is being used to loop through the values in the container as this can put the container into
-an inconsistent state. If you need to do this, you should manually iterate through the container and use the iterator 'Erase' method to erase
-values in a controlled way. For example:
+Iterators may also provide methods for inserting and removing items...
+
+Containers should not be modified while eachin is being used to loop through the values in the container as this can put the container into an inconsistent state. If you need to do this, you should use these optional iterator methods instead of modifying the container:
+
+`Method Erase:Void()` - Erase the iterator from the container.
+
+`Method Insert:Void( value:ValueType )` - Insert a value before the iterator.
+
+For example:
 
 ```
 Local iterator:=container.All()
@@ -72,8 +77,7 @@ Wend
 
 Note that if you erase a value, you should NOT bump the iterator - erase implicitly does this for you.
 
-Finally, IContainer is not a 'real' interface because Monkey2 does not yet support generic interface methods. This feature is planned for a 
-future version of monkey2.
+Finally, IContainer is not a 'real' interface because Monkey2 does not yet support generic interface methods. This feature is planned for a future version of monkey2.
 
 #end
 Interface IContainer<T>
@@ -82,16 +86,24 @@ Interface IContainer<T>
 	
 	'Method All:IIterator<T>()
 
-	'Method Find:IIterator<T>( value:T ) Default...
-
 	
-	'For sequences...
+	'Sequence methods
 	
 	'Method Add( value:T )
 	
-	'Method AddAll( value:T[] ) Default...
+	'Method AddAll( value:T[] )
+	
+	'Method AddAll<C>( values:C )
+	
+	'Method Contains:Bool( value:T )
+	
+	'Method Remove:Bool( value:T )
+	
+	'Method RemoveLast:Bool( value:T )
+	
+	'Method RemoveEach:Int( value:T )
 	
-	'Method AddAll<C>( values:C ) Where C Implements IContainer<T> Default...
+	'Method RemoveIf:Int( condition:Bool( value:T ) )
 	
 End
 
@@ -106,7 +118,7 @@ Interface IIterator<T>
 	'Method Bump()
 	
 	
-	'For sequences...
+	'Sequence methods
 	
 	'Method Erase()
 	

+ 2 - 40
modules/std/collections/list.monkey2

@@ -23,9 +23,6 @@ This connection between elements is achieved using separate Node objects (there
 
 Lists implements the [[IContainer]] interface so can be used with [[Eachin]] loops.
 
-Note that you should NOT modify a list while iterating through it with an eachin loop. Doing so while cause a 'concurrent list
-modification' runtime error in debug mode. Please see [[IContainer]] for more information.
-
 #end
 Class List<T> Implements IContainer<T>
 
@@ -139,14 +136,9 @@ Class List<T> Implements IContainer<T>
 	
 		Field _list:List
 		Field _node:Node
-		Field _seq:Int
-		
-		Method AssertSeq()
-			DebugAssert( _seq=_list._seq,"Concurrent list modification" )
-		End
 		
 		Method AssertCurrent()
-			DebugAssert( Not AtEnd,"Invalid list iterator" )
+			DebugAssert( _node<>_list._head,"Invalid list iterator" )
 		End
 		
 		Public
@@ -156,13 +148,11 @@ Class List<T> Implements IContainer<T>
 		Method New( list:List,node:Node )
 			_list=list
 			_node=node
-			_seq=list._seq
 		End
 
 		#rem monkeydoc Checks whether the iterator has reached the end of the list.
 		#end
 		Property AtEnd:Bool()
-			AssertSeq()
 			Return _node=_list._head
 		End
 		
@@ -196,8 +186,6 @@ Class List<T> Implements IContainer<T>
 			AssertCurrent()
 			_node=_node._succ
 			_node._pred.Remove()
-			_list._seq+=1
-			_seq=_list._seq
 		End
 		
 		#rem monkeydoc Safely insert a value before the iterator.
@@ -206,10 +194,7 @@ Class List<T> Implements IContainer<T>
 		
 		#end
 		Method Insert( value:T )
-			AssertSeq()
 			_node=New Node( value,_node )
-			_list._seq+=1
-			_seq=_list._seq
 		End
 	End
 	
@@ -221,14 +206,9 @@ Class List<T> Implements IContainer<T>
 	
 		Field _list:List
 		Field _node:Node
-		Field _seq:Int
-		
-		Method AssertSeq()
-			DebugAssert( _seq=_list._seq,"Concurrent list modification" )
-		End
 		
 		Method AssertCurrent()
-			DebugAssert( Not AtEnd,"Invalid list iterator" )
+			DebugAssert( _node<>_list._head,"Invalid list iterator" )
 		End
 		
 		Public
@@ -238,13 +218,11 @@ Class List<T> Implements IContainer<T>
 		Method New( list:List,node:Node )
 			_list=list
 			_node=node
-			_seq=list._seq
 		End
 
 		#rem monkeydoc Checks whether the iterator has reached the end of the list.
 		#end
 		Property AtEnd:Bool()
-			AssertSeq()
 			Return _node=_list._head
 		End
 		
@@ -278,8 +256,6 @@ Class List<T> Implements IContainer<T>
 			AssertCurrent()
 			_node=_node._pred
 			_node._succ.Remove()
-			_list._seq+=1
-			_seq=_list._seq
 		End
 		
 		#rem monkeydoc Safely insert a value before the iterator.
@@ -288,18 +264,13 @@ Class List<T> Implements IContainer<T>
 		
 		#end
 		Method Insert( value:T )
-			AssertSeq()
 			_node=New Node( value,_node._succ )
-			_list._seq+=1
-			_seq=_list._seq
 		End
 	End
 	
 	Private
 	
-'	Field _head:=New Node	'FIXME, causes internal compiler error...
 	Field _head:Node
-	Field _seq:Int
 	
 	Public
 	
@@ -430,7 +401,6 @@ Class List<T> Implements IContainer<T>
 	Method Clear()
 		_head._succ=_head
 		_head._pred=_head
-		_seq+=1
 	End
 	
 	#rem monkeydoc Adds a value to the start of the list.
@@ -442,7 +412,6 @@ Class List<T> Implements IContainer<T>
 	#end
 	Method AddFirst:Node( value:T )
 		Local node:=New Node( value,_head._succ )
-		_seq+=1
 		Return node
 	End
 	
@@ -455,7 +424,6 @@ Class List<T> Implements IContainer<T>
 	#end
 	Method AddLast:Node( value:T )
 		Local node:=New Node( value,_head )
-		_seq+=1
 		Return node
 	End
 	
@@ -470,7 +438,6 @@ Class List<T> Implements IContainer<T>
 		Local node:=FindNode( value )
 		If Not node Return False
 		node.Remove()
-		_seq+=1
 		Return True
 	End
 	
@@ -485,7 +452,6 @@ Class List<T> Implements IContainer<T>
 		Local node:=FindLastNode( value )
 		If Not node Return False
 		node.Remove()
-		_seq+=1
 		Return True
 	End
 	
@@ -507,7 +473,6 @@ Class List<T> Implements IContainer<T>
 				node=node._succ
 			Endif
 		Wend
-		If n _seq+=1
 		Return n
 	End
 	
@@ -529,7 +494,6 @@ Class List<T> Implements IContainer<T>
 				node=node._succ
 			Endif
 		Wend
-		If n _seq+=1
 		Return n
 	End
 	
@@ -545,7 +509,6 @@ Class List<T> Implements IContainer<T>
 		
 		Local value:=_head._succ._value
 		_head._succ.Remove()
-		_seq+=1
 		Return value
 	End
 	
@@ -561,7 +524,6 @@ Class List<T> Implements IContainer<T>
 		
 		Local value:=_head._pred._value
 		_head._pred.Remove()
-		_seq+=1
 		Return value
 	End
 	

+ 19 - 38
modules/std/collections/stack.monkey2

@@ -21,9 +21,6 @@ It is very cheap to add values to the end of a stack, but insertion or removal o
 
 Stacks implement the [[IContainer]] interface so can be used with [[Eachin]] loops.
 
-Note that you should NOT modify a stack while iterating through it with an eachin loop. Doing so while cause a 'concurrent stack
-modification' runtime error in debug mode. Please see [[IContainer]] for more information.
-
 #end
 Class Stack<T> Implements IContainer<T>
 
@@ -35,20 +32,14 @@ Class Stack<T> Implements IContainer<T>
 
 		Field _stack:Stack
 		Field _index:Int
-		Field _seq:Int
-		
-		Method AssertSeq()
-			DebugAssert( _seq=_stack._seq,"Concurrent list modification" )
-		End
 		
 		Method AssertCurrent()
-			DebugAssert( Not AtEnd,"Invalid list iterator" )
+			DebugAssert( _index<_stack._length,"Invalid stack iterator" )
 		End
 		
 		Method New( stack:Stack,index:Int )
 			_stack=stack
 			_index=index
-			_seq=stack._seq
 		End
 		
 		Public
@@ -56,8 +47,7 @@ Class Stack<T> Implements IContainer<T>
 		#rem monkeydoc Checks if the iterator has reached the end of the stack.
 		#end
 		Property AtEnd:Bool()
-			AssertSeq()
-			Return _index=_stack._length
+			Return _index>=_stack._length
 		End
 		
 		#rem monkeydoc The value currently pointed to by the iterator.
@@ -81,14 +71,12 @@ Class Stack<T> Implements IContainer<T>
 		
 		After calling this method, the iterator will point to the value after the removed value.
 		
-		Therefore, if you are manually iterating through a stack you should not call [[Bump]] after calling this method or you
-		will end up skipping a value.
+		Therefore, if you are manually iterating through a stack you should not call [[Bump]] after calling this method or you will end up skipping a value.
 		
 		#end
 		Method Erase()
-			AssertSeq()
+			AssertCurrent()
 			_stack.Erase( _index )
-			_seq=_stack._seq
 		End
 		
 		#rem monkeydoc Safely inserts a value before the value pointed to by the iterator.
@@ -97,9 +85,8 @@ Class Stack<T> Implements IContainer<T>
 		
 		#end
 		Method Insert( value:T )
-			AssertSeq()
+			DebugAssert( _index<=_stack._length,"Invalid stack iterator" )
 			_stack.Insert( _index,value )
-			_seq=_stack._seq
 		End
 	End
 	
@@ -111,20 +98,14 @@ Class Stack<T> Implements IContainer<T>
 
 		Field _stack:Stack
 		Field _index:Int
-		Field _seq:Int
-		
-		Method AssertSeq()
-			DebugAssert( _seq=_stack._seq,"Concurrent list modification" )
-		End
 		
 		Method AssertCurrent()
-			DebugAssert( Not AtEnd,"Invalid list iterator" )
+			DebugAssert( _index>=0,"Invalid stack iterator" )
 		End
 		
 		Method New( stack:Stack,index:Int )
 			_stack=stack
 			_index=index
-			_seq=stack._seq
 		End
 		
 		Public
@@ -132,7 +113,6 @@ Class Stack<T> Implements IContainer<T>
 		#rem monkeydoc Checks if the iterator has reached the end of the stack.
 		#end
 		Property AtEnd:Bool()
-			AssertSeq()
 			Return _index=-1
 		End
 		
@@ -163,9 +143,8 @@ Class Stack<T> Implements IContainer<T>
 		#end
 		Method Erase()
 			AssertCurrent()
+			_stack.Erase( _index )
 			_index-=1
-			_stack.Erase( _index+1 )
-			_seq=_stack._seq
 		End
 		
 		#rem monkeydoc Safely inserts a value before the value pointed to by the iterator.
@@ -174,10 +153,9 @@ Class Stack<T> Implements IContainer<T>
 		
 		#end
 		Method Insert( value:T )
-			AssertSeq()
+			DebugAssert( _index<_stack._length,"Invalid stack iterator" )
 			_index+=1
 			_stack.Insert( _index,value )
-			_seq=_stack._seq
 		End
 	End
 	
@@ -185,7 +163,6 @@ Class Stack<T> Implements IContainer<T>
 
 	Field _data:T[]
 	Field _length:Int
-	Field _seq:Int	
 	
 	Public
 	
@@ -199,6 +176,8 @@ Class Stack<T> Implements IContainer<T>
 	
 	New( values:List<T> ) creates a stack with the contents of a list.
 	
+	New( values:Deque<T> ) create a stack with the contents of a deque.
+	
 	New( values:Stack<T> ) create a stack with the contents of another stack.
 	
 	@param length The length of the stack.
@@ -219,14 +198,20 @@ Class Stack<T> Implements IContainer<T>
 		AddAll( values )
 	End
 	
-	Method New( values:Stack<T> )
+	Method New( values:List<T> )
+		AddAll( values )
+	End
+	
+	Method New( values:Deque<T> )
 		_length=values.Length
 		_data=New T[_length]
 		values.Data.CopyTo( _data,0,0,_length )
 	End
 	
-	Method New( values:List<T> )
-		AddAll( values )
+	Method New( values:Stack<T> )
+		_length=values.Length
+		_data=New T[_length]
+		values.Data.CopyTo( _data,0,0,_length )
 	End
 	
 	#rem monkeydoc Checks if the stack is empty.
@@ -323,7 +308,6 @@ Class Stack<T> Implements IContainer<T>
 		
 		Reserve( length )
 		_length=length
-		_seq+=1
 	End
 	
 	#rem monkeydoc Reserves stack storage capacity.
@@ -409,7 +393,6 @@ Class Stack<T> Implements IContainer<T>
 		_data.CopyTo( _data,index,index+1,_length-index )
 		_data[index]=value
 		_length+=1
-		_seq+=1
 	End
 	
 	#rem monkeydoc Gets the value of a stack element.
@@ -479,7 +462,6 @@ Class Stack<T> Implements IContainer<T>
 		Reserve( _length+1 )
 		_data[_length]=value
 		_length+=1
-		_seq+=1
 	End
 	
 	#rem monkeydoc Adds the values in an array or container to the end of the stack.
@@ -783,7 +765,6 @@ Class Stack<T> Implements IContainer<T>
 		DebugAssert( _length,"Stack is empty" )
 		
 		_length-=1
-		_seq+=1
 		Local value:=_data[_length]
 		_data[_length]=Null
 		Return value