diff options
Diffstat (limited to 'vendor/unic-char-range/src/par_iter.rs')
-rw-r--r-- | vendor/unic-char-range/src/par_iter.rs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/vendor/unic-char-range/src/par_iter.rs b/vendor/unic-char-range/src/par_iter.rs new file mode 100644 index 000000000..5b40d221a --- /dev/null +++ b/vendor/unic-char-range/src/par_iter.rs @@ -0,0 +1,110 @@ +// Copyright 2018 The UNIC Project Developers. +// +// See the COPYRIGHT file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rayon; + +use self::rayon::iter::plumbing::{Consumer, ProducerCallback, UnindexedConsumer}; +use self::rayon::prelude::*; +use crate::step::{AFTER_SURROGATE, BEFORE_SURROGATE}; +use crate::CharRange; +use core::char; +use core::ops::Range; + +const SKIP_LENGTH: u32 = + crate::step::AFTER_SURROGATE as u32 - crate::step::BEFORE_SURROGATE as u32 - 1; + +#[derive(Clone, Debug)] +pub struct Iter(rayon::iter::Map<rayon::range::Iter<u32>, fn(u32) -> char>); + +impl ParallelIterator for Iter { + type Item = char; + + fn drive_unindexed<C>(self, consumer: C) -> C::Result + where + C: UnindexedConsumer<Self::Item>, + { + self.0.drive_unindexed(consumer) + } +} + +impl IndexedParallelIterator for Iter { + fn len(&self) -> usize { + self.0.len() + } + + fn drive<C: Consumer<Self::Item>>(self, consumer: C) -> C::Result { + self.0.drive(consumer) + } + + fn with_producer<CB: ProducerCallback<Self::Item>>(self, callback: CB) -> CB::Output { + self.0.with_producer(callback) + } +} + +impl CharRange { + fn compact_range(&self) -> Range<u32> { + let low = self.low as u32; + let high = self.high as u32 + 1; + low..(if self.high >= AFTER_SURROGATE { + high - SKIP_LENGTH + } else { + high + }) + } +} + +impl IntoParallelIterator for CharRange { + type Item = char; + type Iter = Iter; + + fn into_par_iter(self) -> Self::Iter { + Iter(self.compact_range().into_par_iter().map(|c| { + let c = if c > BEFORE_SURROGATE as u32 { + c + SKIP_LENGTH + } else { + c + }; + debug_assert!(c <= BEFORE_SURROGATE as u32 || c >= AFTER_SURROGATE as u32); + debug_assert!(c <= char::MAX as u32); + #[allow(unsafe_code)] + unsafe { + char::from_u32_unchecked(c) + } + })) + } +} + +impl<'a> IntoParallelIterator for &'a CharRange { + type Item = char; + type Iter = Iter; + + fn into_par_iter(self) -> Self::Iter { + (*self).into_par_iter() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn length_agrees() { + assert_eq!(chars!(..).iter().count(), chars!(..).par_iter().count()) + } + + #[test] + #[cfg(feature = "std")] + fn content_agrees() { + assert_eq!( + chars!(..).iter().collect::<Vec<_>>(), + chars!(..).par_iter().collect::<Vec<_>>() + ) + } +} |