use shared::Shared;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt::{Debug, Error, Formatter};
use std::hash::{Hash, Hasher};
use std::iter::{FromIterator, Iterator, Sum};
use std::ops::{Add, Deref};
use std::sync::Arc;
use self::ConsListNode::{Cons, Nil};
#[macro_export]
macro_rules! conslist {
() => { $crate::conslist::ConsList::new() };
( $($x:expr),* ) => {{
let mut l = $crate::conslist::ConsList::new();
$(
l = l.cons($x);
)*
l.reverse()
}};
}
#[inline]
pub fn cons<A, RA, RD>(car: RA, cdr: RD) -> ConsList<A>
where
RA: Shared<A>,
RD: Borrow<ConsList<A>>,
{
cdr.borrow().cons(car)
}
pub struct ConsList<A>(Arc<ConsListNode<A>>);
#[doc(hidden)]
pub enum ConsListNode<A> {
Cons(usize, Arc<A>, ConsList<A>),
Nil,
}
impl<A> ConsList<A> {
pub fn new() -> ConsList<A> {
ConsList(Arc::new(Nil))
}
pub fn singleton<R>(v: R) -> ConsList<A>
where
R: Shared<A>,
{
ConsList(Arc::new(Cons(1, v.shared(), conslist![])))
}
pub fn is_empty(&self) -> bool {
match *self.0 {
Nil => true,
_ => false,
}
}
pub fn cons<R>(&self, car: R) -> ConsList<A>
where
R: Shared<A>,
{
ConsList(Arc::new(Cons(self.len() + 1, car.shared(), self.clone())))
}
pub fn head(&self) -> Option<Arc<A>> {
match *self.0 {
Cons(_, ref a, _) => Some(a.clone()),
_ => None,
}
}
pub fn tail(&self) -> Option<ConsList<A>> {
match *self.0 {
Cons(_, _, ref d) => Some(d.clone()),
Nil => None,
}
}
pub fn uncons(&self) -> Option<(Arc<A>, ConsList<A>)> {
match *self.0 {
Nil => None,
Cons(_, ref a, ref d) => Some((a.clone(), d.clone())),
}
}
pub fn uncons2(&self) -> Option<(Arc<A>, Arc<A>, ConsList<A>)> {
self.uncons()
.and_then(|(a1, d)| d.uncons().map(|(a2, d)| (a1, a2, d)))
}
pub fn len(&self) -> usize {
match *self.0 {
Nil => 0,
Cons(l, _, _) => l,
}
}
pub fn append<R>(&self, right: R) -> Self
where
R: Borrow<Self>,
{
match *self.0 {
Nil => right.borrow().clone(),
Cons(_, ref a, ref d) => cons(a.clone(), &d.append(right)),
}
}
pub fn reverse(&self) -> ConsList<A> {
let mut out = ConsList::new();
for i in self.iter() {
out = out.cons(i);
}
out
}
pub fn iter(&self) -> Iter<A> {
Iter {
current: self.clone(),
}
}
pub fn sort_by<F>(&self, cmp: F) -> ConsList<A>
where
F: Fn(&A, &A) -> Ordering,
{
fn merge<A>(
la: &ConsList<A>,
lb: &ConsList<A>,
cmp: &Fn(&A, &A) -> Ordering,
) -> ConsList<A> {
match (la.uncons(), lb.uncons()) {
(Some((ref a, _)), Some((ref b, ref lb1)))
if cmp(a, b) == Ordering::Greater =>
{
cons(b.clone(), &merge(la, lb1, cmp))
}
(Some((a, la1)), Some((_, _))) => cons(a.clone(), &merge(&la1, lb, cmp)),
(None, _) => lb.clone(),
(_, None) => la.clone(),
}
}
fn merge_pairs<A>(
l: &ConsList<ConsList<A>>,
cmp: &Fn(&A, &A) -> Ordering,
) -> ConsList<ConsList<A>> {
match l.uncons2() {
Some((a, b, rest)) => cons(merge(&a, &b, cmp), &merge_pairs(&rest, cmp)),
_ => l.clone(),
}
}
fn merge_all<A>(
l: &ConsList<ConsList<A>>,
cmp: &Fn(&A, &A) -> Ordering,
) -> ConsList<A> {
match l.uncons() {
None => conslist![],
Some((ref a, ref d)) if d.is_empty() => a.deref().clone(),
_ => merge_all(&merge_pairs(l, cmp), cmp),
}
}
fn ascending<A>(
a: &Arc<A>,
f: &Fn(ConsList<A>) -> ConsList<A>,
l: &ConsList<A>,
cmp: &Fn(&A, &A) -> Ordering,
) -> ConsList<ConsList<A>> {
match l.uncons() {
Some((ref b, ref lb)) if cmp(a, b) != Ordering::Greater => {
ascending(&b.clone(), &|ys| f(cons(a.clone(), &ys)), lb, cmp)
}
_ => cons(f(ConsList::singleton(a.clone())), &sequences(l, cmp)),
}
}
fn descending<A>(
a: &Arc<A>,
la: &ConsList<A>,
lb: &ConsList<A>,
cmp: &Fn(&A, &A) -> Ordering,
) -> ConsList<ConsList<A>> {
match lb.uncons() {
Some((ref b, ref bs)) if cmp(a, b) == Ordering::Greater => {
descending(&b.clone(), &cons(a.clone(), la), bs, cmp)
}
_ => cons(cons(a.clone(), la), &sequences(lb, cmp)),
}
}
fn sequences<A>(
l: &ConsList<A>,
cmp: &Fn(&A, &A) -> Ordering,
) -> ConsList<ConsList<A>> {
match l.uncons2() {
Some((ref a, ref b, ref xs)) if cmp(a, b) == Ordering::Greater => {
descending(&b.clone(), &ConsList::singleton(a.clone()), xs, cmp)
}
Some((ref a, ref b, ref xs)) => {
ascending(&b.clone(), &|l| cons(a.clone(), l), xs, cmp)
}
None => conslist![l.clone()],
}
}
merge_all(&sequences(self, &cmp), &cmp)
}
pub fn ptr_eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
pub fn insert<T>(&self, item: T) -> ConsList<A>
where
A: Ord,
T: Shared<A>,
{
self.insert_ref(item.shared())
}
fn insert_ref(&self, item: Arc<A>) -> ConsList<A>
where
A: Ord,
{
match *self.0 {
Nil => ConsList(Arc::new(Cons(0, item, ConsList::new()))),
Cons(_, ref a, ref d) => {
if a.deref() > item.deref() {
self.cons(item)
} else {
d.insert_ref(item).cons(a.clone())
}
}
}
}
pub fn sort(&self) -> ConsList<A>
where
A: Ord,
{
self.sort_by(Ord::cmp)
}
}
impl<A> ConsList<A>
where
A: Ord,
{
}
impl<A> Clone for ConsList<A> {
fn clone(&self) -> Self {
match *self {
ConsList(ref node) => ConsList(node.clone()),
}
}
}
impl<A> Default for ConsList<A> {
fn default() -> Self {
ConsList::new()
}
}
#[cfg(not(has_specialisation))]
impl<A> PartialEq for ConsList<A>
where
A: PartialEq,
{
fn eq(&self, other: &ConsList<A>) -> bool {
self.len() == other.len() && self.iter().eq(other.iter())
}
}
#[cfg(has_specialisation)]
impl<A> PartialEq for ConsList<A>
where
A: PartialEq,
{
default fn eq(&self, other: &ConsList<A>) -> bool {
self.len() == other.len() && self.iter().eq(other.iter())
}
}
#[cfg(has_specialisation)]
impl<A> PartialEq for ConsList<A>
where
A: Eq,
{
fn eq(&self, other: &ConsList<A>) -> bool {
Arc::ptr_eq(&self.0, &other.0)
|| (self.len() == other.len() && self.iter().eq(other.iter()))
}
}
impl<A> Eq for ConsList<A>
where
A: Eq,
{
}
impl<A> Hash for ConsList<A>
where
A: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
for i in self.iter() {
i.hash(state);
}
}
}
impl<'a, A> Add for &'a ConsList<A> {
type Output = ConsList<A>;
fn add(self, other: Self) -> Self::Output {
self.append(other)
}
}
impl<A> Add for ConsList<A> {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
self.append(&other)
}
}
impl<A> Debug for ConsList<A>
where
A: Debug,
{
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
fn items<A>(l: &ConsList<A>, f: &mut Formatter) -> Result<(), Error>
where
A: Debug,
{
match *l.0 {
Nil => Ok(()),
Cons(_, ref a, ref d) => {
write!(f, ", {:?}", a)?;
items(d, f)
}
}
}
write!(f, "[")?;
match *self.0 {
Nil => Ok(()),
Cons(_, ref a, ref d) => {
write!(f, "{:?}", a)?;
items(d, f)
}
}?;
write!(f, "]")
}
}
pub struct Iter<A> {
#[doc(hidden)]
current: ConsList<A>,
}
impl<A> Iterator for Iter<A> {
type Item = Arc<A>;
fn next(&mut self) -> Option<Self::Item> {
match self.current.uncons() {
None => None,
Some((ref a, ref d)) => {
self.current = d.clone();
Some(a.clone())
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.current.len();
(l, Some(l))
}
}
impl<A> ExactSizeIterator for Iter<A> {}
impl<A> IntoIterator for ConsList<A> {
type Item = Arc<A>;
type IntoIter = Iter<A>;
fn into_iter(self) -> Iter<A> {
self.iter()
}
}
impl<A> Sum for ConsList<A> {
fn sum<I>(it: I) -> Self
where
I: Iterator<Item = Self>,
{
it.fold(Self::new(), |a, b| a.append(b))
}
}
impl<A, T> FromIterator<T> for ConsList<A>
where
T: Shared<A>,
{
fn from_iter<I>(source: I) -> Self
where
I: IntoIterator<Item = T>,
{
source
.into_iter()
.fold(conslist![], |l, v| l.cons(v))
.reverse()
}
}
impl<'a, A, R> From<&'a [R]> for ConsList<A>
where
&'a R: Shared<A>,
{
fn from(slice: &'a [R]) -> Self {
slice.into_iter().map(|a| a.shared()).collect()
}
}
impl<A, R> From<Vec<R>> for ConsList<A>
where
R: Shared<A>,
{
fn from(vec: Vec<R>) -> Self {
vec.into_iter().map(|a| a.shared()).collect()
}
}
impl<'a, A, R> From<&'a Vec<R>> for ConsList<A>
where
&'a R: Shared<A>,
{
fn from(vec: &'a Vec<R>) -> Self {
vec.into_iter().map(|a| a.shared()).collect()
}
}
#[cfg(any(test, feature = "quickcheck"))]
use quickcheck::{Arbitrary, Gen};
#[cfg(any(test, feature = "quickcheck"))]
impl<A: Arbitrary + Sync> Arbitrary for ConsList<A> {
fn arbitrary<G: Gen>(g: &mut G) -> Self {
ConsList::from(Vec::<A>::arbitrary(g))
}
}
#[cfg(any(test, feature = "proptest"))]
pub mod proptest {
use super::*;
use proptest::strategy::{BoxedStrategy, Strategy, ValueTree};
use std::ops::Range;
pub fn conslist<A: Strategy + 'static>(
element: A,
size: Range<usize>,
) -> BoxedStrategy<ConsList<<A::Value as ValueTree>::Value>> {
::proptest::collection::vec(element, size.clone())
.prop_map(ConsList::from)
.boxed()
}
}
#[cfg(test)]
mod test {
use super::proptest::*;
use super::*;
use test::is_sorted;
#[test]
fn exact_size_iterator() {
assert_eq!(10, ConsList::from_iter(1..11).iter().len());
}
#[test]
fn collect_from_iterator() {
let o: ConsList<i32> = vec![5, 6, 7].iter().cloned().collect();
assert_eq!(o, conslist![5, 6, 7]);
}
#[test]
fn disequality() {
let l = ConsList::from_iter(1..6);
assert_ne!(l, cons(0, &l));
assert_ne!(l, conslist![1, 2, 3, 4, 5, 6]);
}
#[test]
fn equality_of_empty_lists() {
let l1 = ConsList::<String>::new();
let l2 = ConsList::<String>::new();
assert_eq!(l1, l2);
}
quickcheck! {
fn length(vec: Vec<i32>) -> bool {
let list = ConsList::from(vec.clone());
vec.len() == list.len()
}
fn equality(vec: Vec<i32>) -> bool {
let list1 = ConsList::from(vec.clone());
let list2 = ConsList::from(vec.clone());
list1 == list2
}
fn order(vec: Vec<i32>) -> bool {
let list = ConsList::from(vec.clone());
list.iter().map(|a| *a).eq(vec.into_iter())
}
fn reverse_a_list(l: ConsList<i32>) -> bool {
let vec: Vec<i32> = l.iter().map(|v| *v).collect();
let rev = ConsList::from_iter(vec.into_iter().rev());
l.reverse() == rev
}
fn append_two_lists(xs: ConsList<i32>, ys: ConsList<i32>) -> bool {
let extended = ConsList::from_iter(xs.iter().map(|v| *v).chain(ys.iter().map(|v| *v)));
xs.append(&ys) == extended
}
fn sort_a_list(l: ConsList<i32>) -> bool {
let sorted = l.sort();
l.len() == sorted.len() && is_sorted(sorted)
}
}
proptest! {
#[test]
fn proptest_a_conslist(ref l in conslist(".*", 10..100)) {
assert!(l.len() < 100);
assert!(l.len() >= 10);
}
}
}