upload code
This commit is contained in:
commit
3f507064ce
111 changed files with 9258 additions and 0 deletions
3
examples/dice.p3l
Normal file
3
examples/dice.p3l
Normal file
|
@ -0,0 +1,3 @@
|
|||
input!(dice);
|
||||
{}
|
||||
output!(dice);
|
262
examples/quicksort.p3l
Normal file
262
examples/quicksort.p3l
Normal file
|
@ -0,0 +1,262 @@
|
|||
type List<T> = Option<Rc<(T, List<T>)>>;
|
||||
type Partition<T> = (List<T>, T, List<T>);
|
||||
|
||||
// Return a random number between 0 (inclusive) and
|
||||
// max (exclusive).
|
||||
fn random(max: int) -> int {
|
||||
while true {
|
||||
let value: int = 0;
|
||||
let max_value: int = 0;
|
||||
while max_value < max {
|
||||
max_value = max_value * 2 + 1;
|
||||
value = value * 2;
|
||||
{ value = value + 1; } [0.5] {}
|
||||
}
|
||||
if value < max {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if the option is `None`.
|
||||
fn is_none<O>(opt: O) -> bool {
|
||||
if let Some(_value) = opt {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Unwrap an option.
|
||||
fn unwrap<T>(opt: Option<T>) -> T {
|
||||
if let Some(value) = opt {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new, empty list.
|
||||
// Complexity: O(1)
|
||||
fn list_new<T>() -> List<T> {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Push a new value to the front of the list.
|
||||
// Complexity: O(1)
|
||||
fn list_push_front<T>(list: List<T>, elem: T) -> List<T> {
|
||||
return Some(Rc((elem, list)));
|
||||
}
|
||||
|
||||
// Pop the value from the front of the list.
|
||||
// Complexity: O(1)
|
||||
fn list_pop_front<T>(list: List<T>) -> (T, List<T>) {
|
||||
if let Some(front) = list {
|
||||
return *front;
|
||||
}
|
||||
}
|
||||
|
||||
// Append a list to the end of this one.
|
||||
// Complexity: O(n)
|
||||
fn list_append<T>(list: List<T>, list2: List<T>) -> List<T> {
|
||||
if is_none::<List<T>>(list) {
|
||||
return list2;
|
||||
}
|
||||
|
||||
let back: List<T> = list;
|
||||
while let Some(front) = back {
|
||||
let tail: List<T> = (*front).1;
|
||||
if is_none::<List<T>>(tail) {
|
||||
break;
|
||||
}
|
||||
back = tail;
|
||||
}
|
||||
|
||||
if let Some(back) = back {
|
||||
back.1 = list2;
|
||||
return list;
|
||||
}
|
||||
// else unreachable - back is always a non-empty list
|
||||
}
|
||||
|
||||
// Return the length of a list.
|
||||
// Complexity: O(n)
|
||||
fn list_len<T>(list: List<T>) -> int {
|
||||
let len: int = 0;
|
||||
while let Some(inner) = list {
|
||||
len = len + 1;
|
||||
list = (*inner).1;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// Swap the value of the two list elements.
|
||||
fn list_swap<T>(list: List<T>, list2: List<T>) {
|
||||
let list: Rc<(T, List<T>)> = unwrap::<Rc<(T, List<T>)>>(list);
|
||||
let list2: Rc<(T, List<T>)> = unwrap::<Rc<(T, List<T>)>>(list2);
|
||||
let tmp: T = (*list).0;
|
||||
list.0 = (*list2).0;
|
||||
list2.0 = tmp;
|
||||
}
|
||||
|
||||
// Swap the n-th and last elements, and return its value.
|
||||
fn list_swap_nth_last<T>(list: List<T>, n: int) -> T {
|
||||
let i: int = 0;
|
||||
let nth: List<T> = None;
|
||||
while let Some(front) = list {
|
||||
if i == n {
|
||||
nth = list;
|
||||
}
|
||||
let tail: List<T> = (*front).1;
|
||||
if is_none::<List<T>>(tail) {
|
||||
let _unit: () = list_swap::<T>(nth, list);
|
||||
return (*front).0;
|
||||
}
|
||||
list = tail;
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the next list element.
|
||||
fn list_next<T>(list: List<T>) -> List<T> {
|
||||
return (*unwrap::<Rc<(T, List<T>)>>(list)).1;
|
||||
}
|
||||
|
||||
// Split the list at index n.
|
||||
fn list_split<T>(list: List<T>, n: int) -> (List<T>, List<T>) {
|
||||
if n == 0 {
|
||||
return (None, list);
|
||||
}
|
||||
|
||||
let list2: List<T> = list;
|
||||
let i: int = 0;
|
||||
while i < n - 1 {
|
||||
list2 = list_next::<T>(list2);
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
if let Some(front) = list2 {
|
||||
list2 = (*front).1;
|
||||
front.1 = None;
|
||||
}
|
||||
return (list, list2);
|
||||
}
|
||||
|
||||
// Increase swap count
|
||||
fn inc_swaps(swaps_and_comps: Rc<(int, int)>) {
|
||||
swaps_and_comps.0 = (*swaps_and_comps).0 + 1;
|
||||
}
|
||||
|
||||
// Increase comparison count
|
||||
fn inc_comps(swaps_and_comps: Rc<(int, int)>) {
|
||||
swaps_and_comps.1 = (*swaps_and_comps).1 + 1;
|
||||
}
|
||||
|
||||
// Randomised quicksort.
|
||||
// Expected complexity: O(n log n)
|
||||
fn quicksort(list: List<int>, swaps_and_comps: Rc<(int, int)>) -> List<int> {
|
||||
if list_len::<int>(list) < 2 {
|
||||
return list;
|
||||
}
|
||||
|
||||
let partition: Partition<int> = partition(list, swaps_and_comps);
|
||||
let list: List<int> = quicksort(partition.0, swaps_and_comps);
|
||||
let pivot: int = partition.1;
|
||||
let list2: List<int> = quicksort(partition.2, swaps_and_comps);
|
||||
|
||||
list2 = list_push_front::<int>(list2, pivot);
|
||||
return list_append::<int>(list, list2);
|
||||
}
|
||||
|
||||
// Partition a list into smaller, pivot, and larger elements
|
||||
fn partition(list: List<int>, swaps_and_comps: Rc<(int, int)>) -> Partition<int> {
|
||||
// choose some random element as pivot and move it to the last position
|
||||
let list_len: int = list_len::<int>(list);
|
||||
let pivot: int = list_swap_nth_last::<int>(list, random(list_len));
|
||||
let _unit: () = inc_swaps(swaps_and_comps);
|
||||
|
||||
// this is our pivot position
|
||||
let iter: List<int> = list;
|
||||
let iter_idx: int = -1;
|
||||
|
||||
// move all elements smaller than our pivot to its left
|
||||
let i: int = 0;
|
||||
let iter2: List<int> = list;
|
||||
while let Some(front) = iter2 {
|
||||
// don't swap out the pivot already
|
||||
if i != list_len - 1 {
|
||||
|
||||
let _unit: () = inc_comps(swaps_and_comps);
|
||||
if (*front).0 <= pivot {
|
||||
// move pivot index forward
|
||||
if iter_idx >= 0 {
|
||||
iter = list_next::<int>(iter);
|
||||
}
|
||||
iter_idx = iter_idx + 1;
|
||||
|
||||
// swap current element with pivot position
|
||||
if iter_idx != i {
|
||||
let _unit: () = list_swap::<int>(iter, iter2);
|
||||
let _unit: () = inc_swaps(swaps_and_comps);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
iter2 = (*front).1;
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
// move pivot to the correct pivot position
|
||||
iter_idx = iter_idx + 1;
|
||||
let _pivot: int = list_swap_nth_last::<int>(list, iter_idx);
|
||||
let _unit: () = inc_swaps(swaps_and_comps);
|
||||
|
||||
// split the list into two
|
||||
let lists: (List<int>, List<int>) = list_split::<int>(list, iter_idx);
|
||||
let pop: (int, List<int>) = list_pop_front::<int>(lists.1);
|
||||
return (lists.0, pop.0, pop.1);
|
||||
}
|
||||
|
||||
// Assert that the list is sorted.
|
||||
fn assert_sorted(list: List<int>) -> () {
|
||||
if let Some(first) = list {
|
||||
if assert_sorted_impl((*first).1, (*first).0) {
|
||||
return ();
|
||||
}
|
||||
// else there's no path to a return statement - assert failed
|
||||
} else {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
fn assert_sorted_impl(list: List<int>, prev: int) -> bool {
|
||||
while let Some(front) = list {
|
||||
let curr: int = (*front).0;
|
||||
if curr < prev {
|
||||
return false;
|
||||
}
|
||||
prev = curr;
|
||||
list = (*front).1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
input!(len);
|
||||
|
||||
// Create a random list.
|
||||
let list: List<int> = list_new::<int>();
|
||||
let i: int = 0;
|
||||
while i < len {
|
||||
list = list_push_front::<int>(list, random(len*2));
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
// Run quicksort.
|
||||
let swaps_and_comps: Rc<(int, int)> = Rc((0, 0));
|
||||
list = quicksort(list, swaps_and_comps);
|
||||
let swaps: int = (*swaps_and_comps).0;
|
||||
let comps: int = (*swaps_and_comps).1;
|
||||
|
||||
// Ensure the list is now sorted.
|
||||
let _unit: () = assert_sorted(list);
|
||||
|
||||
output!(swaps);
|
||||
output!(comps);
|
382
examples/skiplist-1-4.p3l
Normal file
382
examples/skiplist-1-4.p3l
Normal file
|
@ -0,0 +1,382 @@
|
|||
// 0: own level (lowest level is 0)
|
||||
// 1: entry below this one (exists iff level is greater than 0)
|
||||
// 2: entry to the right of this one
|
||||
type SkipList<V> = (int, SkipListLink<V>, Option<SkipListNode<V>>);
|
||||
|
||||
type SkipListLink<V> = Option<Rc<SkipList<V>>>;
|
||||
|
||||
// 0: own level (lowest level is 0)
|
||||
// 1: entry below this one (exists iff level is greater than 0)
|
||||
// 2: entry to the right of this one
|
||||
// 3: key of the column this entry belongs to
|
||||
// 4: value of the column (only on the lowest level)
|
||||
type SkipListNode<V> = Rc<(int, Option<SkipListNode<V>>, Option<SkipListNode<V>>, int, Option<V>)>;
|
||||
|
||||
type Stack<T> = Rc<(Option<(T, Stack<T>)>,)>;
|
||||
|
||||
// Unwrap an option.
|
||||
fn unwrap<T>(opt: Option<T>) -> T {
|
||||
if let Some(value) = opt {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new, empty stack
|
||||
fn stack_new<T>() -> Stack<T> {
|
||||
return Rc((None,));
|
||||
}
|
||||
|
||||
// Push a new value to the stack.
|
||||
fn stack_push<T>(stack: Stack<T>, value: T) {
|
||||
stack.0 = Some((value, Rc(*stack)));
|
||||
}
|
||||
|
||||
// Pop a value from the stack.
|
||||
fn stack_pop<T>(stack: Stack<T>) -> Option<T> {
|
||||
if let Some(top) = (*stack).0 {
|
||||
stack.0 = (*top.1).0;
|
||||
return Some(top.0);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Return a new, empty skiplist.
|
||||
fn skiplist_new<V>() -> SkipList<V> {
|
||||
return (0, None, None);
|
||||
}
|
||||
|
||||
// Return the current maximum level of the skiplist.
|
||||
fn skiplist_level<V>(list: SkipList<V>) -> int {
|
||||
return list.0;
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value into the skiplist at the first position.
|
||||
fn skiplist_insert_first<V>(
|
||||
list: SkipList<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
// decompose list into levels
|
||||
let levels: Stack<Option<SkipListNode<V>>> =
|
||||
stack_new::<Option<SkipListNode<V>>>();
|
||||
let _unit: () = stack_push::<Option<SkipListNode<V>>>(levels, list.2);
|
||||
while let Some(next) = list.1 {
|
||||
list = *next;
|
||||
let _unit: () = stack_push::<Option<SkipListNode<V>>>(levels, list.2);
|
||||
}
|
||||
|
||||
// create new list with just the lowest level
|
||||
let lvl: int = 0;
|
||||
let top: Option<Option<SkipListNode<V>>> =
|
||||
stack_pop::<Option<SkipListNode<V>>>(levels);
|
||||
let new_node: SkipListNode<V> = Rc((
|
||||
0,
|
||||
None,
|
||||
unwrap::<Option<SkipListNode<V>>>(top),
|
||||
key,
|
||||
Some(value)
|
||||
));
|
||||
list = (0, None, Some(new_node));
|
||||
|
||||
// rebuild list up to its original level
|
||||
while let Some(top) = stack_pop::<Option<SkipListNode<V>>>(levels) {
|
||||
lvl = lvl + 1;
|
||||
if new_lvl >= lvl {
|
||||
new_node = Rc((lvl, Some(new_node), top, key, None));
|
||||
} else {
|
||||
let top: SkipListNode<V> = unwrap::<SkipListNode<V>>(top);
|
||||
new_node = Rc((lvl, Some(new_node), (*top).2, (*top).3, None));
|
||||
}
|
||||
list = (lvl, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
// add new levels if necessary
|
||||
while new_lvl > lvl {
|
||||
lvl = lvl + 1;
|
||||
new_node = Rc((lvl, Some(new_node), None, key, None));
|
||||
list = (lvl, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value into the skiplist that needs to be inserted after
|
||||
// the current node. Will be called when entering a new level while
|
||||
// searching for the insert position. Returns the level of the inserted
|
||||
// node.
|
||||
fn skiplist_insert_impl<V>(
|
||||
node: SkipListNode<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> Option<SkipListNode<V>> {
|
||||
// go to the last node in the level whose key is less than the new key
|
||||
while true {
|
||||
if let Some(next) = (*node).2 {
|
||||
if (*next).3 < key {
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// when not at the lowest level, descend
|
||||
if let Some(below) = (*node).1 {
|
||||
let new_node: Option<SkipListNode<V>> =
|
||||
skiplist_insert_impl::<V>(below, new_lvl, key, value);
|
||||
if let Some(new_node) = new_node {
|
||||
let node_lvl: int = (*node).0;
|
||||
if new_lvl >= node_lvl {
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((node_lvl, Some(new_node), (*node).2, key, None));
|
||||
node.2 = Some(new_node);
|
||||
return Some(new_node);
|
||||
}
|
||||
}
|
||||
return new_node;
|
||||
}
|
||||
|
||||
// if we found a node with the exact key, just update the value
|
||||
if (*node).3 == key {
|
||||
node.4 = Some(value);
|
||||
return None;
|
||||
}
|
||||
|
||||
// otherwise, we need to create a new node immediately following the
|
||||
// current one
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((0, None, (*node).2, key, Some(value)));
|
||||
node.2 = Some(new_node);
|
||||
return Some(new_node);
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value with a set level.
|
||||
fn skiplist_insert_with_level<V>(
|
||||
orig_list: SkipList<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
// find the level at which to start search for the insert position
|
||||
let list: SkipList<V> = orig_list;
|
||||
while true {
|
||||
if let Some(level) = list.2 {
|
||||
if (*level).3 <= key {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = list.1 {
|
||||
list = *below;
|
||||
} else {
|
||||
return skiplist_insert_first::<V>(list, new_lvl, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(node) = list.2 {
|
||||
let new_node: Option<SkipListNode<V>> =
|
||||
skiplist_insert_impl::<V>(node, new_lvl, key, value);
|
||||
if let Some(new_node) = new_node {
|
||||
let node_lvl: int = (*node).0;
|
||||
|
||||
// update levels above node_lvl if necessary
|
||||
list = orig_list;
|
||||
if new_lvl >= list.0 {
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((list.0, None, list.2, key, None));
|
||||
list.2 = Some(new_node);
|
||||
}
|
||||
while let Some(below) = list.1 {
|
||||
list = *below;
|
||||
if list.0 <= node_lvl || list.0 < new_lvl {
|
||||
break;
|
||||
}
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((list.0, None, list.2, key, None));
|
||||
list.2 = Some(new_node);
|
||||
}
|
||||
|
||||
// add levels above the list level if necessary
|
||||
list = orig_list;
|
||||
while new_lvl > list.0 {
|
||||
new_node = Rc((list.0, Some(new_node), None, key, None));
|
||||
list = (list.0 + 1, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
return list;
|
||||
} else {
|
||||
return orig_list;
|
||||
}
|
||||
} else {
|
||||
// we are inserting into an empty list
|
||||
return skiplist_insert_first::<V>(list, new_lvl, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Return a random level.
|
||||
fn skiplist_random_level() -> int {
|
||||
let lvl: int = 0;
|
||||
while true {
|
||||
{ lvl = lvl + 1; } [0.25] { return lvl; }
|
||||
}
|
||||
}
|
||||
|
||||
// Take the skiplist, insert a new value, and return the skiplist.
|
||||
fn skiplist_insert<V>(
|
||||
list: SkipList<V>,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
let lvl: int = skiplist_random_level();
|
||||
return skiplist_insert_with_level::<V>(list, lvl, key, value);
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Find a value in the skiplist, starting the search at a specific node.
|
||||
fn skiplist_get_impl<V>(
|
||||
node: SkipListNode<V>,
|
||||
key: int
|
||||
) -> (Option<V>, int) {
|
||||
let steps: int = 1;
|
||||
|
||||
if (*node).3 < key {
|
||||
while true {
|
||||
if let Some(next) = (*node).2 {
|
||||
let next_key: int = (*next).3;
|
||||
steps = steps + 1;
|
||||
if next_key <= key {
|
||||
node = next;
|
||||
if next_key == key {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = (*node).1 {
|
||||
node = below;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*node).3 != key {
|
||||
return (None, steps);
|
||||
}
|
||||
|
||||
// the value is only stored at the lowest level
|
||||
while let Some(below) = (*node).1 {
|
||||
node = below;
|
||||
}
|
||||
return (Some(unwrap::<V>((*node).4)), steps);
|
||||
}
|
||||
|
||||
// Find a value in the skiplist.
|
||||
fn skiplist_get<V>(list: SkipList<V>, key: int) -> (Option<V>, int) {
|
||||
let steps: int = 0;
|
||||
|
||||
while true {
|
||||
if let Some(node) = list.2 {
|
||||
steps = steps + 1;
|
||||
if (*node).3 <= key {
|
||||
let tmp: (Option<V>, int) = skiplist_get_impl::<V>(node, key);
|
||||
return (tmp.0, steps + tmp.1);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = list.1 {
|
||||
list = *below;
|
||||
continue;
|
||||
}
|
||||
|
||||
return (None, steps);
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that the skiplist contains a certain key.
|
||||
fn assert_contains<V>(list: SkipList<V>, key: int) -> () {
|
||||
if let Some(_value) = skiplist_get::<V>(list, key).0 {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Return the length of the skiplist.
|
||||
fn skiplist_len<V>(list: SkipList<V>) -> int {
|
||||
// descend to the lowest level
|
||||
while let Some(next) = list.1 {
|
||||
list = *next;
|
||||
}
|
||||
|
||||
// count the lowest level
|
||||
let node: Option<SkipListNode<V>> = list.2;
|
||||
let len: int = 0;
|
||||
while let Some(next) = node {
|
||||
len = len + 1;
|
||||
node = (*next).2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// Assert that the skiplist has the correct length.
|
||||
fn assert_len<V>(list: SkipList<V>, len: int) -> () {
|
||||
if skiplist_len::<V>(list) == len {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that a value is in a certain range.
|
||||
fn assert_in_range(value: int, min_incl: int, max_excl: int) -> () {
|
||||
if value >= min_incl && value < max_excl {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Return a random number between 0 (inclusive) and
|
||||
// max (exclusive).
|
||||
fn random(max: int) -> int {
|
||||
while true {
|
||||
let value: int = 0;
|
||||
let max_value: int = 0;
|
||||
while max_value < max {
|
||||
max_value = max_value * 2 + 1;
|
||||
value = value * 2;
|
||||
{ value = value + 1; } [0.25] {}
|
||||
}
|
||||
if value < max {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input!(len);
|
||||
|
||||
// create a new list with entries 0..len
|
||||
let list: SkipList<()> = skiplist_new::<()>();
|
||||
let i: int = 0;
|
||||
while i < len {
|
||||
list = skiplist_insert::<()>(list, i, ());
|
||||
let _unit: () = assert_contains::<()>(list, i);
|
||||
i = i + 1;
|
||||
}
|
||||
let _unit: () = assert_len::<()>(list, len);
|
||||
|
||||
// lookup a random value in the list
|
||||
let key: int = random(len);
|
||||
let _unit: () = assert_in_range(key, 0, len);
|
||||
let lookup: (Option<()>, int) = skiplist_get::<()>(list, key);
|
||||
let _unit: () = unwrap::<()>(lookup.0);
|
||||
|
||||
let steps: int = lookup.1;
|
||||
let lvl: int = skiplist_level::<()>(list);
|
||||
|
||||
output!(len);
|
||||
output!(lvl, steps);
|
382
examples/skiplist-3-8.p3l
Normal file
382
examples/skiplist-3-8.p3l
Normal file
|
@ -0,0 +1,382 @@
|
|||
// 0: own level (lowest level is 0)
|
||||
// 1: entry below this one (exists iff level is greater than 0)
|
||||
// 2: entry to the right of this one
|
||||
type SkipList<V> = (int, SkipListLink<V>, Option<SkipListNode<V>>);
|
||||
|
||||
type SkipListLink<V> = Option<Rc<SkipList<V>>>;
|
||||
|
||||
// 0: own level (lowest level is 0)
|
||||
// 1: entry below this one (exists iff level is greater than 0)
|
||||
// 2: entry to the right of this one
|
||||
// 3: key of the column this entry belongs to
|
||||
// 4: value of the column (only on the lowest level)
|
||||
type SkipListNode<V> = Rc<(int, Option<SkipListNode<V>>, Option<SkipListNode<V>>, int, Option<V>)>;
|
||||
|
||||
type Stack<T> = Rc<(Option<(T, Stack<T>)>,)>;
|
||||
|
||||
// Unwrap an option.
|
||||
fn unwrap<T>(opt: Option<T>) -> T {
|
||||
if let Some(value) = opt {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new, empty stack
|
||||
fn stack_new<T>() -> Stack<T> {
|
||||
return Rc((None,));
|
||||
}
|
||||
|
||||
// Push a new value to the stack.
|
||||
fn stack_push<T>(stack: Stack<T>, value: T) {
|
||||
stack.0 = Some((value, Rc(*stack)));
|
||||
}
|
||||
|
||||
// Pop a value from the stack.
|
||||
fn stack_pop<T>(stack: Stack<T>) -> Option<T> {
|
||||
if let Some(top) = (*stack).0 {
|
||||
stack.0 = (*top.1).0;
|
||||
return Some(top.0);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Return a new, empty skiplist.
|
||||
fn skiplist_new<V>() -> SkipList<V> {
|
||||
return (0, None, None);
|
||||
}
|
||||
|
||||
// Return the current maximum level of the skiplist.
|
||||
fn skiplist_level<V>(list: SkipList<V>) -> int {
|
||||
return list.0;
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value into the skiplist at the first position.
|
||||
fn skiplist_insert_first<V>(
|
||||
list: SkipList<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
// decompose list into levels
|
||||
let levels: Stack<Option<SkipListNode<V>>> =
|
||||
stack_new::<Option<SkipListNode<V>>>();
|
||||
let _unit: () = stack_push::<Option<SkipListNode<V>>>(levels, list.2);
|
||||
while let Some(next) = list.1 {
|
||||
list = *next;
|
||||
let _unit: () = stack_push::<Option<SkipListNode<V>>>(levels, list.2);
|
||||
}
|
||||
|
||||
// create new list with just the lowest level
|
||||
let lvl: int = 0;
|
||||
let top: Option<Option<SkipListNode<V>>> =
|
||||
stack_pop::<Option<SkipListNode<V>>>(levels);
|
||||
let new_node: SkipListNode<V> = Rc((
|
||||
0,
|
||||
None,
|
||||
unwrap::<Option<SkipListNode<V>>>(top),
|
||||
key,
|
||||
Some(value)
|
||||
));
|
||||
list = (0, None, Some(new_node));
|
||||
|
||||
// rebuild list up to its original level
|
||||
while let Some(top) = stack_pop::<Option<SkipListNode<V>>>(levels) {
|
||||
lvl = lvl + 1;
|
||||
if new_lvl >= lvl {
|
||||
new_node = Rc((lvl, Some(new_node), top, key, None));
|
||||
} else {
|
||||
let top: SkipListNode<V> = unwrap::<SkipListNode<V>>(top);
|
||||
new_node = Rc((lvl, Some(new_node), (*top).2, (*top).3, None));
|
||||
}
|
||||
list = (lvl, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
// add new levels if necessary
|
||||
while new_lvl > lvl {
|
||||
lvl = lvl + 1;
|
||||
new_node = Rc((lvl, Some(new_node), None, key, None));
|
||||
list = (lvl, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value into the skiplist that needs to be inserted after
|
||||
// the current node. Will be called when entering a new level while
|
||||
// searching for the insert position. Returns the level of the inserted
|
||||
// node.
|
||||
fn skiplist_insert_impl<V>(
|
||||
node: SkipListNode<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> Option<SkipListNode<V>> {
|
||||
// go to the last node in the level whose key is less than the new key
|
||||
while true {
|
||||
if let Some(next) = (*node).2 {
|
||||
if (*next).3 < key {
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// when not at the lowest level, descend
|
||||
if let Some(below) = (*node).1 {
|
||||
let new_node: Option<SkipListNode<V>> =
|
||||
skiplist_insert_impl::<V>(below, new_lvl, key, value);
|
||||
if let Some(new_node) = new_node {
|
||||
let node_lvl: int = (*node).0;
|
||||
if new_lvl >= node_lvl {
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((node_lvl, Some(new_node), (*node).2, key, None));
|
||||
node.2 = Some(new_node);
|
||||
return Some(new_node);
|
||||
}
|
||||
}
|
||||
return new_node;
|
||||
}
|
||||
|
||||
// if we found a node with the exact key, just update the value
|
||||
if (*node).3 == key {
|
||||
node.4 = Some(value);
|
||||
return None;
|
||||
}
|
||||
|
||||
// otherwise, we need to create a new node immediately following the
|
||||
// current one
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((0, None, (*node).2, key, Some(value)));
|
||||
node.2 = Some(new_node);
|
||||
return Some(new_node);
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value with a set level.
|
||||
fn skiplist_insert_with_level<V>(
|
||||
orig_list: SkipList<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
// find the level at which to start search for the insert position
|
||||
let list: SkipList<V> = orig_list;
|
||||
while true {
|
||||
if let Some(level) = list.2 {
|
||||
if (*level).3 <= key {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = list.1 {
|
||||
list = *below;
|
||||
} else {
|
||||
return skiplist_insert_first::<V>(list, new_lvl, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(node) = list.2 {
|
||||
let new_node: Option<SkipListNode<V>> =
|
||||
skiplist_insert_impl::<V>(node, new_lvl, key, value);
|
||||
if let Some(new_node) = new_node {
|
||||
let node_lvl: int = (*node).0;
|
||||
|
||||
// update levels above node_lvl if necessary
|
||||
list = orig_list;
|
||||
if new_lvl >= list.0 {
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((list.0, None, list.2, key, None));
|
||||
list.2 = Some(new_node);
|
||||
}
|
||||
while let Some(below) = list.1 {
|
||||
list = *below;
|
||||
if list.0 <= node_lvl || list.0 < new_lvl {
|
||||
break;
|
||||
}
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((list.0, None, list.2, key, None));
|
||||
list.2 = Some(new_node);
|
||||
}
|
||||
|
||||
// add levels above the list level if necessary
|
||||
list = orig_list;
|
||||
while new_lvl > list.0 {
|
||||
new_node = Rc((list.0, Some(new_node), None, key, None));
|
||||
list = (list.0 + 1, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
return list;
|
||||
} else {
|
||||
return orig_list;
|
||||
}
|
||||
} else {
|
||||
// we are inserting into an empty list
|
||||
return skiplist_insert_first::<V>(list, new_lvl, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Return a random level.
|
||||
fn skiplist_random_level() -> int {
|
||||
let lvl: int = 0;
|
||||
while true {
|
||||
{ lvl = lvl + 1; } [0.375] { return lvl; }
|
||||
}
|
||||
}
|
||||
|
||||
// Take the skiplist, insert a new value, and return the skiplist.
|
||||
fn skiplist_insert<V>(
|
||||
list: SkipList<V>,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
let lvl: int = skiplist_random_level();
|
||||
return skiplist_insert_with_level::<V>(list, lvl, key, value);
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Find a value in the skiplist, starting the search at a specific node.
|
||||
fn skiplist_get_impl<V>(
|
||||
node: SkipListNode<V>,
|
||||
key: int
|
||||
) -> (Option<V>, int) {
|
||||
let steps: int = 1;
|
||||
|
||||
if (*node).3 < key {
|
||||
while true {
|
||||
if let Some(next) = (*node).2 {
|
||||
let next_key: int = (*next).3;
|
||||
steps = steps + 1;
|
||||
if next_key <= key {
|
||||
node = next;
|
||||
if next_key == key {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = (*node).1 {
|
||||
node = below;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*node).3 != key {
|
||||
return (None, steps);
|
||||
}
|
||||
|
||||
// the value is only stored at the lowest level
|
||||
while let Some(below) = (*node).1 {
|
||||
node = below;
|
||||
}
|
||||
return (Some(unwrap::<V>((*node).4)), steps);
|
||||
}
|
||||
|
||||
// Find a value in the skiplist.
|
||||
fn skiplist_get<V>(list: SkipList<V>, key: int) -> (Option<V>, int) {
|
||||
let steps: int = 0;
|
||||
|
||||
while true {
|
||||
if let Some(node) = list.2 {
|
||||
steps = steps + 1;
|
||||
if (*node).3 <= key {
|
||||
let tmp: (Option<V>, int) = skiplist_get_impl::<V>(node, key);
|
||||
return (tmp.0, steps + tmp.1);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = list.1 {
|
||||
list = *below;
|
||||
continue;
|
||||
}
|
||||
|
||||
return (None, steps);
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that the skiplist contains a certain key.
|
||||
fn assert_contains<V>(list: SkipList<V>, key: int) -> () {
|
||||
if let Some(_value) = skiplist_get::<V>(list, key).0 {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Return the length of the skiplist.
|
||||
fn skiplist_len<V>(list: SkipList<V>) -> int {
|
||||
// descend to the lowest level
|
||||
while let Some(next) = list.1 {
|
||||
list = *next;
|
||||
}
|
||||
|
||||
// count the lowest level
|
||||
let node: Option<SkipListNode<V>> = list.2;
|
||||
let len: int = 0;
|
||||
while let Some(next) = node {
|
||||
len = len + 1;
|
||||
node = (*next).2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// Assert that the skiplist has the correct length.
|
||||
fn assert_len<V>(list: SkipList<V>, len: int) -> () {
|
||||
if skiplist_len::<V>(list) == len {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that a value is in a certain range.
|
||||
fn assert_in_range(value: int, min_incl: int, max_excl: int) -> () {
|
||||
if value >= min_incl && value < max_excl {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Return a random number between 0 (inclusive) and
|
||||
// max (exclusive).
|
||||
fn random(max: int) -> int {
|
||||
while true {
|
||||
let value: int = 0;
|
||||
let max_value: int = 0;
|
||||
while max_value < max {
|
||||
max_value = max_value * 2 + 1;
|
||||
value = value * 2;
|
||||
{ value = value + 1; } [0.375] {}
|
||||
}
|
||||
if value < max {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input!(len);
|
||||
|
||||
// create a new list with entries 0..len
|
||||
let list: SkipList<()> = skiplist_new::<()>();
|
||||
let i: int = 0;
|
||||
while i < len {
|
||||
list = skiplist_insert::<()>(list, i, ());
|
||||
let _unit: () = assert_contains::<()>(list, i);
|
||||
i = i + 1;
|
||||
}
|
||||
let _unit: () = assert_len::<()>(list, len);
|
||||
|
||||
// lookup a random value in the list
|
||||
let key: int = random(len);
|
||||
let _unit: () = assert_in_range(key, 0, len);
|
||||
let lookup: (Option<()>, int) = skiplist_get::<()>(list, key);
|
||||
let _unit: () = unwrap::<()>(lookup.0);
|
||||
|
||||
let steps: int = lookup.1;
|
||||
let lvl: int = skiplist_level::<()>(list);
|
||||
|
||||
output!(len);
|
||||
output!(lvl, steps);
|
382
examples/skiplist.p3l
Normal file
382
examples/skiplist.p3l
Normal file
|
@ -0,0 +1,382 @@
|
|||
// 0: own level (lowest level is 0)
|
||||
// 1: entry below this one (exists iff level is greater than 0)
|
||||
// 2: entry to the right of this one
|
||||
type SkipList<V> = (int, SkipListLink<V>, Option<SkipListNode<V>>);
|
||||
|
||||
type SkipListLink<V> = Option<Rc<SkipList<V>>>;
|
||||
|
||||
// 0: own level (lowest level is 0)
|
||||
// 1: entry below this one (exists iff level is greater than 0)
|
||||
// 2: entry to the right of this one
|
||||
// 3: key of the column this entry belongs to
|
||||
// 4: value of the column (only on the lowest level)
|
||||
type SkipListNode<V> = Rc<(int, Option<SkipListNode<V>>, Option<SkipListNode<V>>, int, Option<V>)>;
|
||||
|
||||
type Stack<T> = Rc<(Option<(T, Stack<T>)>,)>;
|
||||
|
||||
// Unwrap an option.
|
||||
fn unwrap<T>(opt: Option<T>) -> T {
|
||||
if let Some(value) = opt {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new, empty stack
|
||||
fn stack_new<T>() -> Stack<T> {
|
||||
return Rc((None,));
|
||||
}
|
||||
|
||||
// Push a new value to the stack.
|
||||
fn stack_push<T>(stack: Stack<T>, value: T) {
|
||||
stack.0 = Some((value, Rc(*stack)));
|
||||
}
|
||||
|
||||
// Pop a value from the stack.
|
||||
fn stack_pop<T>(stack: Stack<T>) -> Option<T> {
|
||||
if let Some(top) = (*stack).0 {
|
||||
stack.0 = (*top.1).0;
|
||||
return Some(top.0);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Return a new, empty skiplist.
|
||||
fn skiplist_new<V>() -> SkipList<V> {
|
||||
return (0, None, None);
|
||||
}
|
||||
|
||||
// Return the current maximum level of the skiplist.
|
||||
fn skiplist_level<V>(list: SkipList<V>) -> int {
|
||||
return list.0;
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value into the skiplist at the first position.
|
||||
fn skiplist_insert_first<V>(
|
||||
list: SkipList<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
// decompose list into levels
|
||||
let levels: Stack<Option<SkipListNode<V>>> =
|
||||
stack_new::<Option<SkipListNode<V>>>();
|
||||
let _unit: () = stack_push::<Option<SkipListNode<V>>>(levels, list.2);
|
||||
while let Some(next) = list.1 {
|
||||
list = *next;
|
||||
let _unit: () = stack_push::<Option<SkipListNode<V>>>(levels, list.2);
|
||||
}
|
||||
|
||||
// create new list with just the lowest level
|
||||
let lvl: int = 0;
|
||||
let top: Option<Option<SkipListNode<V>>> =
|
||||
stack_pop::<Option<SkipListNode<V>>>(levels);
|
||||
let new_node: SkipListNode<V> = Rc((
|
||||
0,
|
||||
None,
|
||||
unwrap::<Option<SkipListNode<V>>>(top),
|
||||
key,
|
||||
Some(value)
|
||||
));
|
||||
list = (0, None, Some(new_node));
|
||||
|
||||
// rebuild list up to its original level
|
||||
while let Some(top) = stack_pop::<Option<SkipListNode<V>>>(levels) {
|
||||
lvl = lvl + 1;
|
||||
if new_lvl >= lvl {
|
||||
new_node = Rc((lvl, Some(new_node), top, key, None));
|
||||
} else {
|
||||
let top: SkipListNode<V> = unwrap::<SkipListNode<V>>(top);
|
||||
new_node = Rc((lvl, Some(new_node), (*top).2, (*top).3, None));
|
||||
}
|
||||
list = (lvl, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
// add new levels if necessary
|
||||
while new_lvl > lvl {
|
||||
lvl = lvl + 1;
|
||||
new_node = Rc((lvl, Some(new_node), None, key, None));
|
||||
list = (lvl, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value into the skiplist that needs to be inserted after
|
||||
// the current node. Will be called when entering a new level while
|
||||
// searching for the insert position. Returns the level of the inserted
|
||||
// node.
|
||||
fn skiplist_insert_impl<V>(
|
||||
node: SkipListNode<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> Option<SkipListNode<V>> {
|
||||
// go to the last node in the level whose key is less than the new key
|
||||
while true {
|
||||
if let Some(next) = (*node).2 {
|
||||
if (*next).3 < key {
|
||||
node = next;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// when not at the lowest level, descend
|
||||
if let Some(below) = (*node).1 {
|
||||
let new_node: Option<SkipListNode<V>> =
|
||||
skiplist_insert_impl::<V>(below, new_lvl, key, value);
|
||||
if let Some(new_node) = new_node {
|
||||
let node_lvl: int = (*node).0;
|
||||
if new_lvl >= node_lvl {
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((node_lvl, Some(new_node), (*node).2, key, None));
|
||||
node.2 = Some(new_node);
|
||||
return Some(new_node);
|
||||
}
|
||||
}
|
||||
return new_node;
|
||||
}
|
||||
|
||||
// if we found a node with the exact key, just update the value
|
||||
if (*node).3 == key {
|
||||
node.4 = Some(value);
|
||||
return None;
|
||||
}
|
||||
|
||||
// otherwise, we need to create a new node immediately following the
|
||||
// current one
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((0, None, (*node).2, key, Some(value)));
|
||||
node.2 = Some(new_node);
|
||||
return Some(new_node);
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Insert a new value with a set level.
|
||||
fn skiplist_insert_with_level<V>(
|
||||
orig_list: SkipList<V>,
|
||||
new_lvl: int,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
// find the level at which to start search for the insert position
|
||||
let list: SkipList<V> = orig_list;
|
||||
while true {
|
||||
if let Some(level) = list.2 {
|
||||
if (*level).3 <= key {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = list.1 {
|
||||
list = *below;
|
||||
} else {
|
||||
return skiplist_insert_first::<V>(list, new_lvl, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(node) = list.2 {
|
||||
let new_node: Option<SkipListNode<V>> =
|
||||
skiplist_insert_impl::<V>(node, new_lvl, key, value);
|
||||
if let Some(new_node) = new_node {
|
||||
let node_lvl: int = (*node).0;
|
||||
|
||||
// update levels above node_lvl if necessary
|
||||
list = orig_list;
|
||||
if new_lvl >= list.0 {
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((list.0, None, list.2, key, None));
|
||||
list.2 = Some(new_node);
|
||||
}
|
||||
while let Some(below) = list.1 {
|
||||
list = *below;
|
||||
if list.0 <= node_lvl || list.0 < new_lvl {
|
||||
break;
|
||||
}
|
||||
let new_node: SkipListNode<V> =
|
||||
Rc((list.0, None, list.2, key, None));
|
||||
list.2 = Some(new_node);
|
||||
}
|
||||
|
||||
// add levels above the list level if necessary
|
||||
list = orig_list;
|
||||
while new_lvl > list.0 {
|
||||
new_node = Rc((list.0, Some(new_node), None, key, None));
|
||||
list = (list.0 + 1, Some(Rc(list)), Some(new_node));
|
||||
}
|
||||
|
||||
return list;
|
||||
} else {
|
||||
return orig_list;
|
||||
}
|
||||
} else {
|
||||
// we are inserting into an empty list
|
||||
return skiplist_insert_first::<V>(list, new_lvl, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Return a random level.
|
||||
fn skiplist_random_level() -> int {
|
||||
let lvl: int = 0;
|
||||
while true {
|
||||
{ lvl = lvl + 1; } [0.5] { return lvl; }
|
||||
}
|
||||
}
|
||||
|
||||
// Take the skiplist, insert a new value, and return the skiplist.
|
||||
fn skiplist_insert<V>(
|
||||
list: SkipList<V>,
|
||||
key: int,
|
||||
value: V
|
||||
) -> SkipList<V> {
|
||||
let lvl: int = skiplist_random_level();
|
||||
return skiplist_insert_with_level::<V>(list, lvl, key, value);
|
||||
}
|
||||
|
||||
// NOT PUBLIC API
|
||||
// Find a value in the skiplist, starting the search at a specific node.
|
||||
fn skiplist_get_impl<V>(
|
||||
node: SkipListNode<V>,
|
||||
key: int
|
||||
) -> (Option<V>, int) {
|
||||
let steps: int = 1;
|
||||
|
||||
if (*node).3 < key {
|
||||
while true {
|
||||
if let Some(next) = (*node).2 {
|
||||
let next_key: int = (*next).3;
|
||||
steps = steps + 1;
|
||||
if next_key <= key {
|
||||
node = next;
|
||||
if next_key == key {
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = (*node).1 {
|
||||
node = below;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*node).3 != key {
|
||||
return (None, steps);
|
||||
}
|
||||
|
||||
// the value is only stored at the lowest level
|
||||
while let Some(below) = (*node).1 {
|
||||
node = below;
|
||||
}
|
||||
return (Some(unwrap::<V>((*node).4)), steps);
|
||||
}
|
||||
|
||||
// Find a value in the skiplist.
|
||||
fn skiplist_get<V>(list: SkipList<V>, key: int) -> (Option<V>, int) {
|
||||
let steps: int = 0;
|
||||
|
||||
while true {
|
||||
if let Some(node) = list.2 {
|
||||
steps = steps + 1;
|
||||
if (*node).3 <= key {
|
||||
let tmp: (Option<V>, int) = skiplist_get_impl::<V>(node, key);
|
||||
return (tmp.0, steps + tmp.1);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(below) = list.1 {
|
||||
list = *below;
|
||||
continue;
|
||||
}
|
||||
|
||||
return (None, steps);
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that the skiplist contains a certain key.
|
||||
fn assert_contains<V>(list: SkipList<V>, key: int) -> () {
|
||||
if let Some(_value) = skiplist_get::<V>(list, key).0 {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Return the length of the skiplist.
|
||||
fn skiplist_len<V>(list: SkipList<V>) -> int {
|
||||
// descend to the lowest level
|
||||
while let Some(next) = list.1 {
|
||||
list = *next;
|
||||
}
|
||||
|
||||
// count the lowest level
|
||||
let node: Option<SkipListNode<V>> = list.2;
|
||||
let len: int = 0;
|
||||
while let Some(next) = node {
|
||||
len = len + 1;
|
||||
node = (*next).2;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// Assert that the skiplist has the correct length.
|
||||
fn assert_len<V>(list: SkipList<V>, len: int) -> () {
|
||||
if skiplist_len::<V>(list) == len {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Assert that a value is in a certain range.
|
||||
fn assert_in_range(value: int, min_incl: int, max_excl: int) -> () {
|
||||
if value >= min_incl && value < max_excl {
|
||||
return ();
|
||||
}
|
||||
}
|
||||
|
||||
// Return a random number between 0 (inclusive) and
|
||||
// max (exclusive).
|
||||
fn random(max: int) -> int {
|
||||
while true {
|
||||
let value: int = 0;
|
||||
let max_value: int = 0;
|
||||
while max_value < max {
|
||||
max_value = max_value * 2 + 1;
|
||||
value = value * 2;
|
||||
{ value = value + 1; } [0.5] {}
|
||||
}
|
||||
if value < max {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input!(len);
|
||||
|
||||
// create a new list with entries 0..len
|
||||
let list: SkipList<()> = skiplist_new::<()>();
|
||||
let i: int = 0;
|
||||
while i < len {
|
||||
list = skiplist_insert::<()>(list, i, ());
|
||||
let _unit: () = assert_contains::<()>(list, i);
|
||||
i = i + 1;
|
||||
}
|
||||
let _unit: () = assert_len::<()>(list, len);
|
||||
|
||||
// lookup a random value in the list
|
||||
let key: int = random(len);
|
||||
let _unit: () = assert_in_range(key, 0, len);
|
||||
let lookup: (Option<()>, int) = skiplist_get::<()>(list, key);
|
||||
let _unit: () = unwrap::<()>(lookup.0);
|
||||
|
||||
let steps: int = lookup.1;
|
||||
let lvl: int = skiplist_level::<()>(list);
|
||||
|
||||
output!(len);
|
||||
output!(lvl, steps);
|
Reference in a new issue