diff --git a/examples/denise/set_vs_list_example.wx b/examples/denise/set_vs_list_example.wx new file mode 100644 index 00000000..4734a4ec --- /dev/null +++ b/examples/denise/set_vs_list_example.wx @@ -0,0 +1,97 @@ + +#Import "" + +Using std.. + +Const ITEMS := 1000000 +Const MAXVALUE := 5000000 + +Enum Bench + Base, Create, Union, Intersection, Difference +End + +Function Main() + + Print "miniBench List vs Set" + Print "Items: "+ITEMS + + Local timesList:= New Int[5] + Local timesSet:= New Int[5] + Local l1 := New List() + Local s1 := New Set( MAXVALUE, ITEMS ) + Local l2 := New List() + Local s2 := New Set( MAXVALUE, ITEMS ) + + SeedRnd(1234) + timesList[Bench.Base] = Millisecs() + For Local i := 0 Until ITEMS + l1.Add( UInt( Rnd( MAXVALUE ) ) ) + l2.Add( UInt( Rnd( MAXVALUE ) ) ) + Next + timesList[Bench.Create] = Millisecs() + Local l_union := l1.Union( l2, False ) + timesList[Bench.Union] = Millisecs() + Local l_inter := l1.Intersect( l2, False ) + timesList[Bench.Intersection] = Millisecs() + Local l_diff := l1.Diff( l2, False ) + timesList[Bench.Difference] = Millisecs() + + SeedRnd(1234) + timesSet[Bench.Base] = Millisecs() + For Local i := 0 Until ITEMS + s1.Add( UInt( Rnd( MAXVALUE ) ) ) + s2.Add( UInt( Rnd( MAXVALUE ) ) ) + Next + timesSet[Bench.Create] = Millisecs() + Local s_union := s1.Union( s2 ) + timesSet[Bench.Union] = Millisecs() + Local s_inter := s1.Intersection( s2 ) + timesSet[Bench.Intersection] = Millisecs() + Local s_diff := s1.Difference( s2 ) + timesSet[Bench.Difference] = Millisecs() + + Local tlc := timesList[Bench.Create] - timesList[Bench.Base] + Local tlu := timesList[Bench.Union] - timesList[Bench.Create] + Local tli := timesList[Bench.Intersection] - timesList[Bench.Union] + Local tld := timesList[Bench.Difference] - timesList[Bench.Intersection] + Local tsc := timesSet[Bench.Create] - timesSet[Bench.Base] + Local tsu := timesSet[Bench.Union] - timesSet[Bench.Create] + Local tsi := timesSet[Bench.Intersection] - timesSet[Bench.Union] + Local tsd := timesSet[Bench.Difference] - timesSet[Bench.Intersection] + + Local alu := l_union.ToArray() + Local asu := s_union.ToArray() + Print "--------------------------" + Print "Lenghts: " + alu.Length + " : " + asu.Length + Print "Checking union..." + For Local z := 0 Until alu.Length + If alu[z] <> asu[z] Print "[" + z + "]: " + alu[z] + " - " + asu[z] + Next + + Local ali := l_inter.ToArray() + Local asi := New Stack( s_inter.ToArray() ) + asi.Sort() + Print "--------------------------" + Print "Lenghts: " + ali.Length + " : " + asi.Length + Print "Checking intersection..." + For Local z := 0 Until ali.Length + If ali[z] <> asi[z] Print "[" + z + "]: " + ali[z] + " - " + asi[z] + Next + + Local ald := l_diff.ToArray() + Local asd := New Stack( s_diff.ToArray() ) + asd.Sort() + Print "--------------------------" + Print "Lenghts: " + ald.Length + " : " + asd.Length + Print "Checking difference..." + For Local z := 0 Until ald.Length + If ald[z] <> asd[z] Print "[" + z + "]: " + ald[z] + " - " + asd[z] + Next + + Print "--------------------------" + Print RSet("Create",20)+" "+RSet("Union",10)+" "+RSet("Intersection",15)+" "+RSet("Difference",15) + Print LSet("Lists",10)+RSet(tlc,9)+" ms"+RSet(tlu,8)+" ms"+RSet(tli,13)+" ms"+RSet(tld,13)+" ms" + Print LSet("Sets",10)+RSet(tsc,9)+" ms"+RSet(tsu,8)+" ms"+RSet(tsi,13)+" ms"+RSet(tsd,13)+" ms" + Print LSet("%",10)+RSet(tlc*100/tsc,9)+"% "+RSet(tlu*100/tsu,9)+"% "+RSet(tli*100/tsi,14)+"% "+RSet(tld*100/tsd,14)+"%" + +End \ No newline at end of file diff --git a/examples/denise/set_vs_map_example.wx b/examples/denise/set_vs_map_example.wx new file mode 100644 index 00000000..3f857a90 --- /dev/null +++ b/examples/denise/set_vs_map_example.wx @@ -0,0 +1,98 @@ + +#Import "" + +Using std.. + +Const ITEMS := 1000000 +Const MAXVALUE := 5000000 + +Enum Bench + Base, Create, Union, Intersection, Difference +End + +Function Main() + + Print "miniBench Map vs Set" + Print "Items: "+ITEMS + + Local timesMap := New Int[5] + Local timesSet:= New Int[5] + Local m1 := New Map() + Local s1 := New Set( MAXVALUE, ITEMS ) + Local m2 := New Map() + Local s2 := New Set( MAXVALUE, ITEMS ) + + SeedRnd(1234) + timesMap[Bench.Base] = Millisecs() + For Local i := 0 Until ITEMS + m1.Add( UInt( Rnd( MAXVALUE ) ), True ) + m2.Add( UInt( Rnd( MAXVALUE ) ), True ) + Next + timesMap[Bench.Create] = Millisecs() + Local m_union := m1.Union( m2, False ) + timesMap[Bench.Union] = Millisecs() + Local m_inter := m1.Intersect( m2, False ) + timesMap[Bench.Intersection] = Millisecs() + Local m_diff := m1.Diff( m2, False ) + timesMap[Bench.Difference] = Millisecs() + + SeedRnd(1234) + timesSet[Bench.Base] = Millisecs() + For Local i := 0 Until ITEMS + s1.Add( UInt( Rnd( MAXVALUE ) ) ) + s2.Add( UInt( Rnd( MAXVALUE ) ) ) + Next + timesSet[Bench.Create] = Millisecs() + Local s_union := s1.Union( s2 ) + timesSet[Bench.Union] = Millisecs() + Local s_inter := s1.Intersection( s2 ) + timesSet[Bench.Intersection] = Millisecs() + Local s_diff := s1.Difference( s2 ) + timesSet[Bench.Difference] = Millisecs() + + Local tmc := timesMap[Bench.Create] - timesMap[Bench.Base] + Local tmu := timesMap[Bench.Union] - timesMap[Bench.Create] + Local tmi := timesMap[Bench.Intersection] - timesMap[Bench.Union] + Local tmd := timesMap[Bench.Difference] - timesMap[Bench.Intersection] + Local tsc := timesSet[Bench.Create] - timesSet[Bench.Base] + Local tsu := timesSet[Bench.Union] - timesSet[Bench.Create] + Local tsi := timesSet[Bench.Intersection] - timesSet[Bench.Union] + Local tsd := timesSet[Bench.Difference] - timesSet[Bench.Intersection] + + Local amu := m_union.KeysToArray() + Local asu := New Stack( s_union.ToArray() ) + asu.Sort() + Print "--------------------------" + Print "Lenghts: " + amu.Length + " : " + asu.Length + Print "Checking union..." + For Local z := 0 Until amu.Length + If amu[z] <> asu[z] Print "[" + z + "]: " + amu[z] + " - " + asu[z] + Next + + Local ami := m_inter.KeysToArray() + Local asi := New Stack( s_inter.ToArray() ) + asi.Sort() + Print "--------------------------" + Print "Lenghts: " + ami.Length + " : " + asi.Length + Print "Checking intersection..." + For Local z := 0 Until ami.Length + If ami[z] <> asi[z] Print "[" + z + "]: " + ami[z] + " - " + asi[z] + Next + + Local amd := m_diff.KeysToArray() + Local asd := New Stack( s_diff.ToArray() ) + asd.Sort() + Print "--------------------------" + Print "Lenghts: " + amd.Length + " : " + asd.Length + Print "Checking difference..." + For Local z := 0 Until amd.Length + If amd[z] <> asd[z] Print "[" + z + "]: " + amd[z] + " - " + asd[z] + Next + + Print "--------------------------" + Print RSet("Create",20)+" "+RSet("Union",10)+" "+RSet("Intersection",15)+" "+RSet("Difference",15) + Print LSet("Maps",10)+RSet(tmc,9)+" ms"+RSet(tmu,8)+" ms"+RSet(tmi,13)+" ms"+RSet(tmd,13)+" ms" + Print LSet("Sets",10)+RSet(tsc,9)+" ms"+RSet(tsu,8)+" ms"+RSet(tsi,13)+" ms"+RSet(tsd,13)+" ms" + Print LSet("%",10)+RSet(tmc*100/tsc,9)+"% "+RSet(tmu*100/tsu,9)+"% "+RSet(tmi*100/tsi,14)+"% "+RSet(tmd*100/tsd,14)+"%" + +End \ No newline at end of file diff --git a/examples/denise/test_operator_to.wx b/examples/denise/test_operator_to.wx new file mode 100644 index 00000000..6cc7a76e --- /dev/null +++ b/examples/denise/test_operator_to.wx @@ -0,0 +1,80 @@ + +#Import "" + +Using std.. + +Function Main() + + Local ln := New List() + Local ls := New List() + Local sn := New Stack() + Local ss := New Stack() + Local dn := New Deque() + Local ds := New Deque() + Local mnn := New Map() + Local mns := New Map() + Local msn := New Map() + Local mss := New Map() + Local sui := New Set() + + ln.Add( 1 ) + ln.Add( 2 ) + ln.Add( 3 ) + Assert( ln = "List[ 1, 2, 3 ]", "Error: " + ln ) + + ls.Add( "1" ) + ls.Add( "2" ) + ls.Add( "3" ) + Assert( ls = "List[ 1, 2, 3 ]", "Error: " + ls ) + + sn.Add( 1 ) + sn.Add( 2 ) + sn.Add( 3 ) + Assert( sn = "Stack[ 1, 2, 3 ]", "Error: " + sn ) + + ss.Add( "1" ) + ss.Add( "2" ) + ss.Add( "3" ) + Assert( ss = "Stack[ 1, 2, 3 ]", "Error: " + ss ) + + dn.AddFirst( 1 ) + dn.AddFirst( 2 ) + dn.AddLast( 3 ) + dn.AddLast( 4 ) + Assert( dn = "Deque[ 2, 1, 3, 4 ]", "Error: " + dn ) + + ds.AddFirst( "1" ) + ds.AddFirst( "2" ) + ds.AddLast( "3" ) + ds.AddLast( "4" ) + Assert( ds = "Deque[ 2, 1, 3, 4 ]", "Error: " + ds ) + + mnn.Add( 1,2 ) + mnn.Add( 3,4 ) + mnn.Add( 1,5 ) + Assert( mnn = "Map{ 1: 2, 3: 4 }", "Error: " + mnn ) + + mns.Add( 1,"2" ) + mns.Add( 3,"4" ) + mns.Add( 1,"5" ) + Assert( mns = "Map{ 1: 2, 3: 4 }", "Error: " + mns ) + + msn.Add( "1",2 ) + msn.Add( "3",4 ) + msn.Add( "1",5 ) + Assert( msn = "Map{ 1: 2, 3: 4 }", "Error: " + msn ) + + mss.Add( "1","2" ) + mss.Add( "3","4" ) + mss.Add( "1","5" ) + Assert( mss = "Map{ 1: 2, 3: 4 }", "Error: " + mss ) + + sui.Add( 1 ) + sui.Add( 2 ) + sui.Add( 3 ) + sui.Add( 2 ) + Assert( sui = "Set{ 1, 2, 3 }", "Error: " + sui ) + + Print "All Ok" + +End diff --git a/modules/std/collections/deque.wx b/modules/std/collections/deque.wx index f09561b9..fec7c435 100644 --- a/modules/std/collections/deque.wx +++ b/modules/std/collections/deque.wx @@ -28,23 +28,24 @@ Please see [[IContainer]] for more information. #end Class Deque Implements IContainer - + #rem wonkeydoc The Deque.Iterator struct. #end Struct Iterator Implements IIterator - + Private Field _deque:Deque Field _index:Int Method AssertCurrent() - DebugAssert( _index<>_deque._tail,"Invalid deque iterator" ) + DebugAssert( _index <> _deque._tail, "Invalid deque iterator" ) End - Method New( deque:Deque,index:Int ) - _deque=deque - _index=index + Method New( deque:Deque, index:Int ) + + _deque = deque + _index = index End Public @@ -52,15 +53,17 @@ Class Deque Implements IContainer #rem wonkeydoc Checks if the iterator has reached the end of the deque. #end Property AtEnd:Bool() - Return _index=_deque._tail + Return _index = _deque._tail End #rem wonkeydoc The value currently pointed to by the iterator. #end Property Current:T() + AssertCurrent() Return _deque._data[_index] Setter( current:T ) + AssertCurrent() _deque._data[_index]=current End @@ -68,9 +71,10 @@ Class Deque Implements IContainer #rem wonkeydoc Bumps the iterator so it points to the next value in the deqeue. #end Method Bump() + AssertCurrent() - _index+=1 - If _index=_deque.Capacity _index=0 + _index += 1 + If _index = _deque.Capacity _index = 0 End Method Erase() @@ -86,44 +90,45 @@ Class Deque Implements IContainer End Method Normalize( capacity:Int ) - - Local length:=Length - Local data:=New T[capacity] + Local length := Length + + Local data := New T[capacity] - If _head<=_tail - _data.CopyTo( data,_head,0,length ) + If _head <= _tail + _data.CopyTo( data, _head, 0, length ) Else - Local n:=Capacity-_head - _data.CopyTo( data,_head,0,n ) - _data.CopyTo( data,0,n,_tail ) + Local n := Capacity - _head + _data.CopyTo( data, _head, 0, n ) + _data.CopyTo( data, 0, n, _tail ) End - _data=data - _tail=length - _head=0 + _data = data + _tail = length + _head = 0 End Public - + #rem wonkeydoc Creates a new deque. @param length Initalize length of the deque. #end Method New() - _data=New T[10] + _data = New T[16] End Method New( length:Int ) - _tail=length - _data=New T[_tail+1] + + _tail = length + _data = New T[_tail + 1] End - + #rem wonkeydoc True if deque is empty. #end Property Empty:Bool() - Return _head=_tail + Return _head = _tail End - + #rem wonkeydoc Gets the storage capacity of the deque. The capacity of a deque is the number of values it can contain before memory needs to be reallocated to store more values. @@ -143,19 +148,20 @@ Class Deque Implements IContainer @return The number of values in the deque. #end Property Length:Int() - If _head<=_tail Return _tail-_head - Return Capacity-_head+_tail + + If _head <= _tail Return _tail - _head + Return _data.Length - _head + _tail End - + #rem wonkeydoc Gets the underlying array used by the deque. Note that the returned array may be longer than the deque length. @return The array used internally by the deque. #end Property Data:T[]() - + If Not _head Return _data - Normalize( Capacity ) + Normalize( _data.Length ) Return _data End @@ -165,23 +171,22 @@ Class Deque Implements IContainer @return A deque iterator. #end Method All:Iterator() - - Return New Iterator( Self,_head ) + Return New Iterator( Self, _head ) End #rem wonkeydoc Converts the deque to an array. @return An array containing each element of the deque. #end Method ToArray:T[]() - - Local data:=New T[Length] - If _head<=_tail - _data.CopyTo( data,_head,0,Length ) + Local data := New T[Length] + + If _head <= _tail + _data.CopyTo( data, _head, 0, Length ) Else - Local n:=Capacity-_head - _data.CopyTo( data,_head,0,n ) - _data.CopyTo( data,0,n,_tail ) + Local n := _data.Length - _head + _data.CopyTo( data, _head, 0, n ) + _data.CopyTo( data, 0, n, _tail ) Endif Return data @@ -199,11 +204,12 @@ Class Deque Implements IContainer @param capacity The new capacity. #end Method Reserve( capacity:Int ) - DebugAssert( capacity>=0 ) - If Capacity>=capacity Return + DebugAssert( capacity >= 0 ) + + If _data.Length >= capacity Return - capacity=Max( Length*2+Length,capacity ) + capacity = Max( Length * 2 + Length, capacity ) Normalize( capacity ) End @@ -211,54 +217,55 @@ Class Deque Implements IContainer #rem wonkeydoc Clears the deque. #end Method Clear() - If _head<=_tail - For Local i:=_head Until _tail - _data[i]=Null + + If _head <= _tail + For Local i := _head Until _tail + _data[i] = Null Next Else - For Local i:=0 Until _tail - _data[i]=Null + For Local i := 0 Until _tail + _data[i] = Null Next - For Local i:=_head Until Capacity - _data[i]=Null + For Local i := _head Until _data.Length + _data[i] = Null Next Endif - _head=0 - _tail=0 + _head = 0 + _tail = 0 End #rem wonkeydoc Adds a value at the start of the deque. #end Method AddFirst( value:T ) - If Length+1=Capacity Reserve( Capacity+1 ) - - _head-=1 - If _head=-1 _head=Capacity-1 - _data[_head]=value + + If Length + 1 = _data.Length Reserve( _data.Length + 1 ) + + _head -= 1 + If _head = -1 _head = _data.Length - 1 + _data[_head] = value End #rem wonkeydoc Adds a value at the end of the deque. #end Method AddLast( value:T ) - If Length+1=Capacity Reserve( Capacity+1 ) - - _data[_tail]=value - _tail+=1 - If _tail=Capacity _tail=0 + + If Length + 1 = _data.Length Reserve( _data.Length + 1 ) + + _data[_tail] = value + _tail += 1 + If _tail = _data.Length _tail = 0 End #rem wonkeydoc @sugar Use [[AddFirst]] #end Method PushFirst( value:T ) - - AddFirst( value) + AddFirst( value ) End - + #rem wonkeydoc @sugar Use [[AddLast]] #end Method PushLast( value:T ) - - AddLast( value) + AddLast( value ) End #rem wonkeydoc Push a value into the deque, the deque do not growth. @@ -266,7 +273,8 @@ Class Deque Implements IContainer @since 2025-07-10 #end Method Push( value:T ) - If _data.Length=_data.Length + + If _data.Length = _data.Length '???? PopLast() End PushFirst( value ) @@ -276,12 +284,13 @@ Class Deque Implements IContainer In debug builds, a runtime error will occur if the deque is empty. #end Method RemoveFirst:T() - DebugAssert( Not Empty,"Illegal operation on empty deque" ) - - Local value:=_data[_head] - _data[_head]=Null - _head+=1 - If _head=Capacity _head=0 + + DebugAssert( Not Empty, "Illegal operation on empty deque" ) + + Local value := _data[_head] + _data[_head] = Null + _head += 1 + If _head = _data.Length _head = 0 Return value End @@ -289,26 +298,25 @@ Class Deque Implements IContainer In debug builds, a runtime error will occur if the deque is empty. #end Method RemoveLast:T() - DebugAssert( Not Empty,"Illegal operation on empty deque" ) - _tail-=1 - If _tail=-1 _tail=Capacity-1 - Local value:=_data[_tail] - _data[_tail]=Null + DebugAssert( Not Empty, "Illegal operation on empty deque" ) + + _tail -= 1 + If _tail = -1 _tail = _data.Length - 1 + Local value := _data[_tail] + _data[_tail] = Null Return value End #rem wonkeydoc @sugar use [[RemoveFirst]]. #end Method PopFirst:T() - Return RemoveFirst() End - + #rem wonkeydoc @sugar use [[RemoveLast]]. #end Method PopLast:T() - Return RemoveLast() End @@ -316,7 +324,8 @@ Class Deque Implements IContainer In debug builds, a runtime error will occur if the deque is empty. #end Method First:T() - DebugAssert( Not Empty,"Illegal operation on empty deque" ) + + DebugAssert( Not Empty, "Illegal operation on empty deque" ) Return _data[_head] End @@ -325,9 +334,10 @@ Class Deque Implements IContainer In debug builds, a runtime error will occur if the deque is empty. #end Method Last:T() - DebugAssert( Not Empty,"Illegal operation on empty deque" ) - Return _data[ _tail>0 ? _tail-1 Else Capacity-1 ] + DebugAssert( Not Empty, "Illegal operation on empty deque" ) + + Return _data[_tail > 0 ? _tail - 1 Else _data.Length - 1] End #rem wonkeydoc Gets the value of a deque element. @@ -335,19 +345,33 @@ Class Deque Implements IContainer or greater than or equal to the length of the deque. #end Method Get:T( index:Int ) - DebugAssert( index>=0 And index= 0 And index < Length, "Deque index out of range" ) + + Return _data[( index + _head ) Mod _data.Length] End #rem wonkeydoc Sets the value of a deque element. In debug builds, a runtime error will occur if `index` is less than 0, or greater than or equal to the length of the deque. #end - Method Set( index:Int,value:T ) - DebugAssert( index>=0 And index= 0 And index < Length, "Deque index out of range" ) + + _data[( index + _head ) Mod _data.Length] = value + End + + Operator To:String() + + Local tt := Typeof( _data[0] ) + Local _arr := Data + Local result := "Deque<" + tt + ">[ " + For Local i := 0 Until Length + If i > 0 result += ", " + result += _arr[( i + _head ) Mod _data.Length] + Next + Return result + " ]" End #rem wonkeydoc Gets the value of a deque element. @@ -355,19 +379,21 @@ Class Deque Implements IContainer or greater than or equal to the length of the deque. #end Operator[]:T( index:Int ) - DebugAssert( index>=0 And index= 0 And index < Length, "Deque index out of range" ) - Return _data[ (index+_head) Mod Capacity ] + Return _data[( index + _head ) Mod _data.Length] End #rem wonkeydoc Sets the value of a deque element. In debug builds, a runtime error will occur if `index` is less than 0, or greater than or equal to the length of the deque. #end - Operator[]=( index:Int,value:T ) - DebugAssert( index>=0 And index= 0 And index < Length, "Deque index out of range" ) - _data[ (index+_head) Mod Capacity ]=value + _data[( index + _head ) Mod _data.Length] = value End 'iDkP's Note: diff --git a/modules/std/collections/list.wx b/modules/std/collections/list.wx index 77b8ee1b..a2feb19e 100644 --- a/modules/std/collections/list.wx +++ b/modules/std/collections/list.wx @@ -23,37 +23,39 @@ This connection between elements is achieved using separate Node objects (there Lists implements the [[IContainer]] interface so can be used with Eachin loops. #end Class List Implements IContainer - + #rem wonkeydoc The List.Node class. #end Class Node - + Private - + Field _succ:Node Field _pred:Node Field _value:T Public - + #rem wonkeydoc Creates a new node not in any list. #end Method New( value:T ) - _value=value - _succ=Self - _pred=Self + + _value = value + _succ = Self + _pred = Self End #rem wonkeydoc Creates a new node with the given successor node. Warning! No error checking is performed! This method should not be used while iterating over the list containing `succ`. #end - Method New( value:T,succ:Node ) - _value=value - _succ=succ - _pred=succ._pred - _pred._succ=Self - succ._pred=Self + Method New( value:T, succ:Node ) + + _value = value + _succ = succ + _pred = succ._pred + _pred._succ = Self + succ._pred = Self End #rem wonkeydoc Gets the node after this node. @@ -67,7 +69,7 @@ Class List Implements IContainer Property Pred:Node() Return _pred End - + #rem wonkeydoc Gets the value contained in this node. #end Property Value:T() @@ -81,82 +83,88 @@ Class List Implements IContainer This method should not be used while iterating over the list containing this node. #end Method Remove() - If _succ._pred<>Self Or _pred._succ<>Self Return - _succ._pred=_pred - _pred._succ=_succ + + If _succ._pred <> Self Or _pred._succ <> Self Return + _succ._pred = _pred + _pred._succ = _succ End #rem wonkeydoc Inserts the node before another node. If the node is already in a list, it is removed before insertion. This method should not be used while iterating over the list containing this node or `node`. #end - Method InsertBefore( node:Node ) Virtual + Method InsertBefore( node:Node ) Virtual + Remove() 'insert - _succ=node - _pred=node._pred - _pred._succ=Self - node._pred=Self + _succ = node + _pred = node._pred + _pred._succ = Self + node._pred = Self End #rem wonkeydoc Inserts the node after another node. If the node is already in a list, it is removed before insertion. This method should not be used while iterating over the list containing this node or `node`. #end - Method InsertAfter( node:Node ) Virtual + Method InsertAfter( node:Node ) Virtual + Remove() 'insert - _pred=node - _succ=node._succ - _succ._pred=Self - node._succ=Self + _pred = node + _succ = node._succ + _succ._pred = Self + node._succ = Self End End #rem wonkeydoc The List.Iterator struct. #end Struct Iterator - + Private - + Field _list:List Field _node:Node Method AssertCurrent() - DebugAssert( _node<>_list._head,"Invalid list iterator" ) + DebugAssert( _node <> _list._head, "Invalid list iterator" ) End Public #rem wonkeydoc Creates a new iterator. #end - Method New( list:List,node:Node ) - _list=list - _node=node + Method New( list:List, node:Node ) + + _list = list + _node = node End - + #rem wonkeydoc Checks whether the iterator has reached the end of the list. #end Property AtEnd:Bool() - Return _node=_list._head + Return _node = _list._head End #rem wonkeydoc The value contained in the node pointed to by the iterator. #end Property Current:T() + AssertCurrent() Return _node._value - Setter( current:T ) + AssertCurrent() - _node._value=current + _node._value = current End #rem wonkeydoc Bumps the iterator so it points to the next node in the list. #end Method Bump() + AssertCurrent() - _node=_node._succ + _node = _node._succ End #rem wonkeydoc Safely erases the node referenced by the iterator. @@ -165,8 +173,9 @@ Class List Implements IContainer will end up skipping a node. #end Method Erase() + AssertCurrent() - _node=_node._succ + _node = _node._succ _node._pred.Remove() End @@ -174,54 +183,58 @@ Class List Implements IContainer After calling this method, the iterator will point to the newly added node. #end Method Insert( value:T ) - _node=New Node( value,_node ) + _node = New Node( value, _node ) End + End #rem wonkeydoc The List.BackwardsIterator struct. #end Struct BackwardsIterator - + Private - + Field _list:List Field _node:Node Method AssertCurrent() - DebugAssert( _node<>_list._head,"Invalid list iterator" ) + DebugAssert( _node <> _list._head, "Invalid list iterator" ) End Public #rem wonkeydoc Creates a new iterator. #end - Method New( list:List,node:Node ) + Method New( list:List, node:Node ) + _list=list _node=node End - + #rem wonkeydoc Checks whether the iterator has reached the end of the list. #end Property AtEnd:Bool() - Return _node=_list._head + Return _node = _list._head End #rem wonkeydoc The value contained in the node pointed to by the iterator. #end Property Current:T() + AssertCurrent() Return _node._value - Setter( current:T ) + AssertCurrent() - _node._value=current + _node._value = current End #rem wonkeydoc Bumps the iterator so it points to the next node in the list. #end Method Bump() + AssertCurrent() - _node=_node._pred + _node = _node._pred End #rem wonkeydoc Safely erases the node referenced by the iterator. @@ -230,8 +243,9 @@ Class List Implements IContainer will end up skipping a node. #end Method Erase() + AssertCurrent() - _node=_node._pred + _node = _node._pred _node._succ.Remove() End @@ -239,8 +253,9 @@ Class List Implements IContainer After calling this method, the iterator will point to the newly added node. #end Method Insert( value:T ) - _node=New Node( value,_node._succ ) + _node = New Node( value, _node._succ ) End + End Private @@ -257,9 +272,9 @@ Class List Implements IContainer @param values An existing array, list or stack. #end Method New() - _head=New Node( Null ) + _head = New Node( Null ) End - + Method New( values:T[] ) Self.New() AddAll( values ) @@ -280,29 +295,30 @@ Class List Implements IContainer @return A list iterator. #end Method All:Iterator() - Return New Iterator( Self,_head._succ ) + Return New Iterator( Self, _head._succ ) End - + #rem wonkeydoc Gets an iterator for visiting list values in reverse order. Returns an iterator suitable for use with Eachin, or for manual iteration. @return A backwards list iterator. #end Method Backwards:BackwardsIterator() - Return New BackwardsIterator( Self,_head._pred ) + Return New BackwardsIterator( Self, _head._pred ) End #rem wonkeydoc Checks whether the list is empty. @return True if the list is empty. #end Property Empty:Bool() - Return _head._succ=_head + Return _head._succ = _head End - + #rem wonkeydoc Gets the first value in the list. In debug builds, a runtime error will occur if the list is empty. @return The first value in the list. #end Property First:T() + DebugAssert( Not Empty ) Return _head._succ._value @@ -313,6 +329,7 @@ Class List Implements IContainer @return The last value in the list. #end Property Last:T() + DebugAssert( Not Empty ) Return _head._pred._value @@ -330,9 +347,9 @@ Class List Implements IContainer ' ' Return true if the list has one item (no more) ' - Return _head._succ=_head ? ( _head._succ<>_head._pred ? True Else False ) Else False + Return _head._succ = _head ? ( _head._succ <> _head._pred ? True Else False ) Else False End - + #rem wonkeydoc Test if the list has exactly two elements @author iDkP from GaragePixel @since 2025-05-11 @@ -343,9 +360,9 @@ Class List Implements IContainer ' ' Return true if the list has two items (no more) ' - Return _head._succ=_head ? ( _head._succ=_head._pred ? True Else False ) Else False + Return _head._succ = _head ? ( _head._succ = _head._pred ? True Else False ) Else False End - + #rem wonkeydoc Test if the list has one or two elements @author iDkP from GaragePixel @since 2025-05-11 @@ -368,7 +385,7 @@ Class List Implements IContainer ' Return HasOne ? 1 Else ( HasTwo ? 2 Else ( Empty ? -1 Else 0 ) ) End - + #rem wonkeydoc Returns if the list has less than n items. Note: This method can be slow when used with large lists, as it must visit each value. @author iDkP from GaragePixel @@ -378,12 +395,13 @@ Class List Implements IContainer @return True if the list has less items than nbItems' value. #end Method HasLess:Bool( nbItems:UInt ) - Local node:=_head._succ,n:=0 - While node<>_head Or n _head Or n < nbItems + node = node._succ + n += 1 Wend - Return n Implements IContainer @return True if the list has more items than nbItems' value. #end Method HasMore:Bool( nbItems:UInt ) - Local result:Bool=True - Local node:=_head._succ,n:=0 - While node<>_head - node=node._succ - If n>nbItems - result=False - Exit - End - n+=1 + + Local result:Bool = True + Local node := _head._succ, n := 0 + While node <> _head + node = node._succ + If n > nbItems + result = False + Exit + End + + n += 1 Wend Return result End - + '---- iDkP added: To:Map, ToMapUByte, ToMapShort, ToMapInt ---- #rem wonkeydoc Cast the list intro a map where the map's key are the list's elements. @@ -423,15 +443,15 @@ Class List Implements IContainer 'Let's say, alternated version, where the list item become the map key '(map as a set: only one occurance accepted) ' - Local map:=New Map() - Local offset:UInt=0 - For Local item:=Eachin Self - map.Set(item,offset) - offset+=1 - End + Local map := New Map() + Local offset:UInt = 0 + For Local item := Eachin Self + map.Set( item, offset ) + offset += 1 + Next Return map End - + #rem wonkeydoc Cast the list intro a map where the map's key are the list's elements. @author iDkP from GaragePixel @since 2025-05-11 @@ -441,7 +461,7 @@ Class List Implements IContainer @param populateWithIdx if True, the map's values will be populated with a index in the range 0,255. @return The new map as Map #end - Method ToMapUByte:Map( defValue:Bool=Null, populateWithIdx:Bool=False ) + Method ToMapUByte:Map( defValue:Bool = Null, populateWithIdx:Bool = False ) ' ' Let's say, alternated version, where the list item become the map key ' Special version with lighter memory print, @@ -453,18 +473,19 @@ Class List Implements IContainer https://discord.com/channels/796336780302876683/850292419781459988/1371074708933574756 #end ' - Local map:=New Map() + Local map := New Map() If populateWithIdx - Local offset:UByte=0 - For Local item:=Eachin Self - map.Set(item,offset) - offset+=1 - End + Local offset:UByte = 0 + For Local item := Eachin Self + map.Set( item, offset ) + offset += 1 + Next Else For Local item:=Eachin Self - map.Set(item,defValue) - End - End + map.Set( item, defValue ) + Next + End + Return map End @@ -505,10 +526,11 @@ Class List Implements IContainer @return The number of values in the list. #end Method Count:Int() 'iDkP: SIGNED 32 bits! - Local node:=_head._succ,n:=0 - While node<>_head - node=node._succ - n+=1 + + Local node := _head._succ, n := 0 + While node <> _head + node = node._succ + n += 1 Wend Return n End @@ -519,20 +541,34 @@ Class List Implements IContainer Method ToArray:T[]() ' Updated by iDkP 'iDkP: Pseudo operator, deprecated ' Return Self - Local n:=Count() - Local data:=New T[n],node:=_head._succ - For Local i:=0 Until n - data[i]=node._value - node=node._succ + Local n := Count() + Local data := New T[n], node := _head._succ + For Local i := 0 Until n + data[i] = node._value + node = node._succ Next Return data End + Operator To:String() Where T Implements INumeric Or T=String + + Local tt := Typeof( _head._value ) + Local idx := 0 + Local result := "List<" + tt + ">[ " + For Local i := Eachin Self + If idx > 0 result += ", " + result += i + idx += 1 + Next + Return result + " ]" + End + #rem wonkeydoc Removes all values from the list. #end Method Clear() - _head._succ=_head - _head._pred=_head + + _head._succ = _head + _head._pred = _head End #rem wonkeydoc Adds a value to the start of the list. @@ -540,7 +576,8 @@ Class List Implements IContainer @return A new node containing the value. #end Method AddFirst:Node( value:T ) - Local node:=New Node( value,_head._succ ) + + Local node := New Node( value, _head._succ ) Return node End @@ -549,7 +586,8 @@ Class List Implements IContainer @return A new node containing the value. #end Method AddLast:Node( value:T ) - Local node:=New Node( value,_head ) + + Local node := New Node( value, _head ) Return node End @@ -558,7 +596,8 @@ Class List Implements IContainer @return True if a value was removed. #end Method Remove:Bool( value:T ) - Local node:=FindNode( value ) + + Local node := FindNode( value ) If Not node Return False node.Remove() Return True @@ -569,7 +608,8 @@ Class List Implements IContainer @return True if a value was removed. #end Method RemoveLast:Bool( value:T ) - Local node:=FindLastNode( value ) + + Local node := FindLastNode( value ) If Not node Return False node.Remove() Return True @@ -580,14 +620,15 @@ Class List Implements IContainer @return The number of values removed. #end Method RemoveEach:Int( value:T ) - Local node:=_head._succ,n:=0 - While node<>_head - If node._value=value - node=node._succ + + Local node := _head._succ, n := 0 + While node <> _head + If node._value = value + node = node._succ node._pred.Remove() - n+=1 + n += 1 Else - node=node._succ + node = node._succ End Wend Return n @@ -598,12 +639,13 @@ Class List Implements IContainer @return The number of values removed. #end Method RemoveIf:Int( condition:Bool( value:T ) ) - Local node:=_head._succ,n:=0 - While node<>_head + + Local node := _head._succ, n := 0 + While node <> _head If condition( node._value ) - node=node._succ + node = node._succ node._pred.Remove() - n+=1 + n += 1 Else node=node._succ End @@ -619,7 +661,7 @@ Class List Implements IContainer DebugAssert( Not Empty ) - Local value:=_head._succ._value + Local value := _head._succ._value _head._succ.Remove() Return value End @@ -632,7 +674,7 @@ Class List Implements IContainer DebugAssert( Not Empty ) - Local value:=_head._pred._value + Local value := _head._pred._value _head._pred.Remove() Return value End @@ -650,13 +692,15 @@ Class List Implements IContainer @param values The values to add. #end Method AddAll( values:T[] ) - For Local value:=Eachin values + + For Local value := Eachin values AddLast( value ) Next End - + Method AddAll( values:C ) Where C Implements IContainer - For Local value:=Eachin values + + For Local value := Eachin values AddLast( value ) Next End @@ -665,86 +709,85 @@ Class List Implements IContainer @param ascending True to sort the stack in ascending order, false to sort in descending order. @param compareFunc Function to be used to compare values when sorting. #end - Method Sort( ascending:Int=True ) - + Method Sort( ascending:Int = True ) + If ascending - Sort( Lambda:Int( x:T,y:T ) - Return x<=>y + Sort( Lambda:Int( x:T, y:T ) + Return x <=> y End ) Else - Sort( Lambda:Int( x:T,y:T ) - Return -(x<=>y) + Sort( Lambda:Int( x:T, y:T ) + Return y <=> x End ) End + End - Method Sort( compareFunc:Int( x:T,y:T ),filter:SortFilter=Null ) - - Local insize:=1 + Method Sort( compareFunc:Int( x:T, y:T ), filter:SortFilter = Null ) - Repeat + Local insize := 1 - Local merges:=0 - Local tail:=_head - Local p:=_head._succ - - While p<>_head - merges+=1 - Local q:=p._succ,qsize:=insize,psize:=1 + Repeat + Local merges := 0 + Local tail := _head + Local p := _head._succ + + While p <> _head + merges += 1 + Local q := p._succ, qsize := insize, psize := 1 - While psize_head - psize+=1 - q=q._succ + While psize < insize And q <> _head + psize += 1 + q = q._succ Wend - + Repeat Local t:Node - If psize And qsize And q<>_head - Local cc:=compareFunc( p._value,q._value ) - If cc<=0 - t=p - p=p._succ - psize-=1 + If psize And qsize And q <> _head + Local cc := compareFunc( p._value, q._value ) + If cc <= 0 + t = p + p = p._succ + psize -= 1 Else - t=q - q=q._succ - qsize-=1 - End + t = q + q = q._succ + qsize -= 1 + Endif Else If psize - t=p - p=p._succ - psize-=1 - Else If qsize And q<>_head - t=q - q=q._succ - qsize-=1 + t = p + p = p._succ + psize -= 1 + Else If qsize And q <> _head + t = q + q = q._succ + qsize -= 1 Else Exit Endif - t._pred=tail - tail._succ=t - tail=t + t._pred = tail + tail._succ = t + tail = t Forever - p=q + p = q Wend - tail._succ=_head - _head._pred=tail - - If merges<=1 Return - - insize*=2 + tail._succ = _head + _head._pred = tail + + If merges <= 1 Return + + insize *= 2 Forever - End #rem wonkeydoc Joins the values in the string list. @param sepeator The separator to be used when joining values. @return The joined values. #end - Method Join:String( separator:String="" ) Where T=String + Method Join:String( separator:String = "" ) Where T=String Return separator.Join( ToArray() ) End - + #rem wonkeydoc Reverses the order of values in the list. @author iDkP from GaragePixel @since 2025-06-18 @@ -752,6 +795,7 @@ Class List Implements IContainer @return The reversed list (self if in-place, new List if not). #end Method Reverse:List( onPlace:Bool=True ) + Local lst:List = onPlace ? Self Else New List( Self ) Local leftNode:Node = lst._head._succ Local rightNode:Node = lst._head._pred @@ -762,7 +806,7 @@ Class List Implements IContainer rightNode._value = temp leftNode = leftNode._succ rightNode = rightNode._pred - End + Next Return lst End @@ -791,7 +835,7 @@ Class List Implements IContainer If Not Empty Return _head._pred Return Null End - + #rem wonkeydoc Gets the first node in the list. @author iDkP from GragePixel @return The first node in the list, or null if the list is empty. @@ -817,10 +861,11 @@ Class List Implements IContainer @return The first node containing the value, or null if the value was not found. #end Method FindNode:Node( value:T ) - Local node:=_head._succ - While node<>_head - If node._value=value Return node - node=node._succ + + Local node := _head._succ + While node <> _head + If node._value = value Return node + node = node._succ Wend Return Null End @@ -830,14 +875,15 @@ Class List Implements IContainer @return The last node containing the value, or null if the value was not found. #end Method FindLastNode:Node( value:T ) - Local node:=_head._pred - While node<>_head - If node._value=value Return node - node=node._pred + + Local node := _head._pred + While node <> _head + If node._value = value Return node + node = node._pred Wend Return Null End - + #rem wonkeydoc Return a copy of the list @return Copy of the list #end @@ -864,17 +910,17 @@ Class List Implements IContainer #rem wonkeydoc Same than AddFirst, but return nothing. @param value The value to add to the list. #end - Method Enqueue(n:T) - AddFirst(n) + Method Enqueue( n:T ) + AddFirst( n ) End - + #rem wonkeydoc Same than RemoveFirst, but return nothing. @param value The value to add to the list. #end Method Dequeue:T() Return RemoveFirst() End - + '---------------------------------------------- ' Mini-library: Set (math) functions with List ' 2025-05-10 - Added by iDkP from GaragePixel @@ -919,45 +965,45 @@ Class List Implements IContainer @param onPlace If False, return a copy of the List @return Copy of the list or Null #end - Method Dedup:List( onPlace:Bool=True ) + Method Dedup:List( onPlace:Bool = True ) ' ' Note: ' "Dedup" for "Deduplicate" ' - Local currList:= onPlace ? Self Else Copy() + Local currList := onPlace ? Self Else Copy() - Local atLeastTwo:=currList.HasOneOrTwo - If atLeastTwo=1 Return currList + Local atLeastTwo := currList.HasOneOrTwo + If atLeastTwo = 1 Return currList - Local firstNode:List.Node=currList.FirstNode - - If atLeastTwo=2 - If firstNode.Value=firstNode.Succ.Value firstNode.Succ.Remove() + Local firstNode:List.Node = currList.FirstNode + + If atLeastTwo = 2 + If firstNode.Value = firstNode.Succ.Value firstNode.Succ.Remove() Return currList - End + Endif - Local seen:= New Map 'We don't care of anything but the red-black tree algorithm, + Local seen := New Map 'We don't care of anything but the red-black tree algorithm, 'so we use the most little datatype: Ubyte for the smallest memory print: 'Using UByte (1 or 0) is more memory-efficient as it consumes only 1 byte per entry 'compared to Null which takes 4-8 bytes on most platforms, 'plus UByte avoids reference-related overhead and GC pressure. - Local current:= _head._succ + Local current := _head._succ While current <> _head - Local foo:= current._succ - If seen.Contains(current._value) + Local foo := current._succ + If seen.Contains( current._value ) ' Remove duplicate current.Remove() Else ' Mark as seen - seen.Set(current._value, 1) - End + seen.Set( current._value, 1 ) + Endif current = foo Wend 'Return currList 'Let's say, for consistancy within the library, that we returns 'Null' if OnPlace Return onPlace ? Null Else currList End - + #rem wonkeydoc Finds the first node in the list containing a value. @author iDkP from GaragePixel @since 2025-05-10 @@ -966,16 +1012,22 @@ Class List Implements IContainer #end Method Contains:Node( value:T ) 'Added by iDkP from GaragePixel 'iDkP: Added as sugar for consistance with map - Return FindNode(value) + Return FindNode( value ) End - + + #rem Contains should return a boolean + Method Contains:Bool( value:T ) + Return FindNode( value ) <> Null + End + #end + #rem wonkeydoc Add each keys from this (param) to self @author iDkP from GaragePixel @since 2025-05-10 @param This is the list to compare. @param onPlace if False, returns a copy of the list, else nothing #end - Method Append:List( this:List, onPlace:Bool=True ) 'Added by iDkP from GaragePixel + Method Append:List( this:List, onPlace:Bool = True ) 'Added by iDkP from GaragePixel ' ' Semi-sugar ' @@ -984,14 +1036,14 @@ Class List Implements IContainer ' Achieves 33 million elements/second for 100K elements ' If onPlace - AddAll(this) + AddAll( this ) Return Null - End - Local result:=Copy() - result.AddAll(this) + Endif + Local result := Copy() + result.AddAll( this ) Return result End - + #rem wonkeydoc Add each item from this (param) that exist in self. @author iDkP from GaragePixel @since 2025-05-10 @@ -1002,7 +1054,7 @@ Class List Implements IContainer @param This The list to compare. @param onPlace if False, returns a copy of the list, else nothing #end - Method Union:List( this:List,onPlace:Bool=True ) 'Added by iDkP from GaragePixel + Method Union:List( this:List, onPlace:Bool = True ) 'Added by iDkP from GaragePixel ' ' Description: ' Add this to self, do not keep duplicates in the output list. @@ -1022,11 +1074,11 @@ Class List Implements IContainer AddAll( this ) Dedup() Return Null - End + Endif '------------------------- "returns a copy of the list" Version - Local result:=Copy() + Local result := Copy() result.AddAll( this ) result.Dedup() Return result @@ -1038,40 +1090,39 @@ Class List Implements IContainer @param This is the list to compare. @param onPlace if False, returns a copy of the list, else nothing #end - Method Intersect:List( this:List, onPlace:Bool=True ) 'Added by iDkP from GaragePixel + Method Intersect:List( this:List, onPlace:Bool = True ) 'Added by iDkP from GaragePixel ' ' Keep in self the keys that exist in this ' ' Note: ' Statut implementation: Approach theorical limits for hash-based set operations - Local map:=ToMapUByte() - Local otherMap:=this.ToMapUByte() - Local result:=New List() + Local map := ToMapUByte() + Local otherMap := this.ToMapUByte() + Local result := New List() ' Add only items that exist in both lists Local itemKey:T 'memoirize -> small earned micro-seconds - For Local item:= Eachin map - itemKey=item.Key - If otherMap.Contains(itemKey) - result.Add(itemKey) - End - End - If onPlace - _head=result._head + For Local item := Eachin map + itemKey = item.Key + If otherMap.Contains( itemKey ) + result.Add( itemKey ) + Endif + Next + If onPlace + _head = result._head Return Null - End - + Endif Return result End - + #rem wonkeydoc Remove all keys from self that exist in this (param) @author iDkP from GaragePixel @since 2025-05-12 @param This is the list to compare. @param onPlace if False, returns a copy of the list, else nothing #end - Method Diff:List( this:List, onPlace:Bool=True ) 'Added by iDkP from GaragePixel + Method Diff:List( this:List, onPlace:Bool = True ) 'Added by iDkP from GaragePixel ' ' Remove all keys from self that exist in this ' @@ -1081,23 +1132,23 @@ Class List Implements IContainer ' while maintaining throughput in the 495K-813K elements/second range ' for large collections. - Local map:=ToMapUByte() - Local otherMap:=this.ToMapUByte() - Local result:=New List() + Local map := ToMapUByte() + Local otherMap := this.ToMapUByte() + Local result := New List() ' Add only items that do not exist in the same time in both lists Local itemKey:T 'memoirize -> small earned micro-seconds - For Local item:= Eachin map - itemKey=item.Key + For Local item := Eachin map + itemKey = item.Key If Not otherMap.Contains(itemKey) result.Add(itemKey) - End - End - If onPlace + Endif + Next + If onPlace _head=result._head Return Null - End - + Endif Return result - End + End + End diff --git a/modules/std/collections/map.wx b/modules/std/collections/map.wx index e4fb913c..11723a62 100644 --- a/modules/std/collections/map.wx +++ b/modules/std/collections/map.wx @@ -49,7 +49,7 @@ Version (2025-07-04) note (iDkP): #end Class Map - + 'iDkP from GaragePixel's note: ' ' New implementation of Map using hint strategy, pointer usage and ubytes @@ -103,7 +103,7 @@ Class Map #rem wonkeydoc The map Node class. #end Class Node - + #rem wonkeydoc Gets the key contained in the node. @return The node's key. #end @@ -117,78 +117,82 @@ Class Map Property Value:V() Return _value Setter( value:V ) - _value=value + _value = value End - + Private - + Field _key:K Field _value:V Field _color:UByte 'Modified by iDkP Field _left:Node Field _right:Node Field _parent:Node - - Method New( key:K,value:V,color:UByte,parent:Node ) - _key=key - _value=value - _color=color - _parent=parent + + Method New( key:K, value:V, color:UByte, parent:Node ) + + _key = key + _value = value + _color = color + _parent = parent End Method Count:Int( n:Int ) 'iDkP: 32 bits! - If _left n=_left.Count( n ) - If _right n=_right.Count( n ) - Return n+1 + + If _left n = _left.Count( n ) + If _right n = _right.Count( n ) + Return n + 1 End - + Method NextNode:Node() + If _right - Local node:=_right + Local node := _right While node._left - node=node._left + node = node._left Wend Return node Endif - Local node:=Self,parent:=_parent - While parent And node=parent._right - node=parent - parent=parent._parent + Local node := Self, parent := _parent + While parent And node = parent._right + node = parent + parent = parent._parent Wend Return parent End Method PrevNode:Node() + If _left - Local node:=_left + Local node := _left While node._right - node=node._right + node = node._right Wend Return node Endif - Local node:=Self,parent:=_parent - While parent And node=parent._left - node=parent - parent=parent._parent + Local node := Self, parent := _parent + While parent And node = parent._left + node = parent + parent = parent._parent Wend Return parent End Method Copy:Node( parent:Node ) - Local node:=New Node( _key,_value,_color,parent ) - If _left node._left=_left.Copy( node ) - If _right node._right=_right.Copy( node ) + Local node := New Node( _key, _value, _color, parent ) + If _left node._left = _left.Copy( node ) + If _right node._right = _right.Copy( node ) Return node End - + End Struct Iterator Property AtEnd:Bool() - Return _node=Null + Return _node = Null End - + Property Valid:Bool() Return _node End @@ -198,7 +202,7 @@ Class Map End Method Bump() - _node=_node.NextNode() + _node = _node.NextNode() End Private @@ -206,17 +210,17 @@ Class Map Field _node:Node Method New( node:Node ) - _node=node + _node = node End End Struct KeyIterator - + Property AtEnd:Bool() - Return _node=Null + Return _node = Null End - + Property Valid:Bool() Return _node End @@ -226,7 +230,7 @@ Class Map End Method Bump() - _node=_node.NextNode() + _node = _node.NextNode() End Private @@ -240,11 +244,11 @@ Class Map End Struct ValueIterator - + Property AtEnd:Bool() - Return _node=Null + Return _node = Null End - + Property Valid:Bool() Return _node End @@ -254,7 +258,7 @@ Class Map End Method Bump() - _node=_node.NextNode() + _node = _node.NextNode() End Private @@ -262,13 +266,13 @@ Class Map Field _node:Node Method New( node:Node ) - _node=node + _node = node End End Struct MapKeys - + Method All:KeyIterator() Return New KeyIterator( _map.FirstNode ) 'Modified by iDkP End @@ -278,13 +282,13 @@ Class Map Field _map:Map Method New( map:Map ) - _map=map + _map = map End End Struct MapValues - + Method All:ValueIterator() Return New ValueIterator( _map.FirstNode ) 'Modified by iDkP End @@ -294,7 +298,7 @@ Class Map Field _map:Map Method New( map:Map ) - _map=map + _map = map End End @@ -328,12 +332,12 @@ Class Map K=Int Or K=Float Or K=Short Or K=Long Or K=Double Or K=Bool Or K=Variant - Local len:=keys.Length - For Local k:=0 Until len - Add(keys[k],prefilled) + Local len := keys.Length + For Local k := 0 Until len + Add( keys[k], prefilled ) End End - + #rem wonkeydoc Creates a new prefilled map with keys and values from pointed arrays. @author iDkP from GaragePixel @since 2025-06-20 @@ -372,21 +376,21 @@ Class Map Method New( keys:K[], values:V[] ) Where (K=Object Or K=String Or K=Int Or K=Float Or K=Short Or K=Long Or K=Double Or K=Bool Or K=Variant) And (V=Object Or V=String Or V=Int Or V=Float Or V=Short Or V=Long Or V=Double Or V=Bool Or V=Variant) - Local klen:=keys.Length - Local vlen:=values.Length - If klen>vlen + Local klen := keys.Length + Local vlen := values.Length + If klen > vlen Local k:Int - For k=0 Until vlen - Add(keys[k],values[k]) - End - For k=vlen Until klen - Add(keys[k],values[vlen-1]) - End + For k = 0 Until vlen + Add( keys[k], values[k] ) + Next + For k = vlen Until klen + Add( keys[k], values[vlen - 1] ) + Next Else For Local k:=0 Until klen - Add(keys[k],values[k]) - End - End + Add( keys[k], values[k] ) + Next + Endif End #rem wonkeydoc Creates a new indexed map with values from an array. @@ -414,12 +418,12 @@ Class Map (V=Object Or V=String Or V=Int Or V=Float Or V=Short Or V=Long Or V=Double Or V=Bool Or V=Variant) And K=Int '32 bits! - Local vlen:=values.Length - For Local k:=0 Until vlen - Add(k,values[k]) - End + Local vlen := values.Length + For Local k := 0 Until vlen + Add( k, values[k] ) + Next End - + #rem wonkeydoc Creates a new map from interleaved key-value pairs (variant array). @author iDkP from GaragePixel @since 2025-06-27 @@ -435,14 +439,14 @@ Class Map (K=Object Or K=String Or K=Int Or K=Float Or K=Short Or K=Long Or K=Double Or K=Bool Or K=Variant) And (V=Object Or V=String Or V=Int Or V=Float Or V=Short Or V=Long Or V=Double Or V=Bool Or V=Variant) - Assert((k.Length Mod 2) = 0,"Pair missing: array length must be even.") - Local len:=k.Length/2 + Assert( ( k.Length Mod 2 ) = 0, "Pair missing: array length must be even." ) + Local len := k.Length / 2 - For Local i:=0 Until len+2 Step 2 - Add(Cast(k[i]),Cast(k[i+1])) + For Local i := 0 Until len + 2 Step 2 + Add( Cast( k[i] ), Cast(k[i + 1])) Next End - + #rem wonkeydoc Creates a new map from interleaved key-value pairs (variant array). @author iDkP from GaragePixel @since 2025-06-27 @@ -526,10 +530,10 @@ Class Map K=Short Or K=Long Or K=Double Or K=Bool Or K=Variant Clear() - Local this:=New Map(keys,values) - Self._root=this._root + Local this := New Map( keys, values ) + Self._root = this._root End - + #rem wonkeydoc Resets a new prefilled map with keys and values created from pointed arrays. @author iDkP from GaragePixel @since 2025-07-02 @@ -548,8 +552,8 @@ Class Map (K=Object Or K=String Or K=Int Or K=Float Or K=Short Or K=Long Or K=Double Or K=Bool Or K=Variant) And (V=Object Or V=String Or V=Int Or V=Float Or V=Short Or V=Long Or V=Double Or V=Bool Or V=Variant) Clear() - Local this:=New Map(keys,values) - Self._root=this._root + Local this := New Map( keys, values ) + Self._root = this._root End #rem @@ -582,35 +586,21 @@ Class Map Self._root=this._root End #end - #rem wonkeydoc Output an string from the data (map as string or numerical types) - @author iDkP from GaragePixel - @since 2025-06-13 - @version 2025-06-30 - Note: If the key or the value are from the Variant type, the element emits "?????" in the string. - stdlib.collections.Map' to type 'monkey.types.String - Note: - The output is automatically sorted according the keys. - For example: - {[one][1]} - {[three][3]} - {[two][2]} - #end - Method To:String() Where - (K=String Or K=Int Or K=Float Or K=Short Or K=Long Or K=Double Or K=Bool Or K=Variant) And - (V=String Or V=Int Or V=Float Or V=Short Or V=Long Or V=Double Or V=Bool Or V=Variant) - 'Patch to fix the casting issue without importing the entire stdlib. TODO: To undone after integrating the types minilib. - local __Variant__:Variant,__t_variant__ :=Typeof(__Variant__) - Local result:String - Local iv:String,ik:String - For Local item:=Eachin Self - iv = Typeof(item.Value)=__t_variant__ ? "?????" Else Cast(item.Value) - ik = Typeof(item.Key)=__t_variant__ ? "?????" Else Cast(item.Key) - result+="{["+ik+"]["+iv+"]}~n" - End - Return result + Operator To:String() Where (K Implements INumeric Or K=String) And (V Implements INumeric Or V=String) + + Local tk := Typeof( _root._key ) + Local tv := Typeof( _root._value ) + Local res := "Map<" + tk + "," + tv + ">{ " + Local idx := 0 + For Local i := Eachin Self + If idx > 0 res += ", " + res += i.Key + ": " + i.Value + idx += 1 + Next + Return res + " }" End - + #rem wonkeydoc Output an verbose string from the data (map as string or numerical types) @author iDkP from GaragePixel @since 2025-06-13 @@ -622,19 +612,19 @@ Class Map (V=String Or V=Int Or V=Float Or V=Short Or V=Long Or V=Double Or V=Bool Or V=Variant) 'Patch to fix the casting issue without importing the entire stdlib. TODO: To undone after integrating the types minilib. - local __Variant__:Variant,__t_variant__ :=Typeof(__Variant__) + local __Variant__:Variant, __t_variant__ :=Typeof( __Variant__ ) - Local result:String="map[~n" - Local iv:String,ik:String - For Local item:=Eachin Self - iv = Typeof(item.Value)=__t_variant__ ? "?????" Else Cast(item.Value) - ik = Typeof(item.Key)=__t_variant__ ? "?????" Else Cast(item.Key) + Local result:String = "map[~n" + Local iv:String, ik:String + For Local item := Eachin Self + iv = Typeof( item.Value ) = __t_variant__ ? "?????" Else Cast( item.Value ) + ik = Typeof( item.Key ) = __t_variant__ ? "?????" Else Cast( item.Key ) result+="{["+ik+"]["+iv+"]}~n" End - result=result.Left(result.Length-2)+"]" + result = result.Left( result.Length - 2 ) + "]" Return result End - + #rem wonkeydoc Gets a node iterator. #end Method All:Iterator() @@ -648,7 +638,7 @@ Class Map Property Keys:MapKeys() Return New MapKeys( Self ) End - + #rem wonkeydoc Gets a view of the map's values. The returned value can be used with an Eachin loop to iterate over the map's values. @return A MapValues object. @@ -661,21 +651,23 @@ Class Map @return A new map. #end Method Copy:Map() + Local root:Node - If _root root=_root.Copy( Null ) + If _root root = _root.Copy( Null ) Return New Map( root ) End #rem wonkeydoc Removes all keys from the map. #end Method Clear() - _root=Null + _root = Null End #rem wonkeydoc Gets the number of keys in the map. @return The number of keys in the map. #end Method Count:Int() 'iDkP: UNSIGNED 32 bits! + If Not _root Return 0 Return _root.Count( 0 ) End @@ -684,15 +676,15 @@ Class Map @return True if the map is empty. #end Property Empty:Bool() - Return _root=Null + Return _root = Null End - + #rem wonkeydoc Checks if the map contains a given key. @param key The key to check for. @return True if the map contains the key. #end Method Contains:Bool( key:K ) - Return FindNode( key )<>Null + Return FindNode( key ) <> Null End #rem wonkeydoc Sets the value associated with a key in the map. @@ -703,8 +695,8 @@ Class Map @param value The value. @return True if a new node was added to the map. #end - Operator[]=( key:K,value:V ) - Set( key,value ) + Operator[]=( key:K, value:V ) + Set( key, value ) End #rem wonkeydoc Gets the value associated with a key in the map. @@ -712,11 +704,12 @@ Class Map @return The value associated with `key`, or null if `key` is not in the map. #end Operator[]:V( key:K ) - Local node:=FindNode( key ) + + Local node := FindNode( key ) If Not node Return Null Return node._value End - + #rem wonkeydoc Casts the map to a list of values. @author iDkP from GaragePixel @since 2025-05-09 @@ -726,13 +719,35 @@ Class Map #end Operator To:List() 'Set a list of values (negligates the keys) - Local list:=New List() - For Local item:=Eachin Self - list.Add(item.Value) - End + Local list := New List() + For Local item := Eachin Self + list.Add( item.Value ) + Next Return list End + Method KeysToArray:K[]() + + Local result := New K[Count()] + Local idx := 0 + For Local k := Eachin Keys + result[idx] = k + idx += 1 + Next + Return result + End + + Method ValuesToArray:V[]() + + Local result := New V[Count()] + Local idx := 0 + For Local v := Eachin Values + result[idx] = v + idx += 1 + Next + Return result + End + #rem wonkeydoc Sets the value associated with a key in the map. If the map does not contain `key`, a new key/value node is added to the map and true is returned. If the map already contains `key`, its associated value is updated and false is returned. @@ -740,47 +755,47 @@ Class Map @param value The value. @return True if a new node was added to the map, false if an existing node was updated. #end - Method Set:Bool( key:K,value:V ) 'Modified by iDkP + Method Set:Bool( key:K, value:V ) 'Modified by iDkP Local cmp:Int - + 'If NotRoot( key,value) 'If NotRoot( Varptr(key),Varptr(value)) 'Modified by iDkP 'If NotRoot( key,Varptr(value)) 'Modified by iDkP If NotRoot( key,value) 'Modified by iDkP - _root=New Node( key,value,ColorRed,Null ) + _root = New Node( key, value, ColorRed, Null ) Return True 'Added by iDkP - End - + Endif + ' Try hint path first if available If _lastAddedNode - cmp=key <=> _lastAddedNode._key + cmp = key <=> _lastAddedNode._key If Not cmp - Local oldValue:=_lastAddedNode._value - _lastAddedNode._value=value + Local oldValue := _lastAddedNode._value + _lastAddedNode._value = value Return True - End - End + Endif + Endif ' Standard insertion logic... - Local node:=_root + Local node := _root Local parent:Node While node - parent=node - cmp=key<=>node._key - If cmp>0 - node=node._right - Elseif cmp<0 - node=node._left + parent = node + cmp = key <=> node._key + If cmp > 0 + node = node._right + Elseif cmp < 0 + node = node._left Else - node._value=value + node._value = value Return False - End + Endif Wend - - AddPair( node, key,value, parent, cmp ) 'Added by iDkP + + AddPair( node, key, value, parent, cmp ) 'Added by iDkP Return True End @@ -792,30 +807,30 @@ Class Map @param value The value. @return True if a new node was added to the map, false if the map was not modified. #end - Method Add:Bool( key:K,value:V ) 'Modified by iDkP + Method Add:Bool( key:K, value:V ) 'Modified by iDkP If NotRoot( key,value) 'Modified by iDkP - _root=New Node( key,value,ColorRed,Null ) + _root = New Node( key, value, ColorRed, Null ) Return True 'Modified by iDkP - End - - Local node:=_root + Endif + + Local node := _root Local parent:Node Local cmp:Int - + While node - parent=node - cmp=key<=>node._key - If cmp>0 - node=node._right - ElseIf cmp<0 + parent = node + cmp = key <=> node._key + If cmp > 0 + node = node._right + ElseIf cmp < 0 node=node._left Else Return False - End + Endif Wend - AddPair( node, key,value, parent, cmp ) 'Added by iDkP + AddPair( node, key, value, parent, cmp ) 'Added by iDkP Return True End @@ -828,9 +843,10 @@ Class Map @return True if the value associated with `key` was updated, false if the map was not modified. #end Method Update:Bool( key:K,value:V ) - Local node:=FindNode( key ) + + Local node := FindNode( key ) If Not node Return False - node._value=value + node._value = value Return True End @@ -839,11 +855,12 @@ Class Map @return The value associated with the key, or null if the key is not in the map. #end Method Get:V( key:K ) - Local node:=FindNode( key ) + + Local node := FindNode( key ) If node Return node._value Return Null End - + #rem wonkeydoc Search if a contained value exists as the value of a key. @author iDkP from GaragePixel @since 2025-07-18 @@ -851,115 +868,116 @@ Class Map @param key The values container. Accepts [[Array]], [[Stack]] and [[List]]. @return -1 if the key hasn't any contained values, or an index corresponding to the value's position in the container. #end - Method Search:Int( key:K,values:Stack ) + Method Search:Int( key:K, values:Stack ) 'Added by iDkP from GaragePixel 2025-07-18 - Return Search(key,values.Data) + Return Search( key, values.Data) End - Method Search:Int( key:K,values:V[] ) + Method Search:Int( key:K, values:V[] ) 'Added by iDkP from GaragePixel 2025-07-18 - Local keynode:=FindNode(key) + Local keynode := FindNode(key) If keynode - Local value:=FindNode(key).Value - Local valuesLength:=values.Length - For Local index:=0 Until valuesLength - If value=values[index] Return index - End - End + Local value := FindNode(key).Value + Local valuesLength := values.Length + For Local index := 0 Until valuesLength + If value = values[index] Return index + Next + Endif Return -1 End - - Method Search:Int( key:K,values:List ) + + Method Search:Int( key:K, values:List ) 'Added by iDkP from GaragePixel 2025-07-18 - Local keynode:=FindNode(key) + Local keynode := FindNode(key) If keynode - Local value:=keynode.Value - Local index:Int=0 - For Local item:=Eachin values - If value=item Return index - index+=1 - End - End + Local value := keynode.Value + Local index:Int = 0 + For Local item := Eachin values + If value = item Return index + index += 1 + Next + Endif Return -1 End - + #rem wonkeydoc Removes a key from the map. @param key The key to remove. @return True if the key was removed, or false if the key is not in the map. #end Method Remove:Bool( key:K ) - Local node:=FindNode( key ) + + Local node := FindNode( key ) If Not node Return False RemoveNode( node ) Return True End - + #rem wonkeydoc Union: Add each keys from this (param) that exist in self @param This The map to compare. @param onPlace if False, returns a copy of the map, else nothing #end - Method Append:Map(this:Map,onPlace:Bool=True) 'Modified by iDkP + Method Append:Map( this:Map, onPlace:Bool = True ) 'Modified by iDkP 'Sugar - Return Union(this,onPlace) + Return Union( this, onPlace ) End - + #rem wonkeydoc Union: Add each keys from this (param) that exist in self @param This The map to compare. @param onPlace if False, returns a copy of the map, else nothing #end - Method Union:Map(this:Map,onPlace:Bool=True) 'Modified by iDkP + Method Union:Map( this:Map, onPlace:Bool = True ) 'Modified by iDkP 'Add this to self - If onPlace - For Local item:= Eachin this - Set(item.Key,item.Value) + If onPlace + For Local item := Eachin this + Set( item.Key, item.Value ) Next Return Null - End - Local result:=Copy() - For Local item:= Eachin this - result.Set(item.Key,item.Value) - End + Endif + Local result := Copy() + For Local item := Eachin this + result.Set( item.Key, item.Value ) + Next Return result End - + #rem wonkeydoc Intersect: Keep all keys from self that exist in this (param) @param This The map to compare. @param onPlace if False, returns a copy of the map, else nothing #end - Method Intersect:Map(this:Map, onPlace:Bool=True) 'Modified by iDkP + Method Intersect:Map( this:Map, onPlace:Bool = True ) 'Modified by iDkP 'Keep in self the keys that exist in this - If onPlace - For Local item:= Eachin Self - If Not this.Contains(item.Key) Self.Remove(item.Key) - End + If onPlace + For Local item := Eachin Self + If Not this.Contains( item.Key ) Self.Remove( item.Key ) + Next Return Null - End - Local result:=Copy() - For Local item:= Eachin result - If Not this.Contains(item.Key) result.Remove(item.Key) - End - Return result + Endif + Local result := Copy() + For Local item := Eachin result + If Not this.Contains( item.Key ) result.Remove( item.Key ) + Next + Return result End #rem wonkeydoc Difference: Remove all keys from self that exist in this (param) @param This The map to compare. @param onPlace if False, returns a copy of the map, else nothing #end - Method Diff:Map(this:Map, onPlace:Bool=True) 'Modified by iDkP + Method Diff:Map( this:Map, onPlace:Bool = True ) 'Modified by iDkP 'Remove all keys from self that exist in this - If onPlace - For Local item:= Eachin Self - If this.Contains(item.Key) Remove(item.Key) - End + If onPlace + For Local item := Eachin Self + If this.Contains( item.Key ) Remove( item.Key ) + Next Return Null - End - Local result:=Copy() - For Local item:= Eachin result - If this.Contains(item.Key) result.Remove(item.Key) - End + Endif + Local result := Copy() + For Local item := Eachin result + If this.Contains( item.Key ) result.Remove( item.Key ) + Next Return result End @@ -969,255 +987,261 @@ Class Map Field _lastAddedNode:Node 'Modified by iDkP Method New( root:Node ) - _root=root + _root = root End Property FirstNode:Node() 'iDkP: passed as property for consistancy - + If Not _root Return Null - - Local node:=_root + + Local node := _root While node._left - node=node._left + node = node._left Wend Return node End Property LastNode:Node() 'iDkP: passed as property for consistancy - + If Not _root Return Null - - Local node:=_root + + Local node := _root While node._right - node=node._right + node = node._right Wend Return node End - + Method FindNode:Node( key:K ) 'Modified by iDkP - + ' Try hint first if available If _lastAddedNode - Local cmp:=key <=> _lastAddedNode._key - If cmp=0 Return _lastAddedNode - End + Local cmp := key <=> _lastAddedNode._key + If cmp = 0 Return _lastAddedNode + Endif ' Standard traversal - Local node:=_root + Local node := _root While node - Local cmp:=key<=>node._key - If cmp>0 - node=node._right - Elseif cmp<0 - node=node._left + Local cmp := key <=> node._key + If cmp > 0 + node = node._right + Elseif cmp < 0 + node = node._left Else Return node - End + Endif Wend Return Null End Method RemoveNode( node:Node ) - Local splice:Node,child:Node + + Local splice:Node, child:Node If Not node._left - splice=node - child=node._right + splice = node + child = node._right Elseif Not node._right - splice=node - child=node._left + splice = node + child = node._left Else - splice=node._left + splice = node._left While splice._right - splice=splice._right + splice = splice._right Wend - child=splice._left - node._key=splice._key - node._value=splice._value - End + child = splice._left + node._key = splice._key + node._value = splice._value + Endif - Local parent:=splice._parent + Local parent := splice._parent If child - child._parent=parent + child._parent = parent Endif If Not parent - _root=child + _root = child Return Endif - If splice=parent._left - parent._left=child + If splice = parent._left + parent._left = child Else - parent._right=child - End + parent._right = child + Endif - If splice._color=ColorBlack + If splice._color = ColorBlack DeleteFixup( child,parent ) - End + Endif End Method RotateLeft( node:Node ) - Local child:=node._right - node._right=child._left + + Local child := node._right + node._right = child._left If child._left - child._left._parent=node + child._left._parent = node Endif - child._parent=node._parent + child._parent = node._parent If node._parent - If node=node._parent._left - node._parent._left=child + If node = node._parent._left + node._parent._left = child Else - node._parent._right=child - End + node._parent._right = child + Endif Else - _root=child - End - child._left=node - node._parent=child + _root = child + Endif + child._left = node + node._parent = child End Method RotateRight( node:Node ) - Local child:=node._left - node._left=child._right + + Local child := node._left + node._left = child._right If child._right - child._right._parent=node - End - child._parent=node._parent + child._right._parent = node + Endif + child._parent = node._parent If node._parent - If node=node._parent._right - node._parent._right=child + If node = node._parent._right + node._parent._right = child Else - node._parent._left=child - End + node._parent._left = child + Endif Else - _root=child - End - child._right=node - node._parent=child + _root = child + Endif + child._right = node + node._parent = child End Method InsertFixup( node:Node ) - While node._parent And node._parent._color=ColorRed And node._parent._parent - If node._parent=node._parent._parent._left - Local uncle:=node._parent._parent._right - If uncle And uncle._color=ColorRed - node._parent._color=ColorBlack - uncle._color=ColorBlack - uncle._parent._color=ColorRed - node=uncle._parent + + While node._parent And node._parent._color = ColorRed And node._parent._parent + If node._parent = node._parent._parent._left + Local uncle := node._parent._parent._right + If uncle And uncle._color = ColorRed + node._parent._color = ColorBlack + uncle._color = ColorBlack + uncle._parent._color = ColorRed + node = uncle._parent Else - If node=node._parent._right - node=node._parent + If node = node._parent._right + node = node._parent RotateLeft( node ) Endif - node._parent._color=ColorBlack - node._parent._parent._color=ColorRed + node._parent._color = ColorBlack + node._parent._parent._color = ColorRed RotateRight( node._parent._parent ) Endif Else - Local uncle:=node._parent._parent._left - If uncle And uncle._color=ColorRed - node._parent._color=ColorBlack - uncle._color=ColorBlack - uncle._parent._color=ColorRed + Local uncle := node._parent._parent._left + If uncle And uncle._color = ColorRed + node._parent._color = ColorBlack + uncle._color = ColorBlack + uncle._parent._color = ColorRed node=uncle._parent Else - If node=node._parent._left - node=node._parent + If node = node._parent._left + node = node._parent RotateRight( node ) End - node._parent._color=ColorBlack - node._parent._parent._color=ColorRed + node._parent._color = ColorBlack + node._parent._parent._color = ColorRed RotateLeft( node._parent._parent ) Endif Endif Wend - _root._color=ColorBlack + _root._color = ColorBlack End - Method DeleteFixup( node:Node,parent:Node ) + Method DeleteFixup( node:Node, parent:Node ) - While node<>_root And (Not node Or node._color=ColorBlack ) - - If node=parent._left + While node <> _root And ( Not node Or node._color = ColorBlack ) - Local sib:=parent._right + If node = parent._left + + Local sib := parent._right - If sib._color=ColorRed - sib._color=ColorBlack - parent._color=ColorRed + If sib._color = ColorRed + sib._color = ColorBlack + parent._color = ColorRed RotateLeft( parent ) - sib=parent._right + sib = parent._right Endif - If (Not sib._left Or sib._left._color=ColorBlack) And (Not sib._right Or sib._right._color=ColorBlack) - sib._color=ColorRed - node=parent - parent=parent._parent + If ( Not sib._left Or sib._left._color = ColorBlack ) And ( Not sib._right Or sib._right._color = ColorBlack ) + sib._color = ColorRed + node = parent + parent = parent._parent Else - If Not sib._right Or sib._right._color=ColorBlack - sib._left._color=ColorBlack - sib._color=ColorRed + If Not sib._right Or sib._right._color = ColorBlack + sib._left._color = ColorBlack + sib._color = ColorRed RotateRight( sib ) - sib=parent._right + sib = parent._right Endif - sib._color=parent._color - parent._color=ColorBlack - sib._right._color=ColorBlack + sib._color = parent._color + parent._color = ColorBlack + sib._right._color = ColorBlack RotateLeft( parent ) node=_root Endif Else - Local sib:=parent._left + Local sib := parent._left - If sib._color=ColorRed - sib._color=ColorBlack - parent._color=ColorRed + If sib._color = ColorRed + sib._color = ColorBlack + parent._color = ColorRed RotateRight( parent ) - sib=parent._left + sib = parent._left Endif If (Not sib._right Or sib._right._color=ColorBlack) And (Not sib._left Or sib._left._color=ColorBlack) - sib._color=ColorRed - node=parent - parent=parent._parent + sib._color = ColorRed + node = parent + parent = parent._parent Else If Not sib._left Or sib._left._color=ColorBlack sib._right._color=ColorBlack - sib._color=ColorRed + sib._color = ColorRed RotateLeft( sib ) - sib=parent._left + sib = parent._left Endif - sib._color=parent._color - parent._color=ColorBlack - sib._left._color=ColorBlack + sib._color = parent._color + parent._color = ColorBlack + sib._left._color = ColorBlack RotateRight( parent ) - node=_root + node = _root Endif Endif Wend - If node node._color=ColorBlack + If node node._color = ColorBlack End - Method NotRoot:Bool( key:K,value:V ) 'Added by iDkP + Method NotRoot:Bool( key:K, value:V ) 'Added by iDkP + If Not _root - _root=New Node( key,value,ColorRed,Null ) + _root = New Node( key, value, ColorRed, Null ) Return True End Return False End - Method AddPair( node:Node, key:K,value:V, parent:Node, cmp:Int ) 'Added by iDkP - node=New Node( key,value,ColorRed,parent ) - _lastAddedNode=node - If cmp>0 - parent._right=node - Else - parent._left=node - End + Method AddPair( node:Node, key:K, value:V, parent:Node, cmp:Int ) 'Added by iDkP + + node = New Node( key, value, ColorRed, parent ) + _lastAddedNode = node + If cmp > 0 + parent._right = node + Else + parent._left = node + Endif InsertFixup( node ) - End - + End + End diff --git a/modules/std/collections/set.wx b/modules/std/collections/set.wx index 0a5f53a4..78718f90 100644 --- a/modules/std/collections/set.wx +++ b/modules/std/collections/set.wx @@ -10,21 +10,22 @@ A Set is an efficient data structure for storing sets of small integers from a l Set implement the [[IContainer]] interface so can be used with Eachin loops. #end Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=UByte - + #rem wonkeydoc The Set.Iterator struct. #end Struct Iterator - + Private - + Field _set:Set Field _index:Int Method AssertCurrent() DebugAssert( _index < _set._n, "Invalid Set iterator" ) End - + Method New( set:Set, index:Int ) + _set = set _index = index End @@ -40,9 +41,11 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U #rem wonkeydoc The value currently pointed to by the iterator. #end Property Current:T() + AssertCurrent() Return _set._dense[_index] Setter( current:T ) + AssertCurrent() _set._dense[_index] = current End @@ -50,6 +53,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U #rem wonkeydoc Bumps the iterator so it points to the next value in the Set. #end Method Bump() + AssertCurrent() _index += 1 End @@ -59,25 +63,24 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U 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() - ' AssertCurrent() - ' _set.Erase( _index ) + RuntimeError( "Erase not supported for Sets" ) End #rem wonkeydoc Safely inserts a value before the value pointed to by the iterator. After calling this method, the iterator will point to the newly added value. #end Method Insert( value:T ) - ' DebugAssert( _index <= _set.n,"Invalid set iterator" ) - ' _set.Insert( _index, value ) + RuntimeError( "Insert not supported for Sets" ) End + End #rem wonkeydoc The Set.BackwardsIterator struct. #end Struct BackwardsIterator - + Private - + Field _set:Set Field _index:Int @@ -86,6 +89,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U End Method New( set:Set, index:Int ) + _set = set _index = index End @@ -101,9 +105,11 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U #rem wonkeydoc The value currently pointed to by the iterator. #end Property Current:T() + AssertCurrent() Return _set._dense[_index] Setter( current:T ) + AssertCurrent() _set._dense[_index] = current End @@ -111,6 +117,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U #rem wonkeydoc Bumps the iterator so it points to the next value in the Set. #end Method Bump() + AssertCurrent() _index -= 1 End @@ -121,23 +128,20 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U will end up skipping a value. #end Method Erase() - ' AssertCurrent() - ' _set.Erase( _index ) - ' _index -= 1 + RuntimeError( "Erase not supported for Sets" ) End #rem wonkeydoc Safely inserts a value before the value pointed to by the iterator. After calling this method, the iterator will point to the newly added value. #end Method Insert( value:T ) - ' DebugAssert( _index < _set.n, "Invalid set iterator" ) - ' _index += 1 - ' _set.Insert( _index, value ) + RuntimeError( "Insert not supported for Sets" ) End + End - + Private - + Field _sparse:T[] Field _dense:T[] Field _maxValue:T @@ -154,7 +158,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U Property Empty:Bool() Return _n = 0 End - + Property First:T() Return Self.Empty ? Null Else _dense[0] End @@ -162,11 +166,11 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U Property Last:T() Return Self.Empty ? Null Else _dense[_n - 1] End - + Property Length:Int() Return _n End - + #rem wonkeydoc Gets an iterator for visiting Set values. Returns an iterator suitable for use with Eachin, or for manual iteration. @return A set iterator. @@ -182,7 +186,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U Method Backwards:BackwardsIterator() Return New BackwardsIterator( Self, _n - 1 ) End - + #rem wonkeydoc Creates a new Set. New() creates an empty default Set. New( MaxValue:T, Capacity:Int ) creates a Set. @@ -195,7 +199,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U @param Capacity The Capacity of the Set. #end Method New( _maxV:T = 512, _cap:Int = 64 ) - + _sparse = New T[_maxV + 1] _dense = New T[_cap] _capacity = _cap @@ -204,7 +208,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U End Method New( values:T[], _maxV:T = 512, _cap:Int = 64 ) - + _sparse = New T[_maxV + 1] _dense = New T[_cap] _capacity = _cap @@ -214,7 +218,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U End Method New( values:List, _maxV:T = 512, _cap:Int = 64 ) - + _sparse = New T[_maxV + 1] _dense = New T[_cap] _capacity = _cap @@ -223,18 +227,18 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U AddAll( values ) End -' Method New( values:Deque, _maxV:T = 512, _cap:Int = 64 ) -' -' _sparse = New T[_maxV + 1] -' _dense = New T[_cap] -' _capacity = _cap -' _maxValue = _maxV -' _n = 0 -' AddAll( values ) -' End + Method New( values:Deque, _maxV:T = 512, _cap:Int = 64 ) + + _sparse = New T[_maxV + 1] + _dense = New T[_cap] + _capacity = _cap + _maxValue = _maxV + _n = 0 + AddAll( values ) + End Method New( values:Stack, _maxV:T = 512, _cap:Int = 64 ) - + _sparse = New T[_maxV + 1] _dense = New T[_cap] _capacity = _cap @@ -244,7 +248,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U End Method New( values:Set, _maxV:T = 512, _cap:Int = 64 ) - + _sparse = New T[_maxV + 1] _dense = New T[_cap] _capacity = _cap @@ -257,7 +261,7 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U @param value The value to add. #end Method Add( value:T ) - + If value > _maxValue Return If _n >= _capacity Return If Contains( value ) Return @@ -266,28 +270,30 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U _sparse[value] = _n _n += 1 End - + #rem wonkeydoc Adds the values in an array or container to the Set. @param values The values to add. #end Method AddAll( values:T[] ) + For Local value := Eachin values Add( value ) Next End - + Method AddAll( values:C ) Where C Implements IContainer + For Local value := Eachin values Add( value ) Next End - + #rem wonkeydoc Delete a value from the Set, if the value is in the Set. @param value The value to remove. @return True if the value was removed. #end Method Remove:Bool( value:T ) - + If Not Contains( value ) Return False Local tmp := _dense[_n - 1] @@ -296,13 +302,13 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U _n -= 1 Return True End - + #rem wonkeydoc Checks if the Set contains a value. @param value The value to check for. @return True if the Set contains the value, else false. #end Method Contains:Bool( value:T ) - + If value > _maxValue Return False If _sparse[value] < _n And _dense[_sparse[value]] = value Return True Return False @@ -315,15 +321,16 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U End Operator To:String() - - Local res:="{ " - For Local i:=0 Until _n + + Local tt := Typeof( _maxValue ) + Local res := "Set<" + tt + ">{ " + For Local i := 0 Until _n If i > 0 res += ", " res += _dense[i] Next Return res + " }" End - + Operator+=( item:T ) Add( item ) End @@ -374,25 +381,21 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U If _n < s._n For Local i := 0 Until _n - If s.Contains( _dense[i] ) - r.Add( _dense[i] ) - End + If s.Contains( _dense[i] ) r.Add( _dense[i] ) Next Else For Local i := 0 Until s._n - If Contains( s._dense[i] ) - r.Add( s._dense[i] ) - End + If Contains( s._dense[i] ) r.Add( s._dense[i] ) Next End - + Return r End #rem wonkeydoc returns the union of both sets. #end Method Union:Set( s:Set ) - + Local uCap := _n + s._n Local uMaxValue := Max( _maxValue, s._maxValue ) Local r := New Set( uMaxValue, uCap ) @@ -407,8 +410,31 @@ Class Set Implements IContainer Where T=ULong Or T=UInt Or T=UShort Or T=U Return r End + #rem wonkeydoc returns the difference of both sets. + #end + Method Difference:Set( s:Set ) + + Local uMaxValue := Max( _maxValue, s._maxValue ) + Local r := New Set( uMaxValue, _n ) + + For Local i := 0 Until _n + If Not s.Contains( _dense[i] ) r.Add( _dense[i] ) + Next + Return r + End + + #rem wonkeydoc returns true if the sets have no items in common. + #end + Method Disjoint:Bool( s:Set ) + + For Local i := 0 Until _n + If s.Contains( _dense[i] ) Return False + Next + Return True + End + Method ToArray:T[]() Return _dense.Slice( 0, _n ) End - + End diff --git a/modules/std/collections/stack.wx b/modules/std/collections/stack.wx index 700e9ee0..08b6bd24 100644 --- a/modules/std/collections/stack.wx +++ b/modules/std/collections/stack.wx @@ -26,23 +26,24 @@ 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. #end Class Stack Implements IContainer - + #rem wonkeydoc The Stack.Iterator struct. #end Struct Iterator 'Implements IIterator - + Private - + Field _stack:Stack Field _index:Int 'iDkP: 32 bits! Method AssertCurrent() - DebugAssert( _index<_stack._length,"Invalid stack iterator" ) + DebugAssert( _index < _stack._length, "Invalid stack iterator" ) End - - Method New( stack:Stack,index:Int ) 'iDkP: 32 bits! - _stack=stack - _index=index + + Method New( stack:Stack, index:Int ) 'iDkP: 32 bits! + + _stack = stack + _index = index End Public @@ -50,24 +51,27 @@ Class Stack Implements IContainer #rem wonkeydoc Checks if the iterator has reached the end of the stack. #end Property AtEnd:Bool() - Return _index>=_stack._length + Return _index >= _stack._length End #rem wonkeydoc The value currently pointed to by the iterator. #end Property Current:T() + AssertCurrent() Return _stack._data[_index] Setter( current:T ) + AssertCurrent() - _stack._data[_index]=current + _stack._data[_index] = current End #rem wonkeydoc Bumps the iterator so it points to the next value in the stack. #end Method Bump() + AssertCurrent() - _index+=1 + _index += 1 End #rem wonkeydoc Safely erases the value pointed to by the iterator. @@ -75,6 +79,7 @@ Class Stack Implements IContainer 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() + AssertCurrent() _stack.Erase( _index ) End @@ -83,28 +88,31 @@ Class Stack Implements IContainer After calling this method, the iterator will point to the newly added value. #end Method Insert( value:T ) - DebugAssert( _index<=_stack._length,"Invalid stack iterator" ) - _stack.Insert( _index,value ) + + DebugAssert( _index <= _stack._length, "Invalid stack iterator" ) + _stack.Insert( _index, value ) End + End #rem wonkeydoc The Stack.BackwardsIterator struct. #end Struct BackwardsIterator 'Implements IIterator - + Private - + Field _stack:Stack 'Field _index:UInt 'iDkP: UNSIGNED 32 bits! Field _index:Int 'iDkP: 32 bits! Method AssertCurrent() - DebugAssert( _index>=0,"Invalid stack iterator" ) + DebugAssert( _index >= 0, "Invalid stack iterator" ) End - Method New( stack:Stack,index:Int ) 'iDkP: 32 bits! - _stack=stack - _index=index + Method New( stack:Stack, index:Int ) 'iDkP: 32 bits! + + _stack = stack + _index = index End Public @@ -112,24 +120,27 @@ Class Stack Implements IContainer #rem wonkeydoc Checks if the iterator has reached the end of the stack. #end Property AtEnd:Bool() - Return _index=-1 + Return _index < 0 End #rem wonkeydoc The value currently pointed to by the iterator. #end Property Current:T() + AssertCurrent() Return _stack._data[_index] Setter( current:T ) + AssertCurrent() - _stack._data[_index]=current + _stack._data[_index] = current End #rem wonkeydoc Bumps the iterator so it points to the next value in the stack. #end Method Bump() + AssertCurrent() - _index-=1 + _index -= 1 End #rem wonkeydoc Safely erases the value pointed to by the iterator. @@ -138,23 +149,25 @@ Class Stack Implements IContainer will end up skipping a value. #end Method Erase() + AssertCurrent() _stack.Erase( _index ) - _index-=1 + _index -= 1 End #rem wonkeydoc Safely inserts a value before the value pointed to by the iterator. After calling this method, the iterator will point to the newly added value. #end Method Insert( value:T ) - DebugAssert( _index<_stack._length,"Invalid stack iterator" ) - _index+=1 - _stack.Insert( _index,value ) + + DebugAssert( _index < _stack._length, "Invalid stack iterator" ) + _index += 1 + _stack.Insert( _index, value ) End End Private - + Field _data:T[] Field _length:Int 'iDkP: 32 bits! @@ -171,55 +184,57 @@ Class Stack Implements IContainer @param values An array, list or stack. #end Method New() - _data=New T[10] + _data = New T[16] End - + Method New( length:Int ) 'iDkP: 32 bits! - _length=length - _data=New T[_length] - End - - Method New( values:T[] ) - AddAll( values ) + + _length = length + _data = New T[_length] End - Method New( values:List ) + Method New( values:T[] ) AddAll( values ) End - Method New( values:Deque ) - _length=values.Length - _data=New T[_length] - values.Data.CopyTo( _data,0,0,_length ) - End +' Method New( values:List ) +' AddAll( values ) +' End +' +' Method New( values:Deque ) +' _length=values.Length +' _data=New T[_length] +' values.Data.CopyTo( _data,0,0,_length ) +' End Method New( values:Stack ) - _length=values.Length - _data=New T[_length] - values.Data.CopyTo( _data,0,0,_length ) + + _length = values.Length + _data = New T[_length] + values.Data.CopyTo( _data, 0, 0, _length ) End #rem wonkeydoc Checks if the stack is empty. @return True if the stack is empty. #end Property Empty:Bool() - Return _length=0 + Return _length = 0 End - + Property First:T() - Return Self.Empty ? Null Else Self[0] + Return Self.Empty ? Null Else _data[0] End Property Last:T() - Return Self.Empty ? Null Else Self[Self.Length-1] + Return Self.Empty ? Null Else _data[_length - 1] End - + #rem wonkeydoc Gets an iterator for visiting stack values. Returns an iterator suitable for use with Eachin, or for manual iteration. @return A stack iterator. #end Method All:Iterator() - Return New Iterator( Self,0 ) + Return New Iterator( Self, 0 ) End #rem wonkeydoc Gets an iterator for visiting stack values in reverse order. @@ -227,14 +242,14 @@ Class Stack Implements IContainer @return A backwards stack iterator. #end Method Backwards:BackwardsIterator() - Return New BackwardsIterator( Self,_length-1 ) + Return New BackwardsIterator( Self, _length - 1 ) End #rem wonkeydoc Converts the stack to an array. @return An array containing each element of the stack. #end Method ToArray:T[]() - Return _data.Slice( 0,_length ) + Return _data.Slice( 0, _length ) End #rem wonkeydoc Gets the underlying array used by the stack. @@ -251,14 +266,14 @@ Class Stack Implements IContainer Property Length:Int() 'iDkP: 32 bits! Return _length End - + #rem wonkeydoc hidden Set the number of values in the stack. Note: This setter is internally used, but public. Do not use it until you know what you do! #end Method SetLength( lenght:Int ) 'iDkP: 32 bits! - _length=lenght + _length = lenght End - + #rem wonkeydoc Gets the storage capacity of the stack. The capacity of a stack is the number of values it can contain before memory needs to be reallocated to store more values. If a stack's length equals its capacity, then the next Add or Insert operation will need to allocate more memory to 'grow' the stack. @@ -266,22 +281,21 @@ Class Stack Implements IContainer how many values a stack is likely to contain, in order to prevent the overhead of excessive memory allocation. @return The current stack capacity. #end - Property Capacity:Int() 'iDkP: 32 bits! Return _data.Length End - + #rem monkeydoc Returns a copy of the stack @return A copy of the current stack #end Method Copy:Stack() - Return New Stack(Self) + Return New Stack( Self ) End - + #rem wonkeydoc Compacts the stack #end Method Compact() - If _length<>_data.Length _data=_data.Slice( 0,_length ) + If _length <> _data.Length _data = _data.Slice( 0, _length ) End #rem wonkeydoc Resizes the stack. @@ -291,14 +305,14 @@ Class Stack Implements IContainer #end Method Resize( length:Int ) 'iDkP: 32 bits! - DebugAssert( length>=0 ) + DebugAssert( length >= 0 ) - For Local i:=length Until _length - _data[i]=Null + For Local i := length Until _length + _data[i] = Null Next Reserve( length ) - _length=length + _length = length End #rem wonkeydoc Reserves stack storage capacity. @@ -310,16 +324,16 @@ Class Stack Implements IContainer #end Method Reserve( capacity:Int ) 'iDkP: 32 bits! - DebugAssert( capacity>=0 ) + DebugAssert( capacity >= 0 ) - If _data.Length>=capacity Return + If _data.Length >= capacity Return - 'capacity=Max( _length*2,capacity ) - capacity=_length*2 > capacity ? _length*2 Else capacity 'Modified by iDkP + 'capacity=Max( _length * 2, capacity ) + capacity = _length * 2 > capacity ? _length * 2 Else capacity 'Modified by iDkP Local data:=New T[capacity] - _data.CopyTo( data,0,0,_length ) - _data=data + _data.CopyTo( data, 0, 0, _length ) + _data = data End #rem wonkeydoc Clears the stack. @@ -335,12 +349,12 @@ Class Stack Implements IContainer #end Method Erase( index:Int ) 'iDkP: 32 bits! - DebugAssert( index>=0 And index<=_length ) + DebugAssert( index >= 0 And index <= _length ) - If index=_length Return + If index = _length Return - _data.CopyTo( _data,index+1,index,_length-index-1 ) - Resize( _length-1 ) + _data.CopyTo( _data, index + 1, index, _length - index - 1 ) + Resize( _length - 1 ) End #rem wonkeydoc Erases a range of elements in the stack. @@ -349,13 +363,13 @@ Class Stack Implements IContainer @param index1 The index of the first element to erase. @param index2 The index of the last+1 element to erase. #end - Method Erase( index1:Int,index2:Int ) 'iDkP: 32 bits! + Method Erase( index1:Int, index2:Int ) 'iDkP: 32 bits! - DebugAssert( index1>=0 And index1<=_length And index2>=0 And index2<=_length And index1<=index2 ) + DebugAssert( index1 >= 0 And index1 <= _length And index2 >= 0 And index2 <= _length And index1 <= index2 ) - If index1=_length Return - _data.CopyTo( _data,index2,index1,_length-index2 ) - Resize( _length-index2+index1 ) + If index1 = _length Return + _data.CopyTo( _data, index2, index1, _length - index2 ) + Resize( _length - index2 + index1 ) End #rem wonkeydoc Inserts a value at an index in the stack. @@ -366,12 +380,12 @@ Class Stack Implements IContainer #end Method Insert( index:Int,value:T ) 'iDkP: 32 bits! - DebugAssert( index>=0 And index<=_length ) + DebugAssert( index >= 0 And index <= _length ) - Reserve( _length+1 ) - _data.CopyTo( _data,index,index+1,_length-index ) - _data[index]=value - _length+=1 + Reserve( _length + 1 ) + _data.CopyTo( _data, index, index + 1, _length - index ) + _data[index] = value + _length += 1 End #rem wonkeydoc Gets the value of a stack element. @@ -380,7 +394,7 @@ Class Stack Implements IContainer #end Method Get:T( index:Int ) 'iDkP: 32 bits! - DebugAssert( index>=0 And index<_length,"Stack index out of range" ) + DebugAssert( index >= 0 And index < _length, "Stack index out of range" ) Return _data[index] End @@ -390,11 +404,22 @@ Class Stack Implements IContainer @param index The index of the element to set. @param value The value to set. #end - Method Set( index:Int,value:T ) 'iDkP: 32 bits! + Method Set( index:Int, value:T ) 'iDkP: 32 bits! - DebugAssert( index>=0 And index<_length,"Stack index out of range" ) + DebugAssert( index >= 0 And index < _length, "Stack index out of range" ) - _data[index]=value + _data[index] = value + End + + Operator To:String() Where T Implements INumeric Or T=String + + Local tt := Typeof( _data[0] ) + Local result := "Stack<" + tt + ">[ " + For Local i := 0 Until _length + If i > 0 result += ", " + result += _data[i] + Next + Return result + " ]" End #rem wonkeydoc Gets the value of a stack element. @@ -402,8 +427,8 @@ Class Stack Implements IContainer @param index The index of the element to get. #end Operator []:T( index:Int ) 'iDkP: 32 bits! - - DebugAssert( index>=0 And index<_length,"Stack index out of range" ) + + DebugAssert( index >= 0 And index < _length, "Stack index out of range" ) Return _data[index] End @@ -413,25 +438,22 @@ Class Stack Implements IContainer @param index The index of the element to set. @param value The value to set. #end - Operator []=( index:Int,value:T ) 'iDkP: 32 bits! - - DebugAssert( index>=0 And index<_length,"Stack index out of range" ) + Operator []=( index:Int, value:T ) 'iDkP: 32 bits! + + DebugAssert( index >= 0 And index < _length, "Stack index out of range" ) - _data[index]=value + _data[index] = value End Operator+=( item:T ) - Self.Add( item ) End Operator-=( item:T ) - Self.Remove( item ) End Operator+=( items:T[] ) - Self.AddAll( items ) End @@ -440,29 +462,32 @@ Class Stack Implements IContainer @param value The value to add. #end Method Add( value:T ) - Reserve( _length+1 ) - _data[_length]=value - _length+=1 + + Reserve( _length + 1 ) + _data[_length] = value + _length += 1 End - + #rem wonkeydoc Adds a value to stack that has no other clone. @param value The value to add. #end Method AddUnique( value:T ) - If Not Self.Contains( value ) Then Self.Add( value ) + If Not Contains( value ) Then Add( value ) End #rem wonkeydoc Adds the values in an array or container to the end of the stack. @param values The values to add. #end Method AddAll( values:T[] ) - Reserve( _length+values.Length ) - values.CopyTo( _data,0,_length,values.Length ) - Resize( _length+values.Length ) + + Reserve( _length + values.Length ) + values.CopyTo( _data, 0, _length, values.Length ) + Resize( _length + values.Length ) End - + Method AddAll( values:C ) Where C Implements IContainer - For Local value:=Eachin values + + For Local value := Eachin values Add( value ) Next End @@ -470,7 +495,8 @@ Class Stack Implements IContainer #rem wonkeydoc @deprecated Use [[AddAll]]. #End Method Append( values:C ) Where C Implements IContainer - For Local value:=Eachin values + + For Local value := Eachin values Add( value ) Next End @@ -481,14 +507,14 @@ Class Stack Implements IContainer @param start The starting index for the search. @return The index of the value in the stack, or -1 if the value was not found. #end - Method FindIndex:Int( value:T,start:Int=0 ) 'iDkP: 32 bits! + Method FindIndex:Int( value:T, start:Int = 0 ) 'iDkP: 32 bits! - DebugAssert( start>=0 And start<=_length ) + DebugAssert( start >= 0 And start <= _length ) - Local i:=start - While i<_length - If _data[i]=value Return i - i+=1 + Local i := start + While i < _length + If _data[i] = value Return i + i += 1 Wend Return -1 End @@ -499,14 +525,14 @@ Class Stack Implements IContainer @param start The starting index for the search. @return The index of the value in the stack, or -1 if the value was not found. #end - Method FindLastIndex:Int( value:T,start:Int=0 ) 'iDkP: 32 bits! + Method FindLastIndex:Int( value:T, start:Int = 0 ) 'iDkP: 32 bits! - DebugAssert( start>=0 And start<=_length ) + DebugAssert( start >= 0 And start <= _length ) - Local i:=_length - While i>start - i-=1 - If _data[i]=value Return i + Local i := _length + While i > start + i -= 1 + If _data[i] = value Return i Wend Return -1 End @@ -516,7 +542,7 @@ Class Stack Implements IContainer @return True if the stack contains the value, else false. #end Method Contains:Bool( value:T ) - Return FindIndex( value )<>-1 + Return FindIndex( value ) <> -1 End #rem wonkeydoc Finds and removes the first matching value from the stack. @@ -524,9 +550,10 @@ Class Stack Implements IContainer @param value The value to remove. @return True if the value was removed. #end - Method Remove:Bool( value:T,start:Int=0 ) 'iDkP: 32 bits! - Local i:=FindIndex( value,start ) - If i=-1 Return False + Method Remove:Bool( value:T, start:Int = 0 ) 'iDkP: 32 bits! + + Local i := FindIndex( value, start ) + If i = -1 Return False Erase( i ) Return True End @@ -536,9 +563,10 @@ Class Stack Implements IContainer @param value The value to remove. @return True if the value was removed. #end - Method RemoveLast:Bool( value:T,start:Int=0 ) 'iDkP: 32 bits! - Local i:=FindLastIndex( value,start ) - If i=-1 Return False + Method RemoveLast:Bool( value:T, start:Int = 0 ) 'iDkP: 32 bits! + + Local i := FindLastIndex( value, start ) + If i = -1 Return False Erase( i ) Return True End @@ -548,14 +576,15 @@ Class Stack Implements IContainer @return The number of values removed. #end Method RemoveEach:Int( value:T ) 'iDkP: 32 bits! - Local put:=0,n:=0 - For Local get:=0 Until _length - If _data[get]=value - n+=1 + + Local put := 0, n := 0 + For Local get := 0 Until _length + If _data[get] = value + n += 1 Continue End - _data[put]=_data[get] - put+=1 + _data[put] = _data[get] + put += 1 Next Resize( put ) Return n @@ -566,14 +595,15 @@ Class Stack Implements IContainer @return The number of values removed. #end Method RemoveIf:Int( condition:Bool( value:T ) ) 'iDkP: 32 bits! - Local put:=0,n:=0 - For Local get:=0 Until _length + + Local put := 0, n := 0 + For Local get := 0 Until _length If condition( _data[get] ) - n+=1 + n += 1 Continue End - _data[put]=_data[get] - put+=1 + _data[put] = _data[get] + put += 1 Next Resize( put ) Return n @@ -588,27 +618,26 @@ Class Stack Implements IContainer @return A new stack. #end Method Slice:Stack( index:Int ) 'iDkP: 32 bits! - - Return Slice( index,_length ) + Return Slice( index, _length ) End - Method Slice:Stack( index1:Int,index2:Int ) 'iDkP: 32 bits! + Method Slice:Stack( index1:Int, index2:Int ) 'iDkP: 32 bits! - If index1<0 - index1=index1+_length > 0 ? index1+_length Else 0 'Modified by iDkP - ElseIf index1>_length - index1=_length + If index1 < 0 + index1 = index1 + _length > 0 ? index1 + _length Else 0 'Modified by iDkP + ElseIf index1 > _length + index1 = _length End - If index2<0 - index2=index2+_length > index1 ? index2 Else index1 'Modified by iDkP - ElseIf index2>_length - index2=_length - ElseIf index2 index1 ? index2 Else index1 'Modified by iDkP + ElseIf index2 > _length + index2 = _length + ElseIf index2 < index1 + index2 = index1 End - Return New Stack( _data.Slice( index1,index2 ) ) + Return New Stack( _data.Slice( index1, index2 ) ) End #rem wonkeydoc Swaps 2 elements in the stack, or 2 stacks. @@ -619,20 +648,22 @@ Class Stack Implements IContainer @param index2 The index of the second element. @param stack The stack to swap with. #end - Method Swap( index1:Int,index2:Int ) 'iDkP: 32 bits! - DebugAssert( index1>=0 And index1<_length And index2>=0 And index2<_length,"Stack index out of range" ) + Method Swap( index1:Int, index2:Int ) 'iDkP: 32 bits! + + DebugAssert( index1 >= 0 And index1 < _length And index2 >= 0 And index2 < _length, "Stack index out of range" ) - Local t:=_data[index1] - _data[index1]=_data[index2] - _data[index2]=t + Local t := _data[index1] + _data[index1] = _data[index2] + _data[index2] = t End Method Swap( stack:Stack ) - Local data:=_data,length:=_length - _data=stack._data - _length=stack._length - stack._data=data - stack._length=length + + Local data := _data, length := _length + _data = stack._data + _length = stack._length + stack._data = data + stack._length = length End #rem wonkeydoc Sorts the stack. @@ -641,18 +672,22 @@ Class Stack Implements IContainer @param lo Index of first value to sort. @param hi Index of last value to sort.@lo Int start index #end - Method Sort( ascending:Int=True ) + Method Sort( ascending:Int = True ) + If ascending - Sort( Lambda:Int( x:T,y:T ) - Return x<=>y + Sort( Lambda:Int( x:T, y:T ) + Return x <=> y End ) + Else - Sort( Lambda:Int( x:T,y:T ) - Return y<=>x + Sort( Lambda:Int( x:T, y:T ) + Return y <=> x End ) + End + End - + ' Method Sort( compareFunc:Int( x:T,y:T ) ) ' Sort( compareFunc,0,_length-1 ) ' End @@ -704,10 +739,11 @@ Class Stack Implements IContainer @param onPlace If True, reverses the stack in place; if False, returns a new reversed copy. @return The reversed stack (self if in-place, new Stack if not). #end - Method Reverse:Stack( onPlace:Bool=True ) + Method Reverse:Stack( onPlace:Bool = True ) + Local stk:Stack = onPlace ? Self Else New Stack( Self ) Local left:Int = 0 - Local right:Int = stk.Count()-1 + Local right:Int = stk.Count() - 1 While left < right Local temp:T = stk[left] stk[left] = stk[right] @@ -723,9 +759,10 @@ Class Stack Implements IContainer @return The top element of the stack. #end Property Top:T() - DebugAssert( _length,"Stack is empty" ) - Return _data[_length-1] + DebugAssert( _length, "Stack is empty" ) + + Return _data[_length - 1] End #rem wonkeydoc Pops the top element off the stack and returns it. @@ -733,11 +770,12 @@ Class Stack Implements IContainer @return The top element of the stack before it was popped. #end Method Pop:T() - DebugAssert( _length,"Stack is empty" ) - _length-=1 - Local value:=_data[_length] - _data[_length]=Null + DebugAssert( _length, "Stack is empty" ) + + _length -= 1 + Local value := _data[_length] + _data[_length] = Null Return value End @@ -754,11 +792,14 @@ Class Stack Implements IContainer @since 2025-07-05 #end Property Average:T() Where T Implements INumeric - Local result:T=0 - For Local n:Int=0 Until Length - result+=_data[n] + + DebugAssert( _length, "Stack is empty" ) + + Local result:T = 0 + For Local n:Int = 0 Until _length + result += _data[n] End - result/=Length + result /= _length Return result End #rem TODO: Tuple and limits integration @@ -817,48 +858,49 @@ Class Stack Implements IContainer @param lo Index of first value to sort. @param hi Index of last value to sort.@lo Int start index #end - Method Sort( compare:Int( x:T,y:T ),filter:StackSortFilter=Null ) - Sort( compare,0,Length-1,filter ) + Method Sort( compare:Int( x:T, y:T ), filter:StackSortFilter = Null ) + Sort( compare, 0, _length - 1, filter ) End - Method Sort( compare:Int( x:T,y:T ),lo:Int,hi:Int,filter:StackSortFilter=Null ) 'iDkP: lo, hi = 32 bits + Method Sort( compare:Int( x:T, y:T ), lo:Int, hi:Int, filter:StackSortFilter = Null ) 'iDkP: lo, hi = 32 bits - If hi<=lo Return + If hi <= lo Return - If lo+1=hi - If compare( Self[hi],Self[lo] )<0 Swap( hi,lo ) + If lo + 1 = hi + If compare( Self[hi], Self[lo] ) < 0 Swap( hi, lo ) Return End - Local i:=(lo+hi)/2 + Local i := (lo + hi) / 2 - If compare( Self[i],Self[lo] )<0 Swap( i,lo ) + If compare( Self[i], Self[lo] ) < 0 Swap( i, lo ) - If compare( Self[hi],Self[i] )<0 - Swap( hi,i ) - If compare( Self[i],Self[lo] )<0 Swap( i,lo ) + If compare( Self[hi], Self[i] ) < 0 + Swap( hi, i ) + If compare( Self[i], Self[lo] ) < 0 Swap( i, lo ) End - Local x:=lo+1 - Local y:=hi-1 + Local x := lo + 1 + Local y := hi - 1 Repeat - Local p:=Self[i] - While compare( Self[x],p )<0 - x+=1 + Local p := Self[i] + While compare( Self[x], p ) < 0 + x += 1 Wend - While compare( p,Self[y] )<0 - y-=1 + While compare( p, Self[y] ) < 0 + y -= 1 Wend - If x>y Exit - If x y Exit + If x < y + Swap( x, y ) + If i = x i = y ElseIf i = y i = x Endif - x+=1 - y-=1 - Until x>y + x += 1 + y -= 1 + Until x > y - Sort( compare,lo,y,filter ) - Sort( compare,x,hi,filter ) + Sort( compare, lo, y, filter ) + Sort( compare, x, hi, filter ) End + End diff --git a/modules/std/permissions/permissions.wx b/modules/std/permissions/permissions.wx index db627c4b..17167bd1 100644 --- a/modules/std/permissions/permissions.wx +++ b/modules/std/permissions/permissions.wx @@ -83,6 +83,10 @@ Class Request finished( iresult ) End + Operator To:String() + Return "ToDo: Fixme!!!" + End + End Function StartNextRequest()