Skip to content

Commit 9d90135

Browse files
committed
Merge branch 'drain-range' of https://github.com/bluss/rfcs
2 parents f404718 + daf752d commit 9d90135

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

text/0000-drain-range-2.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
- Feature Name: drain-range
2+
- Start Date: 2015-08-14
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
8+
Implement `.drain(range)` and `.drain()` respectively as appropriate on collections.
9+
10+
# Motivation
11+
12+
The `drain` methods and their draining iterators serve to mass remove elements
13+
from a collection, receiving them by value in an iterator, while the collection
14+
keeps its allocation intact (if applicable).
15+
16+
The range parameterized variants of drain are a generalization of `drain`, to
17+
affect just a subrange of the collection, for example removing just an index range
18+
from a vector.
19+
20+
`drain` thus serves both to consume all or some elements from a collection without
21+
consuming the collection itself. The ranged `drain` allows bulk removal of
22+
elements, more efficently than any other safe API.
23+
24+
# Detailed design
25+
26+
- Implement `.drain(a..b)` where `a` and `b` are indices, for all
27+
collections that are sequences.
28+
- Implement `.drain()` for other collections. This is just like `.drain(..)` would be
29+
(drain the whole collection).
30+
- Ranged drain accepts all range types, currently .., a.., ..b, a..b,
31+
and drain will accept inclusive end ranges ("closed ranges") when they are implemented.
32+
- Drain removes every element in the range.
33+
- Drain returns an iterator that produces the removed items by value.
34+
- Drain removes the whole range, regardless if you iterate the draining iterator
35+
or not.
36+
- Drain preserves the collection's capacity where it is possible.
37+
38+
## Collections
39+
40+
`Vec` and `String` already have ranged drain, so they are complete.
41+
42+
`HashMap` and `HashSet` already have `.drain()`, so they are complete;
43+
their elements have no meaningful order.
44+
45+
`BinaryHeap` already has `.drain()`, and just like its other iterators,
46+
it promises no particular order. So this collection is already complete.
47+
48+
The following collections need updated implementations:
49+
50+
`VecDeque` should implement `.drain(range)` for index ranges, just like `Vec`
51+
does.
52+
53+
`LinkedList` should implement `.drain(range)` for index ranges. Just
54+
like the other seqences, this is a `O(n)` operation, and `LinkedList` already
55+
has other indexed methods (`.split_off()`).
56+
57+
## `BTreeMap` and `BTreeSet`
58+
59+
`BTreeMap` already has a ranged iterator, `.range(a, b)`, and `drain` for
60+
`BTreeMap` and `BTreeSet` should have arguments completely consistent the range
61+
method. This will be addressed separately.
62+
63+
## Stabilization
64+
65+
The following can be stabilized as they are:
66+
67+
- `HashMap::drain`
68+
- `HashSet::drain`
69+
- `BinaryHeap::drain`
70+
71+
The following can be stabilized, but their argument's trait is not stable:
72+
73+
- `Vec::drain`
74+
- `String::drain`
75+
76+
The following will be heading towards stabilization after changes:
77+
78+
- `VecDeque::drain`
79+
80+
# Drawbacks
81+
82+
- Collections disagree on if they are drained with a range (`Vec`) or not (`HashMap`)
83+
- No trait for the drain method.
84+
85+
# Alternatives
86+
87+
- Use a trait for the drain method and let all collections implement it. This
88+
will force all collections to use a single parameter (a range) for the drain
89+
method.
90+
91+
- Provide `.splice(range, iterator)` for `Vec` instead of `.drain(range)`:
92+
93+
```rust
94+
fn splice<R, I>(&mut self, range: R, iter: I) -> Splice<T>
95+
where R: RangeArgument, I: IntoIterator<T>
96+
```
97+
98+
if the method `.splice()` would both return an iterator of the replaced elements,
99+
and consume an iterator (of arbitrary length) to replace the removed range, then
100+
it includes drain's tasks.
101+
102+
- RFC #574 proposed accepting either a single index (single key for maps)
103+
or a range for ranged drain, so an alternative would be to do that. The
104+
single index case is however out of place, and writing a range that spans
105+
a single index is easy.
106+
107+
- Use the name `.remove_range(a..b)` instead of `.drain(a..b)`. Since the method
108+
has two simultaneous roles, removing a range and yielding a range as an iterator,
109+
either role could guide the name.
110+
This alternative name was not very popular with the rust developers I asked
111+
(but they are already used to what `drain` means in rust context).
112+
113+
- Provide `.drain()` without arguments and separate range drain into a separate
114+
method name, implemented in addition to `drain` where applicable.
115+
116+
- Do not support closed ranges in `drain`.
117+
118+
- `BinaryHeap::drain` could drain the heap in sorted order. The primary proposal
119+
is arbitrary order, to match preexisting `BinaryHeap` iterators.
120+
121+
# Unresolved questions
122+
123+
- Concrete shape of the `BTreeMap` API is not resolved here
124+
- Will closed ranges be used for the `drain` API?

0 commit comments

Comments
 (0)