From f41ecef6d52200743b3672346a59fc1e2068e9e8 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sun, 30 Apr 2017 21:07:39 +0200 Subject: [PATCH 1/2] std_unicode: impl Clone for .split_whitespace() Use custom closure structs for the predicates so that the iterator's clone can simply be derived. This should also reduce virtual call overhead by not using function pointers. --- src/libstd_unicode/lib.rs | 2 ++ src/libstd_unicode/u_str.rs | 50 ++++++++++++++++++++++++++++--------- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs index 7e5ab1a54ab3a..d63878a7a7c24 100644 --- a/src/libstd_unicode/lib.rs +++ b/src/libstd_unicode/lib.rs @@ -36,9 +36,11 @@ #![feature(core_char_ext)] #![feature(decode_utf8)] #![feature(fused)] +#![feature(fn_traits)] #![feature(lang_items)] #![feature(staged_api)] #![feature(try_from)] +#![feature(unboxed_closures)] mod tables; mod u_str; diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index 770b67acd49ef..e138e71c9c12b 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -26,8 +26,9 @@ use core::str::Split; /// [`split_whitespace`]: ../../std/primitive.str.html#method.split_whitespace /// [`str`]: ../../std/primitive.str.html #[stable(feature = "split_whitespace", since = "1.1.0")] +#[derive(Clone)] pub struct SplitWhitespace<'a> { - inner: Filter bool>, fn(&&str) -> bool>, + inner: Filter, IsNotEmpty>, } /// Methods for Unicode string slices @@ -44,17 +45,7 @@ pub trait UnicodeStr { impl UnicodeStr for str { #[inline] fn split_whitespace(&self) -> SplitWhitespace { - fn is_not_empty(s: &&str) -> bool { - !s.is_empty() - } - let is_not_empty: fn(&&str) -> bool = is_not_empty; // coerce to fn pointer - - fn is_whitespace(c: char) -> bool { - c.is_whitespace() - } - let is_whitespace: fn(char) -> bool = is_whitespace; // coerce to fn pointer - - SplitWhitespace { inner: self.split(is_whitespace).filter(is_not_empty) } + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } } #[inline] @@ -139,6 +130,41 @@ impl Iterator for Utf16Encoder impl FusedIterator for Utf16Encoder where I: FusedIterator {} +#[derive(Clone)] +struct IsWhitespace; + +impl FnOnce<(char, )> for IsWhitespace { + type Output = bool; + + extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { + self.call_mut(arg) + } +} + +impl FnMut<(char, )> for IsWhitespace { + extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { + arg.0.is_whitespace() + } +} + +#[derive(Clone)] +struct IsNotEmpty; + +impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { + type Output = bool; + + extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { + extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { + !arg.0.is_empty() + } +} + + #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; From 41aeb9d4ec26c4b6fb118483d2d1375e04b2c62f Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Sun, 30 Apr 2017 21:24:47 +0200 Subject: [PATCH 2/2] std_unicode: Use #[inline] on the split_whitespace predicates --- src/libstd_unicode/u_str.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs index e138e71c9c12b..1454168d2d5cc 100644 --- a/src/libstd_unicode/u_str.rs +++ b/src/libstd_unicode/u_str.rs @@ -136,12 +136,14 @@ struct IsWhitespace; impl FnOnce<(char, )> for IsWhitespace { type Output = bool; + #[inline] extern "rust-call" fn call_once(mut self, arg: (char, )) -> bool { self.call_mut(arg) } } impl FnMut<(char, )> for IsWhitespace { + #[inline] extern "rust-call" fn call_mut(&mut self, arg: (char, )) -> bool { arg.0.is_whitespace() } @@ -153,12 +155,14 @@ struct IsNotEmpty; impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { type Output = bool; + #[inline] extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { self.call_mut(arg) } } impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { + #[inline] extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { !arg.0.is_empty() }