map.bmx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. SuperStrict
  2. Rem
  3. bbdoc: Data structures/Maps
  4. End Rem
  5. Module BRL.Map
  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: Refactored tree based maps."
  13. ModuleInfo "History: Added unit tests."
  14. ModuleInfo "History: 1.10"
  15. ModuleInfo "History: Changed to SuperStrict."
  16. ModuleInfo "History: 1.09"
  17. ModuleInfo "History: Added index operator overloads to maps."
  18. ModuleInfo "History: 1.08"
  19. ModuleInfo "History: Added TStringMap."
  20. ModuleInfo "History: (Debug) Assertion on modification during iteration."
  21. ModuleInfo "History: 1.07 Release"
  22. ModuleInfo "History: Fixed MapKeys/MapValues functions to return enumerators"
  23. ModuleInfo "History: 1.06 Release"
  24. ModuleInfo "History: Restored KeyValue enumerator"
  25. ModuleInfo "History: 1.05 Release"
  26. ModuleInfo "History: Added Copy method"
  27. ModuleInfo "History: 1.04 Release"
  28. ModuleInfo "History: Fixed Clear memleak"
  29. ModuleInfo "History: 1.03 Release"
  30. ModuleInfo "History: Finally changed to red/back tree!"
  31. ModuleInfo "History: Added procedural interface"
  32. ModuleInfo "History: 1.02 Release"
  33. ModuleInfo "History: Fixed TMap.Remove:TNode not returning node"
  34. Import "intmap.bmx"
  35. Import "ptrmap.bmx"
  36. Import "stringmap.bmx"
  37. Import "objectmap.bmx"
  38. Import "map.c"
  39. Private
  40. Global nil:TNode=New TNode
  41. nil._color=TMap.BLACK
  42. nil._parent=nil
  43. nil._left=nil
  44. nil._right=nil
  45. Public
  46. Type TKeyValue
  47. Method Key:Object()
  48. Return _key
  49. End Method
  50. Method Value:Object()
  51. Return _value
  52. End Method
  53. '***** PRIVATE *****
  54. Field _key:Object,_value:Object
  55. End Type
  56. Type TNode Extends TKeyValue
  57. Method NextNode:TNode()
  58. Local node:TNode=Self
  59. If node._right<>nil
  60. node=_right
  61. While node._left<>nil
  62. node=node._left
  63. Wend
  64. Return node
  65. EndIf
  66. Local parent:TNode=_parent
  67. While node=parent._right
  68. node=parent
  69. parent=parent._parent
  70. Wend
  71. Return parent
  72. End Method
  73. Method PrevNode:TNode()
  74. Local node:TNode=Self
  75. If node._left<>nil
  76. node=node._left
  77. While node._right<>nil
  78. node=node._right
  79. Wend
  80. Return node
  81. EndIf
  82. Local parent:TNode=node._parent
  83. While node=parent._left
  84. node=parent
  85. parent=node._parent
  86. Wend
  87. Return parent
  88. End Method
  89. Method Clear()
  90. _parent=Null
  91. If _left<>nil _left.Clear
  92. If _right<>nil _right.Clear
  93. End Method
  94. Method Copy:TNode( parent:TNode )
  95. Local t:TNode=New TNode
  96. t._key=_key
  97. t._value=_value
  98. t._color=_color
  99. t._parent=parent
  100. If _left<>nil t._left=_left.Copy( t )
  101. If _right<>nil t._right=_right.Copy( t )
  102. Return t
  103. End Method
  104. Method Key:Object() Override
  105. Return _key
  106. End Method
  107. Method Value:Object() Override
  108. Return _value
  109. End Method
  110. '***** PRIVATE *****
  111. Field _color:Int,_parent:TNode=nil,_left:TNode=nil,_right:TNode=nil
  112. End Type
  113. Type TNodeEnumerator
  114. Method HasNext:Int()
  115. Return _node<>nil
  116. End Method
  117. Method NextObject:Object()
  118. Local node:TNode=_node
  119. _node=_node.NextNode()
  120. Return node
  121. End Method
  122. '***** PRIVATE *****
  123. Field _node:TNode
  124. End Type
  125. Type TKeyEnumerator Extends TNodeEnumerator
  126. Method NextObject:Object() Override
  127. Local node:TNode=_node
  128. _node=_node.NextNode()
  129. Return node._key
  130. End Method
  131. End Type
  132. Type TValueEnumerator Extends TNodeEnumerator
  133. Method NextObject:Object() Override
  134. Local node:TNode=_node
  135. _node=_node.NextNode()
  136. Return node._value
  137. End Method
  138. End Type
  139. Type TMapEnumerator
  140. Method ObjectEnumerator:TNodeEnumerator()
  141. Return _enumerator
  142. End Method
  143. Field _enumerator:TNodeEnumerator
  144. End Type
  145. '***** PUBLIC *****
  146. Rem
  147. bbdoc: An key/value (Object/Object) map backed by a Red/Black tree.
  148. End Rem
  149. Type TMap
  150. ?Not Threaded
  151. Method Delete()
  152. Clear
  153. End Method
  154. ?
  155. Rem
  156. bbdoc: Clears the map.
  157. about: Removes all keys and values.
  158. End Rem
  159. Method Clear()
  160. If _root=nil Return
  161. _root.Clear
  162. _root=nil
  163. End Method
  164. Rem
  165. bbdoc: Checks if the map is empty.
  166. about: #True if @map is empty, otherwise #False.
  167. End Rem
  168. Method IsEmpty:Int()
  169. Return _root=nil
  170. End Method
  171. Rem
  172. bbdoc: Inserts a key/value pair into the map.
  173. about: If the map already contains @key, its value is overwritten with @value.
  174. End Rem
  175. Method Insert( key:Object,value:Object )
  176. Assert key Else "Can't insert Null key into map"
  177. Local node:TNode=_root,parent:TNode=nil,cmp:Int
  178. While node<>nil
  179. parent=node
  180. cmp=key.Compare( node._key )
  181. If cmp>0
  182. node=node._right
  183. Else If cmp<0
  184. node=node._left
  185. Else
  186. node._value=value
  187. Return
  188. EndIf
  189. Wend
  190. node=New TNode
  191. node._key=key
  192. node._value=value
  193. node._color=RED
  194. node._parent=parent
  195. If parent=nil
  196. _root=node
  197. Return
  198. EndIf
  199. If cmp>0
  200. parent._right=node
  201. Else
  202. parent._left=node
  203. EndIf
  204. _InsertFixup node
  205. End Method
  206. Rem
  207. bbdoc: Checks if the map contains @key.
  208. returns: #True if the map contains @key.
  209. End Rem
  210. Method Contains:Int( key:Object )
  211. Return _FindNode( key )<>nil
  212. End Method
  213. Rem
  214. bbdoc: Finds a value given a @key.
  215. returns: The value associated with @key.
  216. about: If the map does not contain @key, a #Null object is returned.
  217. End Rem
  218. Method ValueForKey:Object( key:Object )
  219. Local node:TNode=_FindNode( key )
  220. If node<>nil Return node._value
  221. End Method
  222. Rem
  223. bbdoc: Remove a key/value pair from the map.
  224. returns: #True if @key was removed, or #False otherwise.
  225. End Rem
  226. Method Remove:Int( key:Object )
  227. Local node:TNode=_FindNode( key )
  228. If node=nil Return 0
  229. _RemoveNode node
  230. Return 1
  231. End Method
  232. Rem
  233. bbdoc: Gets the map keys.
  234. returns: An enumeration object
  235. about: The object returned by #Keys can be used with #EachIn to iterate through the keys in the map.
  236. End Rem
  237. Method Keys:TMapEnumerator()
  238. Local nodeenum:TNodeEnumerator=New TKeyEnumerator
  239. nodeenum._node=_FirstNode()
  240. Local mapenum:TMapEnumerator=New TMapEnumerator
  241. mapenum._enumerator=nodeenum
  242. Return mapenum
  243. End Method
  244. Rem
  245. bbdoc: Get the map values.
  246. returns: An enumeration object.
  247. about: The object returned by #Values can be used with #EachIn to iterate through the values in the map.
  248. End Rem
  249. Method Values:TMapEnumerator()
  250. Local nodeenum:TNodeEnumerator=New TValueEnumerator
  251. nodeenum._node=_FirstNode()
  252. Local mapenum:TMapEnumerator=New TMapEnumerator
  253. mapenum._enumerator=nodeenum
  254. Return mapenum
  255. End Method
  256. Rem
  257. bbdoc: Returns a copy the contents of this map.
  258. End Rem
  259. Method Copy:TMap()
  260. Local map:TMap=New TMap
  261. 'avoid copying an empty map (_root = nil there), else it borks "eachin"
  262. If _root <> nil
  263. map._root=_root.Copy( nil )
  264. EndIf
  265. Return map
  266. End Method
  267. Rem
  268. bbdoc: Returns a node enumeration Object.
  269. about: The object returned by #ObjectEnumerator can be used with #EachIn to iterate through the nodes in the map.
  270. End Rem
  271. Method ObjectEnumerator:TNodeEnumerator()
  272. Local nodeenum:TNodeEnumerator=New TNodeEnumerator
  273. nodeenum._node=_FirstNode()
  274. Return nodeenum
  275. End Method
  276. '***** PRIVATE *****
  277. Method _FirstNode:TNode()
  278. Local node:TNode=_root
  279. While node._left<>nil
  280. node=node._left
  281. Wend
  282. Return node
  283. End Method
  284. Method _LastNode:TNode()
  285. Local node:TNode=_root
  286. While node._right<>nil
  287. node=node._right
  288. Wend
  289. Return node
  290. End Method
  291. Method _FindNode:TNode( key:Object )
  292. Local node:TNode=_root
  293. While node<>nil
  294. Local cmp:Int=key.Compare( node._key )
  295. If cmp>0
  296. node=node._right
  297. Else If cmp<0
  298. node=node._left
  299. Else
  300. Return node
  301. EndIf
  302. Wend
  303. Return node
  304. End Method
  305. Method _RemoveNode( node:TNode )
  306. Local splice:TNode,child:TNode
  307. If node._left=nil
  308. splice=node
  309. child=node._right
  310. Else If node._right=nil
  311. splice=node
  312. child=node._left
  313. Else
  314. splice=node._left
  315. While splice._right<>nil
  316. splice=splice._right
  317. Wend
  318. child=splice._left
  319. node._key=splice._key
  320. node._value=splice._value
  321. EndIf
  322. Local parent:TNode=splice._parent
  323. If child<>nil
  324. child._parent=parent
  325. EndIf
  326. If parent=nil
  327. _root=child
  328. Return
  329. EndIf
  330. If splice=parent._left
  331. parent._left=child
  332. Else
  333. parent._right=child
  334. EndIf
  335. If splice._color=BLACK _DeleteFixup child,parent
  336. End Method
  337. Method _InsertFixup( node:TNode )
  338. While node._parent._color=RED And node._parent._parent<>nil
  339. If node._parent=node._parent._parent._left
  340. Local uncle:TNode=node._parent._parent._right
  341. If uncle._color=RED
  342. node._parent._color=BLACK
  343. uncle._color=BLACK
  344. uncle._parent._color=RED
  345. node=uncle._parent
  346. Else
  347. If node=node._parent._right
  348. node=node._parent
  349. _RotateLeft node
  350. EndIf
  351. node._parent._color=BLACK
  352. node._parent._parent._color=RED
  353. _RotateRight node._parent._parent
  354. EndIf
  355. Else
  356. Local uncle:TNode=node._parent._parent._left
  357. If uncle._color=RED
  358. node._parent._color=BLACK
  359. uncle._color=BLACK
  360. uncle._parent._color=RED
  361. node=uncle._parent
  362. Else
  363. If node=node._parent._left
  364. node=node._parent
  365. _RotateRight node
  366. EndIf
  367. node._parent._color=BLACK
  368. node._parent._parent._color=RED
  369. _RotateLeft node._parent._parent
  370. EndIf
  371. EndIf
  372. Wend
  373. _root._color=BLACK
  374. End Method
  375. Method _RotateLeft( node:TNode )
  376. Local child:TNode=node._right
  377. node._right=child._left
  378. If child._left<>nil
  379. child._left._parent=node
  380. EndIf
  381. child._parent=node._parent
  382. If node._parent<>nil
  383. If node=node._parent._left
  384. node._parent._left=child
  385. Else
  386. node._parent._right=child
  387. EndIf
  388. Else
  389. _root=child
  390. EndIf
  391. child._left=node
  392. node._parent=child
  393. End Method
  394. Method _RotateRight( node:TNode )
  395. Local child:TNode=node._left
  396. node._left=child._right
  397. If child._right<>nil
  398. child._right._parent=node
  399. EndIf
  400. child._parent=node._parent
  401. If node._parent<>nil
  402. If node=node._parent._right
  403. node._parent._right=child
  404. Else
  405. node._parent._left=child
  406. EndIf
  407. Else
  408. _root=child
  409. EndIf
  410. child._right=node
  411. node._parent=child
  412. End Method
  413. Method _DeleteFixup( node:TNode,parent:TNode )
  414. While node<>_root And node._color=BLACK
  415. If node=parent._left
  416. Local sib:TNode=parent._right
  417. If sib._color=RED
  418. sib._color=BLACK
  419. parent._color=RED
  420. _RotateLeft parent
  421. sib=parent._right
  422. EndIf
  423. If sib._left._color=BLACK And sib._right._color=BLACK
  424. sib._color=RED
  425. node=parent
  426. parent=parent._parent
  427. Else
  428. If sib._right._color=BLACK
  429. sib._left._color=BLACK
  430. sib._color=RED
  431. _RotateRight sib
  432. sib=parent._right
  433. EndIf
  434. sib._color=parent._color
  435. parent._color=BLACK
  436. sib._right._color=BLACK
  437. _RotateLeft parent
  438. node=_root
  439. EndIf
  440. Else
  441. Local sib:TNode=parent._left
  442. If sib._color=RED
  443. sib._color=BLACK
  444. parent._color=RED
  445. _RotateRight parent
  446. sib=parent._left
  447. EndIf
  448. If sib._right._color=BLACK And sib._left._color=BLACK
  449. sib._color=RED
  450. node=parent
  451. parent=parent._parent
  452. Else
  453. If sib._left._color=BLACK
  454. sib._right._color=BLACK
  455. sib._color=RED
  456. _RotateLeft sib
  457. sib=parent._left
  458. EndIf
  459. sib._color=parent._color
  460. parent._color=BLACK
  461. sib._left._color=BLACK
  462. _RotateRight parent
  463. node=_root
  464. EndIf
  465. EndIf
  466. Wend
  467. node._color=BLACK
  468. End Method
  469. Rem
  470. bbdoc: Finds a value given a @key using index syntax.
  471. returns: The value associated with @key.
  472. about: If the map does not contain @key, a #Null object is returned.
  473. End Rem
  474. Method Operator[]:Object(key:Object)
  475. Return ValueForKey(key)
  476. End Method
  477. Rem
  478. bbdoc: Inserts a key/value pair into the map using index syntax.
  479. about: If the map already contains @key, its value is overwritten with @value.
  480. End Rem
  481. Method Operator[]=(key:Object, value:Object)
  482. Insert(key, value)
  483. End Method
  484. Const RED:Int=-1,BLACK:Int=1
  485. Field _root:TNode=nil
  486. End Type
  487. Rem
  488. bbdoc: Creates a map
  489. returns: A new map object
  490. End Rem
  491. Function CreateMap:TMap()
  492. Return New TMap
  493. End Function
  494. Rem
  495. bbdoc: Clears a map
  496. about:
  497. #ClearMap removes all keys and values from @map
  498. End Rem
  499. Function ClearMap( map:TMap )
  500. map.Clear
  501. End Function
  502. Rem
  503. bbdoc: Checks if a map is empty
  504. returns: True if @map is empty, otherwise false
  505. End Rem
  506. Function MapIsEmpty:Int( map:TMap )
  507. Return map.IsEmpty()
  508. End Function
  509. Rem
  510. bbdoc: Inserts a key/value pair into a map
  511. about:
  512. If @map already contained @key, it's value is overwritten with @value.
  513. End Rem
  514. Function MapInsert( map:TMap,key:Object,value:Object )
  515. map.Insert key,value
  516. End Function
  517. Rem
  518. bbdoc: Finds a value given a key
  519. returns: The value associated with @key
  520. about:
  521. If @map does not contain @key, a #Null object is returned.
  522. End Rem
  523. Function MapValueForKey:Object( map:TMap,key:Object )
  524. Return map.ValueForKey( key )
  525. End Function
  526. Rem
  527. bbdoc: Checks if a map contains a key
  528. returns: True if @map contains @key
  529. End Rem
  530. Function MapContains:Int( map:TMap,key:Object )
  531. Return map.Contains( key )
  532. End Function
  533. Rem
  534. bbdoc: Removes a key/value pair from a map
  535. End Rem
  536. Function MapRemove( map:TMap,key:Object )
  537. map.Remove key
  538. End Function
  539. Rem
  540. bbdoc: Gets map keys
  541. returns: An iterator object
  542. about:
  543. The object returned by #MapKeys can be used with #EachIn to iterate through
  544. the keys in @map.
  545. End Rem
  546. Function MapKeys:TMapEnumerator( map:TMap )
  547. Return map.Keys()
  548. End Function
  549. Rem
  550. bbdoc: Gets map values
  551. returns: An iterator object
  552. about:
  553. The object returned by #MapValues can be used with #EachIn to iterate through
  554. the values in @map.
  555. End Rem
  556. Function MapValues:TMapEnumerator( map:TMap )
  557. Return map.Values()
  558. End Function
  559. Rem
  560. bbdoc: Copies a map
  561. returns: A copy of @map
  562. End Rem
  563. Function CopyMap:TMap( map:TMap )
  564. Return map.Copy()
  565. End Function