Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deque #144

Closed
wants to merge 13 commits into from
1 change: 1 addition & 0 deletions libs/Forc.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[workspace]
members = [
"deque",
"fixed_point",
"merkle_proof",
"nft",
Expand Down
7 changes: 7 additions & 0 deletions libs/deque/Forc.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[project]
authors = ["Fuel Labs <[email protected]>"]
entry = "main.sw"
license = "Apache-2.0"
name = "deque"

[dependencies]
189 changes: 189 additions & 0 deletions libs/deque/src/main.sw
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
library;
//! The `Deque` type corresponds to the same called data structure.
//! A Deque is defined as a linear data structure that allows insertion and removal of elements from both ends in other words it's a double-ended queue.

pub struct Deque<T> {
front: Vec<T>,
back: Vec<T>,
}

impl<T> Deque<T> {
/// Creates a new, empty deque.
pub fn new() -> Self {
Self {
front: Vec::new(),
back: Vec::new(),
}
}

/// Creates a new, empty deque with the specified capacity.
pub fn with_capacity(capacity: u64) -> Self {
Self {
front: Vec::with_capacity(capacity),
back: Vec::with_capacity(capacity),
}
}

/// Appends an element to the back of the deque.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Appends an element to the back of the deque.
/// Appends an element to the end of the deque.

Sorry, I feel the need to be pedantic here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it would be better to use conventional terminology (back, front etc), so that the users are comfortable with the library.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say follow what Rust does here as usual.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to not use a similar implementation from Rust @rostyslavtyshko ?

pub fn push_back(ref mut self, value: T) {
self.back.push(value);
}

/// Inserts an element at the front of the deque.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Inserts an element at the front of the deque.
/// Inserts an element at the start of the deque.

Here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same argument as here

pub fn push_front(ref mut self, value: T) {
self.front.push(value);
}

// Returns an element from front, in case the `Deque` is empty `None` is returned
pub fn pop_front(ref mut self) -> Option<T> {
rostyslavtyshko marked this conversation as resolved.
Show resolved Hide resolved
if self.front.is_empty() {
if !self.back.is_empty() {
self.front.push(self.back.remove(0))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.front.push(self.back.remove(0))
self.back.remove(0)

Is there a reason that we do not actually remove from the front? Here we remove the first item from the back but then we add it to the end of the front which effectively does not pop the item.

May need to run forc fmt here. and same below

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is to unify the logic and always to pop from front, even if due to some reasons all the elements were in back

forc fmt is run by CI, so seems to be fine

}
}
self.front.pop()
}

// Returns an element from back, in case the `Deque` is empty `None` is returned
pub fn pop_back(ref mut self) -> Option<T> {
if self.back.is_empty() {
if !self.front.is_empty() {
self.back.push(self.front.remove(0))
}
}
self.back.pop()
}

/// Returns the number of elements in the deque.
pub fn len(self) -> u64 {
self.front.len() + self.back.len()
}

/// Returns `true` if the deque is empty.
pub fn is_empty(self) -> bool {
self.front.is_empty() && self.back.is_empty()
}

/// Removes all elements from the deque.
pub fn clear(self) {
self.front.clear();
self.back.clear();
}

/// Returns the maximum number of elements the deque can hold without reallocating.
pub fn capacity(self) -> u64 {
self.front.capacity() + self.back.capacity()
}
}

#[test()]
fn test_new_deque() {
let new_deque: Deque<u64> = Deque::new();
assert(new_deque.is_empty());
assert(new_deque.len() == 0);
}

#[test()]
fn test_deque_push_pop_front() {
let mut deque_push_front = Deque::new();
let mut deque_len = deque_push_front.len();
assert(deque_len == 0);
deque_push_front.push_front(1);
assert(deque_push_front.len() == deque_len + 1);
deque_len = deque_push_front.len();
deque_push_front.push_front(2);
assert(deque_push_front.len() == deque_len + 1);
deque_len = deque_push_front.len();
deque_push_front.push_front(3);
assert(deque_push_front.len() == deque_len + 1);

deque_len = deque_push_front.len();
assert(deque_push_front.pop_front().unwrap() == 3);
assert(deque_push_front.len() == deque_len - 1);
deque_len = deque_push_front.len();
assert(deque_push_front.pop_front().unwrap() == 2);
assert(deque_push_front.len() == deque_len - 1);
deque_len = deque_push_front.len();
assert(deque_push_front.pop_front().unwrap() == 1);
assert(deque_push_front.len() == deque_len - 1);
assert(deque_push_front.pop_front().is_none());
}

#[test()]
fn test_deque_push_front_push_back_pop_front() {
let mut deque_push_back = Deque::new();
let mut deque_len = deque_push_back.len();
assert(deque_len == 0);
deque_push_back.push_front(1);
assert(deque_push_back.len() == deque_len + 1);
deque_len = deque_push_back.len();
deque_push_back.push_back(1);
assert(deque_push_back.len() == deque_len + 1);
deque_len = deque_push_back.len();
deque_push_back.push_back(2);
assert(deque_push_back.len() == deque_len + 1);
deque_len = deque_push_back.len();
deque_push_back.push_back(3);
assert(deque_push_back.len() == deque_len + 1);

deque_len = deque_push_back.len();
assert(deque_push_back.pop_front().unwrap() == 1);
assert(deque_push_back.len() == deque_len - 1);
deque_len = deque_push_back.len();
assert(deque_push_back.pop_front().unwrap() == 1);
assert(deque_push_back.len() == deque_len - 1);
deque_len = deque_push_back.len();
assert(deque_push_back.pop_front().unwrap() == 2);
assert(deque_push_back.len() == deque_len - 1);
deque_len = deque_push_back.len();
assert(deque_push_back.pop_front().unwrap() == 3);
assert(deque_push_back.len() == deque_len - 1);
assert(deque_push_back.pop_front().is_none());
}

#[test()]
fn test_deque_push_pop_back() {
let mut deque = Deque::new();
let mut deque_len = deque.len();
assert(deque_len == 0);
deque.push_back(1);
assert(deque.len() == deque_len + 1);
deque_len = deque.len();
deque.push_back(2);
assert(deque.len() == deque_len + 1);
deque_len = deque.len();
let _ = deque.pop_back();
assert(deque.len() == deque_len - 1);
}

#[test()]
fn test_deque_push_front_pop_back() {
let mut deque_push_back = Deque::new();
let mut deque_len = deque_push_back.len();
assert(deque_len == 0);
deque_push_back.push_front(1);
assert(deque_push_back.len() == deque_len + 1);
deque_len = deque_push_back.len();
deque_push_back.push_front(1);
assert(deque_push_back.len() == deque_len + 1);
deque_len = deque_push_back.len();
deque_push_back.push_front(2);
assert(deque_push_back.len() == deque_len + 1);
deque_len = deque_push_back.len();
deque_push_back.push_front(3);
assert(deque_push_back.len() == deque_len + 1);

deque_len = deque_push_back.len();
assert(deque_push_back.pop_back().unwrap() == 1);
assert(deque_push_back.len() == deque_len - 1);
deque_len = deque_push_back.len();
assert(deque_push_back.pop_back().unwrap() == 1);
assert(deque_push_back.len() == deque_len - 1);
deque_len = deque_push_back.len();
assert(deque_push_back.pop_back().unwrap() == 2);
assert(deque_push_back.len() == deque_len - 1);
deque_len = deque_push_back.len();
assert(deque_push_back.pop_back().unwrap() == 3);
assert(deque_push_back.len() == deque_len - 1);
assert(deque_push_back.pop_back().is_none());
}