7 个版本
使用旧的 Rust 2015
0.4.6 | 2019年10月11日 |
---|---|
0.4.5 | 2018年9月7日 |
0.4.2 | 2018年8月27日 |
0.3.0 | 2018年6月12日 |
#13 in #multimap
211 每月下载量
用于 9 个 crate (2 直接)
66KB
1.5K SLoC
total-order-multi-map
这是一个多值映射,它同时保持所有元素的总插入顺序,这意味着如果您插入以下键值对: (K1, V1)
,(K2, V2)
,(K1, V3)
,它将记住插入顺序确实是这样的(V1
,V2
,V3
)即它不会在每个键的基础上折叠插入顺序。
同时,它应该有与正常 HashMap
相似的数据访问性能(否则我们只需创建一个 Vec
)。
它是通过限制其值仅限于实现 StableDeref
的值来实现的,例如通过 Box<TraitObject>
,它可以通过它有多个对值的指针。虽然它在内部使用不安全性,但提供的接口是安全的。它还确保是 unwind + resume 安全的。
示例
extern crate total_order_multi_map as tomm;
use std::fmt::{self, Display};
use tomm::TotalOrderMultiMap;
/// for now the key has to be copy
type Key = &'static str;
/// the map is made for thinks which dereference
/// e.g. trait objects, through e.g. `String` or
/// `Rc<Debug>` would be fine, too.
type Value = Box<Display>;
fn main() {
let mut map = TotalOrderMultiMap::<Key, Value>::new();
map.add("key1", mk_box_str("val1"));
map.add("key1", mk_my_thingy("val2"));
map.add("key2", mk_box_str("val3"));
map.add("key1", mk_my_thingy("val4"));
map.add("key0", mk_box_str("val5"));
let stringed = map
.iter()
// val is of type `&Display`
.map(|(key, val)| format!("{}:{}", key, val))
.collect::<Vec<_>>();
// as it can be seen the total insertion order was kept
assert_eq!(stringed, &[
"key1:val1".to_owned(),
"key1:val2".to_owned(),
"key2:val3".to_owned(),
"key1:val4".to_owned(),
"key0:val5".to_owned()
]);
// It's also still a multi map.
// Note that the get operation has roughly the same
// performance as in a hash map (through you then
// iterate over the elements associated with the key
// roughly with the speed of iterating over an `Vec`).
{
let values = map.get("key1").expect("key1 is in the map");
let stringed = values
.map(|val| format!("{}", val))
.collect::<Vec<_>>();
assert_eq!(stringed, &[ "val1", "val2", "val4" ]);
}
// but as we have an order we can remove
// "the last inserted" element
let (key, val) = map.pop().unwrap();
assert_eq!(format!("{}:{}", key, val), "key0:val5");
// or remove all for an specific key as it's
// an multi map
map.remove_all("key1");
assert!(map.get("key1").is_none());
println!("DONE (I only contain asserts)")
}
//---- some function to create dummy values for the example ----
fn mk_box_str(inp: &str) -> Box<Display> {
// sadly we can't cast Box<str> to Box<Display>
// (you would need non static vtables for this...)
Box::new(inp.to_owned())
}
#[derive(Debug)]
struct MyThingy { val: String }
impl Display for MyThingy {
fn fmt(&self, fter: &mut fmt::Formatter) -> fmt::Result {
write!(fter, "{}", self.val)
}
}
fn mk_my_thingy(inp: &str) -> Box<Display> {
Box::new(MyThingy { val: inp.to_owned() })
}
缺少的部分
以下内容可以实施并应添加到后续版本中
- 基准测试
- 使用
SmallVec
为多值映射 - 允许对
&mut
访问V::Target
,如果V: StableDeref + DerefMut
- 索引访问
- 索引获取键值对
- 索引删除
- 在
get
的返回值中索引获取 in,即多映射组
- 改进的条目 API
- 允许访问具有相同键的其他值
- 可能将条目 + 插入的结果转换为 get + unwrap 的结果
- 改进的分组迭代,也许吧?
- 当前实现按键分组,但未指示何时切换到下一个值
- 允许非复制键?
- 我们仍然不想复制/克隆键,所以我们必须在那里做一些小诡计
许可证
根据您选择的
- Apache 许可证版本 2.0,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证(LICENSE-MIT 或 http://opensource.org/licenses/MIT)
。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义,您有意提交的任何贡献,包括在您的工作中的包含,都将根据上述方式双重许可,不附加任何其他条款或条件。
更改日志
v0.3
:TotalOrderMultiMap.retain
现在接受一个接受&V::Target
的谓词,而不是&V
v0.4.1
:- 将返回值扁平化到
get
,以返回空迭代器而不是None
- 需要
DerefMut
而不是只是Deref
- 有可变访问方法,如
get_mut
- 将
insert
分割为add
和set
,其中set
替换与键相关联的任何旧值,并返回旧值
- 将返回值扁平化到
v0.4.2
:- 从可变迭代器到非可变迭代器的转换
- 从 IterMut 迭代
- 从 ValuesMut 获取值
- 从 EntryValuesMut 获取 EntryValues
- 从可变迭代器到非可变迭代器的转换
v0.4.3
:- 添加了缺少的重新导出。Values,Values,GroupedValuesMut 现在是公共的,正如它们一开始就应该那样。
v0.4.4
:- 添加了
truncate
方法,允许删除在第一个size
元素之后插入的任何内容
- 添加了
v0.4.5
:- 对于添加的条目
values
,values_mut
方法可以遍历与用于创建条目的键关联的值。
- 对于添加的条目
依赖关系
~26KB