// 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 or the MIT license // , 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, fn(u32) -> char>); impl ParallelIterator for Iter { type Item = char; fn drive_unindexed(self, consumer: C) -> C::Result where C: UnindexedConsumer, { self.0.drive_unindexed(consumer) } } impl IndexedParallelIterator for Iter { fn len(&self) -> usize { self.0.len() } fn drive>(self, consumer: C) -> C::Result { self.0.drive(consumer) } fn with_producer>(self, callback: CB) -> CB::Output { self.0.with_producer(callback) } } impl CharRange { fn compact_range(&self) -> Range { 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::>(), chars!(..).par_iter().collect::>() ) } }