I tried and failed to strip it down, but the code
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
// // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::hashmap::HashMap;
#[allow(default_methods)]
/**
* An "interner" is a data structure that associates values with uint tags, allowing bidirectional
* lookup (ie, given a value, get the tag, or given a tag, get the value). This allows for efficient
* storage and comparison of large values that would be expensive to copy around or compare
*/
// FIXME #7312: inherit `Default` when it exists
pub trait Interner<T> {
pub fn new() -> Self;
/// Create a new interner and intern all the values in `init`
pub fn prefill(init: Iterator<T>) -> Self {
let in = Interner::new();
for init.advance |&v| {
in.intern(v);
}
in
}
/// Intern a value, returning the tag used to refer to it
pub fn intern(&self, val: T) -> uint;
/// Get the value corresponding to a tag
pub fn get(&'self self, tag: uint) -> Option<&'self T>;
/// Get the tag corresponding to a value equivalent to `Q`
pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint>;
}
/**
* A simple implementation of an interner, using a std::hashmap::HashMap for associating a value to a
* tag and storing values in a vector.
*/
pub struct SimpleInterner<T: Eq + IterBytes + Hash + Copy> {
priv map: HashMap<T, uint>,
priv vect: ~[T]
}
impl<T> Interner<T> for SimpleInterner<T> {
pub fn new() -> SimpleInterner<T> {
SimpleInterner {
map: HashMap::new(),
vect: ~[]
}
}
pub fn prefill(init: Iterator<T>) -> SimpleInterner<T> {
let hm = HashMap::new();
hm.reserve_at_least(init.len());
let mut vect = std::vec::with_capacity(init.len());
let mut i = 0;
for init.advance |&v| {
if hm.find_or_insert(v, i) == i {
unsafe {
std::vec::raw::init_elem(vect, i, v);
}
i += 1;
}
}
SimpleInterner {map: hm, vect: vect}
}
pub fn intern(&self, val: T) -> uint {
let i = self.vect.len();
let x = self.map.find_or_insert(val, i);
if x == i {
self.vec.push(val);
}
x
}
pub fn get(&'self self, tag: uint) -> Option<&'self T> {
if tag > self.vect.len() {
None
} else {
Some(&self.vect[tag])
}
}
pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint> {
self.map.find_equiv(val)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_fail]
fn i1 () {
let i: SimpleInterner<~str> = Interner::new();
i.get(13);
}
}
Fails with the ICE
error: internal compiler error: ty::Region#subst(): Reference to self region when given substs with no self region: substs(self_r=None, self_ty=Some('b), tps=['a])
When replace 'self
with 'a
, though, it works:
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
// // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::hashmap::HashMap;
#[allow(default_methods)]
/**
* An "interner" is a data structure that associates values with uint tags, allowing bidirectional
* lookup (ie, given a value, get the tag, or given a tag, get the value). This allows for efficient
* storage and comparison of large values that would be expensive to copy around or compare
*/
// FIXME #7312: inherit `Default` when it exists
pub trait Interner<T> {
pub fn new() -> Self;
/// Create a new interner and intern all the values in `init`
pub fn prefill(init: Iterator<T>) -> Self {
let in = Interner::new();
for init.advance |&v| {
in.intern(v);
}
in
}
/// Intern a value, returning the tag used to refer to it
pub fn intern(&self, val: T) -> uint;
/// Get the value corresponding to a tag
pub fn get<'a>(&'a self, tag: uint) -> Option<&'a T>;
/// Get the tag corresponding to a value equivalent to `Q`
pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint>;
}
/**
* A simple implementation of an interner, using a std::hashmap::HashMap for associating a value to a
* tag and storing values in a vector.
*/
pub struct SimpleInterner<T: Eq + IterBytes + Hash + Copy> {
priv map: HashMap<T, uint>,
priv vect: ~[T]
}
impl<T> Interner<T> for SimpleInterner<T> {
pub fn new() -> SimpleInterner<T> {
SimpleInterner {
map: HashMap::new(),
vect: ~[]
}
}
pub fn prefill(init: Iterator<T>) -> SimpleInterner<T> {
let hm = HashMap::new();
hm.reserve_at_least(init.len());
let mut vect = std::vec::with_capacity(init.len());
let mut i = 0;
for init.advance |&v| {
if hm.find_or_insert(v, i) == i {
unsafe {
std::vec::raw::init_elem(vect, i, v);
}
i += 1;
}
}
SimpleInterner {map: hm, vect: vect}
}
pub fn intern(&self, val: T) -> uint {
let i = self.vect.len();
let x = self.map.find_or_insert(val, i);
if x == i {
self.vec.push(val);
}
x
}
pub fn get<'a>(&'a self, tag: uint) -> Option<&'a T> {
if tag > self.vect.len() {
None
} else {
Some(&self.vect[tag])
}
}
pub fn find_equiv<Q: Hash + IterBytes + Equiv<T>>(&self, val: &Q) -> Option<uint> {
self.map.find_equiv(val)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_fail]
fn i1 () {
let i: SimpleInterner<~str> = Interner::new();
i.get(13);
}
}
Whatever way I tried to strip it down I ended up with a non-ICE failure, so it's probably interaction between two different things.