assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]];
assert_eq!(xs.split_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits);
- let splits: &[&[_]] = &[&[1, 2, 3, 4, 5], &[]];
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits);
- let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5], &[]];
+ let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
assert_eq!(xs.split_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits);
let xs: &[i32] = &[];
assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
}
+#[test]
+fn test_splitator_inclusive_reverse() {
+ let xs = &[1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]];
+ assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]];
+ assert_eq!(xs.split_inclusive(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
+ assert_eq!(xs.split_inclusive(|_| true).rev().collect::<Vec<_>>(), splits);
+
+ let xs: &[i32] = &[];
+ let splits: &[&[i32]] = &[&[]];
+ assert_eq!(xs.split_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+}
+
+#[test]
+fn test_splitator_mut_inclusive() {
+ let xs = &mut [1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 1).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 10).collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
+ assert_eq!(xs.split_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);
+
+ let xs: &mut [i32] = &mut [];
+ let splits: &[&[i32]] = &[&[]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
+}
+
+#[test]
+fn test_splitator_mut_inclusive_reverse() {
+ let xs = &mut [1, 2, 3, 4, 5];
+
+ let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
+ let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
+ assert_eq!(xs.split_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);
+
+ let xs: &mut [i32] = &mut [];
+ let splits: &[&[i32]] = &[&[]];
+ assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
+}
+
#[test]
fn test_splitnator() {
let xs = &[1, 2, 3, 4, 5];
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
let split: Vec<&str> = data.split_inclusive('\n').collect();
- assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n", ""]);
+ assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n"]);
let uppercase_separated = "SheePSharKTurtlECaT";
let mut first_char = true;
- let split: Vec<&str> = uppercase_separated.split_inclusive(|c: char| {
- let split = !first_char && c.is_uppercase();
- first_char = split;
- split
- }).collect();
- assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT", ""]);
+ let split: Vec<&str> = uppercase_separated
+ .split_inclusive(|c: char| {
+ let split = !first_char && c.is_uppercase();
+ first_char = split;
+ split
+ })
+ .collect();
+ assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT"]);
}
+#[test]
+fn test_split_char_iterator_inclusive_rev() {
+ let data = "\nMäry häd ä little lämb\nLittle lämb\n";
+
+ let split: Vec<&str> = data.split_inclusive('\n').rev().collect();
+ assert_eq!(split, ["Little lämb\n", "Märy häd ä little lämb\n", "\n"]);
+
+ // Note that the predicate is stateful and thus dependent
+ // on the iteration order.
+ // (A different predicate is needed for reverse iterator vs normal iterator.)
+ // Not sure if anything can be done though.
+ let uppercase_separated = "SheePSharKTurtlECaT";
+ let mut term_char = true;
+ let split: Vec<&str> = uppercase_separated
+ .split_inclusive(|c: char| {
+ let split = term_char && c.is_uppercase();
+ term_char = c.is_uppercase();
+ split
+ })
+ .rev()
+ .collect();
+ assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]);
+}
#[test]
fn test_rsplit() {
/// assert!(iter.next().is_none());
/// ```
///
- /// If the first element is matched, an empty slice will be the first item
- /// returned by the iterator. Similarly, if the last element in the slice
- /// is matched, an empty slice will be the last item returned by the
- /// iterator:
+ /// If the last element of the slice is matched,
+ /// that element will be considered the terminator of the preceding slice.
+ /// That slice will be the last item returned by the iterator.
///
/// ```
/// #![feature(split_inclusive)]
- /// let slice = [10, 40, 33];
+ /// let slice = [3, 10, 40, 33];
/// let mut iter = slice.split_inclusive(|num| num % 3 == 0);
///
+ /// assert_eq!(iter.next().unwrap(), &[3]);
/// assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
- /// assert_eq!(iter.next().unwrap(), &[]);
/// assert!(iter.next().is_none());
/// ```
- #[unstable(feature = "split_inclusive", issue = "0")]
+ #[unstable(feature = "split_inclusive", issue = "none")]
#[inline]
pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F>
- where F: FnMut(&T) -> bool
+ where
+ F: FnMut(&T) -> bool,
{
- SplitInclusive {
- v: self,
- pred,
- finished: false
- }
+ SplitInclusive { v: self, pred, finished: false }
}
/// Returns an iterator over mutable subslices separated by elements that
/// }
/// assert_eq!(v, [10, 40, 1, 20, 1, 1]);
/// ```
- #[unstable(feature = "split_inclusive", issue = "0")]
+ #[unstable(feature = "split_inclusive", issue = "none")]
#[inline]
pub fn split_inclusive_mut<F>(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F>
- where F: FnMut(&T) -> bool
+ where
+ F: FnMut(&T) -> bool,
{
SplitInclusiveMut { v: self, pred, finished: false }
}
///
/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive
/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "split_inclusive", issue = "0")]
-pub struct SplitInclusive<'a, T:'a, P> where P: FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+pub struct SplitInclusive<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
v: &'a [T],
pred: P,
- finished: bool
+ finished: bool,
}
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitInclusive<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SplitInclusive")
.field("v", &self.v)
}
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<T, P> Clone for SplitInclusive<'_, T, P> where P: Clone + FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+impl<T, P> Clone for SplitInclusive<'_, T, P>
+where
+ P: Clone + FnMut(&T) -> bool,
+{
fn clone(&self) -> Self {
- SplitInclusive {
- v: self.v,
- pred: self.pred.clone(),
- finished: self.finished,
- }
+ SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished }
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+impl<'a, T, P> Iterator for SplitInclusive<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
type Item = &'a [T];
#[inline]
fn next(&mut self) -> Option<&'a [T]> {
- if self.finished { return None; }
+ if self.finished {
+ return None;
+ }
- match self.v.iter().position(|x| (self.pred)(x)) {
- None => self.finish(),
- Some(idx) => {
- let ret = Some(&self.v[..idx + 1]);
- self.v = &self.v[idx + 1..];
- ret
- }
+ let idx =
+ self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len());
+ if idx == self.v.len() {
+ self.finished = true;
}
+ let ret = Some(&self.v[..idx]);
+ self.v = &self.v[idx..];
+ ret
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- if self.finished {
- (0, Some(0))
- } else {
- (1, Some(self.v.len() + 1))
- }
+ if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) }
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
#[inline]
fn next_back(&mut self) -> Option<&'a [T]> {
- if self.finished { return None; }
-
- match self.v.iter().rposition(|x| (self.pred)(x)) {
- None => self.finish(),
- Some(idx) => {
- let ret = Some(&self.v[idx + 1..]);
- self.v = &self.v[..idx];
- ret
- }
+ if self.finished {
+ return None;
}
- }
-}
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<'a, T, P> SplitIter for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool {
- #[inline]
- fn finish(&mut self) -> Option<&'a [T]> {
- if self.finished { None } else { self.finished = true; Some(self.v) }
+ // The last index of self.v is already checked and found to match
+ // by the last iteration, so we start searching a new match
+ // one index to the left.
+ let remainder = if self.v.len() == 0 { &[] } else { &self.v[..(self.v.len() - 1)] };
+ let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0);
+ if idx == 0 {
+ self.finished = true;
+ }
+ let ret = Some(&self.v[idx..]);
+ self.v = &self.v[..idx];
+ ret
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
impl<T, P> FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
/// An iterator over the mutable subslices of the vector which are separated
///
/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut
/// [slices]: ../../std/primitive.slice.html
-#[unstable(feature = "split_inclusive", issue = "0")]
-pub struct SplitInclusiveMut<'a, T:'a, P> where P: FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+pub struct SplitInclusiveMut<'a, T: 'a, P>
+where
+ P: FnMut(&T) -> bool,
+{
v: &'a mut [T],
pred: P,
- finished: bool
+ finished: bool,
}
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<T: fmt::Debug, P> fmt::Debug for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+impl<T: fmt::Debug, P> fmt::Debug for SplitInclusiveMut<'_, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SplitInclusiveMut")
.field("v", &self.v)
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<'a, T, P> SplitIter for SplitInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool {
- #[inline]
- fn finish(&mut self) -> Option<&'a mut [T]> {
- if self.finished {
- None
- } else {
- self.finished = true;
- Some(mem::replace(&mut self.v, &mut []))
- }
- }
-}
-
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool {
+#[unstable(feature = "split_inclusive", issue = "none")]
+impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P>
+where
+ P: FnMut(&T) -> bool,
+{
type Item = &'a mut [T];
#[inline]
fn next(&mut self) -> Option<&'a mut [T]> {
- if self.finished { return None; }
+ if self.finished {
+ return None;
+ }
- let idx_opt = { // work around borrowck limitations
+ let idx_opt = {
+ // work around borrowck limitations
let pred = &mut self.pred;
self.v.iter().position(|x| (*pred)(x))
};
- match idx_opt {
- None => self.finish(),
- Some(idx) => {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(idx+1);
- self.v = tail;
- Some(head)
- }
+ let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len());
+ if idx == self.v.len() {
+ self.finished = true;
}
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(idx);
+ self.v = tail;
+ Some(head)
}
#[inline]
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
-impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> where
+#[unstable(feature = "split_inclusive", issue = "none")]
+impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P>
+where
P: FnMut(&T) -> bool,
{
#[inline]
fn next_back(&mut self) -> Option<&'a mut [T]> {
- if self.finished { return None; }
+ if self.finished {
+ return None;
+ }
- let idx_opt = { // work around borrowck limitations
+ let idx_opt = if self.v.len() == 0 {
+ None
+ } else {
+ // work around borrowck limitations
let pred = &mut self.pred;
- self.v.iter().rposition(|x| (*pred)(x))
+
+ // The last index of self.v is already checked and found to match
+ // by the last iteration, so we start searching a new match
+ // one index to the left.
+ let remainder = &self.v[..(self.v.len() - 1)];
+ remainder.iter().rposition(|x| (*pred)(x))
};
- match idx_opt {
- None => self.finish(),
- Some(idx) => {
- let tmp = mem::replace(&mut self.v, &mut []);
- let (head, tail) = tmp.split_at_mut(idx+1);
- self.v = head;
- Some(tail)
- }
+ let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0);
+ if idx == 0 {
+ self.finished = true;
}
+ let tmp = mem::replace(&mut self.v, &mut []);
+ let (head, tail) = tmp.split_at_mut(idx);
+ self.v = head;
+ Some(tail)
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
/// An iterator over subslices separated by elements that match a predicate
#[inline]
fn next_inclusive(&mut self) -> Option<&'a str> {
- if self.finished { return None }
+ if self.finished {
+ return None;
+ }
let haystack = self.matcher.haystack();
match self.matcher.next_match() {
+ // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
+ // and self.start is either the start of the original string,
+ // or `b` was assigned to it, so it also lies on unicode boundary.
Some((_, b)) => unsafe {
let elt = haystack.get_unchecked(self.start..b);
self.start = b;
#[inline]
fn next_back_inclusive(&mut self) -> Option<&'a str>
- where P::Searcher: ReverseSearcher<'a>
+ where
+ P::Searcher: ReverseSearcher<'a>,
{
- if self.finished { return None }
+ if self.finished {
+ return None;
+ }
if !self.allow_trailing_empty {
self.allow_trailing_empty = true;
- match self.next_back() {
+ match self.next_back_inclusive() {
Some(elt) if !elt.is_empty() => return Some(elt),
- _ => if self.finished { return None }
+ _ => {
+ if self.finished {
+ return None;
+ }
+ }
}
}
let haystack = self.matcher.haystack();
match self.matcher.next_match_back() {
+ // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary,
+ // and self.end is either the end of the original string,
+ // or `b` was assigned to it, so it also lies on unicode boundary.
Some((_, b)) => unsafe {
let elt = haystack.get_unchecked(b..self.end);
self.end = b;
Some(elt)
},
+ // SAFETY: self.start is either the start of the original string,
+ // or start of a substring that represents the part of the string that hasn't
+ // iterated yet. Either way, it is guaranteed to lie on unicode boundary.
+ // self.end is either the end of the original string,
+ // or `b` was assigned to it, so it also lies on unicode boundary.
None => unsafe {
self.finished = true;
Some(haystack.get_unchecked(self.start..self.end))
/// .split_inclusive('\n').collect();
/// assert_eq!(v, ["Mary had a little lamb\n", "little lamb\n", "little lamb."]);
/// ```
- #[unstable(feature = "split_inclusive", issue = "0")]
+ ///
+ /// If the last element of the string is matched,
+ /// that element will be considered the terminator of the preceding substring.
+ /// That substring will be the last item returned by the iterator.
+ ///
+ /// ```
+ /// #![feature(split_inclusive)]
+ /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb.\n"
+ /// .split_inclusive('\n').collect();
+ /// assert_eq!(v, ["Mary had a little lamb\n", "little lamb\n", "little lamb.\n"]);
+ /// ```
+ #[unstable(feature = "split_inclusive", issue = "none")]
#[inline]
pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> {
SplitInclusive(SplitInternal {
start: 0,
end: self.len(),
matcher: pat.into_searcher(self),
- allow_trailing_empty: true,
+ allow_trailing_empty: false,
finished: false,
})
}
///
/// [`split_inclusive`]: ../../std/primitive.str.html#method.split_inclusive
/// [`str`]: ../../std/primitive.str.html
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
pub struct SplitInclusive<'a, P: Pattern<'a>>(SplitInternal<'a, P>);
impl_fn_for_zst! {
};
}
-
-
#[stable(feature = "split_whitespace", since = "1.1.0")]
impl<'a> Iterator for SplitWhitespace<'a> {
type Item = &'a str;
#[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
impl FusedIterator for SplitAsciiWhitespace<'_> {}
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
type Item = &'a str;
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SplitInclusive")
- .field("0", &self.0)
- .finish()
+ f.debug_struct("SplitInclusive").field("0", &self.0).finish()
}
}
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> {
fn clone(&self) -> Self {
SplitInclusive(self.0.clone())
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator
for SplitInclusive<'a, P>
{
}
}
-#[unstable(feature = "split_inclusive", issue = "0")]
+#[unstable(feature = "split_inclusive", issue = "none")]
impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {}
/// An iterator of [`u16`] over the string encoded as UTF-16.