One of the downsides with `c_str` is that it always forces an allocation, and so this could add unnecessary overhead to various calls. This PR implements one of the suggestions @graydon made in #8296 for `vec.with_c_str` in that for a short string can use a small stack array instead of a malloced array for our temporary c string. This ends up being twice as fast for small strings.
There are two things to consider before landing this commit though. First off, I arbitrarily picked the stack array as 32 bytes, and I'm not sure if this a reasonable amount or not. Second, there is a risk that someone can keep a reference to the interior stack pointer, which could cause mayhem if someone were to dereference the pointer. Since we also can easily grab and return interior pointers to vecs though, I don't think this is that much of an issue.
This now makes it unsafe to save the pointer returned by .with_c_str
as that pointer now may be pointing at a stack allocated array.
I arbitrarily chose 32 bytes as the length of the stack vector, and
so it might not be the most optimal size.
before:
test c_str::bench::bench_with_c_str_long ... bench: 539 ns/iter (+/- 91)
test c_str::bench::bench_with_c_str_medium ... bench: 97 ns/iter (+/- 2)
test c_str::bench::bench_with_c_str_short ... bench: 70 ns/iter (+/- 5)
after:
test c_str::bench::bench_with_c_str_long ... bench: 542 ns/iter (+/- 13)
test c_str::bench::bench_with_c_str_medium ... bench: 53 ns/iter (+/- 6)
test c_str::bench::bench_with_c_str_short ... bench: 19 ns/iter (+/- 0)
The current implementation uses `&v[0]` for the lifetime struct field,
but that is a dangling pointer for iterators derived from zero-length
slices.
Example:
let v: [int, ..0] = []; println!("{:?}", v.iter())
std::vec::VecIterator<,int>{ptr: (0x7f3768626100 as *()), end: (0x7f3768626100 as *()), lifetime: &139875951207128}
To replace this parameter, use a field of type `Option<&'self ()>`
that is simply initialized with `None`, but still allows the iterator to
have a lifetime parameter.
This lifts various restrictions on the runtime, for example the character limit
when logging a message. Right now the old debug!-style macros still involve
allocating (because they use fmt! syntax), but the new debug2! macros don't
involve allocating at all (unless the formatter for a type requires allocation.
If an item is skipped due to it being unreachable or for some optimization, then
it shouldn't be encoded into the metadata (because it wasn't present in the
first place).
This is broken, and results in poor performance due to the undefined
behaviour in the LLVM IR. LLVM's `mergefunc` is a *much* better way of
doing this since it merges based on the equality of the bytecode.
For example, consider `std::repr`. It generates different code per
type, but is not included in the type bounds of generics.
The `mergefunc` pass works for most of our code but currently hits an
assert on libstd. It is receiving attention upstream so it will be
ready soon, but I don't think removing this broken code should wait any
longer. I've opened #9536 about enabling it by default.
Closes#8651Closes#3547Closes#2537Closes#6971Closes#9222
If an item is skipped due to it being unreachable or for some optimization, then
it shouldn't be encoded into the metadata (because it wasn't present in the
first place).
extra::ringbuf: Implement method `.swap(uint, uint)` just like vector
RingBuf::swap(&mut self, i, j) swaps the element at indices `i` and `j`
if both elements are in bounds, otherwise it fails.
This slurps up everything inside of an 'extern' block into the enclosing module
in order to document them. The documentation must be on the items themselves,
and they'll show up next to everything else on the module index pages.
Closes#5953
This also includes a fix for yielding from single-threaded schedulers where the scheduler would stop working before its work queue was empty. Fixes the deadlocks that this patch had previously.
Fix#7752.
~~(The glob API is a little funky; I tried to make a small test for it, which I'll add to the end of this description, and its not clear whether globfree is supposed to free solely the structure allocated by glob itself, or if it is going to try to free more than that.)~~ (The previous note was a user-error: I was misusing the CString API.)
Anyway, this seems to work in terms of calling errfunc where expected.)
```rust
#[allow(unused_imports)];
use std::libc::types::os::arch::c95::{c_char, c_int, size_t};
use std::libc::funcs::posix01::glob;
use std::libc::types::os::common::posix01::glob_t;
use std::libc::consts::os::posix01::{GLOB_APPEND, GLOB_DOOFFS, GLOB_ERR,
GLOB_MARK, GLOB_NOCHECK, GLOB_NOSORT,
GLOB_NOESCAPE, GLOB_NOSPACE,
GLOB_ABORTED, GLOB_NOMATCH};
use std::ptr;
use std::c_str;
#[fixed_stack_segment]
fn main() {
let mut g = glob_t {
gl_pathc: 0, // size_t,
__unused1: 0, // c_int,
gl_offs: 2, // size_t,
__unused2: 0, // c_int,
gl_pathv: ptr::null(), // **c_char,
__unused3: ptr::null(), // *c_void,
__unused4: ptr::null(), // *c_void,
__unused5: ptr::null(), // *c_void,
__unused6: ptr::null(), // *c_void,
__unused7: ptr::null(), // *c_void,
__unused8: ptr::null(), // *c_void,
};
extern "C" fn errfunc(_epath: *c_char, _errno: int) -> int {
println!("errfunc called");
return 0;
}
struct Reduced { pathc: size_t, offs: size_t, pathv: **c_char, }
impl Reduced {
fn from(g: &glob_t) -> Reduced {
Reduced {pathc: g.gl_pathc, offs: g.gl_offs, pathv: g.gl_pathv}
}
}
do ("*.rs/*").with_c_str |pat| {
println!("calling glob");
unsafe { glob::glob(pat, GLOB_DOOFFS, errfunc, &mut g); }
println!("After glob call");
println!("g: {:?}", Reduced::from(&g));
for i in range(0, g.gl_pathc as int) {
unsafe {
let p : **c_char = ptr::offset(g.gl_pathv, g.gl_offs as int + i);
let x = c_str::CString::new(*p, false);
match x.as_str() {
Some(s) => {
println!("gl_pathc[{:d}]: {:?}", i, s);
}
None => {
println!("gl_pathc[{:d}]: unvalid", i);
}
}
}
}
}
println!("calling globfree on g: {:?}", g);
unsafe { glob::globfree(&mut g); }
println!("after globfree call");
}
```
I have tried this fix and it seems to work either with single or multiple trait inheritance.
trait Base:Base2 + Base3{
fn foo(&self);
}
trait Base2 {
fn baz(&self);
}
trait Base3{
fn root(&self);
}
trait Super: Base{
fn bar(&self);
}
struct X;
impl Base for X {
fn foo(&self) {
println("base foo");
}
}
impl Base2 for X {
fn baz(&self) {
println("base2 baz");
}
}
impl Base3 for X {
fn root(&self) {
println("base3 root");
}
}
impl Super for X {
fn bar(&self) {
println("super bar");
}
}
fn main() {
let n = X;
let s = &n as &Super;
s.bar();
s.foo(); // super bar
s.baz();
s.root();
}
bmaxa@maxa:~/examples/rust$ rustc error.rs
bmaxa@maxa:~/examples/rust$ ./error
super bar
base foo
base2 baz
base3 root