ptrelford

Unrolled linked list

Sep 23rd, 2015
343
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
OCaml 5.48 KB | None | 0 0
  1. type 'a node = {
  2.   mutable next : 'a node option;
  3.   mutable count : int;
  4.   mutable items : 'a array
  5. }
  6.  
  7. type 'a unrolled_linked_list = {
  8.   node_capacity : int;
  9.   mutable length : int;
  10.   mutable first : 'a node option;
  11.   mutable last : 'a node option
  12. }
  13.  
  14. type 'a t = 'a unrolled_linked_list
  15.  
  16. let make node_capacity =
  17.   { node_capacity = node_capacity;
  18.     length = 0;
  19.     first = None;
  20.     last = None
  21.   }
  22.  
  23. let length (xs:'a t) = xs.length
  24.  
  25. let iter (f:'a -> unit) (xs:'a t) =
  26.   let rec next = function
  27.     | Some node ->
  28.       for i = 0 to node.count-1 do
  29.         f(node.items.(i))
  30.       done;
  31.       next (node.next)
  32.     | None -> ()
  33.   in
  34.   next xs.first
  35.  
  36. let nth (xs:'a t) (n:int) =
  37.   let rec find count = function
  38.     | None -> failwith "Outside bounds"
  39.     | Some node ->
  40.       if n < count + node.count then node.items.(count-n)
  41.       else find (count+node.count) node.next
  42.   in
  43.   find 0 xs.first
  44.  
  45. let add (xs:'a t) (x:'a) =
  46.   let new_node (x:'a) =
  47.     let items = Array.make xs.node_capacity x in
  48.     { next = None;
  49.       count = 1;
  50.       items = items }
  51.   in
  52.   begin
  53.     match xs.last with
  54.     | None ->
  55.       let node = new_node x in
  56.       xs.first <- Some node;
  57.       xs.last <- Some node
  58.     | Some node ->
  59.       if node.count = xs.node_capacity then begin
  60.           let next = new_node x in
  61.           node.next <- Some next;
  62.           xs.last <- Some next
  63.         end else begin
  64.           node.items.(node.count) <- x;
  65.           node.count <- node.count + 1
  66.         end
  67.   end;
  68.   xs.length <- xs.length + 1
  69.  
  70. let split (xs:'a t) node offset =
  71.   let split = xs.node_capacity / 2 in
  72.   match node.next with
  73.   | Some next when next.count = split && offset < split ->
  74.     (* push excess to next node *)
  75.     Array.blit next.items 0 next.items next.count split;
  76.     Array.blit node.items split next.items 0 split;
  77.     next.count <- xs.node_capacity;
  78.     node.count <- node.count - split;
  79.     node, offset
  80.   | Some _ | None ->
  81.     (* insert new node to right *)
  82.     let items = Array.make xs.node_capacity node.items.(0) in
  83.     let new_node =
  84.       { next = node.next;
  85.         count = split;
  86.         items = items } in
  87.     Array.blit node.items split new_node.items 0 split;
  88.     node.next <- Some new_node;
  89.     node.count <- split;
  90.     begin
  91.       match new_node.next with
  92.       | None -> xs.last <- Some new_node
  93.       | Some _ -> ()
  94.     end;
  95.     if offset < node.count then node, offset
  96.     else new_node, offset - node.count
  97.  
  98. let insert_left (xs:'a t) (index:int) (x:'a) =
  99.   let rec find count = function
  100.     | None -> failwith "Outside bounds"
  101.     | Some node ->
  102.       if (index - count) <= node.count then node, index - count
  103.       else find (count+node.count) node.next
  104.   in
  105.   let node, offset = find 0 xs.first in
  106.   let node, offset =
  107.     if node.count = xs.node_capacity then
  108.       split xs node offset
  109.     else
  110.       node, offset
  111.   in
  112.   (* insert item in node *)
  113.   Array.blit node.items offset node.items (offset+1) (node.count-offset);
  114.   node.items.(offset) <- x;
  115.   node.count <- node.count + 1;
  116.   xs.length <- xs.length + 1
  117.  
  118. let insert (xs:'a t) (index:int) (x:'a) =
  119.   if index = xs.length then add xs x
  120.   else insert_left xs index x
  121.  
  122. let remove_at (xs:'a t) (index:int) =
  123.   let rec find count previous node' =
  124.     match node' with
  125.     | None -> failwith "Outside bounds"
  126.     | Some node ->
  127.       if index - count < node.count then previous, node, index - count
  128.       else find (count+node.count) node' node.next
  129.   in
  130.   let previous, node, offset = find 0 None xs.first in
  131.   Array.blit node.items (offset+1) node.items offset (node.count-offset-1);
  132.   node.count <- node.count - 1;
  133.   xs.length <- xs.length - 1;
  134.   let split = xs.node_capacity / 2 in
  135.   (* Pull from right *)
  136.   if node.count < split then begin
  137.     match node.next with
  138.     | None ->
  139.       if node.count = 0 then begin
  140.         match previous with
  141.         | None ->
  142.             xs.first <- None;
  143.             xs.last <- None
  144.         | Some previous' ->
  145.             previous'.next <- None;
  146.             xs.last <- previous
  147.       end
  148.     | Some next ->
  149.       if next.count > split then
  150.         let excess = next.count - split in
  151.         Array.blit next.items 0 node.items node.count excess;
  152.         Array.blit next.items excess next.items 0 excess;
  153.         node.count <- node.count + excess;
  154.         next.count <- next.count - excess
  155.       else
  156.         Array.blit next.items 0 node.items node.count next.count;
  157.         node.count <- node.count + next.count;
  158.         node.next <- next.next;
  159.         match node.next with
  160.         | None -> xs.last <- Some node
  161.         | Some _ -> ()
  162.   end
  163.  
  164. let run_tests tests =
  165.   Printf.printf "1..%d\n" (List.length tests);
  166.   List.iteri (fun i (name, f) ->
  167.     let ok = try f () with _ -> false in
  168.     if ok then Printf.printf "ok %d - %s\n" (i+1) name
  169.     else Printf.printf "not ok %d - %s\n" (i+1) name
  170.   ) tests
  171.  
  172. let add_10 () =
  173.   let xs = make 4 in
  174.   for i = 1 to 10 do add xs 1 done;
  175.   length xs = 10
  176.  
  177. let insert_10 () =
  178.   let xs = make 4 in
  179.   for i = 1 to 10 do insert xs 0 1 done;
  180.   length xs = 10
  181.  
  182. let insert_10_remove_9 () =
  183.   let xs = make 4 in
  184.   for i = 1 to 10 do insert xs 0 1 done;
  185.   for i = 9 downto 1 do remove_at xs i done;
  186.   length xs = 1
  187.  
  188. let tests = [
  189.   "empty", (fun () -> let xs = make 4 in length xs = 0);
  190.   "add 1", (fun () -> let xs = make 4 in add xs 1; length xs = 1);
  191.   "add 10", add_10;
  192.   "insert 10", insert_10;
  193.   "insert 10 - remove 9", insert_10_remove_9
  194. ]
  195.  
  196. let () = run_tests tests
Advertisement
Add Comment
Please, Sign In to add comment