Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified ArrayListLib.twinproj
Binary file not shown.
2 changes: 1 addition & 1 deletion ArrayListLib/Settings
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"project.settingsVersion": 1,
"project.useProjectIdForTypeLibraryId": true,
"project.versionAutoIncrement": "Revision",
"project.versionBuild": 1,
"project.versionBuild": 2,
"project.versionLegalCopyright": "This is free and unencumbered software released into the public domain. For more information, please refer to <https://unlicense.org>",
"project.versionMajor": 1,
"project.versionMinor": 6,
Expand Down
1,248 changes: 629 additions & 619 deletions ArrayListLib/Sources/ArrayList.twin

Large diffs are not rendered by default.

301 changes: 156 additions & 145 deletions ArrayListLib/Sources/Enumerator.twin
Original file line number Diff line number Diff line change
@@ -1,145 +1,156 @@
[ InterfaceId ("00020404-0000-0000-C000-000000000046") ]
[ COMExtensible (True) ]
Public Interface IEnumVARIANT Extends stdole.IUnknown
Sub Next(ByVal celt As Long, ByRef rgvar As Variant, ByRef pceltFetched As Long)
Sub Skip(ByVal celt As Long)
Sub Reset()
Sub Clone(ByRef ppenum As IEnumVARIANT)
End Interface

[ InterfaceId ("8E42D737-24C2-4D3F-8903-4B30E9383C69") ]
[ COMExtensible (True) ]
Public Interface IEnumerator Extends IEnumVARIANT
[ Description ("The Index of the current item being enumerated. If you manually change it, the next item being enumerated will be the one at the specified index.") ]
Property Get CurrentIndex() As Long
Property Let CurrentIndex(Value As Long)
[ Description ("Allows to change the iteration steps count and it's direction.") ]
Property Get CurrentStep() As Long
Property Let CurrentStep(Value As Long)
[ Description ("It's the size of the list, array, or section of it, which is being enumerated. Use with caution and only when enumerating a section of a bigger collection. This won't check for out of bounds.") ]
Property Get CurrentSize() As Long
Property Let CurrentSize(Value As Long)
End Interface

[ ClassId ("5892CEA6-ADE3-4532-B478-1F6122F3537C") ]
[ COMCreatable (True) ]
Public Class Enumerator
Implements IEnumerator

Private CIndex As Long
Private MaxValue As Long
Private Items() As Variant
Private CStep As Long
Private NStep As Long
Private IsEnumerating As Boolean
Private Const E_INVALIDARGS As Long = &H80070057
Private Const S_OK As Long = 0
Private Const S_FALSE As Long = 1

[ Description ("The Index of the current item being enumerated. If you manually change it, the next item being enumerated will be the one at the specified index.") ]
Public Property Get CurrentIndex() As Long Implements IEnumerator.CurrentIndex: CurrentIndex = CIndex: End Property

Public Property Let CurrentIndex(Value As Long) Implements IEnumerator.CurrentIndex: CIndex = Value: NStep = 0: End Property

[ Description ("Allows to change the iteration steps count and it's direction.") ]
Public Property Get CurrentStep() As Long Implements IEnumerator.CurrentStep: CurrentStep = CStep: End Property

Public Property Let CurrentStep(Value As Long) Implements IEnumerator.CurrentStep: CStep = Value: NStep = CStep: End Property

[ Description ("It's the size of the list, array, or section of it, which is being enumerated. Use with caution and only when enumerating a section of a bigger collection. This won't check for out of bounds.") ]
Public Property Get CurrentSize() As Long Implements IEnumerator.CurrentSize: CurrentSize = MaxValue: End Property

Public Property Let CurrentSize(Value As Long) Implements IEnumerator.CurrentSize
MaxValue = Value
PutMem4 ArrPtr(Items) + SAFEARRAY_CELEMENTS_OFFSET, Value
End Property

Public Property Get IsAvailable() As Boolean: IsAvailable = Not IsEnumerating: End Property

Public Sub New()
End Sub

Public Sub New(ByRef TargetArray() As Variant, Optional ByVal Index As Long = 0, Optional ByVal GetCount As Variant, Optional ByVal GetStep As Long = 1, Optional ByRef ThisEnumerator As IEnumerator)
If IsMissing(GetCount) Then GetCount = 1 + UBound(TargetArray) - Index
Bind TargetArray, Index, GetCount, GetStep
Set ThisEnumerator = Me
End Sub

Public Sub Bind(ByRef TargetArray() As Variant, ByVal Index As Long, ByVal GetCount As Long, ByVal GetStep As Long)
Static sa As SAFEARRAY_1D
With sa
.cDims = 1
.cbElements = VARIANT_SIZE
.fFeatures = FADF_VARIANT Or FADF_AUTO
.cLocks = 10
.pvData = VarPtr(TargetArray(Index))
.rgsabound0.cElements = GetCount
End With
VBA.PutMemPtr VarPtrArr(Items), VarPtr(sa)
CStep = GetStep
NStep = 0
MaxValue = GetCount
If CStep < 0 Then
CIndex = GetCount - 1
Else
CIndex = 0
End If
End Sub

[ Enumerator ]
Public Function GetEnumerator() As stdole.IUnknown
Return Me
End Function

/* [ CompilerOptions ("+llvm,+optimize") ] */
[ ArrayBoundsChecks (False) ]
[ IntegerOverflowChecks (False) ]
Private Sub Next(ByVal celt As Long, ByRef rgvar As Variant, ByRef pceltFetched As Long) Implements IEnumerator.Next
If VarPtr(rgvar) = 0 Or celt <> 1 Then
Err.ReturnHResult = E_INVALIDARGS
Else
CIndex += NStep
If CIndex < MaxValue And CIndex >= 0 Then
Assign rgvar, Items(CIndex)
NStep = CStep
If VarPtr(pceltFetched) <> 0 Then pceltFetched = 1
Err.ReturnHResult = S_OK
Else
If VarPtr(pceltFetched) <> 0 Then pceltFetched = 0
IsEnumerating = False
Err.ReturnHResult = S_FALSE
End If
End If
End Sub

Private Sub Skip(ByVal celt As Long) Implements IEnumerator.Skip
CIndex += celt * CStep
If CIndex > MaxValue Then
CIndex = MaxValue + 1
ElseIf CIndex < 0 Then
CIndex = -1
End If
End Sub

Private Sub Reset() Implements IEnumerator.Reset
CIndex = If(CStep < 0, MaxValue - 1, 0)
NStep = 0
IsEnumerating = True
End Sub

Private Sub Clone(ByRef ppenum As IEnumVARIANT) Implements IEnumerator.Clone
Set ppenum = New Enumerator(Items, 0, MaxValue, CStep)
End Sub

/* [ CompilerOptions ("+llvm,+optimize") ] */
[ IntegerOverflowChecks (False) ]
Private Sub Assign(ByRef Target As Variant, ByRef Value As Variant)
If IsObject(Value) Then Set Target = Value Else Target = Value
End Sub

Private Sub Class_Terminate()
On Error Resume Next
If IsArrayInitialized(Items) Then PutMemPtr VarPtrArr(Items), vbNullPtr
On Error GoTo 0
End Sub
End Class
[ InterfaceId ("00020404-0000-0000-C000-000000000046") ]
[ COMExtensible (True) ]
Public Interface IEnumVARIANT Extends stdole.IUnknown
Sub Next(ByVal celt As Long, ByRef rgvar As Variant, ByRef pceltFetched As Long)
Sub Skip(ByVal celt As Long)
Sub Reset()
Sub Clone(ByRef ppenum As IEnumVARIANT)
End Interface

[ InterfaceId ("8E42D737-24C2-4D3F-8903-4B30E9383C69") ]
[ COMExtensible (True) ]
Public Interface IEnumerator Extends IEnumVARIANT
[ Description ("The Index of the current item being enumerated. If you manually change it, the next item being enumerated will be the one at the specified index.") ]
Property Get CurrentIndex() As Long
Property Let CurrentIndex(Value As Long)
[ Description ("Allows to change the iteration steps count and it's direction.") ]
Property Get CurrentStep() As Long
Property Let CurrentStep(Value As Long)
[ Description ("It's the size of the list, array, or section of it, which is being enumerated. Use with caution and only when enumerating a section of a bigger collection. This won't check for out of bounds.") ]
Property Get CurrentSize() As Long
Property Let CurrentSize(Value As Long)
End Interface

[ ClassId ("5892CEA6-ADE3-4532-B478-1F6122F3537C") ]
[ COMCreatable (True) ]
Public Class Enumerator
Implements IEnumerator

Private CIndex As Long
Private MaxValue As Long
Private VT As Integer
Private SizeVT As Long
Private FirstElementAddress As LongPtr
Private CStep As Long
Private NStep As Long
Private IsEnumerating As Boolean
Private Const E_INVALIDARGS As Long = &H80070057
Private Const S_OK As Long = 0
Private Const S_FALSE As Long = 1

#Region "PUBLIC PROPERTIES"
[ Description ("The Index of the current item being enumerated. If you manually change it, the next item being enumerated will be the one at the specified index.") ]
Public Property Get CurrentIndex() As Long Implements IEnumerator.CurrentIndex: CurrentIndex = CIndex: End Property

Public Property Let CurrentIndex(Value As Long) Implements IEnumerator.CurrentIndex: CIndex = Value: NStep = 0: End Property

[ Description ("Allows to change the iteration steps count and it's direction.") ]
Public Property Get CurrentStep() As Long Implements IEnumerator.CurrentStep: CurrentStep = CStep: End Property

Public Property Let CurrentStep(Value As Long) Implements IEnumerator.CurrentStep: CStep = Value: NStep = CStep: End Property

[ Description ("It's the size of the list, array, or section of it, which is being enumerated. Use with caution and only when enumerating a section of a bigger collection. This won't check for out of bounds.") ]
Public Property Get CurrentSize() As Long Implements IEnumerator.CurrentSize: CurrentSize = MaxValue: End Property

Public Property Let CurrentSize(Value As Long) Implements IEnumerator.CurrentSize: MaxValue = Value: End Property

Public Property Get IsAvailable() As Boolean: IsAvailable = Not IsEnumerating: End Property
#End Region

Public Sub New(): End Sub

Public Sub New(TargetArray As Variant, _
Optional ByVal Index As Long = 0, _
Optional ByVal Count As Variant, _
Optional ByVal Step As Long = 1, _
Optional ByRef ThisEnumerator As IEnumerator)
Set ThisEnumerator = Bind(TargetArray, Index, Count, Step)
End Sub

[ Description ("Binds this enumerator to the provided array or any object implementing the IArray interface.") ]
Public Function Bind(TargetArray As Variant, _
Optional ByVal Index As Long = 0, _
Optional ByVal Count As Variant, _
Optional ByVal Step As Long = 1) As Enumerator
If IsObject(TargetArray) AndAlso TypeOf TargetArray Is IArray Then
With C2IArray(TargetArray)
If Index <> 0 Then Index -= .BaseIndex
If IsMissing(Count) Then Count = .Count - Index
Return BindToAddress(.AddressOf(0), Index, Count, Step, vbVariant)
End With
ElseIf IsArray(TargetArray) Then
Dim descriptorAddress As LongPtr
If Index <> 0 Then Index -= LBound(TargetArray)
If IsMissing(Count) Then Count = 1 + (UBound(TargetArray) - LBound(TargetArray)) - Index
SafeArrayDescriptorAndVT VarPtr(TargetArray), descriptorAddress, VT
GetMemPtr descriptorAddress + SAFEARRAY_OFFSETS.pvDataOffset, FirstElementAddress
Return BindToAddress(FirstElementAddress, Index, Count, Step, VT)
End If
End Function

Public Function BindToAddress(TargetAddress As LongPtr, _
Optional ByVal Index As Long = 0, _
Optional ByVal Count As Long = 0, _
Optional ByVal Step As Long = 1, _
Optional ByVal VType As VbVarType = vbVariant) As Enumerator
VT = VType
SizeOfVT VT, SizeVT
FirstElementAddress = TargetAddress
If Index > 0 Then FirstElementAddress += Index * SizeVT
CStep = Step
NStep = 0
MaxValue = Count
CIndex = If(CStep < 0, MaxValue - 1, 0)
IsEnumerating = True
Return Me
End Function

[ Enumerator ]
Public Function GetEnumerator() As stdole.IUnknown
Return Me
End Function

/* [ CompilerOptions ("+llvm,+optimize") ] */
[ ArrayBoundsChecks (False) ]
[ IntegerOverflowChecks (False) ]
Private Sub Next(ByVal celt As Long, ByRef rgvar As Variant, ByRef pceltFetched As Long) Implements IEnumerator.Next
If VarPtr(rgvar) = 0 Or celt <> 1 Then
Err.ReturnHResult = E_INVALIDARGS
Else
CIndex += NStep
If CIndex < MaxValue And CIndex >= 0 Then
PutMem2 VarPtr(rgvar), VT + VT_BYREF
PutMemPtr VarPtr(rgvar) + 8, FirstElementAddress + (CIndex * SizeVT)
NStep = CStep
If VarPtr(pceltFetched) <> 0 Then pceltFetched = 1
Err.ReturnHResult = S_OK
Else
If VarPtr(pceltFetched) <> 0 Then pceltFetched = 0
IsEnumerating = False
Err.ReturnHResult = S_FALSE
End If
End If
End Sub

Private Sub Skip(ByVal celt As Long) Implements IEnumerator.Skip
CIndex += celt * CStep
If CIndex > MaxValue Then
CIndex = MaxValue + 1
ElseIf CIndex < 0 Then
CIndex = -1
End If
End Sub

Private Sub Reset() Implements IEnumerator.Reset
CIndex = If(CStep < 0, MaxValue - 1, 0)
NStep = 0
IsEnumerating = True
End Sub

Private Sub Clone(ByRef ppenum As IEnumVARIANT) Implements IEnumerator.Clone
Dim e As New Enumerator
e.BindToAddress(FirstElementAddress, 0, MaxValue, CStep, VT)
Set ppenum = e
End Sub

End Class
Loading