| Age | Commit message (Collapse) | Author | Lines |
|
|
|
|
|
Prior to this commit, `str` documented that `get_unchecked` had
the precondition that "`begin` must come before `end`". This would appear
to prohibit empty slices (i.e. begin == end).
In practice, get_unchecked is called often with empty slices. Let's relax
the precondition so as to allow them.
|
|
Implement split_inclusive for slice and str
# Overview
* Implement `split_inclusive` for `slice` and `str` and `split_inclusive_mut` for `slice`
* `split_inclusive` is a substring/subslice splitting iterator that includes the matched part in the iterated substrings as a terminator.
* EDIT: The behaviour has now changed, as per @KodrAus 's input, to the same semantics with the `split_terminator` function. I updated the examples below.
* Two examples below:
```Rust
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"]);
```
```Rust
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"]);
```
# Justification for the API
* I was surprised to find that stdlib currently only has splitting iterators that leave out the matched part. In my experience, wanting to leave a substring terminator as a part of the substring is a pretty common usecase.
* This API is strictly more expressive than the standard `split` API: it's easy to get the behaviour of `split` by mapping a subslicing operation that drops the terminator. On the other hand it's impossible to derive this behaviour from `split` without using hacky and brittle `unsafe` code. The normal way to achieve this functionality would be implementing the iterator yourself.
* Especially when dealing with mutable slices, the only way currently is to use `split_at_mut`. This API provides an ergonomic alternative that plays to the strengths of the iterating capabilities of Rust. (Using `split_at_mut` iteratively used to be a real pain before NLL, fortunately the situation is a bit better now.)
# Discussion items
* <s>Does it make sense to mimic `split_terminator` in that the final empty slice would be left off in case of the string/slice ending with a terminator? It might do, as this use case is naturally geared towards considering the matching part as a terminator instead of a separator.</s>
* EDIT: The behaviour was changed to mimic `split_terminator`.
* Does it make sense to have `split_inclusive_mut` for `&mut str`?
|
|
Miscellaneous inlining improvements
These commits inline some hot functions that aren't currently inlined, for some speed wins.
r? @Centril
|
|
It only has two call sites, and the one within `from_utf8` is hot within
rustc itself.
|
|
Updating str.chars docs to mention crates.io.
This might spare someone else a little time searching the stdlib for unicode/grapheme support.
|
|
reverse iteration.
|
|
includes the matched part in the iterated substrings as a terminator.
|
|
|
|
This might spare someone else a little time searching the stdlib for unicode/grapheme support.
|
|
|
|
|
|
|
|
Co-Authored-By: Ralf Jung <post@ralfj.de>
|
|
|
|
|
|
|
|
Require issue = "none" over issue = "0" in unstable attributes
These changes make the use of `issue = "none"` required in unstable attributes throughout the compiler.
Notes:
- #66299 is now in beta so `issue = "none"` is accepted.
- The `tidy` tool now fails on `issue = "0"`.
- Tests that used `issue = "0"` were changed to use `issue = "none"`, except for _one_ that asserts `issue = "0"` can still be used.
- The compiler still allows `issue = "0"` because some submodules require it, this could be disallowed once these are updated.
Resolves #41260
r? @varkor
|
|
|
|
|
|
|
|
Improve code generated for `starts_with(<literal char>)`
This PR includes two minor improvements to the code generated when checking for string prefix/suffix.
The first commit simplifies the str/str operation, by taking advantage of the raw UTF-8 representation.
The second commit replaces the current str/char matching logic with a char->str encoding and then the previous method.
The resulting code should be equivalent in the generic case (one char is being encoded versus one char being decoded), but it becomes easy to optimize in the case of a literal char, which in most cases a developer might expect to be at least as simple as that of a literal string.
This PR should fix #41993
|
|
Add str::strip_prefix and str::strip_suffix
Introduces a counterpart for `Path::strip_prefix` on `str`.
This was also discussed in https://internals.rust-lang.org/t/pre-pr-path-strip-prefix-counterpart-in-str/11364/.
|
|
|
|
functions with a `const` modifier
|
|
|
|
This enables constant folding when matching a literal char.
Fixes #41993.
|
|
The comparison can be performed on the raw bytes, as the chars can
only match if their UTF8 encoding matches.
This avoids the `is_char_boundary` checks and translates to a straight
`u8` slice comparison which is optimized to a memcmp or inline
comparison where appropriate.
|
|
|
|
Made it the same as rmatches()
|
|
|
|
|
|
|
|
|
|
the docs are great at explaining that .len() isn't like in other
languages but stops short of explaining how to get the character length.
r? @steveklabnik
|
|
|
|
|
|
|
|
|
|
Fixes a few repetitions of "like like" in the `trim*` methods documentation of `str`.
|
|
|
|
|
|
|
|
|
|
|
|
Optimize pointer alignment in utf8 validation
This uses (and reuses) the u8 arrays's inherent block alignment when checking whether the current index is block aligned.
I initially thought that this would just move the expensive `align_offset` call out of the while loop and replace it with a subtraction and bitwise AND. But it appears this optimizes much better, too...
before: https://rust.godbolt.org/z/WIPvWl
after: https://rust.godbolt.org/z/-jBPoW
## Benchmarks
https://github.com/jridgewell/faster-from_utf8/tree/pointer-alignment
```
test from_utf8_2_bytes_fast ... bench: 310 ns/iter (+/- 42) = 1290 MB/s
test from_utf8_2_bytes_regular ... bench: 309 ns/iter (+/- 24) = 1294 MB/s
test from_utf8_3_bytes_fast ... bench: 1,027 ns/iter (+/- 62) = 1168 MB/s
test from_utf8_3_bytes_regular ... bench: 1,513 ns/iter (+/- 611) = 793 MB/s
test from_utf8_4_bytes_fast ... bench: 1,788 ns/iter (+/- 26) = 1342 MB/s
test from_utf8_4_bytes_regular ... bench: 1,907 ns/iter (+/- 181) = 1258 MB/s
test from_utf8_all_bytes_fast ... bench: 3,463 ns/iter (+/- 97) = 1155 MB/s
test from_utf8_all_bytes_regular ... bench: 4,083 ns/iter (+/- 89) = 979 MB/s
test from_utf8_ascii_fast ... bench: 88 ns/iter (+/- 4) = 28988 MB/s
test from_utf8_ascii_regular ... bench: 88 ns/iter (+/- 8) = 28988 MB/s
test from_utf8_cyr_fast ... bench: 7,707 ns/iter (+/- 531) = 665 MB/s
test from_utf8_cyr_regular ... bench: 8,202 ns/iter (+/- 135) = 625 MB/s
test from_utf8_enwik8_fast ... bench: 1,135,756 ns/iter (+/- 84,450) = 8804 MB/s
test from_utf8_enwik8_regular ... bench: 1,145,468 ns/iter (+/- 79,601) = 8730 MB/s
test from_utf8_jawik10_fast ... bench: 12,723,844 ns/iter (+/- 473,247) = 785 MB/s
test from_utf8_jawik10_regular ... bench: 13,384,596 ns/iter (+/- 666,997) = 747 MB/s
test from_utf8_mixed_fast ... bench: 2,321 ns/iter (+/- 123) = 2081 MB/s
test from_utf8_mixed_regular ... bench: 2,702 ns/iter (+/- 408) = 1788 MB/s
test from_utf8_mostlyasc_fast ... bench: 249 ns/iter (+/- 10) = 14666 MB/s
test from_utf8_mostlyasc_regular ... bench: 276 ns/iter (+/- 5) = 13231 MB/s
```
|
|
|
|
When possible without changing semantics, implement Iterator::last in terms of DoubleEndedIterator::next_back for types in liballoc and libcore.
Provided that the iterator has finite length and does not trigger user-provided code, this is safe.
What follows is a full list of the DoubleEndedIterators in liballoc/libcore and whether this optimization is safe, and if not, why not.
src/liballoc/boxed.rs
Box: Pass through to avoid defeating optimization of the underlying DoubleIterator implementation. This has no correctness impact.
src/liballoc/collections/binary_heap.rs
Iter: Pass through to avoid defeating optimizations on slice::Iter
IntoIter: Not safe, changes Drop order
Drain: Not safe, changes Drop order
src/liballoc/collections/btree/map.rs
Iter: Safe to call next_back, invokes no user defined code.
IterMut: ditto
IntoIter: Not safe, changes Drop order
Keys: Safe to call next_back, invokes no user defined code.
Values: ditto
ValuesMut: ditto
Range: ditto
RangeMut: ditto
src/liballoc/collections/btree/set.rs
Iter: Safe to call next_back, invokes no user defined code.
IntoIter: Not safe, changes Drop order
Range: Safe to call next_back, invokes no user defined code.
src/liballoc/collections/linked_list.rs
Iter: Safe to call next_back, invokes no user defined code.
IterMut: ditto
IntoIter: Not safe, changes Drop order
src/liballoc/collections/vec_deque.rs
Iter: Safe to call next_back, invokes no user defined code.
IterMut: ditto
IntoIter: Not safe, changes Drop order
Drain: ditto
src/liballoc/string.rs
Drain: Safe because return type is a primitive (char)
src/liballoc/vec.rs
IntoIter: Not safe, changes Drop order
Drain: ditto
Splice: ditto
src/libcore/ascii.rs
EscapeDefault: Safe because return type is a primitive (u8)
src/libcore/iter/adapters/chain.rs
Chain: Not safe, invokes user defined code (Iterator impl)
src/libcore/iter/adapters/flatten.rs
FlatMap: Not safe, invokes user defined code (Iterator impl)
Flatten: ditto
FlattenCompat: ditto
src/libcore/iter/adapters/mod.rs
Rev: Not safe, invokes user defined code (Iterator impl)
Copied: ditto
Cloned: Not safe, invokes user defined code (Iterator impl and T::clone)
Map: Not safe, invokes user defined code (Iterator impl + closure)
Filter: ditto
FilterMap: ditto
Enumerate: Not safe, invokes user defined code (Iterator impl)
Skip: ditto
Fuse: ditto
Inspect: ditto
src/libcore/iter/adapters/zip.rs
Zip: Not safe, invokes user defined code (Iterator impl)
src/libcore/iter/range.rs
ops::Range: Not safe, changes Drop order, but ALREADY HAS SPECIALIZATION
ops::RangeInclusive: ditto
src/libcore/iter/sources.rs
Repeat: Not safe, calling last should iloop.
Empty: No point, iterator is at most one item long.
Once: ditto
OnceWith: ditto
src/libcore/option.rs
Item: No point, iterator is at most one item long.
Iter: ditto
IterMut: ditto
IntoIter: ditto
src/libcore/result.rs
Iter: No point, iterator is at most one item long
IterMut: ditto
IntoIter: ditto
src/libcore/slice/mod.rs
Split: Not safe, invokes user defined closure
SplitMut: ditto
RSplit: ditto
RSplitMut: ditto
Windows: Safe, already has specialization
Chunks: ditto
ChunksMut: ditto
ChunksExact: ditto
ChunksExactMut: ditto
RChunks: ditto
RChunksMut: ditto
RChunksExact: ditto
RChunksExactMut: ditto
src/libcore/str/mod.rs
Chars: Safe, already has specialization
CharIndices: ditto
Bytes: ditto
Lines: Safe to call next_back, invokes no user defined code.
LinesAny: Deprecated
Everything that is generic over P: Pattern: Not safe because Pattern invokes user defined code.
SplitWhitespace: Safe to call next_back, invokes no user defined code.
SplitAsciiWhitespace: ditto
This is attempt 2 of #60130.
r? @sfackler
|
|
Introduced by #58005
|