FADF_EMBEDDED = &H4 ' Array is embedded in a structure
FADF_FIXEDSIZE = &H10 ' Array may not be resized or reallocated
FADF_BSTR = &H100 ' An array of BSTRs
FADF_UNKNOWN = &H200 ' An array of IUnknown*
FADF_DISPATCH = &H400 ' An array of IDispatch*
FADF_VARIANT = &H800 ' An array of VARIANTs
FADF_RESERVED = &HFFFFF0E8 ' Bits reserved for future use
#If False Then
Dim FADF_AUTO, FADF_STATIC, FADF_EMBEDDED, FADF_FIXEDSIZE, FADF_BSTR, FADF_UNKNOWN, FADF_DISPATCH, FADF_VARIANT, FADF_RESERVED
#End If
End Enum
Private Const VT_BYREF = &H4000& ' Tests whether the InitedArray routine was passed a Variant that contains an array, rather than directly an array in the former case ptr already points to the SA structure. Thanks to Monte Hansen for this fix
Private Type SAFEARRAY
cDims As Integer ' Count of dimensions in this array (only 1 supported)
fFeatures As Integer ' Bitfield flags indicating attributes of a particular array
cbElements As Long ' Byte size of each element of the array
cLocks As Long ' Number of times the array has been locked without corresponding unlock
pvData As Long ' Pointer to the start of the array data (use only if cLocks > 0)
End Type
Private Type SABOUNDS ' This module supports single dimension arrays only
cElements As Long ' Count of elements in this dimension
lLBound As Long ' The lower-bounding index of this dimension
lUBound As Long ' The upper-bounding index of this dimension
End Type
Private qs4Lb() As Long, qs4Ub() As Long ' Non-stable non-recursive quicksort stacks
Private ss2Lb() As Long, ss2Ub() As Long ' Stable non-recursive quicksort stacks
Private tw4Lb() As Long, tw4Ub() As Long ' Stable insert/binary runner stacks
Private lA_1() As Long, lA_2() As Long ' Stable quicksort working buffers
' This sub will sort string array items containing numeric
' characters in a more intuitive order. It will take into
' account all occurences of numbers in the string item.
' It is intended for sorting filenames, and will apply the
' same intuitive order for folders in the file path if they
' contain numeric characters.
' Specifying a path is not required, neither do they need to
' have extensions, in fact, they do not need to be filenames;
' just strings that may contain numbers grouped together
' within the string text.
' In other words, it can be used for normal pretty sorting
' operations. But please note, this is intended for sorting
' filenames and is a little slower than the strPrettyNumSort
' sub below because of extra code to handle the extensions.
' If GroupByExtension is specified it will order the items by
' extension, whilst still producing an intuitive order of the
' file path and names that may have numbers within them and
' that have the same extension.
' Note: this will also sort pure numbers, which will group
' positive and negative numbers together from small values
' to large values (or reversed) irrespective of their sign.
' This is version two of the Pretty File Names routine which
' also handles numbers in the extension.
Sub strPrettyFileNames(sA() As String, ByVal lbA As Long, ByVal ubA As Long, Optional ByVal CapsFirst As Boolean = True, Optional ByVal Group As ePrettyFiles = GroupByExtension) '-⌐Rd-
If Not InitedArray(sA, lbA, ubA) Then Exit Sub
Dim aIdx() As Long, lAbuf() As Long
Dim lpS As Long, lpL As Long
Dim walk As Long, cnt As Long
cnt = ubA - lbA + n1 ' Grab array item count
If (cnt < n1) Then Exit Sub ' If nothing to do then exit
strPrettyFileNamesIndexed sA, aIdx, lbA, ubA, CapsFirst, Group
' Now use copymemory to copy the string pointers to a long array buffer for later
' reference to the original strings. We need this to re-order the strings in the
' last step that would over-write needed items if the buffer was not used.
ReDim lAbuf(lbA To ubA) As Long
lpS = VarPtr(sA(lbA))
lpL = VarPtr(lAbuf(lbA))
CopyMemByV lpL, lpS, cnt * n4
' Next we do the actual re-ordering of the array items by referencing the string
' pointers with the index array, and assigning back into the index array ready to
' be copied across to the string array in one copy process.
For walk = lbA To ubA
aIdx(walk) = lAbuf(aIdx(walk))
Next
' The last step assigns the string pointers back into the original array
Sub strPrettyFileNamesIndexed(sA() As String, idxA() As Long, ByVal lbA As Long, ByVal ubA As Long, Optional ByVal CapsFirst As Boolean = True, Optional ByVal Group As ePrettyFiles = GroupByExtension) '-⌐Rd-
If Not InitedArray(sA, lbA, ubA) Then Exit Sub
Dim numsN() As Long, numsE() As Long
Dim sAtemp() As String, lpS As Long
Dim atFN() As tPrettySort
Dim atEXT() As tPrettySort
Dim period() As Long, extens() As Long
Dim filenmP() As Long, extensP() As Long
Dim prevMethod As eCompare
Dim prevOrder As eSortOrder
Dim lenP() As Long, lpads As Long
Dim walk As Long, lpad As Long
Dim lPos As Long, clen As Long
Dim lenFN As Long, lenExt As Long
Dim item As String, lpStr As Long
If (ubA - lbA < n1) Then Exit Sub ' If nothing to do then exit
lpStr = VarPtr(item) ' Cache pointer to the string variable
lpS = VarPtr(sA(lbA)) - (lbA * n4) ' Cache pointer to the string array
ReDim sAtemp(lbA To ubA) As String ' ReDim buffers
ReDim atFN(lbA To ubA) As tPrettySort
ReDim atEXT(lbA To ubA) As tPrettySort
ReDim period(lbA To ubA) As Long
ReDim extens(lbA To ubA) As Long
ReDim lenP(lbA To ubA) As Long
ReDim filenmP(lbA To ubA) As Long
ReDim extensP(lbA To ubA) As Long
' First build an array of data about the filenames to use for the padding process.
' Because filename and extension are distinctive entities in the comparison process
' it is neccessary to do a good deal of preperation to produce the resulting padded
' items for comparison. Pre-calculating the padding data is relatively fast compared
' to string manipulation.
For walk = lbA To ubA ' Loop thru the array items one by one
' + Pretty File Names Compare Function ++++++++++++++++++++++++++++++
' This function will compare two string items containing numeric characters in
' a more intuitive order. It will take into account all occurences of numbers in
' the string items including in their extensions.
' It is intended for comparing filenames, and will apply the same intuitive order
' for folders in the file path if they contain numeric characters.
' Specifying a path is not required, neither do they need to have extensions, in
' fact, they do not need to be filenames; just strings that may contain numbers
' grouped together within the string text.
' In other words, it can be used for normal pretty sorting comparisons.
' But please note, this is intended for comparing filenames and is a little
' slower than the StrCompNumbers compare function below because of extra code
' to handle the extensions.
' If SortByExtension is specified it will compare the items by extension, whilst
' still producing an intuitive order of the file path and names that may have
' numbers within them and that have the same extension.
' Note: this will also sort pure numbers, which will group positive and negative
' numbers together from small values to large values (or reversed) irrespective
' of their sign.
' This is version two of this function which also handles numbers in the extension.
Public Function StrCompFileNames(sThis As String, sThan As String, Optional ByVal CapsFirst As Boolean, Optional ByVal Group As ePrettyFiles = GroupByFolder) As eCompare '-⌐Rd-
Dim periodThis As Long, extensThis As Long
Dim periodThan As Long, extensThan As Long
Dim tFNthis As tPrettySort, tEXTthis As tPrettySort
Dim tFNthan As tPrettySort, tEXTthan As tPrettySort
Dim numsN() As Long, numsE() As Long
Dim lpad As Long, lpads As Long, clen As Long
Dim filenmPthis As Long, extensPthis As Long
Dim filenmPthan As Long, extensPthan As Long
Dim lenPthis As Long, lenPthan As Long
Dim sTempThis As String, sTempThan As String
Dim eComp As eCompare, lPos As Long
Dim lenFN As Long, lenExt As Long
' First, we gather information about our filenames to use for the
' padding process and to access the extensions as needed later.
clen = Len(sThis) ' Cache the items length
lPos = InStrRev(sThis, "\") ' Determine position of the last backslash instance
If lPos = n0 Then lPos = InStrRev(sThis, "/") ' If no backslash then maybe it's a forward slash?
periodThis = InStrRev(sThis, ".") ' Determine position of the last period character
If periodThis = n0 Or periodThis < lPos Then ' If no period or it's before the last slash
periodThis = clen + n1 ' Set to item length instead, + phantom period pos
extensThis = n0
Else ' Record length of this items extension
extensThis = clen - periodThis
lenExt = extensThis
End If
lenFN = periodThis - n1
clen = Len(sThan) ' Cache the items length
lPos = InStrRev(sThan, "\") ' Determine position of the last backslash instance
If lPos = n0 Then lPos = InStrRev(sThan, "/") ' If no backslash then maybe it's a forward slash?
periodThan = InStrRev(sThan, ".") ' Determine position of the last period character
If periodThan = n0 Or periodThan < lPos Then ' If no period or it's before the last slash
periodThan = clen + n1 ' Set to item length instead, + phantom period pos
extensThan = n0
Else ' Record length of than items extension
extensThan = clen - periodThan
If extensThan > lenExt Then lenExt = extensThan
End If
If periodThan - n1 > lenFN Then lenFN = periodThan - n1
' Set nums to the maximum position that numbers can occur in the strings.
ReDim numsN(n0 To lenFN) As Long
ReDim numsE(n0 To lenExt) As Long
' Find all occurences of numeric chars in the filename portion of the items.
GoNumLoop tFNthis, sThis, numsN, periodThis
GoNumLoop tFNthan, sThan, numsN, periodThan
' Next calculate the padding length for all num inst's in each filename, and
' add them together to determine the total padding needed for each filename.
' The total lengths are compared to identify which is longest, and that will
' be used to pre-allocate the string lengths for faster string operations.
lpad = GoPadLoop(tFNthis, numsN) ' Calc the padding length for this filename
lpads = lpad ' Set lpads to this padding length
clen = periodThis - n1 + lpad ' Calc the length of this filename when padded
lenFN = clen ' Set lenFN to this filename length
filenmPthis = clen ' Record the new length of this filename when padded
lpad = GoPadLoop(tFNthan, numsN) ' Calc the padding length for than filename
If lpad > lpads Then lpads = lpad ' Set lpads to longest padding length
clen = periodThan - n1 + lpad ' Calc the length of than filename when padded
If clen > lenFN Then lenFN = clen ' Set lenFN to longest filename length
filenmPthan = clen ' Record the new length of than filename when padded
' Find all occurences of numeric chars in the extension portion of the items.
Mid$(temp, lPos) = Mid$(item, lRead) ' Assign the rest of the item to temp array
End If
End Sub
' + Validate Index Array +++++++++++++++++++++++++++++++++++++++
' This will initialize the passed index array if it is not already.
' This sub-routine requires that the index array be passed either
' prepared for the sort process (see the For loop) or that it be
' uninitialized (or Erased).
' This permits subsequent sorting of the data without interfering
' with the index array if it is already sorted (based on criteria
' that may differ from the current process) and so is not in its
' uninitialized or primary pre-sort state produced by the For loop.
Sub ValidateIdxArray(lIdxA() As Long, ByVal lbA As Long, ByVal ubA As Long)
Dim bReDim As Boolean, lb As Long, ub As Long, j As Long
lb = &H80000000: ub = &H7FFFFFFF
bReDim = Not InitedArray(lIdxA, lb, ub)
If bReDim = False Then
bReDim = lbA < lb Or ubA > ub
End If
If bReDim Then
ReDim lIdxA(lbA To ubA) As Long
For j = lbA To ubA
lIdxA(j) = j
Next
End If
End Sub
' + Stable QuickSort 2.2 Indexed Version ++++++++++++++++++++
' This is an indexed stable non-recursive quicksort.
' This is the latest version of my stable Avalanche algorithm, which
' is a non-recursive quicksort based algorithm that has been written
' from the ground up as a stable alternative to the blindingly fast
' quicksort.
' It has the benifit of indexing which allows the source array to
' remain unchanged. This also allows the index array to be passed
' on to other sort processes to be further manipulated.
' It uses a long array that holds references to the string arrays
' indices. This is known as an indexed sort. No changes are made
' to the source string array.
' After a sort procedure is run the long array is ready as a sorted
' index to the string array items.
' E.G sA(idxA(lo)) returns the lo item in the string array whose
' index may be anywhere in the string array.
Sub strStableSort2Indexed(sA() As String, idxA() As Long, ByVal lbA As Long, ByVal ubA As Long)
' This is my indexed stable non-recursive quick sort
If Not InitedArray(sA, lbA, ubA) Then Exit Sub
Dim item As String, lpStr As Long, lpS As Long
Dim walk As Long, find As Long, midd As Long
Dim base As Long, run As Long, cast As Long
Dim idx clen = gethe eC Write l Dim baUhe pad ' Rec
' It has the benifit of ind
lbA, ubA
che a1rty
End tring, ly as ut assigning any rty
End tringf ind
lbA, ubA
che a1rty
End Oi
lbA,r indices. This is known as F ris ris ris ris r1
' ind)noccurence counter>Rec
' Itkos) tring a=nd
lbA, ubA
sis iuntidxAs) tring a=nd
pecifNps, nulen = get8 Dim bReDim As ing itemste por manipulated.
' It uses a long array that holds references to the string arrays
' indices. This is known as an indexed sort. No changes are made
' to the source string array.
' After a sort proceduredicgths for faster string operations.
lpad = GoPadLoop(tPNthis, nums) ' Ca Sor Aft, spet SortMethod property
End Sub
aod propertyding length fDim baUhe pad ' Rec nu count of thxtCompt processes to be fuocesses lestring arrays
' indices. This ing
ais esses iIf Not l iIf Not l n(idxA(lo)) ed sor
t proceduredicgths for faster
ais Not l iIf NDt8enc * 2ywhcgths y that has bentsm1rtyp_ sA(idxA(lo)) rlylpad ' 0ed).
' This p
CopyMemByV lpL, lp) ed sor
lbA, ubA
che a1rty
End Oi
agptringf ind
lbA, ubA
che_rtOrder = (Cappare '-⌐Rd-
Dim t For los esses =yp_ sA(idx s esses =yp lpL =ex Array (Cappare '-⌐Rd-
Dim t For los essrwggggggggster string building operations.
sTempThis = Space$(lenPthis)
y as lentritidx, ubA
che a1rty
End Oy0nse
sTempThis = Space lptem pad len) rlyl).>aWrite l Dim baUex ArraO rlem pad len) rlyl)pThis = Space lptem pad len) rlyl).>aWri,omplen) rlyl).>aWri,omplen) rlyl).>aWri,ompA(idxA(elenElen) rlyl)pThis "+++++++++++
' Sort with binarysrlyl
' Sort withi As Boolean = True) '-⌐Rd-
If Not Intions.
:)op
If Not lPos > alized (or Erased).
' This permits subsequent sorting ofm prebisteeeee
If rlyC Lonnnnnnnnnnnnis = Space lptem pad leeFdThan por maad leeFxsis iunt If r CopyMeaWri,ompA(ie If rlbA) d Oi
agptrin=r<:ges of numeric chars in the strie
stzed (or Erased). ,ot withi A prevOrderng buildinsubsequent rraO rlem pad n ubA
che atem bosite anywhere in th>y
End Oi
ae strie
Uhe pad ' Rec
' I Tht rrEnd Oi
ae strlbA, ubA ' Reset ruildch If rlbA) dixrting ofm. tsis iunt If r CopyMeaWrt2ilbA) BqaA Mid$(tem E 2< ofn = treDim l idxA,,,,,,,,,,,,,,st
' Sort with binary itemEnd bm = Not InitedArray(lId). ,ot withi SortMeti
'fas lReadRpns sub-routi 2< oindexe of o=A() Write l As Long)hars t num i lP,,,,,,,,
bgesuuuuuuuu If Not InitedArray(sA, lbA, ubA) Then Exit Sub
Dim aIdx() As Long, lAbuf() As Long
Dim lpS As Long, lpL As Long
Dim walk As Long, cnt As Long
cnt = ubA - lbA + n1 ' Grab array item count
If (cnt < n1) Thsivg por walk = lbAnlirXthhhhhhhhhpermits su )hars t num i lP,,f my stable Avalrm walk As Long, cntchn j
ce stCm
' ThiMemByV lpA, lbA, ubA) Then Exit Sub
Dim aIdx() As t j
ce stawb n1 NmpS, lpL,lC lpL,lche a1rt ais o() As t j
d O:s eslum inst's atCm
lee , idxAsA
che a1rty
End Oi
lbA,r indices. This is known as F maet w filenmPthis = clr As -whO rnorettySthis, Mid$(sThi l)as lRe*s known as F i nmPt$(sTis k As Lt pointer a,own adLoop(tPS ubsequent rraO rlem pad n nnt <l' Rec nl2d n n >aWri,ompA(i i,ompA(i ic aIx Descending(-1) : True(-1) >> Ascending(1)
Gn GoPadLoopi=bo lentrit Long
Dim walk As Long, find As Long, midd As Long
Dim base As Long, run As Long, cast As Long
Dim idx clen = gethe eC Write l Dim baUhe pad ' Rec
' It has the benifit of ind
lbA, ubA
che a1rty
End tring, ly as ut assigning anri,omplen) rlyl).>aWrunding a=nis isigninglic chars Dirscest
clen = lPos -faster string operations.
ong, lpS As Long
Dim walk As Long, find As Long, midd As Long
m lpS AEnd Oi
agptringf ind
lbA, ubA n
bRehan, lenrettsms with case-insen Lonngly f, leStore padf indr maad leeFxsis iunt If , leStond
rwith kcompa =ex Array lglye) +
' Sort with bina=ex Arb, nul stawb n1 Nmt pointer a,own adLoop(tPS u .rbm= tPS.idxn(oc) with bina=ex ArbpoidxA,RArbpoidxArnoretdd As Lon lpaad less su )harown as F maet w filenmPthis = clr As -w pad: maet w filenmPthis = clr As -w pad: lo))TThis o, cast As Long
ubA
lpS AEnd Oi
lesd leewe lo))im maet w filenmPthis = clr As -w pad: n d len f re maet w filenmPthis = clr As -w pad: lentrg
rssrwggggggggster stri compVor- i
ag maet w ft length
End If
'Assert oc <= MAX_DISCRETE_OCCUR_NUMS
f Grouptbf 'Assert oc y
End tring, ly as ut oc <= MAX_DISCRETE_OCCUR_NUMS
f Grouptbf 'Assert oc y
End tring, ly as ut ocoupdThan por maad leeFxsis iunt If r CopyMeaWri,ompA(ie If rlbA) d Oi
agptrin=r<:ges of2esdrlbA) d Oi
agp por maadA DaadA ing ofm prU2 f rray t, leStond
rwith kcompa =ex Arrcursive qu n
SutrinAH end
bRehan, lenretagp por maa ' Rec
-otagOlr As -w pad: bRehandfin, lpS As LonDehandfin, l
ud len) rlyl).>aWri,oAs -w pad: n d len fanri,omplnnnnnnis = Space lptem pad le len
SortMetho w filenmPthis = clr As -wnnnnnthis num inst
End Is num inst
End Isw ubAster stri compVor- B tPmd: or maad lea Sornd tring, ly a.
' Next, lprence countnnnnis = Spemp,eeFxsie IsNumc w filenmPthis = clr l filenmPthis l filenmPthis l filenmPthis l filenmPthis l filenmPthis l filenmPthis l =nifIbPthilenmPthis lcompa s s
SutrinAH end
baathi( filenhe a1rtyo Rns e etho w Isw ubAssw ubAlenhe a1rtyog, ByVal lbA'p,eeFxsiAce u ) ' Grab index of next Rter string bReDfor thiilenmPthis lco5nter
is lco5ntAs Long
m lpS AEnd Oi
agptringf ind
,r pos
tAs Long
m lpS AEnd Oi
agptrtem num i d len nd Oi
agsoccurs ' Do until no mor If AEnd Oi
agpt=ex st c lRead As Long, oc As Ltmaetalrm walkl = (Cappare '-⌐Rd-
agpt=ex st c lRead As Long, oc As Ltmaetalrm 6o5ntAL =ex Array (Cappare '-⌐Rd-
Ditt Ditt Ditt etalrmg, oc lbA, ubAotCompare)
w pad: lit
SutrinAHpare)
w pad: lit
SutrinAHD .lL =ex Arragptr(numssssanextOrd End IaadA sm) 'a1rt ' Set occurentrin + n1 As L Isw ubAssw ubAlenhe a1rtyog, ByVaf2esdrlbA) d Oi
agp ad As )elfrs with the index)elfrs with the index)elfrsiables
->d
baUrnith b4-
Ifs itiablex)elfrsiSDumLoop tPNthan, sDi sTeany stabAielfrsi compVlae2 f rray t, ab index of ssw ubAlenhe a1rtyog, ByVaf2esdrlbA) d As Lh :)oplOftsis iunt If r Co filenmPthisointer Nextst If amaetal1 f 0rray lum walkl = (C: atalrmg, ocpyMemByV lp
w pad:aisointer Nexer
iXe datadd len for this pos
maetfrsiableod IaadA sm)t I Co filenmPthisolpfrsiableod IaadA sm)riteroceduredicg Lh :)opeod IaadA s Sutrid lPot As Lhsylo))lestring acdadA s Su nn lPot As Lhsylo))lestring acdadA s Su nn olds references to thi d len Dittnnnnis = Spacu SuPthis = emp array
ce lp)rencb inded+he source afs i
maetfrsiableod IaadA sm)t I source afs , midd As LongbA sive qu
m lpnst) Theotadd ud
baUrnith bprty instAerences to thi d len Dim lpnng arraypl lPot As Lhs sourcet f Gr:'=end
bRehan, lenretagp por maa ' Rec
-otamLoop tPNthan,mpVlae2 Not Initedlk As Long, siablrstring acdadA s Su nulready nn olds ref c DimCo filenmPthisointer Nextst If amaetal1 f 0extst If arrrrr maetfrsiableod IaadA sm)t I Co filenmPthisolpfrsiableod IaadA sm)riteet w ft length
End s Lond s Lond Lond Lond Lond Lond Lond Lond Lond Lond Lond Lond Lond Lond Lond Lond n, la3s End If
d Ls Lond s Lond Lond L nn olds refeb, u Ls Lond s Lond Lond Larsiableod IaadA sm)Du0 Calc sdLoop(tPSsesd lb u Ls im atalrmg, ocpyMemBy sdLoop(tPSpproduced pr. w s Lond sa4r 0Sort 2p(tPBy sdLoop(tPSpproduced pr. wing Not InitedArray(lId)ay t has the benc DimCoet pr. wing gOlr As -w pad: bRehanmByV lp
w pad:aisointly aitive order. It will take into accoet pr(tPSsesd lb u Ls im atlmlr As -whO r'hose
' index may be anywhere in the string array.
Sub strStableSort2Indexed(sA() As String, idxA() As Long, ByVal lbA As Long, ByVal ubA As Long)
' This is my indexed stable non-recursive quick sort
If Not InitedArray(sA, lbA, ubA) Then Exit SunAH endy(sA, lbA, ubA) Then l the . It willBblrstr 2 f rray t, ab index of ssw ubAlenhe a1rtyog, ByVaf2esdrlbA) d As LlpS Aond Lo sdLong
ung(1)
Gn Gtive order.End t)pS Aond Lo n,iong
s))( ThxNothis = clr Isw ub,lCompareing acdadA s eing2iuious Dim yon to seperate upper and lower
' case letters in the order specified by CapsFirst.
' yw pad: lentrg
rssrwggggggggster stri compVor- i
ag maet w ft length
th binary d padding before filenamen.
' yw pabefore filenamen.
' ywgggggggster st png ag maet w 0AIdx() As td: lit
SutrinAHpare)
w pad: lit
SutrinAHD .lL =ex Arragptr(numssssanextOrd End Iaathi( by CapsFirst.
' yw pad: lentrgg, ByValt
cer stri co the order specified by CapsFirst.
' yFPr it
SutridA ' Thisohe order spPindex yog, ByVaf2esth case-insen Lo'Xnd ine-(C: 'stthi d De ord paded Iaathi( by ord paded Iueh++++++++++++++++++++++se-insen g
et w ft le Lo nnis '++++++dicgths for faster stro the
et w f yw pad: le>'stt
-otar s(: lentrgl iIf Not l n(idmae ' Cale Lo nnis ee