Skip to content

libcore: Implement an Equiv trait and use it on hashmaps. #5234

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

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/libcore/cmp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ pub pure fn gt<T:Ord>(v1: &T, v2: &T) -> bool {
(*v1).gt(v2)
}

/// The equivalence relation. Two values may be equivalent even if they are
/// of different types. The most common use case for this relation is
/// container types; e.g. it is often desirable to be able to use `&str`
/// values to look up entries in a container with `~str` keys.
pub trait Equiv<T> {
pure fn equiv(&self, other: &T) -> bool;
}

#[inline(always)]
pub pure fn min<T:Ord>(v1: T, v2: T) -> T {
if v1 < v2 { v1 } else { v2 }
Expand Down
1 change: 1 addition & 0 deletions src/libcore/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

//! Container traits

use cmp::Equiv;
use option::Option;

pub trait Container {
Expand Down
51 changes: 50 additions & 1 deletion src/libcore/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
/// Open addressing with linear probing.
pub mod linear {
use container::{Container, Mutable, Map, Set};
use cmp::Eq;
use cmp::{Eq, Equiv};
use hash::Hash;
use to_bytes::IterBytes;
use iter::BaseIter;
Expand Down Expand Up @@ -107,6 +107,15 @@ pub mod linear {
self.bucket_for_key_with_hash(hash, k)
}

#[inline(always)]
pure fn bucket_for_key_equiv<Q:Hash + IterBytes + Equiv<K>>(
&self,
k: &Q)
-> SearchResult {
let hash = k.hash_keyed(self.k0, self.k1) as uint;
self.bucket_for_key_with_hash_equiv(hash, k)
}

#[inline(always)]
pure fn bucket_for_key_with_hash(&self,
hash: uint,
Expand All @@ -122,6 +131,24 @@ pub mod linear {
TableFull
}

#[inline(always)]
pure fn bucket_for_key_with_hash_equiv<Q:Equiv<K>>(&self,
hash: uint,
k: &Q)
-> SearchResult {
let _ = for self.bucket_sequence(hash) |i| {
match self.buckets[i] {
Some(ref bkt) => {
if bkt.hash == hash && k.equiv(&bkt.key) {
return FoundEntry(i);
}
},
None => return FoundHole(i)
}
};
TableFull
}

/// Expand the capacity of the array to the next power of two
/// and re-insert each of the existing buckets.
#[inline(always)]
Expand Down Expand Up @@ -450,6 +477,28 @@ pub mod linear {
None => fail!(fmt!("No entry found for key: %?", k)),
}
}

/// Return true if the map contains a value for the specified key,
/// using equivalence
pure fn contains_key_equiv<Q:Hash + IterBytes + Equiv<K>>(
&self,
key: &Q)
-> bool {
match self.bucket_for_key_equiv(key) {
FoundEntry(_) => {true}
TableFull | FoundHole(_) => {false}
}
}

/// Return the value corresponding to the key in the map, using
/// equivalence
pure fn find_equiv<Q:Hash + IterBytes + Equiv<K>>(&self, k: &Q)
-> Option<&self/V> {
match self.bucket_for_key_equiv(k) {
FoundEntry(idx) => Some(self.value_for_bucket(idx)),
TableFull | FoundHole(_) => None,
}
}
}

impl<K:Hash + IterBytes + Eq,V:Eq> Eq for LinearMap<K, V> {
Expand Down
8 changes: 7 additions & 1 deletion src/libcore/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
use at_vec;
use cast;
use char;
use cmp::{TotalOrd, Ordering, Less, Equal, Greater};
use cmp::{Equiv, TotalOrd, Ordering, Less, Equal, Greater};
use libc;
use option::{None, Option, Some};
use ptr;
Expand Down Expand Up @@ -898,6 +898,12 @@ impl Ord for @str {
pure fn gt(&self, other: &@str) -> bool { gt((*self), (*other)) }
}

#[cfg(notest)]
impl Equiv<~str> for &str {
#[inline(always)]
pure fn equiv(&self, other: &~str) -> bool { eq_slice(*self, *other) }
}

/*
Section: Iterating through strings
*/
Expand Down
8 changes: 7 additions & 1 deletion src/libcore/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

use container::{Container, Mutable};
use cast;
use cmp::{Eq, Ord, TotalOrd, Ordering, Less, Equal, Greater};
use cmp::{Eq, Equiv, Ord, TotalOrd, Ordering, Less, Equal, Greater};
use iter::BaseIter;
use iter;
use kinds::Copy;
Expand Down Expand Up @@ -1572,6 +1572,12 @@ impl<T:Eq> Eq for @[T] {
pure fn ne(&self, other: &@[T]) -> bool { !(*self).eq(other) }
}

#[cfg(notest)]
impl<T:Eq> Equiv<~[T]> for &[T] {
#[inline(always)]
pure fn equiv(&self, other: &~[T]) -> bool { eq(*self, *other) }
}

// Lexicographical comparison

pure fn cmp<T: TotalOrd>(a: &[T], b: &[T]) -> Ordering {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/typeck/astconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + Durable>(
let mut mt = ast_mt_to_mt(self, rscope, mt);
if a_seq_ty.mutbl == ast::m_mutbl ||
a_seq_ty.mutbl == ast::m_const {
mt = ty::mt { ty: mt.ty, mutbl: ast::m_mutbl };
mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl };
}
return ty::mk_evec(tcx, mt, vst);
}
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3112,7 +3112,7 @@ pub impl Parser {
fn parse_trait_ref_list(&self, ket: &token::Token) -> ~[@trait_ref] {
self.parse_seq_to_before_end(
ket,
seq_sep_none(),
seq_sep_trailing_disallowed(token::BINOP(token::PLUS)),
|p| p.parse_trait_ref()
)
}
Expand Down
5 changes: 4 additions & 1 deletion src/libsyntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,8 +600,11 @@ pub fn print_item(s: @ps, &&item: @ast::item) {
print_generics(s, generics);
if traits.len() != 0u {
word(s.s, ~":");
for traits.each |trait_| {
for traits.eachi |i, trait_| {
nbsp(s);
if i != 0 {
word_space(s, ~"+");
}
print_path(s, trait_.path, false);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/auxiliary/trait_inheritance_auto_xc_aux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ trait Foo { fn f() -> int; }
trait Bar { fn g() -> int; }
trait Baz { fn h() -> int; }

trait Quux: Foo Bar Baz { }
trait Quux: Foo + Bar + Baz { }

impl<T:Foo + Bar + Baz> Quux for T { }
2 changes: 1 addition & 1 deletion src/test/auxiliary/trait_inheritance_overloading_xc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use core::cmp::Eq;

pub trait MyNum : Add<Self,Self> Sub<Self,Self> Mul<Self,Self> Eq {
pub trait MyNum : Add<Self,Self> + Sub<Self,Self> + Mul<Self,Self> + Eq {
}

pub struct MyInt {
Expand Down
15 changes: 9 additions & 6 deletions src/test/compile-fail/issue-3953.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@

use core::cmp::Eq;

trait Hahaha: Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq //~ ERROR Duplicate supertrait in trait declaration
Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq
Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq
Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq
Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq
Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq Eq {}
trait Hahaha: Eq + Eq + Eq + Eq + Eq + //~ ERROR Duplicate supertrait
Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq +
Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq +
Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq +
Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq +
Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq +
Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq +
Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq + Eq +
Eq {}

enum Lol = int;

Expand Down
7 changes: 7 additions & 0 deletions src/test/run-pass/const-vec-syntax.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn f(_: &const [int]) {}

fn main() {
let v = [ 1, 2, 3 ];
f(v);
}

2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-auto-xc-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ extern mod aux(name = "trait_inheritance_auto_xc_2_aux");
use aux::{Foo, Bar, Baz, A};

// We want to extend all Foo, Bar, Bazes to Quuxes
pub trait Quux: Foo Bar Baz { }
pub trait Quux: Foo + Bar + Baz { }
impl<T:Foo + Bar + Baz> Quux for T { }

fn f<T:Quux>(a: &T) {
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-auto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ trait Foo { fn f() -> int; }
trait Bar { fn g() -> int; }
trait Baz { fn h() -> int; }

trait Quux: Foo Bar Baz { }
trait Quux: Foo + Bar + Baz { }

struct A { x: int }

Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-diamond.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
trait A { fn a(&self) -> int; }
trait B: A { fn b(&self) -> int; }
trait C: A { fn c(&self) -> int; }
trait D: B C { fn d(&self) -> int; }
trait D: B + C { fn d(&self) -> int; }

struct S { bogus: () }

Expand Down
4 changes: 2 additions & 2 deletions src/test/run-pass/trait-inheritance-num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ use core::num::NumCast::from;
extern mod std;
use std::cmp::FuzzyEq;

pub trait NumExt: NumCast Eq Ord {}
pub trait NumExt: NumCast + Eq + Ord {}

pub trait FloatExt: NumExt FuzzyEq<Self> {}
pub trait FloatExt: NumExt + FuzzyEq<Self> {}

fn greater_than_one<T:NumExt>(n: &T) -> bool { *n > from(1) }
fn greater_than_one_float<T:FloatExt>(n: &T) -> bool { *n > from(1) }
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-num0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ trait Num {
fn gt(&self, other: &Self) -> bool;
}

pub trait NumExt: Num NumCast { }
pub trait NumExt: Num + NumCast { }

fn greater_than_one<T:NumExt>(n: &T) -> bool {
n.gt(&from(1))
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-num1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use core::cmp::Ord;
use core::num::NumCast::from;

pub trait NumExt: NumCast Ord { }
pub trait NumExt: NumCast + Ord { }

fn greater_than_one<T:NumExt>(n: &T) -> bool {
*n > from(1)
Expand Down
4 changes: 2 additions & 2 deletions src/test/run-pass/trait-inheritance-num2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl TypeExt for f64 {}
impl TypeExt for float {}


pub trait NumExt: TypeExt Eq Ord NumCast {}
pub trait NumExt: TypeExt + Eq + Ord + NumCast {}

impl NumExt for u8 {}
impl NumExt for u16 {}
Expand Down Expand Up @@ -94,7 +94,7 @@ impl IntegerExt for i64 {}
impl IntegerExt for int {}


pub trait FloatExt: NumExt FuzzyEq<Self> {}
pub trait FloatExt: NumExt + FuzzyEq<Self> {}

impl FloatExt for f32 {}
impl FloatExt for f64 {}
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-num3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use core::cmp::{Eq, Ord};
use core::num::NumCast::from;

pub trait NumExt: Eq Ord NumCast {}
pub trait NumExt: Eq + Ord + NumCast {}

impl NumExt for f32 {}

Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-num5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
use core::cmp::{Eq, Ord};
use core::num::NumCast::from;

pub trait NumExt: Eq NumCast {}
pub trait NumExt: Eq + NumCast {}

impl NumExt for f32 {}
impl NumExt for int {}
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-overloading.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use core::cmp::Eq;

trait MyNum : Add<Self,Self> Sub<Self,Self> Mul<Self,Self> Eq { }
trait MyNum : Add<Self,Self> + Sub<Self,Self> + Mul<Self,Self> + Eq { }

struct MyInt { val: int }

Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance-static2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ trait MyNum {
static fn from_int(int) -> Self;
}

pub trait NumExt: MyEq MyNum { }
pub trait NumExt: MyEq + MyNum { }

struct S { v: int }

Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/trait-inheritance2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait Foo { fn f() -> int; }
trait Bar { fn g() -> int; }
trait Baz { fn h() -> int; }

trait Quux: Foo Bar Baz { }
trait Quux: Foo + Bar + Baz { }

struct A { x: int }

Expand Down