Skip to content

Commit 0eaabe8

Browse files
authored
Refactor building from pairs (#129)
1 parent 898d0a8 commit 0eaabe8

File tree

3 files changed

+72
-85
lines changed

3 files changed

+72
-85
lines changed

src/builder.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use crate::{Entry, Slab};
2+
3+
// Building `Slab` from pairs (usize, T).
4+
pub(crate) struct Builder<T> {
5+
slab: Slab<T>,
6+
vacant_list_broken: bool,
7+
first_vacant_index: Option<usize>,
8+
}
9+
10+
impl<T> Builder<T> {
11+
pub(crate) fn with_capacity(capacity: usize) -> Self {
12+
Self {
13+
slab: Slab::with_capacity(capacity),
14+
vacant_list_broken: false,
15+
first_vacant_index: None,
16+
}
17+
}
18+
pub(crate) fn pair(&mut self, key: usize, value: T) {
19+
let slab = &mut self.slab;
20+
if key < slab.entries.len() {
21+
// iterator is not sorted, might need to recreate vacant list
22+
if let Entry::Vacant(_) = slab.entries[key] {
23+
self.vacant_list_broken = true;
24+
slab.len += 1;
25+
}
26+
// if an element with this key already exists, replace it.
27+
// This is consistent with HashMap and BtreeMap
28+
slab.entries[key] = Entry::Occupied(value);
29+
} else {
30+
if self.first_vacant_index.is_none() && slab.entries.len() < key {
31+
self.first_vacant_index = Some(slab.entries.len());
32+
}
33+
// insert holes as necessary
34+
while slab.entries.len() < key {
35+
// add the entry to the start of the vacant list
36+
let next = slab.next;
37+
slab.next = slab.entries.len();
38+
slab.entries.push(Entry::Vacant(next));
39+
}
40+
slab.entries.push(Entry::Occupied(value));
41+
slab.len += 1;
42+
}
43+
}
44+
45+
pub(crate) fn build(self) -> Slab<T> {
46+
let mut slab = self.slab;
47+
if slab.len == slab.entries.len() {
48+
// no vacant entries, so next might not have been updated
49+
slab.next = slab.entries.len();
50+
} else if self.vacant_list_broken {
51+
slab.recreate_vacant_list();
52+
} else if let Some(first_vacant_index) = self.first_vacant_index {
53+
let next = slab.entries.len();
54+
match &mut slab.entries[first_vacant_index] {
55+
Entry::Vacant(n) => *n = next,
56+
_ => unreachable!(),
57+
}
58+
} else {
59+
unreachable!()
60+
}
61+
slab
62+
}
63+
}

src/lib.rs

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ extern crate std as alloc;
118118
#[cfg(feature = "serde")]
119119
mod serde;
120120

121+
mod builder;
122+
121123
use alloc::vec::{self, Vec};
122124
use core::iter::{self, FromIterator, FusedIterator};
123125
use core::{fmt, mem, ops, slice};
@@ -1260,51 +1262,12 @@ impl<T> FromIterator<(usize, T)> for Slab<T> {
12601262
I: IntoIterator<Item = (usize, T)>,
12611263
{
12621264
let iterator = iterable.into_iter();
1263-
let mut slab = Self::with_capacity(iterator.size_hint().0);
1265+
let mut builder = builder::Builder::with_capacity(iterator.size_hint().0);
12641266

1265-
let mut vacant_list_broken = false;
1266-
let mut first_vacant_index = None;
12671267
for (key, value) in iterator {
1268-
if key < slab.entries.len() {
1269-
// iterator is not sorted, might need to recreate vacant list
1270-
if let Entry::Vacant(_) = slab.entries[key] {
1271-
vacant_list_broken = true;
1272-
slab.len += 1;
1273-
}
1274-
// if an element with this key already exists, replace it.
1275-
// This is consistent with HashMap and BtreeMap
1276-
slab.entries[key] = Entry::Occupied(value);
1277-
} else {
1278-
if first_vacant_index.is_none() && slab.entries.len() < key {
1279-
first_vacant_index = Some(slab.entries.len());
1280-
}
1281-
// insert holes as necessary
1282-
while slab.entries.len() < key {
1283-
// add the entry to the start of the vacant list
1284-
let next = slab.next;
1285-
slab.next = slab.entries.len();
1286-
slab.entries.push(Entry::Vacant(next));
1287-
}
1288-
slab.entries.push(Entry::Occupied(value));
1289-
slab.len += 1;
1290-
}
1268+
builder.pair(key, value)
12911269
}
1292-
if slab.len == slab.entries.len() {
1293-
// no vacant entries, so next might not have been updated
1294-
slab.next = slab.entries.len();
1295-
} else if vacant_list_broken {
1296-
slab.recreate_vacant_list();
1297-
} else if let Some(first_vacant_index) = first_vacant_index {
1298-
let next = slab.entries.len();
1299-
match &mut slab.entries[first_vacant_index] {
1300-
Entry::Vacant(n) => *n = next,
1301-
_ => unreachable!(),
1302-
}
1303-
} else {
1304-
unreachable!()
1305-
}
1306-
1307-
slab
1270+
builder.build()
13081271
}
13091272
}
13101273

src/serde.rs

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
44
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
55
use serde::ser::{Serialize, SerializeMap, Serializer};
66

7-
use super::{Entry, Slab};
7+
use super::{builder::Builder, Slab};
88

99
impl<T> Serialize for Slab<T>
1010
where
@@ -39,52 +39,13 @@ where
3939
where
4040
A: MapAccess<'de>,
4141
{
42-
let mut slab = Slab::with_capacity(map.size_hint().unwrap_or(0));
42+
let mut builder = Builder::with_capacity(map.size_hint().unwrap_or(0));
4343

44-
// same as FromIterator impl
45-
let mut vacant_list_broken = false;
46-
let mut first_vacant_index = None;
4744
while let Some((key, value)) = map.next_entry()? {
48-
if key < slab.entries.len() {
49-
// iterator is not sorted, might need to recreate vacant list
50-
if let Entry::Vacant(_) = slab.entries[key] {
51-
vacant_list_broken = true;
52-
slab.len += 1;
53-
}
54-
// if an element with this key already exists, replace it.
55-
// This is consistent with HashMap and BtreeMap
56-
slab.entries[key] = Entry::Occupied(value);
57-
} else {
58-
if first_vacant_index.is_none() && slab.entries.len() < key {
59-
first_vacant_index = Some(slab.entries.len());
60-
}
61-
// insert holes as necessary
62-
while slab.entries.len() < key {
63-
// add the entry to the start of the vacant list
64-
let next = slab.next;
65-
slab.next = slab.entries.len();
66-
slab.entries.push(Entry::Vacant(next));
67-
}
68-
slab.entries.push(Entry::Occupied(value));
69-
slab.len += 1;
70-
}
71-
}
72-
if slab.len == slab.entries.len() {
73-
// no vacant entries, so next might not have been updated
74-
slab.next = slab.entries.len();
75-
} else if vacant_list_broken {
76-
slab.recreate_vacant_list();
77-
} else if let Some(first_vacant_index) = first_vacant_index {
78-
let next = slab.entries.len();
79-
match &mut slab.entries[first_vacant_index] {
80-
Entry::Vacant(n) => *n = next,
81-
_ => unreachable!(),
82-
}
83-
} else {
84-
unreachable!()
45+
builder.pair(key, value)
8546
}
8647

87-
Ok(slab)
48+
Ok(builder.build())
8849
}
8950
}
9051

0 commit comments

Comments
 (0)