| extern crate arrayvec; | ||
| #[macro_use] extern crate bencher; | ||
| use arrayvec::ArrayString; | ||
| use bencher::Bencher; | ||
| fn try_push_c(b: &mut Bencher) { | ||
| let mut v = ArrayString::<[u8; 512]>::new(); | ||
| b.iter(|| { | ||
| v.clear(); | ||
| while v.try_push('c').is_ok() { | ||
| } | ||
| v.len() | ||
| }); | ||
| b.bytes = v.capacity() as u64; | ||
| } | ||
| fn try_push_alpha(b: &mut Bencher) { | ||
| let mut v = ArrayString::<[u8; 512]>::new(); | ||
| b.iter(|| { | ||
| v.clear(); | ||
| while v.try_push('α').is_ok() { | ||
| } | ||
| v.len() | ||
| }); | ||
| b.bytes = v.capacity() as u64; | ||
| } | ||
| // Yes, pushing a string char-by-char is slow. Use .push_str. | ||
| fn try_push_string(b: &mut Bencher) { | ||
| let mut v = ArrayString::<[u8; 512]>::new(); | ||
| let input = "abcαβγ“”"; | ||
| b.iter(|| { | ||
| v.clear(); | ||
| for ch in input.chars().cycle() { | ||
| if !v.try_push(ch).is_ok() { | ||
| break; | ||
| } | ||
| } | ||
| v.len() | ||
| }); | ||
| b.bytes = v.capacity() as u64; | ||
| } | ||
| fn push_c(b: &mut Bencher) { | ||
| let mut v = ArrayString::<[u8; 512]>::new(); | ||
| b.iter(|| { | ||
| v.clear(); | ||
| while !v.is_full() { | ||
| v.push('c'); | ||
| } | ||
| v.len() | ||
| }); | ||
| b.bytes = v.capacity() as u64; | ||
| } | ||
| fn push_alpha(b: &mut Bencher) { | ||
| let mut v = ArrayString::<[u8; 512]>::new(); | ||
| b.iter(|| { | ||
| v.clear(); | ||
| while !v.is_full() { | ||
| v.push('α'); | ||
| } | ||
| v.len() | ||
| }); | ||
| b.bytes = v.capacity() as u64; | ||
| } | ||
| fn push_string(b: &mut Bencher) { | ||
| let mut v = ArrayString::<[u8; 512]>::new(); | ||
| let input = "abcαβγ“”"; | ||
| b.iter(|| { | ||
| v.clear(); | ||
| for ch in input.chars().cycle() { | ||
| if !v.is_full() { | ||
| v.push(ch); | ||
| } else { | ||
| break; | ||
| } | ||
| } | ||
| v.len() | ||
| }); | ||
| b.bytes = v.capacity() as u64; | ||
| } | ||
| benchmark_group!(benches, try_push_c, try_push_alpha, try_push_string, push_c, | ||
| push_alpha, push_string); | ||
| benchmark_main!(benches); |
+54
| // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT | ||
| // file at the top-level directory of this distribution and at | ||
| // http://rust-lang.org/COPYRIGHT. | ||
| // | ||
| // 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. | ||
| // | ||
| // Original authors: alexchrichton, bluss | ||
| // UTF-8 ranges and tags for encoding characters | ||
| const TAG_CONT: u8 = 0b1000_0000; | ||
| const TAG_TWO_B: u8 = 0b1100_0000; | ||
| const TAG_THREE_B: u8 = 0b1110_0000; | ||
| const TAG_FOUR_B: u8 = 0b1111_0000; | ||
| const MAX_ONE_B: u32 = 0x80; | ||
| const MAX_TWO_B: u32 = 0x800; | ||
| const MAX_THREE_B: u32 = 0x10000; | ||
| /// Placeholder | ||
| pub struct EncodeUtf8Error; | ||
| /// Encode a char into buf using UTF-8. | ||
| /// | ||
| /// On success, return the byte length of the encoding (1, 2, 3 or 4).<br> | ||
| /// On error, return `EncodeUtf8Error` if the buffer was too short for the char. | ||
| #[inline] | ||
| pub fn encode_utf8(ch: char, buf: &mut [u8]) -> Result<usize, EncodeUtf8Error> | ||
| { | ||
| let code = ch as u32; | ||
| if code < MAX_ONE_B && buf.len() >= 1 { | ||
| buf[0] = code as u8; | ||
| return Ok(1); | ||
| } else if code < MAX_TWO_B && buf.len() >= 2 { | ||
| buf[0] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; | ||
| buf[1] = (code & 0x3F) as u8 | TAG_CONT; | ||
| return Ok(2); | ||
| } else if code < MAX_THREE_B && buf.len() >= 3 { | ||
| buf[0] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; | ||
| buf[1] = (code >> 6 & 0x3F) as u8 | TAG_CONT; | ||
| buf[2] = (code & 0x3F) as u8 | TAG_CONT; | ||
| return Ok(3); | ||
| } else if buf.len() >= 4 { | ||
| buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; | ||
| buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT; | ||
| buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT; | ||
| buf[3] = (code & 0x3F) as u8 | TAG_CONT; | ||
| return Ok(4); | ||
| }; | ||
| Err(EncodeUtf8Error) | ||
| } | ||
+12
-12
@@ -15,3 +15,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "arrayvec" | ||
| version = "0.4.4" | ||
| version = "0.4.5" | ||
| authors = ["bluss"] | ||
@@ -33,6 +33,6 @@ description = "A vector with fixed capacity, backed by an array (it can be stored on the stack too). Implements fixed capacity ArrayVec and ArrayString." | ||
| harness = false | ||
| [dependencies.nodrop] | ||
| version = "0.1.8" | ||
| default-features = false | ||
| [[bench]] | ||
| name = "arraystring" | ||
| harness = false | ||
| [dependencies.serde] | ||
@@ -43,7 +43,7 @@ version = "1.0" | ||
| [dependencies.odds] | ||
| version = "0.2.23" | ||
| [dependencies.nodrop] | ||
| version = "0.1.12" | ||
| default-features = false | ||
| [dev-dependencies.bencher] | ||
| version = "0.1.4" | ||
| [dev-dependencies.serde_test] | ||
| version = "1.0" | ||
@@ -53,9 +53,9 @@ [dev-dependencies.matches] | ||
| [dev-dependencies.serde_test] | ||
| version = "1.0" | ||
| [dev-dependencies.bencher] | ||
| version = "0.1.4" | ||
| [features] | ||
| serde-1 = ["serde"] | ||
| std = [] | ||
| use_union = [] | ||
| default = ["std"] | ||
| std = [] | ||
| serde-1 = ["serde"] |
+11
-0
@@ -25,2 +25,13 @@ | ||
| - 0.4.5 | ||
| - Add methods to ``ArrayString`` by @DenialAdams: | ||
| - ``.pop() -> Option<char>`` | ||
| - ``.truncate(new_len)`` | ||
| - ``.remove(index) -> char`` | ||
| - Remove dependency on crate odds | ||
| - Document debug assertions in unsafe methods better | ||
| - 0.4.4 | ||
@@ -27,0 +38,0 @@ |
+99
-5
@@ -15,3 +15,3 @@ use std::borrow::Borrow; | ||
| use CapacityError; | ||
| use odds::char::encode_utf8; | ||
| use char::encode_utf8; | ||
@@ -224,2 +224,95 @@ #[cfg(feature="serde-1")] | ||
| /// Removes the last character from the string and returns it. | ||
| /// | ||
| /// Returns `None` if this `ArrayString` is empty. | ||
| /// | ||
| /// ``` | ||
| /// use arrayvec::ArrayString; | ||
| /// | ||
| /// let mut s = ArrayString::<[_; 3]>::from("foo").unwrap(); | ||
| /// | ||
| /// assert_eq!(s.pop(), Some('o')); | ||
| /// assert_eq!(s.pop(), Some('o')); | ||
| /// assert_eq!(s.pop(), Some('f')); | ||
| /// | ||
| /// assert_eq!(s.pop(), None); | ||
| /// ``` | ||
| #[inline] | ||
| pub fn pop(&mut self) -> Option<char> { | ||
| let ch = match self.chars().rev().next() { | ||
| Some(ch) => ch, | ||
| None => return None, | ||
| }; | ||
| let new_len = self.len() - ch.len_utf8(); | ||
| unsafe { | ||
| self.set_len(new_len); | ||
| } | ||
| Some(ch) | ||
| } | ||
| /// Shortens this `ArrayString` to the specified length. | ||
| /// | ||
| /// If `new_len` is greater than the string’s current length, this has no | ||
| /// effect. | ||
| /// | ||
| /// ***Panics*** if `new_len` does not lie on a `char` boundary. | ||
| /// | ||
| /// ``` | ||
| /// use arrayvec::ArrayString; | ||
| /// | ||
| /// let mut string = ArrayString::<[_; 6]>::from("foobar").unwrap(); | ||
| /// string.truncate(3); | ||
| /// assert_eq!(&string[..], "foo"); | ||
| /// string.truncate(4); | ||
| /// assert_eq!(&string[..], "foo"); | ||
| /// ``` | ||
| #[inline] | ||
| pub fn truncate(&mut self, new_len: usize) { | ||
| if new_len <= self.len() { | ||
| assert!(self.is_char_boundary(new_len)); | ||
| unsafe { | ||
| // In libstd truncate is called on the underlying vector, | ||
| // which in turns drops each element. | ||
| // As we know we don't have to worry about Drop, | ||
| // we can just set the length (a la clear.) | ||
| self.set_len(new_len); | ||
| } | ||
| } | ||
| } | ||
| /// Removes a `char` from this `ArrayString` at a byte position and returns it. | ||
| /// | ||
| /// This is an `O(n)` operation, as it requires copying every element in the | ||
| /// array. | ||
| /// | ||
| /// ***Panics*** if `idx` is larger than or equal to the `ArrayString`’s length, | ||
| /// or if it does not lie on a `char` boundary. | ||
| /// | ||
| /// ``` | ||
| /// use arrayvec::ArrayString; | ||
| /// | ||
| /// let mut s = ArrayString::<[_; 3]>::from("foo").unwrap(); | ||
| /// | ||
| /// assert_eq!(s.remove(0), 'f'); | ||
| /// assert_eq!(s.remove(1), 'o'); | ||
| /// assert_eq!(s.remove(0), 'o'); | ||
| /// ``` | ||
| #[inline] | ||
| pub fn remove(&mut self, idx: usize) -> char { | ||
| let ch = match self[idx..].chars().next() { | ||
| Some(ch) => ch, | ||
| None => panic!("cannot remove a char from the end of a string"), | ||
| }; | ||
| let next = idx + ch.len_utf8(); | ||
| let len = self.len(); | ||
| unsafe { | ||
| ptr::copy(self.xs.as_ptr().offset(next as isize), | ||
| self.xs.as_mut_ptr().offset(idx as isize), | ||
| len - next); | ||
| self.set_len(len - (next - idx)); | ||
| } | ||
| ch | ||
| } | ||
| /// Make the string empty. | ||
@@ -232,8 +325,9 @@ pub fn clear(&mut self) { | ||
| /// Set the strings's length. | ||
| /// Set the strings’s length. | ||
| /// | ||
| /// May panic if `length` is greater than the capacity. | ||
| /// | ||
| /// This function is `unsafe` because it changes the notion of the | ||
| /// number of “valid” bytes in the string. Use with care. | ||
| /// | ||
| /// This method uses *debug assertions* to check the validity of `length` | ||
| /// and may use other debug assertions. | ||
| #[inline] | ||
@@ -250,3 +344,3 @@ pub unsafe fn set_len(&mut self, length: usize) { | ||
| /// Return a mutable slice of the whole string's buffer | ||
| /// Return a mutable slice of the whole string’s buffer | ||
| unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] { | ||
@@ -253,0 +347,0 @@ slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity()) |
+1
-1
| /// Trait for fixed size arrays. | ||
| pub unsafe trait Array { | ||
| /// The array's element type | ||
| /// The array’s element type | ||
| type Item; | ||
@@ -6,0 +6,0 @@ #[doc(hidden)] |
+8
-8
@@ -28,3 +28,2 @@ //! **arrayvec** provides the types `ArrayVec` and `ArrayString`: | ||
| #![cfg_attr(not(feature="std"), no_std)] | ||
| extern crate odds; | ||
| extern crate nodrop; | ||
@@ -66,2 +65,3 @@ #[cfg(feature="serde-1")] | ||
| mod array_string; | ||
| mod char; | ||
| mod range; | ||
@@ -231,3 +231,3 @@ mod errors; | ||
| /// | ||
| /// This method *may* use debug assertions to check that the arrayvec is not full. | ||
| /// This method uses *debug assertions* to check that the arrayvec is not full. | ||
| /// | ||
@@ -451,3 +451,3 @@ /// ``` | ||
| /// | ||
| /// If `len` is greater than the vector's current length this has no | ||
| /// If `len` is greater than the vector’s current length this has no | ||
| /// effect. | ||
@@ -507,9 +507,9 @@ /// | ||
| /// Set the vector's length without dropping or moving out elements | ||
| /// Set the vector’s length without dropping or moving out elements | ||
| /// | ||
| /// May use debug assertions to check that `length` is not greater than the | ||
| /// capacity. | ||
| /// This method is `unsafe` because it changes the notion of the | ||
| /// number of “valid” elements in the vector. Use with care. | ||
| /// | ||
| /// This function is `unsafe` because it changes the notion of the | ||
| /// number of “valid” elements in the vector. Use with care. | ||
| /// This method uses *debug assertions* to check that check that `length` is | ||
| /// not greater than the capacity. | ||
| #[inline] | ||
@@ -516,0 +516,0 @@ pub unsafe fn set_len(&mut self, length: usize) { |
Sorry, the diff of this file is not supported yet