|
| 1 | +use super::TrustedLen; |
| 2 | + |
1 | 3 | /// Conversion from an [`Iterator`].
|
2 | 4 | ///
|
3 | 5 | /// By implementing `FromIterator` for a type, you define how it will be
|
@@ -460,6 +462,27 @@ pub trait Extend<A> {
|
460 | 462 | fn extend_reserve(&mut self, additional: usize) {
|
461 | 463 | let _ = additional;
|
462 | 464 | }
|
| 465 | + |
| 466 | + /// Extends a collection with one element, without checking there is enough capacity for it. |
| 467 | + /// |
| 468 | + /// # Safety |
| 469 | + /// |
| 470 | + /// **For callers:** This must only be called when we know the collection has enough capacity |
| 471 | + /// to contain the new item, for example because we previously called `extend_reserve`. |
| 472 | + /// |
| 473 | + /// **For implementors:** For a collection to unsafely rely on this method's safety precondition (that is, |
| 474 | + /// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words, |
| 475 | + /// callers may assume that if they `extend_reserve`ed enough space they can call this method. |
| 476 | +
|
| 477 | + // This method is for internal usage only. It is only on the trait because of specialization's limitations. |
| 478 | + #[unstable(feature = "extend_one_unchecked", issue = "none")] |
| 479 | + #[doc(hidden)] |
| 480 | + unsafe fn extend_one_unchecked(&mut self, item: A) |
| 481 | + where |
| 482 | + Self: Sized, |
| 483 | + { |
| 484 | + self.extend_one(item); |
| 485 | + } |
463 | 486 | }
|
464 | 487 |
|
465 | 488 | #[stable(feature = "extend_for_unit", since = "1.28.0")]
|
@@ -499,33 +522,102 @@ where
|
499 | 522 | fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) {
|
500 | 523 | let (a, b) = self;
|
501 | 524 | let iter = into_iter.into_iter();
|
| 525 | + SpecTupleExtend::extend(iter, a, b); |
| 526 | + } |
| 527 | + |
| 528 | + fn extend_one(&mut self, item: (A, B)) { |
| 529 | + self.0.extend_one(item.0); |
| 530 | + self.1.extend_one(item.1); |
| 531 | + } |
| 532 | + |
| 533 | + fn extend_reserve(&mut self, additional: usize) { |
| 534 | + self.0.extend_reserve(additional); |
| 535 | + self.1.extend_reserve(additional); |
| 536 | + } |
| 537 | + |
| 538 | + unsafe fn extend_one_unchecked(&mut self, item: (A, B)) { |
| 539 | + // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`. |
| 540 | + unsafe { |
| 541 | + self.0.extend_one_unchecked(item.0); |
| 542 | + self.1.extend_one_unchecked(item.1); |
| 543 | + } |
| 544 | + } |
| 545 | +} |
| 546 | + |
| 547 | +fn default_extend_tuple<A, B, ExtendA, ExtendB>( |
| 548 | + iter: impl Iterator<Item = (A, B)>, |
| 549 | + a: &mut ExtendA, |
| 550 | + b: &mut ExtendB, |
| 551 | +) where |
| 552 | + ExtendA: Extend<A>, |
| 553 | + ExtendB: Extend<B>, |
| 554 | +{ |
| 555 | + fn extend<'a, A, B>( |
| 556 | + a: &'a mut impl Extend<A>, |
| 557 | + b: &'a mut impl Extend<B>, |
| 558 | + ) -> impl FnMut((), (A, B)) + 'a { |
| 559 | + move |(), (t, u)| { |
| 560 | + a.extend_one(t); |
| 561 | + b.extend_one(u); |
| 562 | + } |
| 563 | + } |
| 564 | + |
| 565 | + let (lower_bound, _) = iter.size_hint(); |
| 566 | + if lower_bound > 0 { |
| 567 | + a.extend_reserve(lower_bound); |
| 568 | + b.extend_reserve(lower_bound); |
| 569 | + } |
| 570 | + |
| 571 | + iter.fold((), extend(a, b)); |
| 572 | +} |
| 573 | + |
| 574 | +trait SpecTupleExtend<A, B> { |
| 575 | + fn extend(self, a: &mut A, b: &mut B); |
| 576 | +} |
502 | 577 |
|
| 578 | +impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter |
| 579 | +where |
| 580 | + ExtendA: Extend<A>, |
| 581 | + ExtendB: Extend<B>, |
| 582 | + Iter: Iterator<Item = (A, B)>, |
| 583 | +{ |
| 584 | + default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { |
| 585 | + default_extend_tuple(self, a, b); |
| 586 | + } |
| 587 | +} |
| 588 | + |
| 589 | +impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter |
| 590 | +where |
| 591 | + ExtendA: Extend<A>, |
| 592 | + ExtendB: Extend<B>, |
| 593 | + Iter: TrustedLen<Item = (A, B)>, |
| 594 | +{ |
| 595 | + fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { |
503 | 596 | fn extend<'a, A, B>(
|
504 | 597 | a: &'a mut impl Extend<A>,
|
505 | 598 | b: &'a mut impl Extend<B>,
|
506 | 599 | ) -> impl FnMut((), (A, B)) + 'a {
|
507 |
| - move |(), (t, u)| { |
508 |
| - a.extend_one(t); |
509 |
| - b.extend_one(u); |
| 600 | + // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen` |
| 601 | + // so its `size_hint` is exact. |
| 602 | + move |(), (t, u)| unsafe { |
| 603 | + a.extend_one_unchecked(t); |
| 604 | + b.extend_one_unchecked(u); |
510 | 605 | }
|
511 | 606 | }
|
512 | 607 |
|
513 |
| - let (lower_bound, _) = iter.size_hint(); |
| 608 | + let (lower_bound, upper_bound) = self.size_hint(); |
| 609 | + |
| 610 | + if upper_bound.is_none() { |
| 611 | + // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway. |
| 612 | + default_extend_tuple(self, a, b); |
| 613 | + return; |
| 614 | + } |
| 615 | + |
514 | 616 | if lower_bound > 0 {
|
515 | 617 | a.extend_reserve(lower_bound);
|
516 | 618 | b.extend_reserve(lower_bound);
|
517 | 619 | }
|
518 | 620 |
|
519 |
| - iter.fold((), extend(a, b)); |
520 |
| - } |
521 |
| - |
522 |
| - fn extend_one(&mut self, item: (A, B)) { |
523 |
| - self.0.extend_one(item.0); |
524 |
| - self.1.extend_one(item.1); |
525 |
| - } |
526 |
| - |
527 |
| - fn extend_reserve(&mut self, additional: usize) { |
528 |
| - self.0.extend_reserve(additional); |
529 |
| - self.1.extend_reserve(additional); |
| 621 | + self.fold((), extend(a, b)); |
530 | 622 | }
|
531 | 623 | }
|
0 commit comments