linkedlist.bmx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  1. Strict
  2. Rem
  3. bbdoc: Data structures/Linked lists
  4. End Rem
  5. Module BRL.LinkedList
  6. ModuleInfo "Version: 1.11"
  7. ModuleInfo "Author: Mark Sibly"
  8. ModuleInfo "License: zlib/libpng"
  9. ModuleInfo "Copyright: Blitz Research Ltd"
  10. ModuleInfo "Modserver: BRL"
  11. ModuleInfo "History: 1.11"
  12. ModuleInfo "History: Fixed Delete issues with revised GC finalizer."
  13. ModuleInfo "History: 1.10"
  14. ModuleInfo "History: Fixed TLink removal during iteration issue."
  15. ModuleInfo "History: 1.09"
  16. ModuleInfo "History: Added internal count."
  17. ModuleInfo "History: (Debug) Assertion on modification during iteration."
  18. ModuleInfo "History: 1.08"
  19. ModuleInfo "History: Clear TLink fields on Remove()."
  20. ModuleInfo "History: Added enumeration pool."
  21. ModuleInfo "History: 1.07 Release"
  22. ModuleInfo "History: Changed Reverse to maintain TLink stability"
  23. ModuleInfo "History: 1.06 Release"
  24. ModuleInfo "History: Added optional CompareFunc parameter to Sort"
  25. ModuleInfo "History: 1.05 Release"
  26. ModuleInfo "History: Sort now swaps links instead of values"
  27. Function CompareObjects( o1:Object,o2:Object )
  28. Return o1.Compare( o2 )
  29. End Function
  30. Rem
  31. bbdoc: Link Object used by TList
  32. End Rem
  33. Type TLink
  34. Field _value:Object
  35. Field _succ:TLink,_pred:TLink
  36. Rem
  37. bbdoc: Returns the Object associated with this Link.
  38. End Rem
  39. Method Value:Object()
  40. Return _value
  41. End Method
  42. Rem
  43. bbdoc: Returns the next link in the List.
  44. End Rem
  45. Method NextLink:TLink()
  46. If _succ._value<>_succ Return _succ
  47. End Method
  48. Rem
  49. bbdoc: Returns the previous link in the List.
  50. End Rem
  51. Method PrevLink:TLink()
  52. If _pred._value<>_pred Return _pred
  53. End Method
  54. Rem
  55. bbdoc: Removes the link from the List.
  56. End Rem
  57. Method Remove()
  58. _pred._succ=_succ
  59. _succ._pred=_pred
  60. _value=Null
  61. End Method
  62. End Type
  63. Rem
  64. bbdoc: Enumerator Object use by TList in order to implement Eachin support.
  65. End Rem
  66. Type TListEnum
  67. Field _link:TLink
  68. Method HasNext()
  69. Return _link._value<>_link
  70. End Method
  71. Method NextObject:Object()
  72. Local value:Object=_link._value
  73. Assert value<>_link
  74. _link=_link._succ
  75. Return value
  76. End Method
  77. End Type
  78. Rem
  79. bbdoc: Linked List
  80. End Rem
  81. Type TList
  82. Field _head:TLink
  83. Field _count:Int = -1
  84. Method _pad()
  85. End Method
  86. Method New()
  87. _head=New TLink
  88. _head._succ=_head
  89. _head._pred=_head
  90. _head._value=_head
  91. End Method
  92. '?Not Threaded
  93. Method Delete()
  94. ' Clear
  95. ' _head._value=Null
  96. ' _head._succ=Null
  97. ' _head._pred=Null
  98. End Method
  99. '?
  100. Rem
  101. bbdoc: Clear a linked list
  102. about: Removes all objects from @list.
  103. End Rem
  104. Method Clear()
  105. While _head._succ<>_head
  106. _head._succ.Remove
  107. Wend
  108. _count = 0
  109. End Method
  110. Rem
  111. bbdoc: Check if list is empty
  112. returns: True if list is empty, else false
  113. end rem
  114. Method IsEmpty()
  115. Return _head._succ=_head
  116. End Method
  117. Rem
  118. bbdoc: Check if list contains a value
  119. returns: True if list contains @value, else false
  120. end rem
  121. Method Contains( value:Object )
  122. Local link:TLink=_head._succ
  123. While link<>_head
  124. If link._value.Compare( value )=0 Return True
  125. link=link._succ
  126. Wend
  127. Return False
  128. End Method
  129. Rem
  130. bbdoc: Add an object to the start of the list
  131. returns: A link object
  132. End Rem
  133. Method AddFirst:TLink( value:Object )
  134. Assert value Else "Can't insert Null object into list"
  135. Return InsertAfterLink( value,_head )
  136. End Method
  137. Rem
  138. bbdoc: Add an object to the end of the list
  139. returns: A link object
  140. End Rem
  141. Method AddLast:TLink( value:Object )
  142. Assert value Else "Can't insert Null object into list"
  143. Return InsertBeforeLink( value,_head )
  144. End Method
  145. Rem
  146. bbdoc: Returns the first object in the list
  147. about: Returns Null if the list is empty.
  148. End Rem
  149. Method First:Object()
  150. If IsEmpty() Return
  151. Return _head._succ._value
  152. End Method
  153. Rem
  154. bbdoc: Returns the last object in the list
  155. about: Returns Null if the list is empty.
  156. End Rem
  157. Method Last:Object()
  158. If IsEmpty() Return
  159. Return _head._pred._value
  160. End Method
  161. Rem
  162. bbdoc: Removes and returns the first object in the list.
  163. about: Returns Null if the list is empty.
  164. End Rem
  165. Method RemoveFirst:Object()
  166. If IsEmpty() Return
  167. Local value:Object=_head._succ._value
  168. _head._succ.remove
  169. If _count > -1 Then
  170. _count :- 1
  171. End If
  172. Return value
  173. End Method
  174. Rem
  175. bbdoc: Removes and returns the last object in the list.
  176. about: Returns Null if the list is empty.
  177. End Rem
  178. Method RemoveLast:Object()
  179. If IsEmpty() Return
  180. Local value:Object=_head._pred._value
  181. _head._pred.remove
  182. If _count > -1 Then
  183. _count :- 1
  184. End If
  185. Return value
  186. End Method
  187. Rem
  188. bbdoc: Returns the first link the list or null if the list is empty.
  189. End Rem
  190. Method FirstLink:TLink()
  191. If _head._succ<>_head Return _head._succ
  192. End Method
  193. Rem
  194. bbdoc: Returns the last link the list or null if the list is empty.
  195. End Rem
  196. Method LastLink:TLink()
  197. If _head._pred<>_head Return _head._pred
  198. End Method
  199. Rem
  200. bbdoc: Inserts an object before the specified list link.
  201. End Rem
  202. Method InsertBeforeLink:TLink( value:Object,succ:TLink )
  203. Assert value Else "Can't insert Null object into list"
  204. Local link:TLink=New TLink
  205. link._value=value
  206. link._succ=succ
  207. link._pred=succ._pred
  208. link._pred._succ=link
  209. succ._pred=link
  210. If _count > -1 Then
  211. _count :+ 1
  212. End If
  213. Return link
  214. End Method
  215. Rem
  216. bbdoc: Inserts an object after the specified list link.
  217. End Rem
  218. Method InsertAfterLink:TLink( value:Object,pred:TLink )
  219. Assert value Else "Can't insert Null object into list"
  220. Local link:TLink=New TLink
  221. link._value=value
  222. link._pred=pred
  223. link._succ=pred._succ
  224. link._succ._pred=link
  225. pred._succ=link
  226. If _count > -1 Then
  227. _count :+ 1
  228. End If
  229. Return link
  230. End Method
  231. Rem
  232. bbdoc: Returns the first link in the list with the given value, or null if none found.
  233. End Rem
  234. Method FindLink:TLink( value:Object )
  235. Local link:TLink=_head._succ
  236. While link<>_head
  237. If link._value.Compare( value )=0 Return link
  238. link=link._succ
  239. Wend
  240. End Method
  241. Rem
  242. bbdoc: Returns the value of the link at the given index.
  243. about: Throws an exception if the index is out of range (must be 0..list.Count()-1 inclusive).
  244. End Rem
  245. Method ValueAtIndex:Object( index )
  246. Assert index>=0 Else "Object index must be positive"
  247. Local link:TLink=_head._succ
  248. While link<>_head
  249. If Not index Return link._value
  250. link=link._succ
  251. index:-1
  252. Wend
  253. RuntimeError "List index out of range"
  254. End Method
  255. Rem
  256. bbdoc: Count list length
  257. returns: The numbers of objects in @list.
  258. end rem
  259. Method Count()
  260. If _count = -1 Then
  261. _count = 0
  262. Local link:TLink=_head._succ
  263. While link<>_head
  264. _count:+1
  265. link=link._succ
  266. Wend
  267. End If
  268. Return _count
  269. End Method
  270. Rem
  271. bbdoc: Remove an object from a linked list
  272. about: Remove scans a list for the specified value and removes its link.
  273. End Rem
  274. Method Remove( value:Object )
  275. Local link:TLink=FindLink( value )
  276. If Not link Return False
  277. link.Remove
  278. If _count > -1 Then
  279. _count :- 1
  280. End If
  281. Return True
  282. End Method
  283. Rem
  284. bbdoc: Swap contents with the list specified.
  285. End Rem
  286. Method Swap( list:TList )
  287. Local head:TLink=_head
  288. _head=list._head
  289. list._head=head
  290. Local c:Int = list._count
  291. list._count = _count
  292. _count = c
  293. End Method
  294. Rem
  295. bbdoc: Creates an identical copy of the list.
  296. End Rem
  297. Method Copy:TList()
  298. Local list:TList=New TList
  299. list._count = 0
  300. Local link:TLink=_head._succ
  301. While link<>_head
  302. list.AddLast link._value
  303. link=link._succ
  304. Wend
  305. Return list
  306. End Method
  307. Rem
  308. bbdoc: Reverse the order of the list.
  309. End Rem
  310. Method Reverse()
  311. Local pred:TLink=_head,succ:TLink=pred._succ
  312. Repeat
  313. Local link:TLink=succ._succ
  314. pred._pred=succ
  315. succ._succ=pred
  316. pred=succ
  317. succ=link
  318. Until pred=_head
  319. End Method
  320. Rem
  321. bbdoc: Creates a new list that is the reversed version of this list.
  322. End Rem
  323. Method Reversed:TList()
  324. Local list:TList=New TList
  325. list._count = 0
  326. Local link:TLink=_head._succ
  327. While link<>_head
  328. list.AddFirst link._value
  329. link=link._succ
  330. Wend
  331. Return list
  332. End Method
  333. Rem
  334. bbdoc: Sort a list in either ascending (default) or decending order.
  335. about: User types should implement a Compare method in order to be sorted.
  336. End Rem
  337. Method Sort( ascending=True,compareFunc( o1:Object,o2:Object )=CompareObjects )
  338. Local ccsgn=-1
  339. If ascending ccsgn=1
  340. Local insize=1
  341. Repeat
  342. Local merges
  343. Local tail:TLink=_head
  344. Local p:TLink=_head._succ
  345. While p<>_head
  346. merges:+1
  347. Local q:TLink=p._succ,qsize=insize,psize=1
  348. While psize<insize And q<>_head
  349. psize:+1
  350. q=q._succ
  351. Wend
  352. Repeat
  353. Local t:TLink
  354. If psize And qsize And q<>_head
  355. Local cc=CompareFunc( p._value,q._value ) * ccsgn
  356. If cc<=0
  357. t=p
  358. p=p._succ
  359. psize:-1
  360. Else
  361. t=q
  362. q=q._succ
  363. qsize:-1
  364. EndIf
  365. Else If psize
  366. t=p
  367. p=p._succ
  368. psize:-1
  369. Else If qsize And q<>_head
  370. t=q
  371. q=q._succ
  372. qsize:-1
  373. Else
  374. Exit
  375. EndIf
  376. t._pred=tail
  377. tail._succ=t
  378. tail=t
  379. Forever
  380. p=q
  381. Wend
  382. tail._succ=_head
  383. _head._pred=tail
  384. If merges<=1 Then
  385. Return
  386. End If
  387. insize:*2
  388. Forever
  389. End Method
  390. Method ObjectEnumerator:TListEnum()
  391. Local enumeration:TListEnum=New TListEnum
  392. enumeration._link=_head._succ
  393. Return enumeration
  394. End Method
  395. Rem
  396. bbdoc: convert a list to an array
  397. returns: An array of objects
  398. end rem
  399. Method ToArray:Object[]()
  400. Local arr:Object[Count()],i
  401. Local link:TLink=_head._succ
  402. While link<>_head
  403. arr[i]=link._value
  404. link=link._succ
  405. i:+1
  406. Wend
  407. Return arr
  408. End Method
  409. Rem
  410. bbdoc: Create a list from an array
  411. returns: A new linked list
  412. end rem
  413. Function FromArray:TList( arr:Object[] )
  414. Local list:TList=New TList
  415. For Local i=0 Until arr.length
  416. list.AddLast arr[i]
  417. Next
  418. Return list
  419. End Function
  420. Rem
  421. bbdoc: Remove an object from a linked list.
  422. End Rem
  423. Method RemoveLink( link:TLink )
  424. If _count > -1 Then
  425. _count :- 1
  426. End If
  427. link.Remove
  428. End Method
  429. End Type
  430. Rem
  431. bbdoc: Create a linked list
  432. returns: A new linked list object
  433. End Rem
  434. Function CreateList:TList()
  435. Return New TList
  436. End Function
  437. Rem
  438. bbdoc: Clear a linked list
  439. about: Removes all objects from @list.
  440. end rem
  441. Function ClearList( list:TList )
  442. list.Clear
  443. End Function
  444. Rem
  445. bbdoc: Count list length
  446. returns: The numbers of objects in @list.
  447. end rem
  448. Function CountList( list:TList )
  449. Return list.Count()
  450. End Function
  451. Rem
  452. bbdoc: Check if list is empty
  453. returns: True if list is empty, else false
  454. end rem
  455. Function ListIsEmpty( list:TList )
  456. Return list.IsEmpty()
  457. End Function
  458. Rem
  459. bbdoc: Check if list contains a value
  460. returns: True if list contains @value, else false
  461. end rem
  462. Function ListContains( list:TList,value:Object )
  463. Return list.Contains( value )
  464. End Function
  465. Rem
  466. bbdoc: Sort a list
  467. end rem
  468. Function SortList( list:TList,ascending=True,compareFunc( o1:Object,o2:Object )=CompareObjects )
  469. list.Sort ascending,compareFunc
  470. End Function
  471. Rem
  472. bbdoc: Create a list from an array
  473. returns: A new linked list
  474. end rem
  475. Function ListFromArray:TList( arr:Object[] )
  476. Return TList.FromArray( arr )
  477. End Function
  478. Rem
  479. bbdoc: convert a list to an array
  480. returns: An array of objects
  481. end rem
  482. Function ListToArray:Object[]( list:TList )
  483. Return list.ToArray()
  484. End Function
  485. Rem
  486. bbdoc: Swap the contents of 2 lists
  487. end rem
  488. Function SwapLists( list_x:TList,list_y:TList )
  489. list_x.Swap list_y
  490. End Function
  491. Rem
  492. bbdoc: Reverse the order of elements of a list
  493. end rem
  494. Function ReverseList( list:TList )
  495. list.Reverse
  496. End Function
  497. Rem
  498. bbdoc: Find a link in a list
  499. returns: The link containting @value
  500. end rem
  501. Function ListFindLink:TLink( list:TList,value:Object )
  502. Return list.FindLink( value )
  503. End Function
  504. Rem
  505. bbdoc: Remove an object from a linked list referenced by a link
  506. about: #ListRemoveLink removes an object from the linked list referenced by the given link
  507. End Rem
  508. Function ListRemoveLink( list:TList,link:TLink )
  509. list.RemoveLink( link )
  510. End Function
  511. Rem
  512. bbdoc: Add an object to a linked list
  513. returns: A link object
  514. end rem
  515. Function ListAddLast:TLink( list:TList,value:Object )
  516. Return list.AddLast( value )
  517. End Function
  518. Rem
  519. bbdoc: Returns the first object in the list
  520. about: Returns Null if the list is empty.
  521. End Rem
  522. Function ListGetFirst:Object( list:TList )
  523. Return list.First()
  524. EndFunction
  525. Rem
  526. bbdoc: Returns the last object in the list
  527. about: Returns Null if the list is empty.
  528. End Rem
  529. Function ListGetLast:Object( list:TList )
  530. Return list.Last()
  531. EndFunction
  532. Rem
  533. bbdoc: Add an object to a linked list
  534. returns: A link object
  535. end rem
  536. Function ListAddFirst:TLink( list:TList,value:Object )
  537. Return list.AddFirst( value )
  538. End Function
  539. Rem
  540. bbdoc: Removes and returns the first object in the list.
  541. about: Returns Null if the list is empty.
  542. End Rem
  543. Function ListRemoveFirst:Object( list:TList )
  544. Return list.RemoveFirst()
  545. End Function
  546. Rem
  547. bbdoc: Removes and returns the last object in the list.
  548. about: Returns Null if the list is empty.
  549. End Rem
  550. Function ListRemoveLast:Object( list:TList )
  551. Return list.RemoveLast()
  552. End Function
  553. Rem
  554. bbdoc: Remove an object from a linked list
  555. about: #ListRemove scans a list for the specified value and removes its link.
  556. End Rem
  557. Function ListRemove( list:TList,value:Object )
  558. list.Remove( value )
  559. End Function