You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lib.Collections.asp 20KB

8 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. <%
  2. '=======================================================================================================================
  3. ' KVArray
  4. ' Relatively painless implementation of key/value pair arrays without requiring a full Scripting.Dictionary COM instance.
  5. ' A KVArray is a standard array where element i is the key and element i+1 is the value. Loops must step by 2.
  6. '=======================================================================================================================
  7. 'given a KVArray and key index, returns the key and value
  8. 'pre: kv_array has at least key_idx and key_idx + 1 values
  9. 'post: key and val are populated
  10. Sub KeyVal(kv_array, key_idx, ByRef key, ByRef val)
  11. if (key_idx + 1 > ubound(kv_array)) then err.raise 1, "KeyVal", "expected key_idx < " & ubound(kv_array) - 1 & ", got: " & key_idx
  12. key = kv_array(key_idx)
  13. val = kv_array(key_idx + 1)
  14. End Sub
  15. '---------------------------------------------------------------------------------------------------------------------
  16. 'Given a KVArray, a key and a value, appends the key and value to the end of the KVArray
  17. Sub KVAppend(ByRef kv_array, key, val)
  18. dim i : i = ubound(kv_array)
  19. redim preserve kv_array(i + 2)
  20. kv_array(i + 1) = key
  21. kv_array(i + 2) = val
  22. End Sub
  23. '-----------------------------------------------------------------------------------------------------------------------
  24. 'Given a KVArray and two variants, populates the first variant with all keys and the second variant with all values.
  25. 'If
  26. 'Pre: kv_array has at least key_idx and key_idx + 1 values
  27. 'Post: key_array contains all keys in kvarray.
  28. ' val_array contains all values in kvarray.
  29. ' key_array and val_array values are in corresponding order, i.e. key_array(i) corresponds to val_array(i).
  30. Sub KVUnzip(kv_array, key_array, val_array)
  31. dim kv_array_size : kv_array_size = ubound(kv_array)
  32. dim num_pairs : num_pairs = (kv_array_size + 1) / 2
  33. dim result_array_size : result_array_size = num_pairs - 1
  34. 'Extend existing key_array or create new array to hold the keys
  35. If IsArray(key_array) then
  36. redim preserve key_array(ubound(key_array) + result_array_size)
  37. Else
  38. key_array = Array()
  39. redim key_array(result_array_size)
  40. End If
  41. 'Extend existing val array or create new array to hold the values
  42. If IsArray(val_array) then
  43. redim preserve val_array(ubound(val_array) + result_array_size)
  44. Else
  45. val_array = Array()
  46. redim val_array(num_pairs - 1)
  47. End If
  48. 'Unzip the KVArray into the two output arrays
  49. dim i, key, val
  50. dim key_val_arrays_idx : key_val_arrays_idx = 0 ' used to sync loading the key_array and val_array
  51. For i = 0 to ubound(kv_array) step 2
  52. KeyVal kv_array, i, key, val
  53. key_array(key_val_arrays_idx) = key
  54. val_array(key_val_arrays_idx) = val
  55. key_val_arrays_idx = key_val_arrays_idx + 1 ' increment by 1 because loop goes to next pair in kv_array
  56. Next
  57. End Sub
  58. '---------------------------------------------------------------------------------------------------------------------
  59. 'Given a KVArray, dumps it to the screen. Useful for debugging purposes.
  60. Sub DumpKVArray(kv_array)
  61. dim i, key, val
  62. For i = 0 to ubound(kv_array) step 2
  63. KeyVal kv_array, i, key, val
  64. put key & " => " & val & "<br>"
  65. Next
  66. End Sub
  67. '=======================================================================================================================
  68. ' Pair Class
  69. ' Holds a pair of values, i.e. a key value pair, recordset field name/value pair, etc.
  70. ' Similar to the C++ STL std::pair class. Useful for some iteration and the like.
  71. '
  72. ' This was an interesting idea but so far has not really been used, oh well......
  73. '=======================================================================================================================
  74. Class Pair_Class
  75. Private m_first, m_second
  76. Public Property Get First : First = m_first : End Property
  77. Public Property Get [Second] : [Second] = m_second : End Property
  78. Public Default Property Get TO_String
  79. TO_String = First & " " & [Second]
  80. End Property
  81. Public Sub Initialize(ByVal firstval, ByVal secondval)
  82. Assign m_first, firstval
  83. Assign m_second, secondval
  84. End Sub
  85. 'Swaps the two values
  86. Public Sub Swap
  87. dim tmp
  88. Assign tmp, m_second
  89. Assign m_second, m_first
  90. Assign m_first, tmp
  91. End Sub
  92. End Class
  93. Function MakePair(ByVal firstval, ByVal secondval)
  94. dim P : set P = new Pair_Class
  95. P.Initialize firstval, secondval
  96. set MakePair = P
  97. End Function
  98. '=======================================================================================================================
  99. ' Linked List - From the Tolerable lib
  100. '=======================================================================================================================
  101. ' This is just here for reference
  102. Class Iterator_Class
  103. Public Function HasNext()
  104. End Function
  105. Public Function PeekNext()
  106. End Function
  107. Public Function GetNext()
  108. End Function
  109. Public Function HasPrev()
  110. End Function
  111. Public Function PeekPrev()
  112. End Function
  113. Public Function GetPrev()
  114. End Function
  115. End Class
  116. Class Enumerator_Source_Iterator_Class
  117. Private m_iter
  118. Public Sub Initialize(ByVal iter)
  119. Set m_iter = iter
  120. End Sub
  121. Private Sub Class_Terminate()
  122. Set m_iter = Nothing
  123. End Sub
  124. Public Sub GetNext(ByRef retval, ByRef successful)
  125. If m_iter.HasNext Then
  126. Assign retval, m_iter.GetNext
  127. successful = True
  128. Else
  129. successful = False
  130. End If
  131. End Sub
  132. End Class
  133. Public Function En_Iterator(ByVal iter)
  134. Dim retval
  135. Set retval = New Enumerator_Source_Iterator_Class
  136. retval.Initialize iter
  137. Set En_Iterator = Enumerator(retval)
  138. End Function
  139. Class LinkedList_Node_Class
  140. Public m_prev
  141. Public m_next
  142. Public m_value
  143. Private Sub Class_Initialize()
  144. Set m_prev = Nothing
  145. Set m_next = Nothing
  146. End Sub
  147. Private Sub Class_Terminate()
  148. Set m_prev = Nothing
  149. Set m_next = Nothing
  150. Set m_value = Nothing
  151. End Sub
  152. Public Sub SetValue(ByVal value)
  153. Assign m_value, value
  154. End Sub
  155. End Class
  156. Class Iterator_LinkedList_Class
  157. Private m_left
  158. Private m_right
  159. Public Sub Initialize(ByVal r)
  160. Set m_left = Nothing
  161. Set m_right = r
  162. End Sub
  163. Private Sub Class_Terminate()
  164. Set m_Left = Nothing
  165. Set m_Right = Nothing
  166. End Sub
  167. Public Function HasNext()
  168. HasNext = Not(m_right Is Nothing)
  169. End Function
  170. Public Function PeekNext()
  171. Assign PeekNext, m_right.m_value
  172. End Function
  173. Public Function GetNext()
  174. Assign GetNext, m_right.m_value
  175. Set m_left = m_right
  176. Set m_right = m_right.m_next
  177. End Function
  178. Public Function HasPrev()
  179. HasPrev = Not(m_left Is Nothing)
  180. End Function
  181. Public Function PeekPrev()
  182. Assign PeekPrev, m_left.m_value
  183. End Function
  184. Public Function GetPrev()
  185. Assign GetPrev, m_left.m_value
  186. Set m_right = m_left
  187. Set m_left = m_left.m_prev
  188. End Function
  189. End Class
  190. '-----------------------------------------------------------------------------------------------------------------------
  191. Class LinkedList_Class
  192. Private m_first
  193. Private m_last
  194. Private m_size
  195. Private Sub Class_Initialize()
  196. Me.Reset
  197. End Sub
  198. Private Sub Class_Terminate()
  199. Me.Reset
  200. End Sub
  201. Public Function Clear()
  202. Set m_first = Nothing
  203. Set m_last = Nothing
  204. m_size = 0
  205. Set Clear = Me
  206. End Function
  207. Private Function NewNode(ByVal value)
  208. Dim retval
  209. Set retval = New LinkedList_Node_Class
  210. retval.SetValue value
  211. Set NewNode = retval
  212. End Function
  213. Public Sub Reset()
  214. Set m_first = Nothing
  215. Set m_last = Nothing
  216. m_size = 0
  217. End Sub
  218. Public Function IsEmpty()
  219. IsEmpty = (m_last Is Nothing)
  220. End Function
  221. Public Property Get Count
  222. Count = m_size
  223. End Property
  224. 'I just like .Size better than .Count sometimes, sue me
  225. Public Property Get Size
  226. Size = m_size
  227. End Property
  228. Public Function Iterator()
  229. Dim retval
  230. Set retval = New Iterator_LinkedList_Class
  231. retval.Initialize m_first
  232. Set Iterator = retval
  233. End Function
  234. Public Function Push(ByVal value)
  235. Dim temp
  236. Set temp = NewNode(value)
  237. If Me.IsEmpty Then
  238. Set m_first = temp
  239. Set m_last = temp
  240. Else
  241. Set temp.m_prev = m_last
  242. Set m_last.m_next = temp
  243. Set m_last = temp
  244. End If
  245. m_size = m_size + 1
  246. Set Push = Me
  247. End Function
  248. Public Function Peek()
  249. ' TODO: Error handling
  250. Assign Peek, m_last.m_value
  251. End Function
  252. ' Alias for Peek
  253. Public Function Back()
  254. ' TODO: Error handling
  255. Assign Back, m_last.m_value
  256. End Function
  257. Public Function Pop()
  258. Dim temp
  259. ' TODO: Error Handling
  260. Assign Pop, m_last.m_value
  261. Set temp = m_last
  262. Set m_last = temp.m_prev
  263. Set temp.m_prev = Nothing
  264. If m_last Is Nothing Then
  265. Set m_first = Nothing
  266. Else
  267. Set m_last.m_next = Nothing
  268. End If
  269. m_size = m_size - 1
  270. End Function
  271. Public Function Unshift(ByVal value)
  272. Dim temp
  273. Set temp = NewNode(value)
  274. If Me.IsEmpty Then
  275. Set m_first = temp
  276. Set m_last = temp
  277. Else
  278. Set temp.m_next = m_first
  279. Set m_first.m_prev = temp
  280. Set m_first = temp
  281. End If
  282. m_size = m_size + 1
  283. Set Unshift = Me
  284. End Function
  285. ' Alias for Peek
  286. Public Function Front()
  287. ' TODO: Error handling
  288. Assign Front, m_first.m_value
  289. End Function
  290. Public Function Shift()
  291. Dim temp
  292. ' TODO: Error Handling
  293. Assign Shift, m_first.m_value
  294. Set temp = m_first
  295. Set m_first = temp.m_next
  296. Set temp.m_next = Nothing
  297. If m_first Is Nothing Then
  298. Set m_last = Nothing
  299. Else
  300. Set m_first.m_prev = Nothing
  301. End If
  302. m_size = m_size - 1
  303. End Function
  304. Public Function TO_Array()
  305. Dim i, iter
  306. ReDim retval(Me.Count - 1)
  307. i = 0
  308. Set iter = Me.Iterator
  309. While iter.HasNext
  310. retval(i) = iter.GetNext
  311. i = i + 1
  312. Wend
  313. TO_Array = retval
  314. End Function
  315. Public Function TO_En()
  316. Set TO_En = En_Iterator(Iterator)
  317. End Function
  318. End Class
  319. '=======================================================================================================================
  320. ' Dynamic Array - From the Tolerable lib
  321. '=======================================================================================================================
  322. Class DynamicArray_Class
  323. Private m_data
  324. Private m_size
  325. Public Sub Initialize(ByVal d, ByVal s)
  326. m_data = d
  327. m_size = s
  328. End Sub
  329. Private Sub Class_Terminate()
  330. Set m_data = Nothing
  331. End Sub
  332. Public Property Get Capacity
  333. Capacity = UBOUND(m_data) + 1
  334. End Property
  335. Public Property Get Count
  336. Count = m_size
  337. End Property
  338. ' Alias for Count
  339. Public Property Get Size
  340. Size = m_size
  341. End Property
  342. Public Function IsEmpty()
  343. IsEmpty = (m_size = 0)
  344. End Function
  345. Public Function Clear()
  346. m_size = 0
  347. Set Clear = Me
  348. End Function
  349. Private Sub Grow
  350. ' TODO: There's probably a better way to
  351. ' do this. Doubling might be excessive
  352. ReDim Preserve m_data(UBOUND(m_data) * 2)
  353. End Sub
  354. Public Function Push(ByVal val)
  355. If m_size >= UBOUND(m_data) Then
  356. Grow
  357. End If
  358. Assign m_data(m_size), val
  359. m_size = m_size + 1
  360. Set Push = Me
  361. End Function
  362. ' Look at the last element
  363. Public Function Peek()
  364. Assign Peek, m_data(m_size - 1)
  365. End Function
  366. ' Look at the last element and
  367. ' pop it off of the list
  368. Public Function Pop()
  369. Assign Pop, m_data(m_size - 1)
  370. m_size = m_size - 1
  371. End Function
  372. ' If pseudo_index < 0, then we assume we're counting
  373. ' from the back of the Array.
  374. Private Function CalculateIndex(ByVal pseudo_index)
  375. If pseudo_index >= 0 Then
  376. CalculateIndex = pseudo_index
  377. Else
  378. CalculateIndex = m_size + pseudo_index
  379. End If
  380. End Function
  381. Public Default Function Item(ByVal i)
  382. Assign Item, m_data(CalculateIndex(i))
  383. End Function
  384. ' This does not treat negative indices as wrap-around.
  385. ' Thus, it is slightly faster.
  386. Public Function FastItem(ByVal i)
  387. Assign FastItem, m_data(i)
  388. End Function
  389. Public Function Slice(ByVal s, ByVal e)
  390. s = CalculateIndex(s)
  391. e = CalculateIndex(e)
  392. If e < s Then
  393. Set Slice = DynamicArray()
  394. Else
  395. ReDim retval(e - s)
  396. Dim i, j
  397. j = 0
  398. For i = s to e
  399. Assign retval(j), m_data(i)
  400. j = j + 1
  401. Next
  402. Set Slice = DynamicArray1(retval)
  403. End If
  404. End Function
  405. Public Function Iterator()
  406. Dim retval
  407. Set retval = New Iterator_DynamicArray_Class
  408. retval.Initialize Me
  409. Set Iterator = retval
  410. End Function
  411. Public Function TO_En()
  412. Set TO_En = En_Iterator(Me.Iterator)
  413. End Function
  414. Public Function TO_Array()
  415. Dim i
  416. ReDim retval(m_size - 1)
  417. For i = 0 to UBOUND(retval)
  418. Assign retval(i), m_data(i)
  419. Next
  420. TO_Array = retval
  421. End Function
  422. End Class
  423. Public Function DynamicArray()
  424. ReDim data(3)
  425. Set DynamicArray = DynamicArray2(data, 0)
  426. End Function
  427. Public Function DynamicArray1(ByVal data)
  428. Set DynamicArray1 = DynamicArray2(data, UBOUND(data) + 1)
  429. End Function
  430. Private Function DynamicArray2(ByVal data, ByVal size)
  431. Dim retval
  432. Set retval = New DynamicArray_Class
  433. retval.Initialize data, size
  434. Set DynamicArray2 = retval
  435. End Function
  436. Class Iterator_DynamicArray_Class
  437. Private m_dynamic_array
  438. Private m_index
  439. Public Sub Initialize(ByVal dynamic_array)
  440. Set m_dynamic_array = dynamic_array
  441. m_index = 0
  442. End Sub
  443. Private Sub Class_Terminate
  444. Set m_dynamic_array = Nothing
  445. End Sub
  446. Public Function HasNext()
  447. HasNext = (m_index < m_dynamic_array.Size)
  448. End Function
  449. Public Function PeekNext()
  450. Assign PeekNext, m_dynamic_array.FastItem(m_index)
  451. End Function
  452. Public Function GetNext()
  453. Assign GetNext, m_dynamic_array.FastItem(m_index)
  454. m_index = m_index + 1
  455. End Function
  456. Public Function HasPrev()
  457. HasPrev = (m_index > 0)
  458. End Function
  459. Public Function PeekPrev()
  460. Assign PeekPrev, m_dynamic_array.FastItem(m_index - 1)
  461. End Function
  462. Public Function GetPrev()
  463. Assign GetPrev, m_dynamic_array.FastItem(m_index - 1)
  464. m_index = m_index - 1
  465. End Function
  466. End Class
  467. '=======================================================================================================================
  468. ' Other Iterators
  469. '=======================================================================================================================
  470. '!!! EXPERIMENTAL !!! May not be very useful, oh well...
  471. Class Iterator_Recordset_Class
  472. Private m_rs
  473. Private m_record_count
  474. Private m_current_index
  475. Private m_field_names 'cached array
  476. Public Sub Initialize(ByVal rs)
  477. Set m_rs = rs
  478. m_rs.MoveFirst
  479. m_rs.MovePrevious
  480. m_record_count = rs.RecordCount
  481. m_current_index = 0
  482. 'cache field names
  483. m_field_names = array()
  484. redim m_field_names(m_rs.Fields.Count)
  485. dim field
  486. dim i : i = 0
  487. for each field in m_rs.Fields
  488. m_field_names(i) = field.Name
  489. next
  490. End Sub
  491. Private Sub Class_Terminate
  492. Set m_rs = Nothing
  493. End Sub
  494. Public Function HasNext()
  495. HasNext = (m_current_index < m_record_count)
  496. put "m_current_index := " & m_current_index
  497. put "m_record_count := " & m_record_count
  498. End Function
  499. Public Function PeekNext
  500. if HasNext then
  501. m_rs.MoveNext
  502. Assign PeekNext, GetPairs
  503. m_rs.MovePrevious
  504. else
  505. set PeekNext = Nothing
  506. end if
  507. End Function
  508. Private Function GetPairs
  509. End Function
  510. Public Function GetNext
  511. if m_current_index < m_record_count then
  512. Assign GetNext, m_rs
  513. m_rs.MoveNext
  514. m_current_index = m_current_index + 1
  515. else
  516. set GetNext = Nothing
  517. end if
  518. End Function
  519. Public Function HasPrev()
  520. if m_rs.BOF then
  521. HasPrev = false
  522. else
  523. m_rs.MovePrevious
  524. HasPrev = Choice(m_rs.BOF, false, true)
  525. m_rs.MoveNext
  526. end if
  527. End Function
  528. Public Function PeekPrev
  529. m_rs.MovePrevious
  530. if m_rs.BOF then
  531. set PeekPrev = Nothing
  532. else
  533. Assign PeekPrev, m_rs
  534. end if
  535. m_rs.MoveNext
  536. End Function
  537. Public Function GetPrev
  538. m_rs.MovePrevious
  539. if m_rs.BOF then
  540. set GetPrev = Nothing
  541. else
  542. Assign GetPrev, m_rs
  543. end if
  544. End Function
  545. End Class
  546. Class Iterator_Dictionary_Class
  547. Private m_dic
  548. Private m_keys 'array
  549. Private m_idx 'current array index
  550. Private m_keys_ubound 'cached ubound(m_keys)
  551. Public Sub Initialize(ByVal dic)
  552. set m_dic = dic
  553. m_keys = m_dic.Keys()
  554. m_idx = -1
  555. m_keys_ubound = ubound(m_keys)
  556. End Sub
  557. Private Sub Class_Terminate
  558. set m_dic = Nothing
  559. End Sub
  560. Public Function HasNext()
  561. HasNext = (m_idx < m_keys_ubound)
  562. End Function
  563. Public Function PeekNext()
  564. Assign PeekNext, m_dic(m_keys(m_idx + 1))
  565. End Function
  566. Public Function GetNext()
  567. Assign GetNext, m_dic(m_keys(m_idx + 1))
  568. m_idx = m_idx + 1
  569. End Function
  570. Public Function HasPrev()
  571. HasPrev = (m_idx > 0)
  572. End Function
  573. Public Function PeekPrev()
  574. Assign PeekPrev, m_dic(m_keys(m_idx - 1))
  575. End Function
  576. Public Function GetPrev()
  577. Assign GetPrev, m_dic(m_keys(m_idx - 1))
  578. m_idx = m_idx - 1
  579. End Function
  580. End Class
  581. '=======================================================================================================================
  582. ' Iterator Factory
  583. '=======================================================================================================================
  584. 'Returns the appropriate iterator for the passed-in collection. Errors if unknown collection.
  585. Function IteratorFor(col)
  586. dim result
  587. select case typename(col)
  588. case "LinkedList_Class" : set result = new Iterator_LinkedList_Class
  589. case "Dictionary" : set result = new Iterator_Dictionary_Class
  590. case "Recordset" : set result = new Iterator_Recordset_Class
  591. end select
  592. result.Initialize col
  593. set IteratorFor = result
  594. End Function
  595. %>

Powered by TurnKey Linux.