Skip to content

Commit

Permalink
fully tested
Browse files Browse the repository at this point in the history
  • Loading branch information
schurhammer committed May 2, 2024
1 parent 6f1303c commit 87bd77a
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 45 deletions.
71 changes: 63 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,72 @@

Data structures in pure Gleam.

## Quick start
## Supported Structures

### Priority Queue


`gleamy/priority_queue`:

This priority queue is a wrapper around `gleamy/pairing_heap` ,providing additional functionality. The priority is comparison based in ascending order (lowest priority first).


### Heap

These heaps are min-heaps, providing efficient access to the minimum value based on a given comparison function.


`gleamy/pairing_heap`:

This is the recommended heap structure for most use cases. However, for some non-linear use cases the performance can degrade because of the amortized nature of this structure.


`gleamy/leftist_heap`:

This heap structure has consistent performance across all use cases.


### Non-Empty List


`gleamy/non_empty_list`:

Non-Empty list is a list structure that always contains at least one item.


### Map

Maps are used for key-value lookups. Keys are compared with a user-provided comparison function.


`gleamy/map`:

This is a wrapper around `red_black_tree_map` providing additional utility functions.


`gleamy/red_black_tree_map`:

A map based on a red-black balanced tree structure.


### Set

Sets are used to store a collection of items. Items are compared with a user-provided comparison function to remove duplicate values.


`gleamy/set`:

This is a wrapper around `red_black_tree_set` providing additional utility functions.


`gleamy/red_black_tree_map`:

A set based on a red-black balanced tree structure.

```sh
gleam run # Run the project
gleam test # Run the tests
gleam shell # Run an Erlang shell
```

## Installation

If available on Hex this package can be added to your Gleam project:
This package can be added to your Gleam project:

```sh
gleam add gleamy_structures
Expand All @@ -24,4 +79,4 @@ gleam add gleamy_structures
and its documentation can be found at <https://hexdocs.pm/gleamy_structures>.

## Contributions Welcome
Feel free to make PRs, issues, or requests for new data structures and functions :) Especially welcome would be more rigorous tests and reviews of the implementation compared to source materials.
Feel free to make PRs, issues, or requests for new data structures and functions :)
2 changes: 1 addition & 1 deletion gleam.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.5.0"
# Fill out these fields if you intend to generate HTML documentation or publish
# your project to the Hex package manager.
licences = ["Apache-2.0"]
description = "Data structures in pure Gleam including tree, heap, non empty list, and priority queue."
description = "Data structures in pure Gleam including tree, heap, non empty list, map, set, and priority queue."
repository = { type = "github", user = "schurhammer", repo = "gleamy_structures" }
links = [{ title = "Website", href = "https://github.com/schurhammer/gleamy_structures" }]

Expand Down
20 changes: 0 additions & 20 deletions src/gleamy/red_black_tree_map.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ pub fn foldr(tree: Tree(k, v), acc: b, fun: fn(b, k, v) -> b) -> b {
do_foldr(tree.root, acc, fun)
}

pub fn draw(tree: Tree(k, v), to_string: fn(k, v) -> String) -> String {
do_draw(tree.root, 0, to_string)
}

fn ins(node: Node(k, v), x: #(k, v), compare: fn(k, k) -> Order) -> Node(k, v) {
case node {
E -> T(R, E, x, E)
Expand Down Expand Up @@ -214,19 +210,3 @@ fn do_indent(acc: String, i: Int) -> String {
i -> do_indent(". " <> acc, i - 1)
}
}

fn do_draw(
node: Node(k, v),
indent: Int,
to_string: fn(k, v) -> String,
) -> String {
case node {
T(_, l, k, r) -> {
let ls = do_draw(l, indent + 1, to_string)
let ks = do_indent(to_string(k.0, k.1) <> "\n", indent)
let rs = do_draw(r, indent + 1, to_string)
ls <> ks <> rs
}
_ -> ""
}
}
16 changes: 0 additions & 16 deletions src/gleamy/red_black_tree_set.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ pub fn foldr(tree: Tree(a), acc: b, fun: fn(b, a) -> b) -> b {
do_foldr(tree.root, acc, fun)
}

pub fn draw(tree: Tree(a), to_string: fn(a) -> String) {
do_draw(tree.root, 0, to_string)
}

fn ins(node, x, compare) {
case node {
E -> T(R, E, x, E)
Expand Down Expand Up @@ -210,15 +206,3 @@ fn do_indent(acc, i) {
i -> do_indent(". " <> acc, i - 1)
}
}

fn do_draw(node, indent, to_string) {
case node {
T(_, l, k, r) -> {
let ls = do_draw(l, indent + 1, to_string)
let ks = do_indent(to_string(k) <> "\n", indent)
let rs = do_draw(r, indent + 1, to_string)
ls <> ks <> rs
}
_ -> ""
}
}
53 changes: 53 additions & 0 deletions test/leftist_heap_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import gleam/int
import gleamy/pairing_heap as heap
import gleeunit/should

pub fn find_test() {
let heap = heap.new(int.compare)

heap.find_min(heap)
|> should.equal(Error(Nil))

let heap = heap.insert(heap, 3)

heap.find_min(heap)
|> should.equal(Ok(3))

let heap = heap.insert(heap, 1)

heap.find_min(heap)
|> should.equal(Ok(1))

let heap = heap.insert(heap, 4)

heap.find_min(heap)
|> should.equal(Ok(1))
}

pub fn delete_test() {
let heap =
heap.new(int.compare)
|> heap.insert(3)
|> heap.insert(1)
|> heap.insert(4)
|> heap.insert(1)
|> heap.insert(5)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 1)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 1)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 3)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 4)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 5)

heap.delete_min(heap)
|> should.equal(Error(Nil))
}
53 changes: 53 additions & 0 deletions test/pairing_heap_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import gleam/int
import gleamy/leftist_heap as heap
import gleeunit/should

pub fn find_test() {
let heap = heap.new(int.compare)

heap.find_min(heap)
|> should.equal(Error(Nil))

let heap = heap.insert(heap, 3)

heap.find_min(heap)
|> should.equal(Ok(3))

let heap = heap.insert(heap, 1)

heap.find_min(heap)
|> should.equal(Ok(1))

let heap = heap.insert(heap, 4)

heap.find_min(heap)
|> should.equal(Ok(1))
}

pub fn delete_test() {
let heap =
heap.new(int.compare)
|> heap.insert(3)
|> heap.insert(1)
|> heap.insert(4)
|> heap.insert(1)
|> heap.insert(5)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 1)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 1)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 3)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 4)

let assert Ok(#(x, heap)) = heap.delete_min(heap)
should.equal(x, 5)

heap.delete_min(heap)
|> should.equal(Error(Nil))
}
72 changes: 72 additions & 0 deletions test/red_black_tree_map_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import gleam/string
import gleamy/red_black_tree_map as map
import gleeunit/should

pub fn insert_and_find_test() {
let map = map.new(string.compare)
let updated_map =
map
|> map.insert("key1", "value1")
|> map.insert("key2", "value2")

updated_map
|> map.find("key1")
|> should.equal(Ok(#("key1", "value1")))

updated_map
|> map.find("key2")
|> should.equal(Ok(#("key2", "value2")))
}

pub fn delete_test() {
let map =
map.new(string.compare)
|> map.insert("key1", "value1")
|> map.insert("key2", "value2")

let updated_map =
map
|> map.delete("key1")

updated_map
|> map.find("key1")
|> should.equal(Error(Nil))

updated_map
|> map.find("key2")
|> should.equal(Ok(#("key2", "value2")))
}

pub fn fold_test() {
let map =
map.new(string.compare)
|> map.insert("key1", "value1")
|> map.insert("key2", "value2")
|> map.insert("key3", "value3")

let result =
map
|> map.fold(0, fn(a, _, _) { a + 1 })

result
|> should.equal(3)
}

pub fn missing_keys_test() {
let map =
map.new(string.compare)
|> map.insert("key1", "value1")
|> map.insert("key2", "value2")

map
|> map.find("key3")
|> should.equal(Error(Nil))

let updated_map =
map
|> map.delete("key3")

updated_map
|> map.find("key3")
|> should.equal(Error(Nil))
}
Loading

0 comments on commit 87bd77a

Please sign in to comment.