aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAria Shrimpton <me@aria.rip>2024-03-19 15:59:13 +0000
committerAria Shrimpton <me@aria.rip>2024-03-19 21:27:31 +0000
commit443951f481148db0b06d545d6f22a06f59df2606 (patch)
tree46e5a7ef534cacc9a989113e84efebeede715684
parent69f00cd8d8fe977e59feddb166f018be6480110c (diff)
more library types & more consistent naming
-rw-r--r--src/crates/library/src/adaptive.rs8
-rw-r--r--src/crates/library/src/lib.rs19
-rw-r--r--src/crates/library/src/proptest/strategies.rs18
-rw-r--r--src/crates/library/src/sortedvec.rs (renamed from src/crates/library/src/sorted_vector.rs)0
-rw-r--r--src/crates/library/src/sortedvecmap.rs139
-rw-r--r--src/crates/library/src/sortedvecset.rs (renamed from src/crates/library/src/sorted_unique_vector.rs)72
-rw-r--r--src/crates/library/src/vecmap.rs143
-rw-r--r--src/crates/library/src/vecset.rs356
8 files changed, 705 insertions, 50 deletions
diff --git a/src/crates/library/src/adaptive.rs b/src/crates/library/src/adaptive.rs
index 179a2fa..5f21716 100644
--- a/src/crates/library/src/adaptive.rs
+++ b/src/crates/library/src/adaptive.rs
@@ -194,12 +194,11 @@ where
mod tests {
use std::collections::HashSet;
- use crate::{traits::Container, AdaptiveContainer, SortedUniqueVec};
+ use crate::{traits::Container, AdaptiveContainer, SortedVecSet};
#[test]
fn adaptive_container_lo_functionality() {
- let mut c: AdaptiveContainer<10, SortedUniqueVec<_>, HashSet<_>, usize> =
- Default::default();
+ let mut c: AdaptiveContainer<10, SortedVecSet<_>, HashSet<_>, usize> = Default::default();
for i in 0..5 {
c.insert(i);
@@ -210,8 +209,7 @@ mod tests {
#[test]
fn adaptive_container_adapts() {
- let mut c: AdaptiveContainer<10, SortedUniqueVec<_>, HashSet<_>, usize> =
- Default::default();
+ let mut c: AdaptiveContainer<10, SortedVecSet<_>, HashSet<_>, usize> = Default::default();
for i in 1..=9 {
c.insert(i);
diff --git a/src/crates/library/src/lib.rs b/src/crates/library/src/lib.rs
index 44df8db..4a0c94f 100644
--- a/src/crates/library/src/lib.rs
+++ b/src/crates/library/src/lib.rs
@@ -10,9 +10,6 @@ pub use profiler::{MappingProfilerWrapper, ProfilerWrapper};
mod adaptive;
pub use adaptive::AdaptiveContainer;
-mod sorted_unique_vector;
-mod sorted_vector;
-
mod btreemap;
mod hashmap;
mod hashset;
@@ -20,8 +17,20 @@ mod list;
mod treeset;
mod vector;
-pub use sorted_unique_vector::SortedUniqueVec;
-pub use sorted_vector::SortedVec;
+mod vecset;
+pub use vecset::VecSet;
+
+mod vecmap;
+pub use vecmap::VecMap;
+
+mod sortedvec;
+pub use sortedvec::SortedVec;
+
+mod sortedvecset;
+pub use sortedvecset::SortedVecSet;
+
+mod sortedvecmap;
+pub use sortedvecmap::SortedVecMap;
#[cfg(test)]
pub mod proptest;
diff --git a/src/crates/library/src/proptest/strategies.rs b/src/crates/library/src/proptest/strategies.rs
index e61daa4..69a860e 100644
--- a/src/crates/library/src/proptest/strategies.rs
+++ b/src/crates/library/src/proptest/strategies.rs
@@ -2,18 +2,18 @@ use proptest::prelude::*;
use std::ops::Range;
-use crate::{SortedUniqueVec, SortedVec};
+use crate::{SortedVec, SortedVecSet, VecSet};
use proptest::collection::vec;
-pub fn sorted_unique_vec<T: Strategy + 'static>(
+pub fn sorted_vec_set<T: Strategy + 'static>(
element: T,
size: Range<usize>,
-) -> impl Strategy<Value = SortedUniqueVec<T::Value>>
+) -> impl Strategy<Value = SortedVecSet<T::Value>>
where
<T as Strategy>::Value: PartialEq + Ord,
{
- vec(element, size.clone()).prop_map(SortedUniqueVec::from_vec)
+ vec(element, size.clone()).prop_map(SortedVecSet::from_vec)
}
pub fn sorted_vec<T: Strategy + 'static>(
@@ -25,3 +25,13 @@ where
{
vec(element, size.clone()).prop_map(SortedVec::from_vec)
}
+
+pub fn vec_set<T: Strategy + 'static>(
+ element: T,
+ size: Range<usize>,
+) -> impl Strategy<Value = VecSet<T::Value>>
+where
+ <T as Strategy>::Value: Ord,
+{
+ vec(element, size.clone()).prop_map(VecSet::from_vec)
+}
diff --git a/src/crates/library/src/sorted_vector.rs b/src/crates/library/src/sortedvec.rs
index 925e3ef..925e3ef 100644
--- a/src/crates/library/src/sorted_vector.rs
+++ b/src/crates/library/src/sortedvec.rs
diff --git a/src/crates/library/src/sortedvecmap.rs b/src/crates/library/src/sortedvecmap.rs
new file mode 100644
index 0000000..1f05200
--- /dev/null
+++ b/src/crates/library/src/sortedvecmap.rs
@@ -0,0 +1,139 @@
+/*LIBSPEC-NAME*
+rust-hashmap-spec primrose_library::SortedVecMap
+*ENDLIBSPEC-NAME*/
+
+use crate::{traits::Mapping, vecmap::extract_key};
+use std::{hash::Hash, mem::replace};
+
+#[derive(Clone)]
+pub struct SortedVecMap<K, V> {
+ v: Vec<(K, V)>,
+}
+
+/*IMPL*
+Mapping
+*ENDIMPL*/
+impl<K: Ord + Hash, V> Mapping<K, V> for SortedVecMap<K, V> {
+ /*LIBSPEC*
+ /*OPNAME*
+ len op-len pre-len post-len
+ *ENDOPNAME*/
+ (define (pre-len xs) (is-map? xs))
+ (define (op-len xs) (cons xs (length xs)))
+ (define (post-len xs r) (equal? r (op-len xs)))
+ *ENDLIBSPEC*/
+ fn len(&self) -> usize {
+ self.v.len()
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ contains op-contains pre-contains post-contains
+ *ENDOPNAME*/
+ (define (pre-contains xs) (is-map? xs))
+ (define (op-contains xs k) (assoc k xs))
+ (define (post-contains xs k r) (equal? r (op-contains xs k)))
+ *ENDLIBSPEC*/
+ fn contains(&mut self, key: &K) -> bool {
+ self.v.binary_search_by_key(&key, extract_key).is_ok()
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ insert op-insert pre-insert post-insert
+ *ENDOPNAME*/
+ (define (pre-insert xs) (is-map? xs))
+ (define (op-insert xs k v)
+ (let ([idx (index-where xs (lambda (p) (equal? k (car p))))])
+ (cond [idx (list-set xs idx (cons k v))]
+ [else (list* (cons k v) xs)])))
+ (define (post-insert xs k v r) (equal? r (op-insert xs k v)))
+ *ENDLIBSPEC*/
+ fn insert(&mut self, key: K, val: V) -> Option<V> {
+ match self.v.binary_search_by_key(&&key, extract_key) {
+ Ok(idx) => Some(replace(&mut self.v[idx].1, val)),
+ Err(idx) => {
+ self.v.insert(idx, (key, val));
+ None
+ }
+ }
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ get op-get pre-get post-get
+ *ENDOPNAME*/
+ (define (pre-get xs) (is-map? xs))
+ (define (op-get xs k) (cdr (assoc k xs)))
+ (define (post-get xs k r) (equal? r (op-get xs k)))
+ *ENDLIBSPEC*/
+ fn get(&self, key: &K) -> Option<&V> {
+ Some(&self.v[self.v.binary_search_by_key(&key, extract_key).ok()?].1)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ remove op-remove pre-remove post-remove
+ *ENDOPNAME*/
+ (define (pre-remove xs) (is-map? xs))
+ (define (op-remove xs k) (cdr (assoc k xs)))
+ (define (post-remove xs k r) (equal? r (op-remove xs k)))
+ *ENDLIBSPEC*/
+ fn remove(&mut self, key: &K) -> Option<V> {
+ Some(
+ self.v
+ .remove(self.v.binary_search_by_key(&key, extract_key).ok()?)
+ .1,
+ )
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ clear op-clear pre-clear post-clear
+ *ENDOPNAME*/
+ (define (pre-clear xs) (is-map? xs))
+ (define (op-clear xs) null)
+ (define (post-clear xs r) (equal? r (op-clear xs)))
+ *ENDLIBSPEC*/
+ fn clear(&mut self) {
+ self.v.clear()
+ }
+
+ fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a K, &'a V)> + 'a
+ where
+ K: 'a,
+ V: 'a,
+ {
+ self.v.iter().map(|(k, v)| (k, v))
+ }
+}
+
+impl<K, V> Default for SortedVecMap<K, V> {
+ fn default() -> Self {
+ Self { v: Vec::default() }
+ }
+}
+
+impl<K: Ord, V> FromIterator<(K, V)> for SortedVecMap<K, V> {
+ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
+ let mut v: Vec<(K, V)> = iter.into_iter().collect();
+ v.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
+ v.dedup_by(|(k1, _), (k2, _)| k1 == k2);
+ Self { v }
+ }
+}
+
+impl<K, V> IntoIterator for SortedVecMap<K, V> {
+ type Item = (K, V);
+
+ type IntoIter = std::vec::IntoIter<(K, V)>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.v.into_iter()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ // TODO
+}
diff --git a/src/crates/library/src/sorted_unique_vector.rs b/src/crates/library/src/sortedvecset.rs
index b974693..0016374 100644
--- a/src/crates/library/src/sorted_unique_vector.rs
+++ b/src/crates/library/src/sortedvecset.rs
@@ -1,5 +1,5 @@
/*LIBSPEC-NAME*
-rust-eager-unique-vec-spec primrose_library::SortedUniqueVec
+rust-eager-unique-vec-spec primrose_library::SortedVecSet
*ENDLIBSPEC-NAME*/
use crate::traits::{Container, Indexable};
@@ -8,19 +8,19 @@ use std::vec::Vec;
/// A Unique Vector
#[derive(Debug, Clone)]
-pub struct SortedUniqueVec<T> {
+pub struct SortedVecSet<T> {
v: Vec<T>,
}
-impl<T: PartialEq + std::cmp::Ord> SortedUniqueVec<T> {
- pub fn from_vec(mut v: Vec<T>) -> SortedUniqueVec<T> {
+impl<T: PartialEq + std::cmp::Ord> SortedVecSet<T> {
+ pub fn from_vec(mut v: Vec<T>) -> SortedVecSet<T> {
v.sort();
v.dedup();
- SortedUniqueVec { v }
+ SortedVecSet { v }
}
- pub fn new() -> SortedUniqueVec<T> {
- SortedUniqueVec { v: Vec::new() }
+ pub fn new() -> SortedVecSet<T> {
+ SortedVecSet { v: Vec::new() }
}
pub fn len(&self) -> usize {
@@ -71,17 +71,17 @@ impl<T: PartialEq + std::cmp::Ord> SortedUniqueVec<T> {
/*IMPL*
Container
*ENDIMPL*/
-impl<T: Ord + PartialEq> Container<T> for SortedUniqueVec<T> {
+impl<T: Ord + PartialEq> Container<T> for SortedVecSet<T> {
/*LIBSPEC*
/*OPNAME*
len op-len pre-len post-len
*ENDOPNAME*/
(define (op-len xs) (cons xs (length xs)))
- (define (pre-len xs) (equal? xs (remove-duplicates xs)))
+ (define (pre-len xs) (equal? xs (remove-duplicates (sort xs))))
(define (post-len xs r) (equal? r (op-len xs)))
*ENDLIBSPEC*/
fn len(&self) -> usize {
- SortedUniqueVec::len(self)
+ SortedVecSet::len(self)
}
/*LIBSPEC*
@@ -92,11 +92,11 @@ impl<T: Ord + PartialEq> Container<T> for SortedUniqueVec<T> {
(cond
[(list? (member x xs)) (cons xs #t)]
[else (cons xs #f)]))
- (define (pre-contains xs) (equal? xs (remove-duplicates xs)))
+ (define (pre-contains xs) (equal? xs (remove-duplicates (sort xs))))
(define (post-contains xs x r) (equal? r (op-contains xs x)))
*ENDLIBSPEC*/
fn contains(&self, x: &T) -> bool {
- SortedUniqueVec::contains(self, x) // use fully qualified syntax to avoid function name collision
+ SortedVecSet::contains(self, x) // use fully qualified syntax to avoid function name collision
}
/*LIBSPEC*
@@ -104,11 +104,11 @@ impl<T: Ord + PartialEq> Container<T> for SortedUniqueVec<T> {
is-empty op-is-empty pre-is-empty post-is-empty
*ENDOPNAME*/
(define (op-is-empty xs) (cons xs (null? xs)))
- (define (pre-is-empty xs) (equal? xs (remove-duplicates xs)))
+ (define (pre-is-empty xs) (equal? xs (remove-duplicates (sort xs))))
(define (post-is-empty xs r) (equal? r (op-is-empty xs)))
*ENDLIBSPEC*/
fn is_empty(&self) -> bool {
- SortedUniqueVec::is_empty(self)
+ SortedVecSet::is_empty(self)
}
/*LIBSPEC*
@@ -116,11 +116,11 @@ impl<T: Ord + PartialEq> Container<T> for SortedUniqueVec<T> {
clear op-clear pre-clear post-clear
*ENDOPNAME*/
(define (op-clear xs) null)
- (define (pre-clear xs) (equal? xs (remove-duplicates xs)))
+ (define (pre-clear xs) (equal? xs (remove-duplicates (sort xs))))
(define (post-clear xs r) (equal? r (op-clear xs)))
*ENDLIBSPEC*/
fn clear(&mut self) {
- SortedUniqueVec::clear(self);
+ SortedVecSet::clear(self);
}
/*LIBSPEC*
@@ -128,11 +128,11 @@ impl<T: Ord + PartialEq> Container<T> for SortedUniqueVec<T> {
insert op-insert pre-insert post-insert
*ENDOPNAME*/
(define (op-insert xs x) (remove-duplicates (append xs (list x))))
- (define (pre-insert xs) (equal? xs (remove-duplicates xs)))
+ (define (pre-insert xs) (equal? xs (remove-duplicates (sort xs))))
(define (post-insert xs x ys) (equal? ys (op-insert xs x)))
*ENDLIBSPEC*/
fn insert(&mut self, elt: T) {
- SortedUniqueVec::push(self, elt);
+ SortedVecSet::push(self, elt);
}
/*LIBSPEC*
@@ -143,7 +143,7 @@ impl<T: Ord + PartialEq> Container<T> for SortedUniqueVec<T> {
(cond
[(list? (member x xs)) (cons (remove x xs) x)]
[else (cons xs null)]))
- (define (pre-remove xs) (equal? xs (remove-duplicates xs)))
+ (define (pre-remove xs) (equal? xs (remove-duplicates (sort xs))))
(define (post-remove xs r) (equal? r (op-remove xs)))
*ENDLIBSPEC*/
fn remove(&mut self, elt: T) -> Option<T> {
@@ -161,7 +161,7 @@ impl<T: Ord + PartialEq> Container<T> for SortedUniqueVec<T> {
/*IMPL*
Indexable
*ENDIMPL*/
-impl<T: PartialEq + Ord> Indexable<T> for SortedUniqueVec<T> {
+impl<T: PartialEq + Ord> Indexable<T> for SortedVecSet<T> {
/*LIBSPEC*
/*OPNAME*
first op-first pre-first post-first
@@ -174,7 +174,7 @@ impl<T: PartialEq + Ord> Indexable<T> for SortedUniqueVec<T> {
(define (post-first xs r) (equal? r (op-first xs)))
*ENDLIBSPEC*/
fn first(&self) -> Option<&T> {
- SortedUniqueVec::first(self)
+ SortedVecSet::first(self)
}
/*LIBSPEC*
@@ -189,7 +189,7 @@ impl<T: PartialEq + Ord> Indexable<T> for SortedUniqueVec<T> {
(define (post-last xs r) (equal? r (op-last xs)))
*ENDLIBSPEC*/
fn last(&self) -> Option<&T> {
- SortedUniqueVec::last(self)
+ SortedVecSet::last(self)
}
/*LIBSPEC*
@@ -209,13 +209,13 @@ impl<T: PartialEq + Ord> Indexable<T> for SortedUniqueVec<T> {
}
}
-impl<T: Ord> Default for SortedUniqueVec<T> {
+impl<T: Ord> Default for SortedVecSet<T> {
fn default() -> Self {
Self::new()
}
}
-impl<T> IntoIterator for SortedUniqueVec<T> {
+impl<T> IntoIterator for SortedVecSet<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;
@@ -224,7 +224,7 @@ impl<T> IntoIterator for SortedUniqueVec<T> {
}
}
-impl<E: Ord> FromIterator<E> for SortedUniqueVec<E> {
+impl<E: Ord> FromIterator<E> for SortedVecSet<E> {
fn from_iter<T: IntoIterator<Item = E>>(iter: T) -> Self {
let mut v = Vec::from_iter(iter);
v.sort();
@@ -236,11 +236,11 @@ impl<E: Ord> FromIterator<E> for SortedUniqueVec<E> {
#[cfg(test)]
mod tests {
use super::*;
- use crate::proptest::{strategies::sorted_unique_vec, *};
+ use crate::proptest::{strategies::sorted_vec_set, *};
use im::conslist::ConsList;
use proptest::prelude::*;
- fn abstraction<T>(v: SortedUniqueVec<T>) -> ConsList<T>
+ fn abstraction<T>(v: SortedVecSet<T>) -> ConsList<T>
where
T: PartialEq + Ord,
{
@@ -254,7 +254,7 @@ mod tests {
})]
#[test]
- fn test_sorted_unique_vec_len(ref mut v in sorted_unique_vec(".*", 0..100)) {
+ fn test_sorted_vec_set_len(ref mut v in sorted_vec_set(".*", 0..100)) {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
@@ -264,7 +264,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_contains(ref mut v in sorted_unique_vec(".*", 0..100), a in ".*") {
+ fn test_sorted_vec_set_contains(ref mut v in sorted_vec_set(".*", 0..100), a in ".*") {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
@@ -274,7 +274,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_is_empty(ref mut v in sorted_unique_vec(".*", 0..100)) {
+ fn test_sorted_vec_set_is_empty(ref mut v in sorted_vec_set(".*", 0..100)) {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
@@ -284,7 +284,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_insert(ref mut v in sorted_unique_vec(0_usize..100, 0..100), a in 0_usize..100) {
+ fn test_sorted_vec_set_insert(ref mut v in sorted_vec_set(0_usize..100, 0..100), a in 0_usize..100) {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list).sort());
@@ -295,7 +295,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_clear(ref mut v in sorted_unique_vec(".*", 0..100)) {
+ fn test_sorted_vec_set_clear(ref mut v in sorted_vec_set(".*", 0..100)) {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
@@ -306,7 +306,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_remove(ref mut v in sorted_unique_vec(".*", 0..100), a in ".*") {
+ fn test_sorted_vec_set_remove(ref mut v in sorted_vec_set(".*", 0..100), a in ".*") {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
@@ -318,7 +318,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_first(ref mut v in sorted_unique_vec(".*", 0..100)) {
+ fn test_sorted_vec_set_first(ref mut v in sorted_vec_set(".*", 0..100)) {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
@@ -330,7 +330,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_last(ref mut v in sorted_unique_vec(".*", 0..100)) {
+ fn test_sorted_vec_set_last(ref mut v in sorted_vec_set(".*", 0..100)) {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
@@ -342,7 +342,7 @@ mod tests {
}
#[test]
- fn test_sorted_unique_vec_nth(ref mut v in sorted_unique_vec(".*", 0..100), n in 0usize..100) {
+ fn test_sorted_vec_set_nth(ref mut v in sorted_vec_set(".*", 0..100), n in 0usize..100) {
let abs_list = abstraction(v.clone());
//pre
assert_eq!(abs_list, unique(&abs_list));
diff --git a/src/crates/library/src/vecmap.rs b/src/crates/library/src/vecmap.rs
new file mode 100644
index 0000000..700f78b
--- /dev/null
+++ b/src/crates/library/src/vecmap.rs
@@ -0,0 +1,143 @@
+/*LIBSPEC-NAME*
+rust-hashmap-spec primrose_library::VecMap
+*ENDLIBSPEC-NAME*/
+
+use crate::traits::Mapping;
+use std::hash::Hash;
+
+#[derive(Clone)]
+pub struct VecMap<K, V> {
+ v: Vec<(K, V)>,
+}
+
+pub(crate) fn extract_key<K, V>((k, _): &(K, V)) -> &K {
+ k
+}
+
+pub(crate) fn extract_value<K, V>((_, v): &(K, V)) -> &V {
+ v
+}
+
+/*IMPL*
+Mapping
+*ENDIMPL*/
+impl<K: Ord + Hash, V> Mapping<K, V> for VecMap<K, V> {
+ /*LIBSPEC*
+ /*OPNAME*
+ len op-len pre-len post-len
+ *ENDOPNAME*/
+ (define (pre-len xs) (is-map? xs))
+ (define (op-len xs) (cons xs (length xs)))
+ (define (post-len xs r) (equal? r (op-len xs)))
+ *ENDLIBSPEC*/
+ fn len(&self) -> usize {
+ self.v.len()
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ contains op-contains pre-contains post-contains
+ *ENDOPNAME*/
+ (define (pre-contains xs) (is-map? xs))
+ (define (op-contains xs k) (assoc k xs))
+ (define (post-contains xs k r) (equal? r (op-contains xs k)))
+ *ENDLIBSPEC*/
+ fn contains(&mut self, key: &K) -> bool {
+ self.v.iter().any(|(k, _)| k == key)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ insert op-insert pre-insert post-insert
+ *ENDOPNAME*/
+ (define (pre-insert xs) (is-map? xs))
+ (define (op-insert xs k v)
+ (let ([idx (index-where xs (lambda (p) (equal? k (car p))))])
+ (cond [idx (list-set xs idx (cons k v))]
+ [else (list* (cons k v) xs)])))
+ (define (post-insert xs k v r) (equal? r (op-insert xs k v)))
+ *ENDLIBSPEC*/
+ fn insert(&mut self, key: K, val: V) -> Option<V> {
+ let old = if let Some(idx) = self.v.iter().position(|(k, _)| *k == key) {
+ Some(self.v.remove(idx).1)
+ } else {
+ None
+ };
+ self.v.push((key, val));
+ old
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ get op-get pre-get post-get
+ *ENDOPNAME*/
+ (define (pre-get xs) (is-map? xs))
+ (define (op-get xs k) (cdr (assoc k xs)))
+ (define (post-get xs k r) (equal? r (op-get xs k)))
+ *ENDLIBSPEC*/
+ fn get(&self, key: &K) -> Option<&V> {
+ self.v.iter().find(|(k, _)| k == key).map(extract_value)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ remove op-remove pre-remove post-remove
+ *ENDOPNAME*/
+ (define (pre-remove xs) (is-map? xs))
+ (define (op-remove xs k) (cdr (assoc k xs)))
+ (define (post-remove xs k r) (equal? r (op-remove xs k)))
+ *ENDLIBSPEC*/
+ fn remove(&mut self, key: &K) -> Option<V> {
+ Some(self.v.remove(self.v.iter().position(|(k, _)| k == key)?).1)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ clear op-clear pre-clear post-clear
+ *ENDOPNAME*/
+ (define (pre-clear xs) (is-map? xs))
+ (define (op-clear xs) null)
+ (define (post-clear xs r) (equal? r (op-clear xs)))
+ *ENDLIBSPEC*/
+ fn clear(&mut self) {
+ self.v.clear()
+ }
+
+ fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a K, &'a V)> + 'a
+ where
+ K: 'a,
+ V: 'a,
+ {
+ self.v.iter().map(|(k, v)| (k, v))
+ }
+}
+
+impl<K, V> Default for VecMap<K, V> {
+ fn default() -> Self {
+ Self { v: Vec::default() }
+ }
+}
+
+impl<K: Ord, V> FromIterator<(K, V)> for VecMap<K, V> {
+ fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
+ let mut v: Vec<(K, V)> = iter.into_iter().collect();
+ v.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
+ v.dedup_by(|(k1, _), (k2, _)| k1 == k2);
+ Self { v }
+ }
+}
+
+impl<K, V> IntoIterator for VecMap<K, V> {
+ type Item = (K, V);
+
+ type IntoIter = std::vec::IntoIter<(K, V)>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.v.into_iter()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ // TODO
+}
diff --git a/src/crates/library/src/vecset.rs b/src/crates/library/src/vecset.rs
new file mode 100644
index 0000000..ccf747a
--- /dev/null
+++ b/src/crates/library/src/vecset.rs
@@ -0,0 +1,356 @@
+/*LIBSPEC-NAME*
+rust-eager-unique-vec-spec primrose_library::VecSet
+*ENDLIBSPEC-NAME*/
+
+use crate::traits::{Container, Indexable};
+
+use std::vec::Vec;
+
+/// A set represented by a Vector, where items aren't necessarily sorted.
+#[derive(Debug, Clone)]
+pub struct VecSet<T> {
+ v: Vec<T>,
+}
+
+impl<T: PartialEq + std::cmp::Ord> VecSet<T> {
+ pub fn from_vec(mut v: Vec<T>) -> VecSet<T> {
+ v.sort();
+ v.dedup();
+ VecSet { v }
+ }
+
+ pub fn new() -> VecSet<T> {
+ VecSet { v: Vec::new() }
+ }
+
+ pub fn len(&self) -> usize {
+ self.v.len()
+ }
+
+ pub fn contains(&self, x: &T) -> bool {
+ self.v.contains(x)
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.len() == 0
+ }
+
+ // Duplicated elements will be discarded
+ pub fn push(&mut self, value: T) {
+ if !self.contains(&value) {
+ self.v.push(value);
+ }
+ }
+
+ pub fn pop(&mut self) -> Option<T> {
+ self.v.pop()
+ }
+
+ pub fn remove(&mut self, index: usize) -> T {
+ self.v.swap_remove(index)
+ }
+
+ pub fn clear(&mut self) {
+ self.v.clear()
+ }
+
+ pub fn first(&self) -> Option<&T> {
+ self.v.first()
+ }
+
+ pub fn last(&self) -> Option<&T> {
+ self.v.last()
+ }
+
+ pub fn to_vec(self) -> Vec<T> {
+ self.v
+ }
+}
+
+/*IMPL*
+Container
+*ENDIMPL*/
+impl<T: Ord + PartialEq> Container<T> for VecSet<T> {
+ /*LIBSPEC*
+ /*OPNAME*
+ len op-len pre-len post-len
+ *ENDOPNAME*/
+ (define (op-len xs) (cons xs (length xs)))
+ (define (pre-len xs) (equal? xs (sort xs)))
+ (define (post-len xs r) (equal? r (op-len xs)))
+ *ENDLIBSPEC*/
+ fn len(&self) -> usize {
+ VecSet::len(self)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ contains op-contains pre-contains post-contains
+ *ENDOPNAME*/
+ (define (op-contains xs x)
+ (cond
+ [(list? (member x xs)) (cons xs #t)]
+ [else (cons xs #f)]))
+ (define (pre-contains xs) (equal? xs (sort xs)))
+ (define (post-contains xs x r) (equal? r (op-contains xs x)))
+ *ENDLIBSPEC*/
+ fn contains(&self, x: &T) -> bool {
+ VecSet::contains(self, x) // use fully qualified syntax to avoid function name collision
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ is-empty op-is-empty pre-is-empty post-is-empty
+ *ENDOPNAME*/
+ (define (op-is-empty xs) (cons xs (null? xs)))
+ (define (pre-is-empty xs) (equal? xs (sort xs)))
+ (define (post-is-empty xs r) (equal? r (op-is-empty xs)))
+ *ENDLIBSPEC*/
+ fn is_empty(&self) -> bool {
+ VecSet::is_empty(self)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ clear op-clear pre-clear post-clear
+ *ENDOPNAME*/
+ (define (op-clear xs) null)
+ (define (pre-clear xs) (equal? xs (sort xs)))
+ (define (post-clear xs r) (equal? r (op-clear xs)))
+ *ENDLIBSPEC*/
+ fn clear(&mut self) {
+ VecSet::clear(self);
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ insert op-insert pre-insert post-insert
+ *ENDOPNAME*/
+ (define (op-insert xs x) (sort (append xs (list x))))
+ (define (pre-insert xs) (equal? xs (sort xs)))
+ (define (post-insert xs x ys) (equal? ys (op-insert xs x)))
+ *ENDLIBSPEC*/
+ fn insert(&mut self, elt: T) {
+ VecSet::push(self, elt);
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ remove op-remove pre-remove post-remove
+ *ENDOPNAME*/
+ (define (op-remove xs x)
+ (cond
+ [(list? (member x xs)) (cons (remove x xs) x)]
+ [else (cons xs null)]))
+ (define (pre-remove xs) (equal? xs (sort xs)))
+ (define (post-remove xs r) (equal? r (op-remove xs)))
+ *ENDLIBSPEC*/
+ fn remove(&mut self, elt: T) -> Option<T> {
+ let idx = self.iter().position(|x| *x == elt)?;
+ Some(self.v.remove(idx))
+ }
+
+ fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T>
+ where
+ T: 'a,
+ {
+ self.v.iter()
+ }
+}
+
+/*IMPL*
+Indexable
+*ENDIMPL*/
+impl<T: PartialEq + Ord> Indexable<T> for VecSet<T> {
+ /*LIBSPEC*
+ /*OPNAME*
+ first op-first pre-first post-first
+ *ENDOPNAME*/
+ (define (op-first xs)
+ (cond
+ [(null? xs) (cons xs null)]
+ [else (cons xs (first xs))]))
+ (define (pre-first xs) #t)
+ (define (post-first xs r) (equal? r (op-first xs)))
+ *ENDLIBSPEC*/
+ fn first(&self) -> Option<&T> {
+ VecSet::first(self)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ last op-last pre-last post-last
+ *ENDOPNAME*/
+ (define (op-last xs)
+ (cond
+ [(null? xs) (cons xs null)]
+ [else (cons xs (last xs))]))
+ (define (pre-last xs) #t)
+ (define (post-last xs r) (equal? r (op-last xs)))
+ *ENDLIBSPEC*/
+ fn last(&self) -> Option<&T> {
+ VecSet::last(self)
+ }
+
+ /*LIBSPEC*
+ /*OPNAME*
+ nth op-nth pre-nth post-nth
+ *ENDOPNAME*/
+ (define (op-nth xs n)
+ (cond
+ [(>= n (length xs)) (cons xs null)]
+ [(< n 0) (cons xs null)]
+ [else (cons xs (list-ref xs n))]))
+ (define (pre-nth xs) #t)
+ (define (post-nth xs n r) (equal? r (op-nth xs n)))
+ *ENDLIBSPEC*/
+ fn nth(&self, n: usize) -> Option<&T> {
+ self.v.get(n)
+ }
+}
+
+impl<T: Ord> Default for VecSet<T> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+impl<T> IntoIterator for VecSet<T> {
+ type Item = T;
+ type IntoIter = std::vec::IntoIter<T>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.v.into_iter()
+ }
+}
+
+impl<E: Ord> FromIterator<E> for VecSet<E> {
+ fn from_iter<T: IntoIterator<Item = E>>(iter: T) -> Self {
+ let mut v = Vec::from_iter(iter);
+ v.sort();
+ v.dedup();
+ Self { v }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::proptest::{strategies::vec_set, *};
+ use im::conslist::ConsList;
+ use proptest::prelude::*;
+
+ fn abstraction<T>(v: VecSet<T>) -> ConsList<T>
+ where
+ T: PartialEq + Ord,
+ {
+ let list: ConsList<T> = ConsList::from(v.to_vec());
+ list
+ }
+
+ proptest! {
+ #![proptest_config(ProptestConfig {
+ cases: 100, .. ProptestConfig::default()
+ })]
+
+ #[test]
+ fn test_vec_set_len(ref mut v in vec_set(".*", 0..100)) {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ assert_eq!(Container::<String>::len(v), abs_list.len());
+ assert_eq!(abstraction(v.clone()), abs_list);
+ }
+
+ #[test]
+ fn test_vec_set_contains(ref mut v in vec_set(".*", 0..100), a in ".*") {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ assert_eq!(Container::<String>::contains(v, &a), contains(&abs_list, &a));
+ assert_eq!(abstraction(v.clone()), abs_list);
+ }
+
+ #[test]
+ fn test_vec_set_is_empty(ref mut v in vec_set(".*", 0..100)) {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ assert_eq!(Container::<String>::is_empty(v), abs_list.is_empty());
+ assert_eq!(abstraction(v.clone()), abs_list);
+ }
+
+ #[test]
+ fn test_vec_set_insert(ref mut v in vec_set(0_usize..100, 0..100), a in 0_usize..100) {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ let after_list = unique(&abs_list.append(conslist![a.clone()]));
+ Container::<usize>::insert(v, a.clone());
+ assert_eq!(abstraction(v.clone()), after_list);
+ }
+
+ #[test]
+ fn test_vec_set_clear(ref mut v in vec_set(".*", 0..100)) {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ let after_list = clear(&abs_list);
+ Container::<String>::clear(v);
+ assert_eq!(abstraction(v.clone()), after_list);
+ }
+
+ #[test]
+ fn test_vec_set_remove(ref mut v in vec_set(".*", 0..100), a in ".*") {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ let (after_list, abs_elem) = remove(&abs_list, a.clone());
+ let elem = Container::<String>::remove(v, a.clone());
+ assert_eq!(abstraction(v.clone()), after_list);
+ assert_eq!(elem, abs_elem);
+ }
+
+ #[test]
+ fn test_vec_set_first(ref mut v in vec_set(".*", 0..100)) {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ let elem = Indexable::<String>::first(v);
+ let abs_first = first(&abs_list);
+ assert_eq!(elem, abs_first);
+ assert_eq!(abstraction(v.clone()), abs_list);
+ }
+
+ #[test]
+ fn test_vec_set_last(ref mut v in vec_set(".*", 0..100)) {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ let elem = Indexable::<String>::last(v);
+ let abs_last = last(&abs_list);
+ assert_eq!(elem, abs_last);
+ assert_eq!(abstraction(v.clone()), abs_list);
+ }
+
+ #[test]
+ fn test_vec_set_nth(ref mut v in vec_set(".*", 0..100), n in 0usize..100) {
+ let abs_list = abstraction(v.clone());
+ //pre
+ assert_eq!(abs_list, unique(&abs_list));
+ //post
+ let elem = Indexable::<String>::nth(v, n);
+ let abs_nth = nth(&abs_list, n);
+ assert_eq!(elem, abs_nth);
+ assert_eq!(abstraction(v.clone()), abs_list);
+ }
+ }
+}