-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
added deque implementation and the relevant tests. It can be a useful…
… data structure for the pretty-printer implementation
- Loading branch information
Showing
9 changed files
with
183 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
|
||
/* | ||
This file is a part of ficus language project. | ||
See ficus/LICENSE for the licensing terms | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
/* | ||
This file is a part of ficus language project. | ||
See ficus/LICENSE for the licensing terms | ||
*/ | ||
|
||
// very simple list-based deque | ||
|
||
exception NullQueueError | ||
|
||
// the name is very short, but it's convenient to reference this type as Deque.t | ||
@object type 't t = {head: 't list; tail: 't list} | ||
|
||
fun empty(_: 't t): bool | ||
{ | ||
| {head=[], tail=[]} => true | ||
| _ => false | ||
} | ||
|
||
fun length(d: 't t) = d.head.length() + d.tail.length() | ||
fun rev(d: 't t) = t {head=d.tail, tail=d.head} | ||
|
||
// could improve performance in many cases but the worst one | ||
operator == (d1: 't t, d2: 't t) = list(d1) == list(d2) | ||
|
||
fun first(d: 't t): 't | ||
{ | ||
| {head=x :: _} => x | ||
| {tail=_ :: _} => d.tail.last() | ||
| _ => throw NullQueueError | ||
} | ||
|
||
fun last(d: 't t): 't | ||
{ | ||
| {tail=x :: _} => x | ||
| {head=_ :: _} => d.head.last() | ||
| _ => throw NullQueueError | ||
} | ||
|
||
fun pop_front(d: 't t): ('t, 't t) | ||
{ | ||
| {head=x :: rest, tail} => (x, t {head=rest, tail=tail}) | ||
| {tail=_ :: _} => pop_front(t {head=d.tail.rev(), tail=[]}) | ||
| _ => throw NullQueueError | ||
} | ||
|
||
fun push_front(d: 't t, x: 't): 't t = t {head=x::d.head, tail=d.tail} | ||
|
||
fun pop_back(d: 't t): ('t, 't t) | ||
{ | ||
| {head, tail=x :: rest} => (x, t {head=head, tail=rest}) | ||
| {head=_ :: _} => pop_back(t {head=[], tail=d.head.rev()}) | ||
| _ => throw NullQueueError | ||
} | ||
|
||
fun push_back(d: 't t, x: 't): 't t = t {head=d.head, tail=x::d.tail} | ||
|
||
fun from_list(l: 't list): 't t = t {head=l, tail=[]} | ||
fun list(d: 't t): 't list = d.head + d.tail.rev() | ||
fun array(d: 't t): 't list | ||
{ | ||
val h = [for x <- d.head {x}] | ||
val t = [for x <- d.tail.rev() {x}] | ||
[\h, \t] | ||
} | ||
|
||
fun map(d: 't t, f: 't -> 'rt): 'rt t | ||
{ | ||
val new_head = [: for x <- d.head {f(x)} :] | ||
val new_tail = [: for x <- d.tail {f(x)} :] | ||
t {head=new_head, tail=new_tail} | ||
} | ||
|
||
fun app(d: 't t, f: 't -> void, ~in_order:bool=true): void | ||
{ | ||
for x <- d.head {f(x)} | ||
for x <- (if in_order {d.tail.rev()} else {d.tail}) {f(x)} | ||
} | ||
|
||
fun foldl(d: 't t, f: ('t, 'acc) -> 'acc, res0: 'acc): 'acc | ||
{ | ||
val fold res=res0 for x <- d.head {f(x, res)} | ||
fold res=res for x <- d.tail.rev() {f(x, res)} | ||
} | ||
|
||
fun foldr(d: 't t, f: ('t, 'acc) -> 'acc, res0: 'acc): 'acc | ||
{ | ||
val fold res=res0 for x <- d.tail {f(x, res)} | ||
fold res=res for x <- d.head.rev() {f(x, res)} | ||
} | ||
|
||
fun string(d: 't t) | ||
{ | ||
val len = length(d) | ||
val elems = array(len, "") | ||
for x@i <- d.head {elems[i] = repr(x)} | ||
for x@i <- d.tail {elems[len-i-1] = repr(x)} | ||
join_embrace("[", "]", ", ", elems) | ||
} | ||
|
||
fun print(d: 't t) | ||
{ | ||
print("[") | ||
for x@i <- d.head { | ||
if i > 0 {print(", ")} | ||
print_repr(x) | ||
} | ||
val nonempty = (!d.head.empty() :> int) | ||
for x@i <- d.tail.rev() { | ||
if i+nonempty > 0 {print(", ")} | ||
print_repr(x) | ||
} | ||
print("]") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
This file is a part of ficus language project. | ||
See ficus/LICENSE for the licensing terms | ||
*/ | ||
|
||
// tests for the deque type | ||
from UTest import * | ||
import Deque | ||
|
||
TEST("deque.simple", fun() { | ||
val d = Deque.t {head=[: 1, 2, 3, 4, 5 :], tail=[: 7, 6 :]} | ||
EXPECT_EQ(d.list(), [: 1, 2, 3, 4, 5, 6, 7 :]) | ||
EXPECT_EQ(d.first(), 1) | ||
EXPECT_EQ(d.last(), 7) | ||
val (x, d) = d.pop_back() | ||
val (y, d) = d.pop_back() | ||
val (z, d) = d.pop_back() | ||
EXPECT_EQ(d.list(), [: 1, 2, 3, 4 :]) | ||
EXPECT_EQ(x, 7) | ||
EXPECT_EQ(y, 6) | ||
EXPECT_EQ(z, 5) | ||
EXPECT_EQ(d.first(), 1) | ||
EXPECT_EQ(d.last(), 4) | ||
val d = d.push_back(100) | ||
val d = d.push_back(200) | ||
val d = d.push_back(300) | ||
EXPECT_EQ(d.list(), [: 1, 2, 3, 4, 100, 200, 300 :]) | ||
val (x, d) = d.pop_front() | ||
val (y, d) = d.pop_front() | ||
EXPECT_EQ(d.list(), [: 3, 4, 100, 200, 300 :]) | ||
EXPECT_EQ(x, 1) | ||
EXPECT_EQ(y, 2) | ||
EXPECT_EQ(d.first(), 3) | ||
EXPECT_EQ(d.last(), 300) | ||
val d = d.push_front(-1) | ||
val d = d.push_front(-2) | ||
val d = d.push_front(-3) | ||
EXPECT_EQ(d.list(), [: -3, -2, -1, 3, 4, 100, 200, 300 :]) | ||
EXPECT_EQ(d.length(), 8) | ||
EXPECT_EQ(f"{d.rev()}", "[300, 200, 100, 4, 3, -1, -2, -3]") | ||
EXPECT_EQ(f"{d.map(fun (i) {i*-3})}", "[9, 6, 3, -9, -12, -300, -600, -900]") | ||
EXPECT_EQ(d.foldl(fun (i, s) {s*i}, 1), -432000000) | ||
EXPECT_EQ(d.foldr(fun (i, s) {s+"."+string(i)}, "0"), "0.300.200.100.4.3.-1.-2.-3") | ||
}) |