blob: 5b40d221a0b7ad5150024845c71b1ac30406f589 [file] [log] [blame]
// 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<_>>()
)
}
}