Compare commits
	
		
			5 Commits
		
	
	
		
			8a01142ad7
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 0fde06efe7 | |||
| f9aa688f5d | |||
| a5efb0ae8d | |||
| f013d3320d | |||
| 34d4bf1055 | 
@@ -17,3 +17,5 @@ gleam_stdlib = ">= 0.44.0 and < 2.0.0"
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
gleeunit = ">= 1.0.0 and < 2.0.0"
 | 
			
		||||
startest = ">= 0.7.0 and < 1.0.0"
 | 
			
		||||
glychee = ">= 1.1.2 and < 2.0.0"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,36 @@
 | 
			
		||||
# You typically do not need to edit this file
 | 
			
		||||
 | 
			
		||||
packages = [
 | 
			
		||||
  { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
 | 
			
		||||
  { name = "benchee", version = "1.4.0", build_tools = ["mix"], requirements = ["deep_merge", "statistex", "table"], otp_app = "benchee", source = "hex", outer_checksum = "299CD10DD8CE51C9EA3DDB74BB150F93D25E968F93E4C1FA31698A8E4FA5D715" },
 | 
			
		||||
  { name = "bigben", version = "1.0.1", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "bigben", source = "hex", outer_checksum = "190E489610A80D76C48BACC75EB8314BD184FF0220AB0F251ABE760B993B91BB" },
 | 
			
		||||
  { name = "birl", version = "1.8.0", build_tools = ["gleam"], requirements = ["gleam_regexp", "gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "2AC7BA26F998E3DFADDB657148BD5DDFE966958AD4D6D6957DD0D22E5B56C400" },
 | 
			
		||||
  { name = "deep_merge", version = "1.0.0", build_tools = ["mix"], requirements = [], otp_app = "deep_merge", source = "hex", outer_checksum = "CE708E5F094B9CD4E8F2BE4F00D2F4250C4095BE93F8CD6D018C753894885430" },
 | 
			
		||||
  { name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
 | 
			
		||||
  { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
 | 
			
		||||
  { name = "gleam_community_ansi", version = "1.4.3", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_regexp", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "8A62AE9CC6EA65BEA630D95016D6C07E4F9973565FA3D0DE68DC4200D8E0DD27" },
 | 
			
		||||
  { name = "gleam_community_colour", version = "2.0.2", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "E34DD2C896AC3792151EDA939DA435FF3B69922F33415ED3C4406C932FBE9634" },
 | 
			
		||||
  { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
 | 
			
		||||
  { name = "gleam_javascript", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "EF6C77A506F026C6FB37941889477CD5E4234FCD4337FF0E9384E297CB8F97EB" },
 | 
			
		||||
  { name = "gleam_json", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "874FA3C3BB6E22DD2BB111966BD40B3759E9094E05257899A7C08F5DE77EC049" },
 | 
			
		||||
  { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" },
 | 
			
		||||
  { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
 | 
			
		||||
  { name = "gleam_stdlib", version = "0.65.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "7C69C71D8C493AE11A5184828A77110EB05A7786EBF8B25B36A72F879C3EE107" },
 | 
			
		||||
  { name = "gleam_time", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "DCDDC040CE97DA3D2A925CDBBA08D8A78681139745754A83998641C8A3F6587E" },
 | 
			
		||||
  { name = "gleam_yielder", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_yielder", source = "hex", outer_checksum = "8E4E4ECFA7982859F430C57F549200C7749823C106759F4A19A78AEA6687717A" },
 | 
			
		||||
  { name = "gleeunit", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "FDC68A8C492B1E9B429249062CD9BAC9B5538C6FBF584817205D0998C42E1DAC" },
 | 
			
		||||
  { name = "glint", version = "1.2.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "2214C7CEFDE457CEE62140C3D4899B964E05236DA74E4243DFADF4AF29C382BB" },
 | 
			
		||||
  { name = "glychee", version = "1.1.2", build_tools = ["gleam"], requirements = ["benchee"], otp_app = "glychee", source = "hex", outer_checksum = "41784216C213F223095BB3FC3EDDB60CC537835B2340A868EA3931193F7F3824" },
 | 
			
		||||
  { name = "ranger", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_yielder"], otp_app = "ranger", source = "hex", outer_checksum = "C8988E8F8CDBD3E7F4D8F2E663EF76490390899C2B2885A6432E942495B3E854" },
 | 
			
		||||
  { name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" },
 | 
			
		||||
  { name = "snag", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "7E9F06390040EB5FAB392CE642771484136F2EC103A92AE11BA898C8167E6E17" },
 | 
			
		||||
  { name = "startest", version = "0.7.0", build_tools = ["gleam"], requirements = ["argv", "bigben", "birl", "exception", "gleam_community_ansi", "gleam_erlang", "gleam_javascript", "gleam_regexp", "gleam_stdlib", "glint", "simplifile", "tom"], otp_app = "startest", source = "hex", outer_checksum = "71B9CB82C4B8779A4BD54C7151DF7D0B0F778D0DDE805B782B44EFA7BA8F50DA" },
 | 
			
		||||
  { name = "statistex", version = "1.1.0", build_tools = ["mix"], requirements = [], otp_app = "statistex", source = "hex", outer_checksum = "F5950EA26AD43246BA2CCE54324AC394A4E7408FDCF98B8E230F503A0CBA9CF5" },
 | 
			
		||||
  { name = "tom", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "74D0C5A3761F7A7D06994755D4D5AD854122EF8E9F9F76A3E7547606D8C77091" },
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[requirements]
 | 
			
		||||
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
 | 
			
		||||
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
 | 
			
		||||
glychee = { version = ">= 1.1.2 and < 2.0.0" }
 | 
			
		||||
startest = { version = ">= 0.7.0 and < 1.0.0" }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										254
									
								
								src/dllist.gleam
									
									
									
									
									
								
							
							
						
						
									
										254
									
								
								src/dllist.gleam
									
									
									
									
									
								
							@@ -11,7 +11,7 @@ pub opaque type Node(a) {
 | 
			
		||||
 | 
			
		||||
pub type DLList(a) {
 | 
			
		||||
  DLList(counter: Int, current: Int, mem: dict.Dict(Int, Node(a)))
 | 
			
		||||
  // CyclicList(counter: Int, current: Int, mem: dict.Dict(Int, Node(a)))
 | 
			
		||||
  CyclicList(counter: Int, current: Int, mem: dict.Dict(Int, Node(a)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn main() {
 | 
			
		||||
@@ -35,27 +35,43 @@ pub fn main() {
 | 
			
		||||
 | 
			
		||||
  // from_list([1, 2, 3, 4]) |> echo
 | 
			
		||||
 | 
			
		||||
  let l1 = new() |> insert(1)
 | 
			
		||||
  let l1 = new() |> insert(1) |> insert(2)
 | 
			
		||||
  l1 |> echo
 | 
			
		||||
  let l1t = take(l1, 5)
 | 
			
		||||
  l1t |> echo
 | 
			
		||||
  let l2 = insert(l1, 2)
 | 
			
		||||
  l2 |> echo
 | 
			
		||||
  let l2t = take(l2, 5)
 | 
			
		||||
  l2t |> echo
 | 
			
		||||
  get(l1) |> echo
 | 
			
		||||
  // let l1t = take(l1, 5)
 | 
			
		||||
  // l1t |> echo
 | 
			
		||||
  // let l2 = insert(l1, 2) |> move_left
 | 
			
		||||
  // l2 |> echo
 | 
			
		||||
  // let l2t = take(l2, 5)
 | 
			
		||||
  // l2t |> echo
 | 
			
		||||
 | 
			
		||||
  let l3 = insert(l2, 3)
 | 
			
		||||
  l3 |> echo
 | 
			
		||||
  let l3t = take(l3, 7)
 | 
			
		||||
  l3t |> echo
 | 
			
		||||
  let l3t2 = take_rev(l3, 7)
 | 
			
		||||
  l3t2 |> echo
 | 
			
		||||
  // let l3 = insert(l2, 3)
 | 
			
		||||
  // l3 |> echo
 | 
			
		||||
  // to_list(l3) |> echo
 | 
			
		||||
  // let l3t = take(l3, 7)
 | 
			
		||||
  // l3t |> echo
 | 
			
		||||
  // let l3t2 = take_rev(l3, 7)
 | 
			
		||||
  // l3t2 |> echo
 | 
			
		||||
  // let l1 = new_cyclic() |> echo
 | 
			
		||||
  // let l2 = l1 |> insert(1) |> insert(2) |> insert(3)
 | 
			
		||||
  // to_list(l2) |> echo
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn new() -> DLList(a) {
 | 
			
		||||
  DLList(1, 0, dict.new())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn new_cyclic() -> DLList(a) {
 | 
			
		||||
  CyclicList(1, 0, dict.new())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn clear(list: DLList(a)) -> DLList(a) {
 | 
			
		||||
  case list {
 | 
			
		||||
    DLList(_, _, _) -> DLList(1, 0, dict.new())
 | 
			
		||||
    CyclicList(_, _, _) -> CyclicList(1, 0, dict.new())
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_curr_node(list: DLList(a)) -> Result(Node(a), Nil) {
 | 
			
		||||
  dict.get(list.mem, list.current)
 | 
			
		||||
}
 | 
			
		||||
@@ -70,39 +86,71 @@ pub fn is_empty(list: DLList(a)) -> Bool {
 | 
			
		||||
 | 
			
		||||
pub fn insert(list: DLList(a), val: a) -> DLList(a) {
 | 
			
		||||
  let ref = list.counter
 | 
			
		||||
  let new_entry_ref = case list {
 | 
			
		||||
    DLList(_, _, _) -> 0
 | 
			
		||||
    CyclicList(_, _, _) -> ref
 | 
			
		||||
  }
 | 
			
		||||
  case is_empty(list) {
 | 
			
		||||
    True -> {
 | 
			
		||||
      let node = Node(val, ref, ref)
 | 
			
		||||
      DLList(ref + 1, ref, dict.insert(list.mem, ref, node))
 | 
			
		||||
      let node = Node(val, new_entry_ref, new_entry_ref)
 | 
			
		||||
      update_record(
 | 
			
		||||
        list,
 | 
			
		||||
        Some(ref + 1),
 | 
			
		||||
        Some(ref),
 | 
			
		||||
        Some(dict.insert(list.mem, ref, node)),
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
    False -> {
 | 
			
		||||
      let assert Ok(curr_node) = dict.get(list.mem, list.current)
 | 
			
		||||
      let curr_node_2 = Node(..curr_node, right: ref)
 | 
			
		||||
      let assert Ok(curr_node) = get_curr_node(list)
 | 
			
		||||
      let next = curr_node.right
 | 
			
		||||
 | 
			
		||||
      let next_node = case next == list.current {
 | 
			
		||||
        True -> Ok(curr_node_2)
 | 
			
		||||
        True -> Ok(Node(..curr_node, right: ref))
 | 
			
		||||
        False -> dict.get(list.mem, next)
 | 
			
		||||
      }
 | 
			
		||||
      let new_mem = case next == list.current {
 | 
			
		||||
        True -> list.mem
 | 
			
		||||
        False -> dict.insert(list.mem, list.current, curr_node_2)
 | 
			
		||||
        False ->
 | 
			
		||||
          dict.insert(list.mem, list.current, Node(..curr_node, right: ref))
 | 
			
		||||
      }
 | 
			
		||||
      let new_mem = case next_node {
 | 
			
		||||
        Ok(next_node) -> {
 | 
			
		||||
          let next_node_2 = Node(..next_node, left: ref)
 | 
			
		||||
          dict.insert(new_mem, next, next_node_2)
 | 
			
		||||
          dict.insert(new_mem, next, Node(..next_node, left: ref))
 | 
			
		||||
        }
 | 
			
		||||
        Error(_) -> new_mem
 | 
			
		||||
      }
 | 
			
		||||
      let new_node = Node(val, list.current, next)
 | 
			
		||||
 | 
			
		||||
      let new_mem = dict.insert(new_mem, ref, new_node)
 | 
			
		||||
      DLList(list.counter + 1, list.counter, new_mem)
 | 
			
		||||
      update_record(
 | 
			
		||||
        list,
 | 
			
		||||
        Some(list.counter + 1),
 | 
			
		||||
        Some(list.counter),
 | 
			
		||||
        Some(dict.insert(new_mem, ref, Node(val, list.current, next))),
 | 
			
		||||
      )
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn update_record(
 | 
			
		||||
  list: DLList(a),
 | 
			
		||||
  counter: Option(Int),
 | 
			
		||||
  current: Option(Int),
 | 
			
		||||
  mem: Option(dict.Dict(Int, Node(a))),
 | 
			
		||||
) -> DLList(a) {
 | 
			
		||||
  case list {
 | 
			
		||||
    DLList(_, _, _) ->
 | 
			
		||||
      DLList(
 | 
			
		||||
        counter: option.unwrap(counter, list.counter),
 | 
			
		||||
        current: option.unwrap(current, list.current),
 | 
			
		||||
        mem: option.unwrap(mem, list.mem),
 | 
			
		||||
      )
 | 
			
		||||
    CyclicList(_, _, _) ->
 | 
			
		||||
      CyclicList(
 | 
			
		||||
        counter: option.unwrap(counter, list.counter),
 | 
			
		||||
        current: option.unwrap(current, list.current),
 | 
			
		||||
        mem: option.unwrap(mem, list.mem),
 | 
			
		||||
      )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn delete(list: DLList(a)) -> DLList(a) {
 | 
			
		||||
  let #(mem, curr_node) = remove_lookup(list, list.current)
 | 
			
		||||
  case curr_node {
 | 
			
		||||
@@ -111,53 +159,61 @@ pub fn delete(list: DLList(a)) -> DLList(a) {
 | 
			
		||||
      let l = curr_node.left
 | 
			
		||||
      let r = curr_node.right
 | 
			
		||||
      case l, r {
 | 
			
		||||
        0, 0 -> new()
 | 
			
		||||
        0, n if n == list.current -> new()
 | 
			
		||||
        n, 0 if n == list.current -> new()
 | 
			
		||||
        n, m if n == list.current && m == list.current -> new()
 | 
			
		||||
        0, 0 -> clear(list)
 | 
			
		||||
        0, n if n == list.current -> clear(list)
 | 
			
		||||
        n, 0 if n == list.current -> clear(list)
 | 
			
		||||
        n, m if n == list.current && m == list.current -> clear(list)
 | 
			
		||||
        _, 0 -> {
 | 
			
		||||
          DLList(
 | 
			
		||||
            ..list,
 | 
			
		||||
            current: l,
 | 
			
		||||
            mem: update_dict_entry(mem, l, fn(n) { Node(..n, right: r) }),
 | 
			
		||||
          update_record(
 | 
			
		||||
            list,
 | 
			
		||||
            None,
 | 
			
		||||
            Some(l),
 | 
			
		||||
            Some(update_dict_entry(mem, l, fn(n) { Node(..n, right: r) })),
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
        _, r if r == list.current -> {
 | 
			
		||||
          DLList(
 | 
			
		||||
            ..list,
 | 
			
		||||
            current: l,
 | 
			
		||||
            mem: update_dict_entry(mem, l, fn(n) { Node(..n, right: l) }),
 | 
			
		||||
          update_record(
 | 
			
		||||
            list,
 | 
			
		||||
            None,
 | 
			
		||||
            Some(l),
 | 
			
		||||
            Some(update_dict_entry(mem, l, fn(n) { Node(..n, right: l) })),
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
        0, _ -> {
 | 
			
		||||
          DLList(
 | 
			
		||||
            ..list,
 | 
			
		||||
            current: r,
 | 
			
		||||
            mem: update_dict_entry(mem, r, fn(n) { Node(..n, left: l) }),
 | 
			
		||||
          update_record(
 | 
			
		||||
            list,
 | 
			
		||||
            None,
 | 
			
		||||
            Some(r),
 | 
			
		||||
            Some(update_dict_entry(mem, r, fn(n) { Node(..n, left: l) })),
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
        l, _ if l == list.current -> {
 | 
			
		||||
          DLList(
 | 
			
		||||
            ..list,
 | 
			
		||||
            current: r,
 | 
			
		||||
            mem: update_dict_entry(mem, r, fn(n) { Node(..n, left: r) }),
 | 
			
		||||
          update_record(
 | 
			
		||||
            list,
 | 
			
		||||
            None,
 | 
			
		||||
            Some(r),
 | 
			
		||||
            Some(update_dict_entry(mem, r, fn(n) { Node(..n, left: r) })),
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
        l, r if l == r -> {
 | 
			
		||||
          DLList(
 | 
			
		||||
            ..list,
 | 
			
		||||
            current: r,
 | 
			
		||||
            mem: update_dict_entry(mem, r, fn(n) {
 | 
			
		||||
              Node(..n, left: r, right: r)
 | 
			
		||||
            }),
 | 
			
		||||
          update_record(
 | 
			
		||||
            list,
 | 
			
		||||
            None,
 | 
			
		||||
            Some(r),
 | 
			
		||||
            Some(
 | 
			
		||||
              update_dict_entry(mem, r, fn(n) { Node(..n, left: r, right: r) }),
 | 
			
		||||
            ),
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
        _, _ -> {
 | 
			
		||||
          DLList(
 | 
			
		||||
            ..list,
 | 
			
		||||
            current: r,
 | 
			
		||||
            mem: update_dict_entry(mem, r, fn(n) { Node(..n, left: l) })
 | 
			
		||||
          update_record(
 | 
			
		||||
            list,
 | 
			
		||||
            None,
 | 
			
		||||
            Some(r),
 | 
			
		||||
            Some(
 | 
			
		||||
              update_dict_entry(mem, r, fn(n) { Node(..n, left: l) })
 | 
			
		||||
              |> update_dict_entry(l, fn(n) { Node(..n, right: r) }),
 | 
			
		||||
            ),
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
@@ -174,8 +230,8 @@ fn do_move_right(list: DLList(a)) -> Result(DLList(a), Nil) {
 | 
			
		||||
    Error(_) -> Error(Nil)
 | 
			
		||||
    Ok(node) -> {
 | 
			
		||||
      case node.right {
 | 
			
		||||
        0 -> Ok(list)
 | 
			
		||||
        r -> Ok(DLList(..list, current: r))
 | 
			
		||||
        0 -> Error(Nil)
 | 
			
		||||
        r -> Ok(update_record(list, None, Some(r), None))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -191,8 +247,8 @@ fn do_move_left(list: DLList(a)) -> Result(DLList(a), Nil) {
 | 
			
		||||
    Error(_) -> Error(Nil)
 | 
			
		||||
    Ok(node) -> {
 | 
			
		||||
      case node.left {
 | 
			
		||||
        0 -> Ok(list)
 | 
			
		||||
        l -> Ok(DLList(..list, current: l))
 | 
			
		||||
        0 -> Error(Nil)
 | 
			
		||||
        l -> Ok(update_record(list, None, Some(l), None))
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@@ -202,17 +258,29 @@ pub fn from_list(list: List(a)) -> DLList(a) {
 | 
			
		||||
  list.fold(list, new(), insert)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn from_list_cyclic(list: List(a)) -> DLList(a) {
 | 
			
		||||
  list.fold(list, new_cyclic(), insert)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn take(list: DLList(a), n_times: Int) -> List(a) {
 | 
			
		||||
  take_loop(list, n_times, [])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn take_loop(list: DLList(a), n_times: Int, acc: List(a)) -> List(a) {
 | 
			
		||||
  list |> echo
 | 
			
		||||
  use <- bool.guard(when: is_empty(list), return: [])
 | 
			
		||||
  case n_times {
 | 
			
		||||
    0 -> list.reverse(acc)
 | 
			
		||||
    n -> {
 | 
			
		||||
      let assert Ok(item) = get(list)
 | 
			
		||||
      take_loop(move_right(list), n - 1, [item, ..acc])
 | 
			
		||||
      case get(list) {
 | 
			
		||||
        Error(_) -> []
 | 
			
		||||
        Ok(item) -> {
 | 
			
		||||
          case move_right(list) {
 | 
			
		||||
            r if r != list -> take_loop(r, n - 1, [item, ..acc])
 | 
			
		||||
            _ -> list.reverse([item, ..acc])
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -226,42 +294,62 @@ fn take_rev_loop(list: DLList(a), n_times: Int, acc: List(a)) -> List(a) {
 | 
			
		||||
  case n_times {
 | 
			
		||||
    0 -> list.reverse(acc)
 | 
			
		||||
    n -> {
 | 
			
		||||
      let assert Ok(item) = get(list)
 | 
			
		||||
      take_rev_loop(move_left(list), n - 1, [item, ..acc])
 | 
			
		||||
      case get(list) {
 | 
			
		||||
        Error(_) -> []
 | 
			
		||||
        Ok(item) -> {
 | 
			
		||||
          case move_left(list) {
 | 
			
		||||
            l if l != list -> take_rev_loop(l, n - 1, [item, ..acc])
 | 
			
		||||
            _ -> list.reverse([item, ..acc])
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn to_list(list: DLList(a)) -> List(a) {
 | 
			
		||||
  case is_empty(list) {
 | 
			
		||||
    True -> []
 | 
			
		||||
    False -> {
 | 
			
		||||
      let assert Ok(a) = get(list)
 | 
			
		||||
      [a, ..to_list_loop(list.current, do_move_right(list))]
 | 
			
		||||
    }
 | 
			
		||||
  let list = case list {
 | 
			
		||||
    DLList(_, _, _) -> DLList(..list, current: 1)
 | 
			
		||||
    CyclicList(_, _, _) -> list
 | 
			
		||||
  }
 | 
			
		||||
  to_list_loop(Ok(list), list.current, []) |> list.reverse
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn to_list_loop(ref: Int, list: Result(DLList(a), Nil)) -> List(a) {
 | 
			
		||||
  case list {
 | 
			
		||||
fn to_list_loop(
 | 
			
		||||
  list: Result(DLList(a), Nil),
 | 
			
		||||
  start_ref: Int,
 | 
			
		||||
  acc: List(a),
 | 
			
		||||
) -> List(a) {
 | 
			
		||||
  case list |> echo {
 | 
			
		||||
    Error(_) -> acc
 | 
			
		||||
    Ok(DLList(_, _, _) as list) -> {
 | 
			
		||||
      case get(list) {
 | 
			
		||||
        Error(_) -> []
 | 
			
		||||
    Ok(DLList(_, current, _)) if current == ref -> []
 | 
			
		||||
    Ok(list) -> {
 | 
			
		||||
      let assert Ok(a) = get(list)
 | 
			
		||||
      [a, ..to_list_loop(ref, do_move_right(list))]
 | 
			
		||||
        Ok(val) -> to_list_loop(do_move_right(list), start_ref, [val, ..acc])
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    Ok(CyclicList(_, _, _) as list) -> {
 | 
			
		||||
      case get(list) {
 | 
			
		||||
        Error(_) -> []
 | 
			
		||||
        Ok(_) if start_ref == list.current && acc != [] -> acc
 | 
			
		||||
        Ok(val) -> to_list_loop(do_move_right(list), start_ref, [val, ..acc])
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn update(list: DLList(a), value: a) -> Result(DLList(a), Nil) {
 | 
			
		||||
  use <- bool.guard(when: is_empty(list), return: Error(Nil))
 | 
			
		||||
  let assert Ok(curr_node) = get_curr_node(list)
 | 
			
		||||
  Ok(
 | 
			
		||||
    DLList(
 | 
			
		||||
      ..list,
 | 
			
		||||
      mem: dict.insert(list.mem, list.current, Node(..curr_node, val: value)),
 | 
			
		||||
    ),
 | 
			
		||||
  )
 | 
			
		||||
  case get_curr_node(list) {
 | 
			
		||||
    Error(_) -> Error(Nil)
 | 
			
		||||
    Ok(curr_node) ->
 | 
			
		||||
      Ok(update_record(
 | 
			
		||||
        list,
 | 
			
		||||
        None,
 | 
			
		||||
        None,
 | 
			
		||||
        Some(dict.insert(list.mem, list.current, Node(..curr_node, val: value))),
 | 
			
		||||
      ))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn update_dict_entry(
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										113
									
								
								test/benchmark.gleam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								test/benchmark.gleam
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
import dllist
 | 
			
		||||
import gleam/list
 | 
			
		||||
import glychee/benchmark
 | 
			
		||||
import glychee/configuration
 | 
			
		||||
 | 
			
		||||
@target(erlang)
 | 
			
		||||
pub fn main() {
 | 
			
		||||
  configuration.initialize()
 | 
			
		||||
  configuration.set_pair(configuration.Warmup, 2)
 | 
			
		||||
  configuration.set_pair(configuration.Parallel, 2)
 | 
			
		||||
 | 
			
		||||
  benchmark2()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@target(erlang)
 | 
			
		||||
fn benchmark() {
 | 
			
		||||
  benchmark.run(
 | 
			
		||||
    [
 | 
			
		||||
      benchmark.Function(
 | 
			
		||||
        label: "list append",
 | 
			
		||||
        callable: fn(data: #(List(Int), Int)) {
 | 
			
		||||
          fn() {
 | 
			
		||||
            list.fold(data.0, [], fn(acc, i) { [i, ..acc] })
 | 
			
		||||
            |> list.reverse
 | 
			
		||||
            |> insert_at(data.1, 999)
 | 
			
		||||
            Nil
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
      ),
 | 
			
		||||
      benchmark.Function(
 | 
			
		||||
        label: "dllist insert",
 | 
			
		||||
        callable: fn(data: #(List(Int), Int)) {
 | 
			
		||||
          fn() {
 | 
			
		||||
            list.fold(data.0, dllist.new(), fn(acc, i) { dllist.insert(acc, i) })
 | 
			
		||||
            |> move_left_n(data.1)
 | 
			
		||||
            |> dllist.insert(999)
 | 
			
		||||
            Nil
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
      ),
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      benchmark.Data(label: "6 Items", data: #(list.range(1, 6), 3)),
 | 
			
		||||
      benchmark.Data(label: "10 Items", data: #(list.range(1, 10), 5)),
 | 
			
		||||
      benchmark.Data(label: "100 Items", data: #(list.range(1, 100), 50)),
 | 
			
		||||
    ],
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@target(erlang)
 | 
			
		||||
fn benchmark2() {
 | 
			
		||||
  benchmark.run(
 | 
			
		||||
    [
 | 
			
		||||
      benchmark.Function(
 | 
			
		||||
        label: "list append",
 | 
			
		||||
        callable: fn(data: #(List(Int), dllist.DLList(Int), Int)) {
 | 
			
		||||
          fn() {
 | 
			
		||||
            let _ = insert_at(data.0, data.2, 999)
 | 
			
		||||
            Nil
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
      ),
 | 
			
		||||
      benchmark.Function(
 | 
			
		||||
        label: "dllist insert",
 | 
			
		||||
        callable: fn(data: #(List(Int), dllist.DLList(Int), Int)) {
 | 
			
		||||
          fn() {
 | 
			
		||||
            let _ = dllist.insert(data.1, 999)
 | 
			
		||||
            Nil
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
      ),
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      benchmark.Data(label: "6 Items", data: #(
 | 
			
		||||
        list.range(1, 6),
 | 
			
		||||
        dllist.from_list(list.range(1, 6)) |> move_left_n(3),
 | 
			
		||||
        3,
 | 
			
		||||
      )),
 | 
			
		||||
      benchmark.Data(label: "10 Items", data: #(
 | 
			
		||||
        list.range(1, 10),
 | 
			
		||||
        dllist.from_list(list.range(1, 10)) |> move_left_n(5),
 | 
			
		||||
        5,
 | 
			
		||||
      )),
 | 
			
		||||
      benchmark.Data(label: "100 Items", data: #(
 | 
			
		||||
        list.range(1, 100),
 | 
			
		||||
        dllist.from_list(list.range(1, 100)) |> move_left_n(50),
 | 
			
		||||
        50,
 | 
			
		||||
      )),
 | 
			
		||||
      benchmark.Data(label: "1000 Items", data: #(
 | 
			
		||||
        list.range(1, 1000),
 | 
			
		||||
        dllist.from_list(list.range(1, 1000)) |> move_left_n(500),
 | 
			
		||||
        500,
 | 
			
		||||
      )),
 | 
			
		||||
      benchmark.Data(label: "10000 Items", data: #(
 | 
			
		||||
        list.range(1, 10_000),
 | 
			
		||||
        dllist.from_list(list.range(1, 10_000)) |> move_left_n(5000),
 | 
			
		||||
        5000,
 | 
			
		||||
      )),
 | 
			
		||||
    ],
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn insert_at(list: List(a), pos: Int, value: a) -> List(a) {
 | 
			
		||||
  let #(l1, l2) = list.split(list, pos)
 | 
			
		||||
  list.append(l1, [value, ..l2])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn move_left_n(list: dllist.DLList(a), n: Int) -> dllist.DLList(a) {
 | 
			
		||||
  case n {
 | 
			
		||||
    0 -> list
 | 
			
		||||
    n -> move_left_n(dllist.move_left(list), n - 1)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +1,61 @@
 | 
			
		||||
import gleeunit
 | 
			
		||||
import dllist
 | 
			
		||||
import gleam/dict
 | 
			
		||||
import startest
 | 
			
		||||
 | 
			
		||||
pub fn main() -> Nil {
 | 
			
		||||
  gleeunit.main()
 | 
			
		||||
  startest.run(startest.default_config())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gleeunit test functions end in `_test`
 | 
			
		||||
pub fn hello_world_test() {
 | 
			
		||||
  let name = "Joe"
 | 
			
		||||
  let greeting = "Hello, " <> name <> "!"
 | 
			
		||||
 | 
			
		||||
  assert greeting == "Hello, Joe!"
 | 
			
		||||
pub fn new_tests() {
 | 
			
		||||
  startest.describe("new instance", [
 | 
			
		||||
    startest.it("terminated list", fn() {
 | 
			
		||||
      assert dllist.new() == dllist.DLList(1, 0, dict.from_list([]))
 | 
			
		||||
    }),
 | 
			
		||||
    startest.it("cyclic list", fn() {
 | 
			
		||||
      assert dllist.new_cyclic() == dllist.CyclicList(1, 0, dict.from_list([]))
 | 
			
		||||
    }),
 | 
			
		||||
  ])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn is_empty_tests() {
 | 
			
		||||
  startest.describe("is_emtpy", [
 | 
			
		||||
    startest.it("terminated list", fn() {
 | 
			
		||||
      assert dllist.is_empty(dllist.new())
 | 
			
		||||
 | 
			
		||||
      assert !dllist.is_empty(dllist.new() |> dllist.insert(1))
 | 
			
		||||
    }),
 | 
			
		||||
    startest.it("cyclic list", fn() {
 | 
			
		||||
      assert dllist.is_empty(dllist.new_cyclic())
 | 
			
		||||
 | 
			
		||||
      assert !dllist.is_empty(dllist.new_cyclic() |> dllist.insert(1))
 | 
			
		||||
    }),
 | 
			
		||||
  ])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn from_list_tests() {
 | 
			
		||||
  startest.describe("from_list", [
 | 
			
		||||
    startest.it("terminated list", fn() {
 | 
			
		||||
      assert dllist.is_empty(dllist.from_list([]))
 | 
			
		||||
 | 
			
		||||
      assert !dllist.is_empty(dllist.from_list([1]))
 | 
			
		||||
 | 
			
		||||
      assert dllist.from_list([1]) |> dllist.get == Ok(1)
 | 
			
		||||
      assert dllist.from_list([1, 2, 3, 4]) |> dllist.get == Ok(4)
 | 
			
		||||
 | 
			
		||||
      assert dllist.from_list([1]) |> dllist.to_list == [1]
 | 
			
		||||
      assert dllist.from_list([1, 2, 3, 4]) |> dllist.to_list == [1, 2, 3, 4]
 | 
			
		||||
    }),
 | 
			
		||||
    startest.it("cyclic list", fn() {
 | 
			
		||||
      assert dllist.is_empty(dllist.from_list_cyclic([]))
 | 
			
		||||
 | 
			
		||||
      assert !dllist.is_empty(dllist.from_list_cyclic([1]))
 | 
			
		||||
 | 
			
		||||
      assert dllist.from_list_cyclic([1]) |> dllist.get == Ok(1)
 | 
			
		||||
      assert dllist.from_list_cyclic([1, 2, 3, 4]) |> dllist.get == Ok(4)
 | 
			
		||||
 | 
			
		||||
      assert dllist.from_list_cyclic([1]) |> dllist.to_list == [1]
 | 
			
		||||
      assert dllist.from_list_cyclic([1, 2, 3, 4]) |> dllist.to_list
 | 
			
		||||
        == [4, 1, 2, 3]
 | 
			
		||||
    }),
 | 
			
		||||
  ])
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user