Skip to content

VecDeque::truncate_to_range #785

@cammeresi

Description

@cammeresi

Proposal

Problem statement

VecDeque currently allows truncating down to a specific length via dropping elements from the front (truncate_front) or the back (truncate), but it lacks a way to specify a range that should be kept while truncating the rest (which might truncate both ends).

Motivating examples or use cases

A system collects metrics during a period in which a benchmark is run, but collection inevitably starts before the load is applied and continues for some time after it ends. Let's clip off those pre- and post-test data points before analyzing the results.

// example data
let mut metrics = [0, 0, 0, 1, 2, 3, 2, 1, 0, 0].iter().collect::<VecDeque<_>>();
// during collection, push_back; truncate_front is called to ensure events don't grow without bound

// if the metric is zero, assume the test either had not yet started or had already ended
let start = metrics.iter().position(|&&x| x > 0).unwrap_or_default();
let end = metrics.iter().rposition(|&&x| x > 0).unwrap_or_default() + 1;

// metrics.truncate_to_range(start..end);
metrics.truncate(end);
metrics.truncate_front(metrics.len() - start);

assert!(metrics.into_iter().eq([1, 2, 3, 2, 1].iter()));

for x in metrics.iter() {
    // analysis...
}

Other ideas:

Solution sketch

pub fn truncate_to_range<R>(&mut self, range: R)
where
    R: RangeBounds<usize>,
{
    // Implementation largely similar to truncate/truncate_front.
    //
    // (1) validate range
    // (2) try to reduce to no-op, clear, truncate, or truncate_front
    // (3) otherwise, compute up to three regions to drop:
    //     if kept region is entirely in front
    //         then we drop front and back parts of front and all of back
    //     else if kept region is entirely in back
    //         then we drop front and back parts of back and all of front
    //     else kept region straddles the slice boundary,
    //         so we drop front part of front and back part of back
    // (4) set head and len
    // (5) drop regions via guards/drop_in_place
}

I'm sure that there will be bikeshedding about the name. I wanted the name to include "range" since it's the range that sets it apart from, e.g., a retain, and this isn't a retain since it has no predicate. The "to" should make clear that the range is what you'll be left with, not what you're removing. The "truncate" should serve to indicate that this operation is fast (if there is no drop code), as truncates of data structures or database tables are usually fast.

In discussion, truncate_both was brought up as a negative suggestion.

Alternatives

  • truncate + truncate_front + math
  • drain into a new VecDeque
  • make_contiguous and narrow the slice
  • as_slices and narrow the two slices

Links and related work

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

  • We think this problem seems worth solving, and the standard library might be the right place to solve it.
  • We think that this probably doesn't belong in the standard library.

Second, if there's a concrete solution:

  • We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
  • We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions