|
| 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 |
@@ -429,6 +431,30 @@ pub trait Extend<A> { |
429 | 431 | } |
430 | 432 | } |
431 | 433 |
|
| 434 | +// This trait is exported so collections outside of `core` can implement it. |
| 435 | +#[doc(hidden)] |
| 436 | +#[unstable(feature = "extend_unchecked", issue = "none")] |
| 437 | +pub trait ExtendUnchecked<A>: Extend<A> { |
| 438 | + /// Extends a collection with one element, without checking there is enough capacity for it. |
| 439 | + /// |
| 440 | + /// **Note:** For a collection to unsafely rely on this method's safety precondition (that is, |
| 441 | + /// invoke UB if they are violated), it must implement `extend_reserve` correctly. In other words, |
| 442 | + /// callers may assume that if they `extend_reserve`ed enough space they can call this method. |
| 443 | + /// |
| 444 | + /// # Safety |
| 445 | + /// |
| 446 | + /// This must only be called when we know the collection has enough capacity to contain the new item, |
| 447 | + /// for example because we previously called `extend_reserve`. |
| 448 | + unsafe fn extend_one_unchecked(&mut self, item: A); |
| 449 | +} |
| 450 | + |
| 451 | +#[unstable(feature = "extend_unchecked", issue = "none")] |
| 452 | +impl<A, T: Extend<A>> ExtendUnchecked<A> for T { |
| 453 | + default unsafe fn extend_one_unchecked(&mut self, item: A) { |
| 454 | + self.extend_one(item); |
| 455 | + } |
| 456 | +} |
| 457 | + |
432 | 458 | #[stable(feature = "extend_for_unit", since = "1.28.0")] |
433 | 459 | impl Extend<()> for () { |
434 | 460 | fn extend<T: IntoIterator<Item = ()>>(&mut self, iter: T) { |
@@ -466,33 +492,108 @@ where |
466 | 492 | fn extend<T: IntoIterator<Item = (A, B)>>(&mut self, into_iter: T) { |
467 | 493 | let (a, b) = self; |
468 | 494 | let iter = into_iter.into_iter(); |
| 495 | + SpecTupleExtend::extend(iter, a, b); |
| 496 | + } |
| 497 | + |
| 498 | + fn extend_one(&mut self, item: (A, B)) { |
| 499 | + self.0.extend_one(item.0); |
| 500 | + self.1.extend_one(item.1); |
| 501 | + } |
469 | 502 |
|
| 503 | + fn extend_reserve(&mut self, additional: usize) { |
| 504 | + self.0.extend_reserve(additional); |
| 505 | + self.1.extend_reserve(additional); |
| 506 | + } |
| 507 | +} |
| 508 | + |
| 509 | +impl<A, B, ExtendA, ExtendB> ExtendUnchecked<(A, B)> for (ExtendA, ExtendB) |
| 510 | +where |
| 511 | + ExtendA: Extend<A>, |
| 512 | + ExtendB: Extend<B>, |
| 513 | +{ |
| 514 | + unsafe fn extend_one_unchecked(&mut self, item: (A, B)) { |
| 515 | + // SAFETY: Those are our safety preconditions, and we correctly forward `extend_reserve`. |
| 516 | + unsafe { |
| 517 | + self.0.extend_one_unchecked(item.0); |
| 518 | + self.1.extend_one_unchecked(item.1); |
| 519 | + } |
| 520 | + } |
| 521 | +} |
| 522 | + |
| 523 | +fn default_extend_tuple<A, B, ExtendA, ExtendB>( |
| 524 | + iter: impl Iterator<Item = (A, B)>, |
| 525 | + a: &mut ExtendA, |
| 526 | + b: &mut ExtendB, |
| 527 | +) where |
| 528 | + ExtendA: Extend<A>, |
| 529 | + ExtendB: Extend<B>, |
| 530 | +{ |
| 531 | + fn extend<'a, A, B>( |
| 532 | + a: &'a mut impl Extend<A>, |
| 533 | + b: &'a mut impl Extend<B>, |
| 534 | + ) -> impl FnMut((), (A, B)) + 'a { |
| 535 | + move |(), (t, u)| { |
| 536 | + a.extend_one(t); |
| 537 | + b.extend_one(u); |
| 538 | + } |
| 539 | + } |
| 540 | + |
| 541 | + let (lower_bound, _) = iter.size_hint(); |
| 542 | + if lower_bound > 0 { |
| 543 | + a.extend_reserve(lower_bound); |
| 544 | + b.extend_reserve(lower_bound); |
| 545 | + } |
| 546 | + |
| 547 | + iter.fold((), extend(a, b)); |
| 548 | +} |
| 549 | + |
| 550 | +trait SpecTupleExtend<A, B> { |
| 551 | + fn extend(self, a: &mut A, b: &mut B); |
| 552 | +} |
| 553 | + |
| 554 | +impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter |
| 555 | +where |
| 556 | + ExtendA: Extend<A>, |
| 557 | + ExtendB: Extend<B>, |
| 558 | + Iter: Iterator<Item = (A, B)>, |
| 559 | +{ |
| 560 | + default fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { |
| 561 | + default_extend_tuple(self, a, b); |
| 562 | + } |
| 563 | +} |
| 564 | + |
| 565 | +impl<A, B, ExtendA, ExtendB, Iter> SpecTupleExtend<ExtendA, ExtendB> for Iter |
| 566 | +where |
| 567 | + ExtendA: Extend<A>, |
| 568 | + ExtendB: Extend<B>, |
| 569 | + Iter: TrustedLen<Item = (A, B)>, |
| 570 | +{ |
| 571 | + fn extend(self, a: &mut ExtendA, b: &mut ExtendB) { |
470 | 572 | fn extend<'a, A, B>( |
471 | 573 | a: &'a mut impl Extend<A>, |
472 | 574 | b: &'a mut impl Extend<B>, |
473 | 575 | ) -> impl FnMut((), (A, B)) + 'a { |
474 | | - move |(), (t, u)| { |
475 | | - a.extend_one(t); |
476 | | - b.extend_one(u); |
| 576 | + // SAFETY: We reserve enough space for the `size_hint`, and the iterator is `TrustedLen` |
| 577 | + // so its `size_hint` is exact. |
| 578 | + move |(), (t, u)| unsafe { |
| 579 | + a.extend_one_unchecked(t); |
| 580 | + b.extend_one_unchecked(u); |
477 | 581 | } |
478 | 582 | } |
479 | 583 |
|
480 | | - let (lower_bound, _) = iter.size_hint(); |
| 584 | + let (lower_bound, upper_bound) = self.size_hint(); |
| 585 | + |
| 586 | + if upper_bound.is_none() { |
| 587 | + // We cannot reserve more than `usize::MAX` items, and this is likely to go out of memory anyway. |
| 588 | + default_extend_tuple(self, a, b); |
| 589 | + return; |
| 590 | + } |
| 591 | + |
481 | 592 | if lower_bound > 0 { |
482 | 593 | a.extend_reserve(lower_bound); |
483 | 594 | b.extend_reserve(lower_bound); |
484 | 595 | } |
485 | 596 |
|
486 | | - iter.fold((), extend(a, b)); |
487 | | - } |
488 | | - |
489 | | - fn extend_one(&mut self, item: (A, B)) { |
490 | | - self.0.extend_one(item.0); |
491 | | - self.1.extend_one(item.1); |
492 | | - } |
493 | | - |
494 | | - fn extend_reserve(&mut self, additional: usize) { |
495 | | - self.0.extend_reserve(additional); |
496 | | - self.1.extend_reserve(additional); |
| 597 | + self.fold((), extend(a, b)); |
497 | 598 | } |
498 | 599 | } |
0 commit comments