PageRenderTime 42ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/FSharpx.Core/DataStructures/AltBinaryRandomAccessList.fs

http://github.com/dmohl/fsharpx
F# | 371 lines | 269 code | 79 blank | 23 comment | 40 complexity | 4f812cf21787d955768c86eb97be43be MD5 | raw file
Possible License(s): Apache-2.0, CC-BY-SA-3.0, GPL-2.0
  1. // originally published by Julien
  2. // original implementation taken from http://lepensemoi.free.fr/index.php/2010/02/11/alternative-binary-random-access-list
  3. //J.F. added remove, trys, length, append, rev
  4. namespace FSharpx.DataStructures
  5. open System.Collections
  6. open System.Collections.Generic
  7. type AltBinRndAccList<'a> =
  8. | Nil
  9. | Zero of AltBinRndAccList<'a * 'a>
  10. | One of 'a * AltBinRndAccList<'a * 'a>
  11. with
  12. interface IRandomAccessList<'a> with
  13. member this.Cons (x : 'a) = AltBinRndAccList.cons x this :> _
  14. member this.Count() = AltBinRndAccList.length (0, 1, this)
  15. member this.Head() =
  16. let x, _ = AltBinRndAccList.uncons this
  17. x
  18. member this.TryGetHead() =
  19. match AltBinRndAccList.tryUncons this with
  20. | None -> None
  21. | Some( x, _) -> Some(x)
  22. member this.IsEmpty() = AltBinRndAccList.isEmpty this
  23. member this.Length() = AltBinRndAccList.length (0, 1, this)
  24. member this.Lookup i = AltBinRndAccList.lookup i this
  25. member this.TryLookup i = AltBinRndAccList.tryLookup i this
  26. member this.Rev() = AltBinRndAccList.rev this :> _
  27. member this.Tail() =
  28. let _, xs = AltBinRndAccList.uncons this
  29. xs :> _
  30. member this.TryGetTail() =
  31. match AltBinRndAccList.tryUncons this with
  32. | None -> None
  33. | Some( _, Nil) -> None
  34. | Some( _, xs) -> Some(xs :> _)
  35. member this.Uncons() =
  36. let x, xs = AltBinRndAccList.uncons this
  37. x, xs :> _
  38. member this.TryUncons() =
  39. match AltBinRndAccList.tryUncons this with
  40. | None -> None
  41. | Some(x, xs) -> Some(x, xs :> _)
  42. member this.Update i y = AltBinRndAccList.fupdate ((fun x -> y), i, this) :> _
  43. member this.TryUpdate i y =
  44. match AltBinRndAccList.ftryUpdate ((fun x -> y), i, this) with
  45. | None -> None
  46. | Some(x) -> Some(x :> _)
  47. member this.GetEnumerator() =
  48. let e = seq {
  49. match AltBinRndAccList.tryUncons this with
  50. | None -> ()
  51. | Some(x, xs) ->
  52. yield x
  53. yield! xs}
  54. e.GetEnumerator()
  55. member this.GetEnumerator() = (this :> _ seq).GetEnumerator() :> IEnumerator
  56. and AltBinRndAccList<'a>
  57. with
  58. static member internal cons (x : 'a) : AltBinRndAccList<'a> -> AltBinRndAccList<'a> = function
  59. | Nil -> One (x, Nil)
  60. | Zero ps -> One (x, ps)
  61. | One(y, ps) -> Zero(AltBinRndAccList.cons (x,y) ps)
  62. static member internal isEmpty : AltBinRndAccList<'a> -> bool = function Nil -> true | _ -> false
  63. static member internal length : int * int * AltBinRndAccList<'a> -> int = function
  64. | len, acc, Nil -> len
  65. | len, acc, One(x, Nil) -> len + acc
  66. | len, acc, One(x, ps) -> AltBinRndAccList.length ((len + acc), (2 * acc), ps)
  67. | len, acc, Zero ps -> AltBinRndAccList.length (len, (2 * acc), ps)
  68. static member internal lookup (i:int) : AltBinRndAccList<'a> -> 'a = function
  69. | Nil -> raise Exceptions.OutOfBounds
  70. | One(x, ps) ->
  71. if i = 0 then x else AltBinRndAccList.lookup (i-1) (Zero ps)
  72. | Zero ps ->
  73. let (x, y) = AltBinRndAccList.lookup (i/2) ps
  74. if i % 2 = 0 then x else y
  75. static member internal tryLookup (i:int) : AltBinRndAccList<'a> -> 'a option = function
  76. | Nil -> None
  77. | One(x, ps) ->
  78. if i = 0 then Some(x) else AltBinRndAccList.tryLookup (i-1) (Zero ps)
  79. | Zero ps ->
  80. match (AltBinRndAccList.tryLookup (i/2) ps) with
  81. | None -> None
  82. | Some (x, y) -> if i % 2 = 0 then Some(x) else Some(y)
  83. static member internal ofSeq (s:seq<'a>) : AltBinRndAccList<'a> =
  84. if Seq.isEmpty s then Nil
  85. else
  86. let a = Array.ofSeq s
  87. let rec loop (acc: AltBinRndAccList<'a>) dec (a': array<'a>) =
  88. if dec < 0 then acc
  89. else loop (AltBinRndAccList.cons a'.[dec] acc) (dec - 1) a'
  90. loop Nil (a.Length - 1) a
  91. static member internal uncons : AltBinRndAccList<'a> -> 'a * AltBinRndAccList<'a> = function
  92. | Nil -> raise Exceptions.Empty
  93. | One(x, Nil) -> (x, Nil)
  94. | One(x, ps) -> (x, Zero ps)
  95. | Zero ps ->
  96. let (x,y), ps' = AltBinRndAccList.uncons ps
  97. x, (One (y, ps'))
  98. static member internal tryUncons : AltBinRndAccList<'a> -> ('a * AltBinRndAccList<'a>) option = function
  99. | Nil -> None
  100. | One(x, Nil) -> Some(x, Nil)
  101. | One(x, ps) -> Some(x, Zero ps)
  102. | Zero ps ->
  103. let (x,y), ps' = AltBinRndAccList.uncons ps
  104. Some(x, (One (y, ps')))
  105. static member internal fremove : int * array<'a> * int * AltBinRndAccList<'a> -> int * AltBinRndAccList<'a> = function
  106. | i, _, _, Nil -> raise Exceptions.OutOfBounds
  107. | 0, _, aIdx, One(x, ps) -> aIdx, Zero(ps)
  108. | i, a, aIdx, One (x, ps) ->
  109. Array.set a aIdx x
  110. AltBinRndAccList.fremove (i-1, a, (aIdx+1), Zero ps)
  111. | 0, _, aIdx, Zero ps ->
  112. let (x,y), ps' = AltBinRndAccList.uncons ps
  113. aIdx, One(y, ps')
  114. | 1, _, aIdx, Zero ps ->
  115. let (x,y), ps' = AltBinRndAccList.uncons ps
  116. aIdx, One(x, ps')
  117. | i, a, aIdx, Zero ps ->
  118. let (x,y), ps' = AltBinRndAccList.uncons ps
  119. Array.set a aIdx x
  120. Array.set a (aIdx + 1) y
  121. AltBinRndAccList.fremove ((i-2), a, (aIdx + 2), Zero ps')
  122. static member internal ftryRemove : int * array<'a> * int * AltBinRndAccList<'a> -> int * AltBinRndAccList<'a> option = function
  123. | i, _, _, Nil -> 0, None
  124. | 0, _, aIdx, One(x, ps) -> aIdx, Some(Zero(ps))
  125. | i, a, aIdx, One (x, ps) ->
  126. Array.set a aIdx x
  127. AltBinRndAccList.ftryRemove (i-1, a, (aIdx+1), Zero ps)
  128. | 0, _, aIdx, Zero ps ->
  129. let (x,y), ps' = AltBinRndAccList.uncons ps
  130. aIdx, Some(One(y, ps'))
  131. | 1, _, aIdx, Zero ps ->
  132. let (x,y), ps' = AltBinRndAccList.uncons ps
  133. aIdx, Some(One(x, ps'))
  134. | i, a, aIdx, Zero ps ->
  135. let (x,y), ps' = AltBinRndAccList.uncons ps
  136. Array.set a aIdx x
  137. Array.set a (aIdx + 1) y
  138. AltBinRndAccList.ftryRemove ((i-2), a, (aIdx + 2), Zero ps')
  139. static member internal rev : AltBinRndAccList<'a> -> AltBinRndAccList<'a> = function
  140. | Nil -> Nil
  141. | xs ->
  142. let rec loop xs' acc =
  143. match (AltBinRndAccList.tryUncons xs') with
  144. | None -> acc
  145. | Some(x, xs'') -> loop xs'' (AltBinRndAccList.cons x acc)
  146. loop xs Nil
  147. static member internal fupdate : ('a -> 'a) * int * AltBinRndAccList<'a> -> AltBinRndAccList<'a> = function
  148. | f, i, Nil -> raise Exceptions.OutOfBounds
  149. | f, 0, One(x, ps) -> One(f x, ps)
  150. | f, i, One (x, ps) -> AltBinRndAccList.cons x (AltBinRndAccList.fupdate (f, i-1, Zero ps))
  151. | f, i, Zero ps ->
  152. let f' (x, y) = if i % 2= 0 then f x, y else x, f y
  153. Zero(AltBinRndAccList.fupdate(f', i/2, ps))
  154. static member internal ftryUpdate : ('a -> 'a) * int * AltBinRndAccList<'a> -> AltBinRndAccList<'a> option = function
  155. | f, i, Nil -> None
  156. | f, 0, One(x, ps) -> Some(One(f x, ps))
  157. | f, i, One (x, ps) ->
  158. match (AltBinRndAccList.ftryUpdate (f, i-1, Zero ps)) with
  159. | None -> None
  160. | Some(ps') -> Some(AltBinRndAccList.cons x ps')
  161. | f, i, Zero ps ->
  162. let f' (x, y) = if i % 2= 0 then f x, y else x, f y
  163. match (AltBinRndAccList.ftryUpdate(f', i/2, ps)) with
  164. | None -> None
  165. | Some(ps') -> Some(Zero(ps'))
  166. static member internal append : AltBinRndAccList<'a> * AltBinRndAccList<'a> -> AltBinRndAccList<'a> = function
  167. | Nil, Nil -> Nil
  168. | xs, Nil -> xs
  169. | Nil, ys -> ys
  170. | xs, ys ->
  171. let xs' = AltBinRndAccList.rev xs
  172. let rec loop xs'' acc =
  173. match (AltBinRndAccList.tryUncons xs'') with
  174. | None -> acc
  175. | Some(x, xs'') -> loop xs'' (AltBinRndAccList.cons x acc)
  176. loop xs' ys
  177. member this.Cons (x : 'a) = AltBinRndAccList.cons x this
  178. member this.Head() =
  179. let x, _ = AltBinRndAccList.uncons this
  180. x
  181. member this.TryGetHead() =
  182. match AltBinRndAccList.tryUncons this with
  183. | None -> None
  184. | Some( x, _) -> Some(x)
  185. member this.IsEmpty() = AltBinRndAccList.isEmpty this
  186. member this.Length() = AltBinRndAccList.length (0, 1, this)
  187. member this.Lookup i = AltBinRndAccList.lookup i this
  188. member this.TryLookup i = AltBinRndAccList.tryLookup i this
  189. member this.Remove i =
  190. if i = 0 then
  191. match (AltBinRndAccList.uncons this) with
  192. | _, Zero(Nil) -> Nil
  193. | _, x -> x
  194. else
  195. let front = Array.create i (fst (AltBinRndAccList.uncons this))
  196. match (AltBinRndAccList.fremove (i, front, 0, this)) with
  197. | _, Zero(Nil) -> Nil
  198. | frontLen, x ->
  199. let rec loop i' (front':'a array) (back:AltBinRndAccList<'a>) =
  200. match i' with
  201. | i'' when i'' > -1 -> loop (i''- 1) front' ( AltBinRndAccList.cons front'.[i''] back)
  202. | i'' -> back
  203. loop (frontLen - 1) front x
  204. member this.TryRemove i =
  205. if i = 0 then
  206. match (AltBinRndAccList.uncons this) with
  207. | _, Zero(Nil) -> Some(Nil)
  208. | _, x -> Some(x)
  209. else
  210. let front = Array.create i (fst (AltBinRndAccList.uncons this))
  211. match (AltBinRndAccList.ftryRemove (i, front, 0, this)) with
  212. | _, None -> None
  213. | _, Some(Zero(Nil)) -> Some(Nil)
  214. | frontLen, Some(x) ->
  215. let rec loop i' (front':'a array) (back:AltBinRndAccList<'a>) =
  216. match i' with
  217. | i'' when i'' > -1 -> loop (i''- 1) front' ( AltBinRndAccList.cons front'.[i''] back)
  218. | i'' -> Some(back)
  219. loop (frontLen - 1) front x
  220. member this.Rev() = AltBinRndAccList.rev this
  221. member this.Tail() =
  222. let _, xs = AltBinRndAccList.uncons this
  223. xs
  224. member this.TryGetTail() =
  225. match AltBinRndAccList.tryUncons this with
  226. | None -> None
  227. | Some( _, Nil) -> None
  228. | Some( _, xs) -> Some(xs)
  229. member this.Uncons() =
  230. let x, xs = AltBinRndAccList.uncons this
  231. x, xs
  232. member this.TryUncons() =
  233. match AltBinRndAccList.tryUncons this with
  234. | None -> None
  235. | Some(x, xs) -> Some(x, xs)
  236. member this.Update i y = AltBinRndAccList.fupdate ((fun x -> y), i, this)
  237. member this.TryUpdate i y =
  238. match AltBinRndAccList.ftryUpdate ((fun x -> y), i, this) with
  239. | None -> None
  240. | Some(x) -> Some(x)
  241. [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
  242. module AltBinaryRandomAccessList =
  243. //pattern discriminator
  244. let (|Cons|Nil|) (l: AltBinRndAccList<'a>) = match l.TryUncons() with Some(a,b) -> Cons(a,b) | None -> Nil
  245. ///returns random access list from elements of 2 random access lists concatenated
  246. let append xs ys = AltBinRndAccList.append (xs, ys)
  247. ///returns a new random access list with the element added to the beginning
  248. let inline cons x (xs: AltBinRndAccList<'a>) = xs.Cons x
  249. ///returns the first element
  250. let head xs =
  251. let x, _ = AltBinRndAccList.uncons xs
  252. x
  253. ///returns a empty random access list
  254. let empty = Nil
  255. ///returns option first element
  256. let tryGetHead xs =
  257. match (AltBinRndAccList.tryUncons xs) with
  258. | None -> None
  259. | Some( x, _) -> Some(x)
  260. ///returns true if the random access list has no elements
  261. let inline isEmpty (xs: AltBinRndAccList<'a>) = xs.IsEmpty()
  262. ///returns the count of elememts
  263. let inline length (xs: AltBinRndAccList<'a>) = xs.Length()
  264. ///returns element by index
  265. let rec lookup i xs = AltBinRndAccList.lookup i xs
  266. ///returns option element by index
  267. let rec tryLookup i xs = AltBinRndAccList.tryLookup i xs
  268. ///returns random access list from the sequence
  269. let ofSeq s = AltBinRndAccList.ofSeq s
  270. ///returns random access list with element removed by index
  271. let inline remove i (xs: AltBinRndAccList<'a>) = xs.Remove i
  272. ///returns option random access list with element removed by index
  273. let inline tryRemove i (xs: AltBinRndAccList<'a>) = xs.TryRemove i
  274. //returns random access list reversed
  275. let inline rev (xs: AltBinRndAccList<'a>) = xs.Rev()
  276. ///returns a new random access list of the elements trailing the first element
  277. let tail xs =
  278. let _, xs' = AltBinRndAccList.uncons xs
  279. xs'
  280. ///returns a option random access list of the elements trailing the first element
  281. let tryGetTail xs =
  282. match (AltBinRndAccList.tryUncons xs) with
  283. | None -> None
  284. | Some( _, xs') -> Some(xs')
  285. ///returns the first element and tail
  286. let inline uncons (xs: AltBinRndAccList<'a>) = xs.Uncons()
  287. ///returns the option first element and tail
  288. let inline tryUncons (xs: AltBinRndAccList<'a>) = xs.TryUncons()
  289. ///returns random access list with element updated by index
  290. let inline update i y (xs: AltBinRndAccList<'a>) = xs.Update i y
  291. ///returns option random access list with element updated by index
  292. let inline tryUpdate i y (xs: AltBinRndAccList<'a>) = xs.TryUpdate i y