Skip to content

Commit 31be331

Browse files
committed
collections: Deprecate shift_char for insert/remove
This commit deprecates the String::shift_char() function in favor of the addition of an insert()/remove() pair of functions. This aligns the API with Vec in that characters can be inserted at arbitrary positions. Additionaly, there is no `_char` suffix due to the rationaled laid out in the previous commit. These functions are both introduced as unstable as their failure semantics, while in line with slices/vectors, are uncertain about whether they should remain the same.
1 parent 79b4ce0 commit 31be331

File tree

1 file changed

+87
-15
lines changed

1 file changed

+87
-15
lines changed

src/libcollections/string.rs

Lines changed: 87 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -727,37 +727,80 @@ impl String {
727727
self.vec.remove(0)
728728
}
729729

730-
/// Removes the first character from the string buffer and returns it.
731-
/// Returns `None` if this string buffer is empty.
730+
/// Deprecated, call `remove(0)` instead
731+
#[deprecated = "call .remove(0) instead"]
732+
pub fn shift_char(&mut self) -> Option<char> {
733+
self.remove(0)
734+
}
735+
736+
/// Removes the character from the string buffer at byte position `idx` and
737+
/// returns it. Returns `None` if `idx` is out of bounds.
732738
///
733739
/// # Warning
734740
///
735-
/// This is a O(n) operation as it requires copying every element in the buffer.
741+
/// This is a O(n) operation as it requires copying every element in the
742+
/// buffer.
743+
///
744+
/// # Failure
745+
///
746+
/// If `idx` does not lie on a character boundary, then this function will
747+
/// fail.
736748
///
737749
/// # Example
738750
///
739751
/// ```
740752
/// let mut s = String::from_str("foo");
741-
/// assert_eq!(s.shift_char(), Some('f'));
742-
/// assert_eq!(s.shift_char(), Some('o'));
743-
/// assert_eq!(s.shift_char(), Some('o'));
744-
/// assert_eq!(s.shift_char(), None);
753+
/// assert_eq!(s.remove(0), Some('f'));
754+
/// assert_eq!(s.remove(1), Some('o'));
755+
/// assert_eq!(s.remove(0), Some('o'));
756+
/// assert_eq!(s.remove(0), None);
745757
/// ```
746-
pub fn shift_char(&mut self) -> Option<char> {
758+
#[unstable = "the failure semantics of this function and return type \
759+
may change"]
760+
pub fn remove(&mut self, idx: uint) -> Option<char> {
747761
let len = self.len();
748-
if len == 0 {
749-
return None
750-
}
762+
if idx >= len { return None }
751763

752-
let CharRange {ch, next} = self.as_slice().char_range_at(0);
753-
let new_len = len - next;
764+
let CharRange { ch, next } = self.as_slice().char_range_at(idx);
754765
unsafe {
755-
ptr::copy_memory(self.vec.as_mut_ptr(), self.vec.as_ptr().offset(next as int), new_len);
756-
self.vec.set_len(new_len);
766+
ptr::copy_memory(self.vec.as_mut_ptr().offset(idx as int),
767+
self.vec.as_ptr().offset(next as int),
768+
len - next);
769+
self.vec.set_len(len - (next - idx));
757770
}
758771
Some(ch)
759772
}
760773

774+
/// Insert a character into the string buffer at byte position `idx`.
775+
///
776+
/// # Warning
777+
///
778+
/// This is a O(n) operation as it requires copying every element in the
779+
/// buffer.
780+
///
781+
/// # Failure
782+
///
783+
/// If `idx` does not lie on a character boundary or is out of bounds, then
784+
/// this function will fail.
785+
pub fn insert(&mut self, idx: uint, ch: char) {
786+
let len = self.len();
787+
assert!(idx <= len);
788+
assert!(self.as_slice().is_char_boundary(idx));
789+
self.vec.reserve_additional(4);
790+
let mut bits = [0, ..4];
791+
let amt = ch.encode_utf8(bits).unwrap();
792+
793+
unsafe {
794+
ptr::copy_memory(self.vec.as_mut_ptr().offset((idx + amt) as int),
795+
self.vec.as_ptr().offset(idx as int),
796+
len - idx);
797+
ptr::copy_memory(self.vec.as_mut_ptr().offset(idx as int),
798+
bits.as_ptr(),
799+
amt);
800+
self.vec.set_len(len + amt);
801+
}
802+
}
803+
761804
/// Views the string buffer as a mutable sequence of bytes.
762805
///
763806
/// This is unsafe because it does not check
@@ -1209,6 +1252,35 @@ mod tests {
12091252
assert_eq!(b.as_slice(), "1234522");
12101253
}
12111254

1255+
#[test]
1256+
fn remove() {
1257+
let mut s = "ศไทย中华Việt Nam; foobar".to_string();;
1258+
assert_eq!(s.remove(0), Some('ศ'));
1259+
assert_eq!(s.len(), 33);
1260+
assert_eq!(s.as_slice(), "ไทย中华Việt Nam; foobar");
1261+
assert_eq!(s.remove(33), None);
1262+
assert_eq!(s.remove(300), None);
1263+
assert_eq!(s.remove(17), Some('ệ'));
1264+
assert_eq!(s.as_slice(), "ไทย中华Vit Nam; foobar");
1265+
}
1266+
1267+
#[test] #[should_fail]
1268+
fn remove_bad() {
1269+
"ศ".to_string().remove(1);
1270+
}
1271+
1272+
#[test]
1273+
fn insert() {
1274+
let mut s = "foobar".to_string();
1275+
s.insert(0, 'ệ');
1276+
assert_eq!(s.as_slice(), "ệfoobar");
1277+
s.insert(6, 'ย');
1278+
assert_eq!(s.as_slice(), "ệfooยbar");
1279+
}
1280+
1281+
#[test] #[should_fail] fn insert_bad1() { "".to_string().insert(1, 't'); }
1282+
#[test] #[should_fail] fn insert_bad2() { "ệ".to_string().insert(1, 't'); }
1283+
12121284
#[bench]
12131285
fn bench_with_capacity(b: &mut Bencher) {
12141286
b.iter(|| {

0 commit comments

Comments
 (0)