Rust libstd内での特殊化の使用例 (1.23.0時点)

概要: Rust libstd内では既に特殊化が使用されているので、特定の条件を満たすことでより効率なコードが生成される。

PartialEq<[T]>

  • 最適化される処理: スライスの比較処理
    • 間接的に最適化される処理: Vec<T>, str, String の比較など
  • 条件: 内部トレイト BytewiseEquality が実装されている場合。具体的には要素型が u8, i8, u16, i16, u32, i32, u64, i64, usize, isize, char, bool の場合
  • 理由: memcmpで効率的に比較できるため。
  • ディスパッチ用トレイト: 内部トレイト SlicePartialEq

Vec<T>::from_iter, Vec<T>::extend (ムーブ)

  • 最適化される処理: TイテレータからのVec<T>の生成延長
    • 間接的に最適化される処理: iter.collect::<Vec<_>>() など
  • 条件1: unstableかつunsafeなトレイト TrustedLen が実装されている場合。これは size_hint が正確な長さを与えることをunsafeレベルで保証するトレイトである。 (ExactSizeIteratorはsafeであり、契約の内容も微妙に異なる)
    • [T], Option<T>, Result<T, E> 由来のイテレータstr.bytes(), iter::empty(), iter::once(), (n..m), (n..=m)TrustedLen である。
    • rev(), cloned(), chain(), zip(), map(), enumerate()TrustedLen を保つ。
  • 理由1: 通常の生成/延長処理では、容量を気にしながら適宜再確保をする必要があるが、イテレータの長さが判明している場合は、最初に再確保したあとはループの各ステップでは容量チェックを省略できるから。
  • 条件2: イテレータvec.into_iter() 自体だった場合
  • 理由2: 当該イテレータが一度も消費されていない場合、単にもとの vec を復元するだけでよいから。
  • ディスパッチ用トレイト: 内部トレイト SpecExtend

Vec<T>::from_iter, Vec<T>::extend (参照)

  • 最適化される処理: &TイテレータからのVec<T>の延長 (T: Copy のとき可能)
  • 条件: スライスの slice.iter() に由来するとき
  • 理由: memcpy で効率よくコピー可能で、再確保も高々1回でよく、パニックガードが要らないから。
  • ディスパッチ用トレイト: 内部トレイト SpecExtend (上と同じ)

BinaryHeap<T>::extend, LinkedList<T>::extend

  • 最適化される処理: イテレータからのBinaryHeap<T>の延長LinkedList<T>の延長
    • 間接的に最適化される処理: iter.collect::<LinkedList<_>>() など
  • 条件1: BinaryHeap<T>BinaryHeap<T> で延長する場合
  • 理由1: swapして逆向きに追加したほうが速い場合や、ヒープの再ビルドをしたほうが速い場合がある。
  • 条件2: LinkedList<T>LinkedList<T> で延長する場合
  • 理由2: 単に連結すればよい。
  • ディスパッチ用トレイト: 内部トレイト SpecExtend

vec![x; n]

  • 最適化される処理: vec![x; n] (内部的には隠し関数 alloc::vec::from_elem)
  • 条件1: 要素型が u8
  • 理由1: memset で効率的に塗れるため。
  • 条件2: 要素型が u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64 で値が0のとき
  • 理由2: memset で効率的に塗れるため。
  • ディスパッチ用トレイト: 内部トレイト SpecFromElem

ToString

  • 最適化される処理: to_stringによる文字列化 (一般には Display に対して実装される)
  • 条件: str, Cow<'a, str>, String のいずれかの場合
  • 理由: 文字列をコピーするだけだから。
  • ディスパッチ用トレイト: なし (ToString を直接特殊化)

iter.zip

iter.fuse

  • 最適化される処理: iter.fuse() で得られるイテレータの実装
  • 条件: unstableなトレイト FusedIterator が実装されている場合。つまり、元のイテレータが既に、「Noneを出力したら以降はずっとNone」という性質を満たしているとき。
  • 理由: 既にfusedなので、self.doneフラグをチェックする必要がなくなる。
  • ディスパッチ用トレイト: なし (Iterator, DoubleEndedIterator を直接特殊化)

Arc<[T]>::from, Rc<[T]>::from

  • 最適化される処理: &[T] から Arc<[T]>, Rc<[T]> を作る処理 (一般には T: Clone なら使える)
  • 条件: T: Copy のとき
  • 理由: memcpy で効率的に複製できるし、 clone と違ってpanicしないのでパニックガードが要らない。
  • ディスパッチ用トレイト: ArcFromSlice, RcFromSlice