diff --git a/AUTHORS.txt b/AUTHORS.txt index 83d8d9ef0c8b5..0f20e510adcd8 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -518,6 +518,7 @@ Luke Francl Luke Metz Luke Steensen Luqman Aden +Łukasz Niemier Magnus Auvinen Mahmut Bulut Makoto Nakashima @@ -997,5 +998,4 @@ xales zofrex zslayton zzmp -Łukasz Niemier 克雷 diff --git a/configure b/configure index 9aebfe07967d9..9b9de9da06716 100755 --- a/configure +++ b/configure @@ -19,6 +19,11 @@ err() { exit 1 } +run() { + msg "$@" + "$@" +} + need_ok() { if [ $? -ne 0 ] then @@ -36,8 +41,7 @@ need_cmd() { make_dir() { if [ ! -d $1 ] then - msg "mkdir -p $1" - mkdir -p $1 + run mkdir -p $1 fi } @@ -46,8 +50,7 @@ copy_if_changed() { then msg "leaving $2 unchanged" else - msg "cp $1 $2" - cp -f $1 $2 + run cp -f $1 $2 chmod u-w $2 # make copied artifact read-only fi } @@ -57,8 +60,7 @@ move_if_changed() { then msg "leaving $2 unchanged" else - msg "mv $1 $2" - mv -f $1 $2 + run mv -f $1 $2 chmod u-w $2 # make moved artifact read-only fi } @@ -733,6 +735,20 @@ then probe CFG_JAVAC javac fi +# the valgrind rpass tests will fail if you don't have a valgrind, but they're +# only disabled if you opt out. +if [ -z "$CFG_VALGRIND" ] +then + # If the user has explicitly asked for valgrind tests, then fail + if [ -n "$CFG_ENABLE_VALGRIND" ] && [ -n "$CFG_ENABLE_VALGRIND_PROVIDED" ] + then + err "No valgrind present, but valgrind tests explicitly requested" + else + CFG_DISABLE_VALGRIND_RPASS=1 + putvar CFG_DISABLE_VALGRIND_RPASS + fi +fi + if [ ! -z "$CFG_GDB" ] then # Store GDB's version @@ -844,7 +860,7 @@ then CFG_OSX_GCC_VERSION=$("$CFG_GCC" --version 2>&1 | grep "Apple LLVM version") if [ $? -eq 0 ] then - step_msg "on OS X 10.9, forcing use of clang" + step_msg "on OS X >=10.9, forcing use of clang" CFG_ENABLE_CLANG=1 else if [ $("$CFG_GCC" --version 2>&1 | grep -c ' 4\.[0-6]') -ne 0 ]; then diff --git a/mk/dist.mk b/mk/dist.mk index 57adaee51980b..75c6219c5f04f 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -52,6 +52,7 @@ PKG_FILES := \ doc \ driver \ etc \ + error-index-generator \ $(foreach crate,$(CRATES),lib$(crate)) \ libcollectionstest \ libcoretest \ diff --git a/mk/main.mk b/mk/main.mk index 9ac96aa90f6b9..738580cb5b5e0 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -195,6 +195,7 @@ ifndef CFG_DISABLE_VALGRIND_RPASS $(info cfg: valgrind-rpass command set to $(CFG_VALGRIND)) CFG_VALGRIND_RPASS :=$(CFG_VALGRIND) else + $(info cfg: disabling valgrind run-pass tests) CFG_VALGRIND_RPASS := endif diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 2ee391a937433..3ff7f3cc70ada 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -226,7 +226,7 @@ pub fn run_tests(config: &Config) { } // android debug-info test uses remote debugger - // so, we test 1 task at once. + // so, we test 1 thread at once. // also trying to isolate problems with adb_run_wrapper.sh ilooping env::set_var("RUST_TEST_THREADS","1"); } @@ -234,7 +234,7 @@ pub fn run_tests(config: &Config) { match config.mode { DebugInfoLldb => { // Some older versions of LLDB seem to have problems with multiple - // instances running in parallel, so only run one test task at a + // instances running in parallel, so only run one test thread at a // time. env::set_var("RUST_TEST_THREADS", "1"); } diff --git a/src/doc/complement-design-faq.md b/src/doc/complement-design-faq.md index 1a0155d4773ec..fb157c65d957b 100644 --- a/src/doc/complement-design-faq.md +++ b/src/doc/complement-design-faq.md @@ -96,7 +96,7 @@ code should need to run is a stack. possibility is covered by the `match`, adding further variants to the `enum` in the future will prompt a compilation failure, rather than runtime panic. Second, it makes cost explicit. In general, the only safe way to have a -non-exhaustive match would be to panic the task if nothing is matched, though +non-exhaustive match would be to panic the thread if nothing is matched, though it could fall through if the type of the `match` expression is `()`. This sort of hidden cost and special casing is against the language's philosophy. It's easy to ignore certain cases by using the `_` wildcard: diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index 92e2fd93df406..e51e7d414a891 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -62,15 +62,15 @@ Data values in the language can only be constructed through a fixed set of initi * There is no global inter-crate namespace; all name management occurs within a crate. * Using another crate binds the root of _its_ namespace into the user's namespace. -## Why is panic unwinding non-recoverable within a task? Why not try to "catch exceptions"? +## Why is panic unwinding non-recoverable within a thread? Why not try to "catch exceptions"? -In short, because too few guarantees could be made about the dynamic environment of the catch block, as well as invariants holding in the unwound heap, to be able to safely resume; we believe that other methods of signalling and logging errors are more appropriate, with tasks playing the role of a "hard" isolation boundary between separate heaps. +In short, because too few guarantees could be made about the dynamic environment of the catch block, as well as invariants holding in the unwound heap, to be able to safely resume; we believe that other methods of signalling and logging errors are more appropriate, with threads playing the role of a "hard" isolation boundary between separate heaps. Rust provides, instead, three predictable and well-defined options for handling any combination of the three main categories of "catch" logic: * Failure _logging_ is done by the integrated logging subsystem. -* _Recovery_ after a panic is done by trapping a task panic from _outside_ - the task, where other tasks are known to be unaffected. +* _Recovery_ after a panic is done by trapping a thread panic from _outside_ + the thread, where other threads are known to be unaffected. * _Cleanup_ of resources is done by RAII-style objects with destructors. Cleanup through RAII-style destructors is more likely to work than in catch blocks anyways, since it will be better tested (part of the non-error control paths, so executed all the time). @@ -91,8 +91,8 @@ We don't know if there's an obvious, easy, efficient, stock-textbook way of supp There's a lot of debate on this topic; it's easy to find a proponent of default-sync or default-async communication, and there are good reasons for either. Our choice rests on the following arguments: -* Part of the point of isolating tasks is to decouple tasks from one another, such that assumptions in one task do not cause undue constraints (or bugs, if violated!) in another. Temporal coupling is as real as any other kind; async-by-default relaxes the default case to only _causal_ coupling. -* Default-async supports buffering and batching communication, reducing the frequency and severity of task-switching and inter-task / inter-domain synchronization. +* Part of the point of isolating threads is to decouple threads from one another, such that assumptions in one thread do not cause undue constraints (or bugs, if violated!) in another. Temporal coupling is as real as any other kind; async-by-default relaxes the default case to only _causal_ coupling. +* Default-async supports buffering and batching communication, reducing the frequency and severity of thread-switching and inter-thread / inter-domain synchronization. * Default-async with transmittable channels is the lowest-level building block on which more-complex synchronization topologies and strategies can be built; it is not clear to us that the majority of cases fit the 2-party full-synchronization pattern rather than some more complex multi-party or multi-stage scenario. We did not want to force all programs to pay for wiring the former assumption into all communications. ## Why are channels half-duplex (one-way)? diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 80a4b63cc5f79..4897b27dec35d 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -329,7 +329,7 @@ view_item : extern_crate_decl | use_decl ; ```antlr extern_crate_decl : "extern" "crate" crate_name -crate_name: ident | ( string_lit as ident ) +crate_name: ident | ( ident "as" ident ) ``` ##### Use declarations @@ -789,8 +789,8 @@ bound := path | lifetime ### Boxes -## Tasks +## Threads -### Communication between tasks +### Communication between threads -### Task lifecycle +### Thread lifecycle diff --git a/src/doc/reference.md b/src/doc/reference.md index ac65b93445572..16fdcfa301392 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -752,11 +752,10 @@ provided in the `extern_crate_decl`. The external crate is resolved to a specific `soname` at compile time, and a runtime linkage requirement to that `soname` is passed to the linker for loading at runtime. The `soname` is resolved at compile time by scanning the -compiler's library path and matching the optional `crateid` provided as a -string literal against the `crateid` attributes that were declared on the -external crate when it was compiled. If no `crateid` is provided, a default -`name` attribute is assumed, equal to the `ident` given in the -`extern_crate_decl`. +compiler's library path and matching the optional `crateid` provided against +the `crateid` attributes that were declared on the external crate when it was +compiled. If no `crateid` is provided, a default `name` attribute is assumed, +equal to the `ident` given in the `extern_crate_decl`. Three examples of `extern crate` declarations: @@ -2029,7 +2028,7 @@ makes it possible to declare these operations. For example, the `str` module in the Rust standard library defines the string equality function: ```{.ignore} -#[lang="str_eq"] +#[lang = "str_eq"] pub fn eq_slice(a: &str, b: &str) -> bool { // details elided } @@ -3636,7 +3635,7 @@ that have since been removed): * ML Kit, Cyclone: region based memory management * Haskell (GHC): typeclasses, type families * Newsqueak, Alef, Limbo: channels, concurrency -* Erlang: message passing, task failure, ~~linked task failure~~, +* Erlang: message passing, thread failure, ~~linked thread failure~~, ~~lightweight concurrency~~ * Swift: optional bindings * Scheme: hygienic macros diff --git a/src/doc/style/errors/handling.md b/src/doc/style/errors/handling.md index cc5b5b475769c..9b8a00d73665b 100644 --- a/src/doc/style/errors/handling.md +++ b/src/doc/style/errors/handling.md @@ -1,7 +1,7 @@ % Handling errors -### Use task isolation to cope with failure. [FIXME] +### Use thread isolation to cope with failure. [FIXME] -> **[FIXME]** Explain how to isolate tasks and detect task failure for recovery. +> **[FIXME]** Explain how to isolate threads and detect thread failure for recovery. ### Consuming `Result` [FIXME] diff --git a/src/doc/style/errors/signaling.md b/src/doc/style/errors/signaling.md index 95db4f8afa03c..24cd5957f8aac 100644 --- a/src/doc/style/errors/signaling.md +++ b/src/doc/style/errors/signaling.md @@ -11,13 +11,13 @@ Errors fall into one of three categories: The basic principle of the convention is that: * Catastrophic errors and programming errors (bugs) can and should only be -recovered at a *coarse grain*, i.e. a task boundary. +recovered at a *coarse grain*, i.e. a thread boundary. * Obstructions preventing an operation should be reported at a maximally *fine grain* -- to the immediate invoker of the operation. ## Catastrophic errors -An error is _catastrophic_ if there is no meaningful way for the current task to +An error is _catastrophic_ if there is no meaningful way for the current thread to continue after the error occurs. Catastrophic errors are _extremely_ rare, especially outside of `libstd`. @@ -28,7 +28,7 @@ Catastrophic errors are _extremely_ rare, especially outside of `libstd`. For errors like stack overflow, Rust currently aborts the process, but could in principle panic, which (in the best case) would allow -reporting and recovery from a supervisory task. +reporting and recovery from a supervisory thread. ## Contract violations @@ -44,7 +44,7 @@ existing borrows have been relinquished. A contract violation is always a bug, and for bugs we follow the Erlang philosophy of "let it crash": we assume that software *will* have bugs, and we -design coarse-grained task boundaries to report, and perhaps recover, from these +design coarse-grained thread boundaries to report, and perhaps recover, from these bugs. ### Contract design diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md index 94eda59b95b65..8f721a9767672 100644 --- a/src/doc/style/ownership/builders.md +++ b/src/doc/style/ownership/builders.md @@ -23,7 +23,7 @@ If `T` is such a data structure, consider introducing a `T` _builder_: 4. The builder should provide one or more "_terminal_" methods for actually building a `T`. The builder pattern is especially appropriate when building a `T` involves side -effects, such as spawning a task or launching a process. +effects, such as spawning a thread or launching a process. In Rust, there are two variants of the builder pattern, differing in the treatment of ownership, as described below. @@ -115,24 +115,24 @@ Sometimes builders must transfer ownership when constructing the final type `T`, meaning that the terminal methods must take `self` rather than `&self`: ```rust -// A simplified excerpt from std::task::TaskBuilder +// A simplified excerpt from std::thread::Builder -impl TaskBuilder { - /// Name the task-to-be. Currently the name is used for identification +impl ThreadBuilder { + /// Name the thread-to-be. Currently the name is used for identification /// only in failure messages. - pub fn named(mut self, name: String) -> TaskBuilder { + pub fn named(mut self, name: String) -> ThreadBuilder { self.name = Some(name); self } - /// Redirect task-local stdout. - pub fn stdout(mut self, stdout: Box) -> TaskBuilder { + /// Redirect thread-local stdout. + pub fn stdout(mut self, stdout: Box) -> ThreadBuilder { self.stdout = Some(stdout); // ^~~~~~ this is owned and cannot be cloned/re-used self } - /// Creates and executes a new child task. + /// Creates and executes a new child thread. pub fn spawn(self, f: proc():Send) { // consume self ... @@ -141,7 +141,7 @@ impl TaskBuilder { ``` Here, the `stdout` configuration involves passing ownership of a `Writer`, -which must be transferred to the task upon construction (in `spawn`). +which must be transferred to the thread upon construction (in `spawn`). When the terminal methods of the builder require ownership, there is a basic tradeoff: @@ -158,17 +158,17 @@ builder methods for a consuming builder should take and returned an owned ```rust // One-liners -TaskBuilder::new().named("my_task").spawn(proc() { ... }); +ThreadBuilder::new().named("my_thread").spawn(proc() { ... }); // Complex configuration -let mut task = TaskBuilder::new(); -task = task.named("my_task_2"); // must re-assign to retain ownership +let mut thread = ThreadBuilder::new(); +thread = thread.named("my_thread_2"); // must re-assign to retain ownership if reroute { - task = task.stdout(mywriter); + thread = thread.stdout(mywriter); } -task.spawn(proc() { ... }); +thread.spawn(proc() { ... }); ``` One-liners work as before, because ownership is threaded through each of the diff --git a/src/doc/style/ownership/destructors.md b/src/doc/style/ownership/destructors.md index 8f58aa6c6d2f1..1cfcd78d20da8 100644 --- a/src/doc/style/ownership/destructors.md +++ b/src/doc/style/ownership/destructors.md @@ -8,7 +8,7 @@ go out of scope. ### Destructors should not fail. [FIXME: needs RFC] -Destructors are executed on task failure, and in that context a failing +Destructors are executed on thread failure, and in that context a failing destructor causes the program to abort. Instead of failing in a destructor, provide a separate method for checking for diff --git a/src/doc/style/style/comments.md b/src/doc/style/style/comments.md index 347750ce6020d..b2d2d9ab6b4d6 100644 --- a/src/doc/style/style/comments.md +++ b/src/doc/style/style/comments.md @@ -5,7 +5,7 @@ Use line comments: ``` rust -// Wait for the main task to return, and set the process error code +// Wait for the main thread to return, and set the process error code // appropriately. ``` @@ -13,7 +13,7 @@ Instead of: ``` rust /* - * Wait for the main task to return, and set the process error code + * Wait for the main thread to return, and set the process error code * appropriately. */ ``` @@ -55,7 +55,7 @@ For example: /// Sets up a default runtime configuration, given compiler-supplied arguments. /// /// This function will block until the entire pool of M:N schedulers has -/// exited. This function also requires a local task to be available. +/// exited. This function also requires a local thread to be available. /// /// # Arguments /// @@ -64,7 +64,7 @@ For example: /// * `main` - The initial procedure to run inside of the M:N scheduling pool. /// Once this procedure exits, the scheduling pool will begin to shut /// down. The entire pool (and this function) will only return once -/// all child tasks have finished executing. +/// all child threads have finished executing. /// /// # Return value /// diff --git a/src/doc/style/style/naming/containers.md b/src/doc/style/style/naming/containers.md index 04204f0f88aec..dfed4f9f75a58 100644 --- a/src/doc/style/style/naming/containers.md +++ b/src/doc/style/style/naming/containers.md @@ -5,7 +5,7 @@ they enclose. Accessor methods often have variants to access the data by value, by reference, and by mutable reference. In general, the `get` family of methods is used to access contained -data without any risk of task failure; they return `Option` as +data without any risk of thread failure; they return `Option` as appropriate. This name is chosen rather than names like `find` or `lookup` because it is appropriate for a wider range of container types. diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index 3c64e0b14de42..d6590e956a841 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -6,7 +6,7 @@ and more cores, yet many programmers aren't prepared to fully utilize them. Rust's memory safety features also apply to its concurrency story too. Even concurrent Rust programs must be memory safe, having no data races. Rust's type -system is up to the task, and gives you powerful ways to reason about +system is up to the thread, and gives you powerful ways to reason about concurrent code at compile time. Before we talk about the concurrency features that come with Rust, it's important diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index e4809214bd48e..95b39a660636a 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -214,7 +214,7 @@ we can use the `unwrap()` method: io::stdin().read_line(&mut buffer).unwrap(); ``` -`unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give +`unwrap()` will `panic!` if the `Result` is `Err`. This basically says "Give me the value, and if something goes wrong, just crash." This is less reliable than matching the error and attempting to recover, but is also significantly shorter. Sometimes, just crashing is appropriate. diff --git a/src/doc/trpl/guessing-game.md b/src/doc/trpl/guessing-game.md index 6b58f7dfde817..12dd087f20c09 100644 --- a/src/doc/trpl/guessing-game.md +++ b/src/doc/trpl/guessing-game.md @@ -131,7 +131,9 @@ prints a [string][strings] to the screen. let mut guess = String::new(); ``` -Now we’re getting interesting! There’s a lot going on in this little line. The first thing to notice is that this is a [let statement][let], which is used to create ‘variable bindings’. They take this form: +Now we’re getting interesting! There’s a lot going on in this little line. +The first thing to notice is that this is a [let statement][let], which is +used to create ‘variable bindings’. They take this form: ```rust,ignore let foo = bar; @@ -171,7 +173,7 @@ bound to: `String::new()`. [string]: ../std/string/struct.String.html -The `::new()` syntax is uses `::` because this is an ‘associated function’ of +The `::new()` syntax uses `::` because this is an ‘associated function’ of a particular type. That is to say, it’s associated with `String` itself, rather than a particular instance of a `String`. Some languages call this a ‘static method’. @@ -358,11 +360,10 @@ rand="0.3.0" The `[dependencies]` section of `Cargo.toml` is like the `[package]` section: everything that follows it is part of it, until the next section starts. Cargo uses the dependencies section to know what dependencies on external -crates you have, and what versions you require. In this case, we’ve used `*`, -which means that we’ll use the latest version of `rand`. Cargo understands -[Semantic Versioning][semver], which is a standard for writing version -numbers. If we wanted a specific version or range of versions, we could be -more specific here. [Cargo’s documentation][cargodoc] contains more details. +crates you have, and what versions you require. In this case, we’ve used version `0.3.0`. +Cargo understands [Semantic Versioning][semver], which is a standard for writing version +numbers. If we wanted to use the latest version we could use `*` or we could use a range +of versions. [Cargo’s documentation][cargodoc] contains more details. [semver]: http://semver.org [cargodoc]: http://doc.crates.io/crates-io.html @@ -410,7 +411,7 @@ $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ``` -So, we told Cargo we wanted any version of `rand`, and so it fetched the latest +So, we told Cargo we wanted any `0.3.x` version of `rand`, and so it fetched the latest version at the time this was written, `v0.3.8`. But what happens when next week, version `v0.3.9` comes out, with an important bugfix? While getting bugfixes is important, what if `0.3.9` contains a regression that breaks our @@ -712,7 +713,7 @@ variety of numbers, we need to give Rust a hint as to the exact type of number we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust we’re going to annotate its type. `u32` is an unsigned, thirty-two bit integer. Rust has [a number of built-in number types][number], but we’ve -chosen `u32`. It’s a good default choice for a small positive numer. +chosen `u32`. It’s a good default choice for a small positive number. [parse]: ../std/primitive.str.html#method.parse [number]: primitive-types.html#numeric-types @@ -921,7 +922,7 @@ failure. Each contains more information: the successful parsed integer, or an error type. In this case, we `match` on `Ok(num)`, which sets the inner value of the `Ok` to the name `num`, and then we just return it on the right-hand side. In the `Err` case, we don’t care what kind of error it is, so we just -use `_` intead of a name. This ignores the error, and `continue` causes us +use `_` instead of a name. This ignores the error, and `continue` causes us to go to the next iteration of the `loop`. Now we should be good! Let’s try: diff --git a/src/doc/trpl/iterators.md b/src/doc/trpl/iterators.md index 76f6a4243a062..abb14a6020524 100644 --- a/src/doc/trpl/iterators.md +++ b/src/doc/trpl/iterators.md @@ -42,7 +42,7 @@ loop is just a handy way to write this `loop`/`match`/`break` construct. `for` loops aren't the only thing that uses iterators, however. Writing your own iterator involves implementing the `Iterator` trait. While doing that is outside of the scope of this guide, Rust provides a number of useful iterators -to accomplish various tasks. Before we talk about those, we should talk about a +to accomplish various threads. Before we talk about those, we should talk about a Rust anti-pattern. And that's using ranges like this. Yes, we just talked about how ranges are cool. But ranges are also very diff --git a/src/doc/trpl/lang-items.md b/src/doc/trpl/lang-items.md index 5c27c03e8e0b2..4808ad6ff1feb 100644 --- a/src/doc/trpl/lang-items.md +++ b/src/doc/trpl/lang-items.md @@ -7,7 +7,7 @@ The `rustc` compiler has certain pluggable operations, that is, functionality that isn't hard-coded into the language, but is implemented in libraries, with a special marker to tell the compiler -it exists. The marker is the attribute `#[lang="..."]` and there are +it exists. The marker is the attribute `#[lang = "..."]` and there are various different values of `...`, i.e. various different 'lang items'. @@ -28,7 +28,7 @@ extern { #[lang = "owned_box"] pub struct Box(*mut T); -#[lang="exchange_malloc"] +#[lang = "exchange_malloc"] unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { let p = libc::malloc(size as libc::size_t) as *mut u8; @@ -39,7 +39,7 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { p } -#[lang="exchange_free"] +#[lang = "exchange_free"] unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) { libc::free(ptr as *mut libc::c_void) } diff --git a/src/doc/trpl/lifetimes.md b/src/doc/trpl/lifetimes.md index 981286c82d798..86164a08a430f 100644 --- a/src/doc/trpl/lifetimes.md +++ b/src/doc/trpl/lifetimes.md @@ -116,7 +116,7 @@ fn main() { } ``` -[struct]: structs.html +[structs]: structs.html As you can see, `struct`s can also have lifetimes. In a similar way to functions, diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md index 2c0c8ea73c03c..86b9445338966 100644 --- a/src/doc/trpl/match.md +++ b/src/doc/trpl/match.md @@ -50,7 +50,7 @@ side of a `let` binding or directly where an expression is used: ```rust let x = 5; -let numer = match x { +let number = match x { 1 => "one", 2 => "two", 3 => "three", diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index ed4e9dd359b6d..c5dd25516f319 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -129,7 +129,7 @@ circle to any arbitrary size. # Static methods -You can also define methods that do not take a `self` parameter. Here’s a +You can also define static methods that do not take a `self` parameter. Here’s a pattern that’s very common in Rust code: ``` @@ -188,7 +188,7 @@ struct CircleBuilder { impl CircleBuilder { fn new() -> CircleBuilder { - CircleBuilder { x: 0.0, y: 0.0, radius: 0.0, } + CircleBuilder { x: 0.0, y: 0.0, radius: 1.0, } } fn x(&mut self, coordinate: f64) -> &mut CircleBuilder { diff --git a/src/doc/trpl/mutability.md b/src/doc/trpl/mutability.md index 816bfb1797061..9b386acdca214 100644 --- a/src/doc/trpl/mutability.md +++ b/src/doc/trpl/mutability.md @@ -78,14 +78,14 @@ When we call `clone()`, the `Arc` needs to update the reference count. Yet we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take `&mut 5` or anything. So what gives? -To this, we have to go back to the core of Rust’s guiding philosophy, memory -safety, and the mechanism by which Rust guarantees it, the +To understand this, we have to go back to the core of Rust’s guiding +philosophy, memory safety, and the mechanism by which Rust guarantees it, the [ownership][ownership] system, and more specifically, [borrowing][borrowing]: > You may have one or the other of these two kinds of borrows, but not both at > the same time: > -> * 0 to N references (`&T`) to a resource. +> * one or more references (`&T`) to a resource. > * exactly one mutable reference (`&mut T`) [ownership]: ownership.html diff --git a/src/doc/trpl/ownership.md b/src/doc/trpl/ownership.md index 3003156f875aa..971bb7cd700db 100644 --- a/src/doc/trpl/ownership.md +++ b/src/doc/trpl/ownership.md @@ -3,7 +3,7 @@ This guide is one of three presenting Rust’s ownership system. This is one of Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, -memory safety. The there are a few distinct concepts, each with its own +memory safety. There are a few distinct concepts, each with its own chapter: * ownership, which you’re reading now. @@ -59,6 +59,7 @@ deterministically, at the end of the scope. [vect]: ../std/vec/struct.Vec.html [heap]: the-stack-and-the-heap.html +[bindings]: variable-bindings.html # Move semantics @@ -122,7 +123,7 @@ let v2 = v; The first line creates some data for the vector on the [stack][sh], `v`. The vector’s data, however, is stored on the [heap][sh], and so it contains a -pointer to that data. When we move `v` to `v2`, it creates a copy of that data, +pointer to that data. When we move `v` to `v2`, it creates a copy of that pointer, for `v2`. Which would mean two pointers to the contents of the vector on the heap. That would be a problem: it would violate Rust’s safety guarantees by introducing a data race. Therefore, Rust forbids using `v` after we’ve done the @@ -173,7 +174,7 @@ fn foo(v: Vec) -> Vec { } ``` -This would get very tedius. It gets worse the more things we want to take ownership of: +This would get very tedious. It gets worse the more things we want to take ownership of: ```rust fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) { diff --git a/src/doc/trpl/primitive-types.md b/src/doc/trpl/primitive-types.md index e017e222c7417..bb2bf028700d2 100644 --- a/src/doc/trpl/primitive-types.md +++ b/src/doc/trpl/primitive-types.md @@ -176,7 +176,7 @@ Slices have type `&[T]`. We’ll talk about that `T` when we cover [generics]: generics.html -You can find more documentation for `slices`s [in the standard library +You can find more documentation for slices [in the standard library documentation][slice]. [slice]: ../std/primitive.slice.html diff --git a/src/doc/trpl/references-and-borrowing.md b/src/doc/trpl/references-and-borrowing.md index 82533becef342..da416e994c4c5 100644 --- a/src/doc/trpl/references-and-borrowing.md +++ b/src/doc/trpl/references-and-borrowing.md @@ -3,7 +3,7 @@ This guide is one of three presenting Rust’s ownership system. This is one of Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, -memory safety. The there are a few distinct concepts, each with its own +memory safety. There are a few distinct concepts, each with its own chapter: * [ownership][ownership], ownership, the key concept diff --git a/src/doc/trpl/traits.md b/src/doc/trpl/traits.md index ea5d2ed711fed..51ee4bf0cdc28 100644 --- a/src/doc/trpl/traits.md +++ b/src/doc/trpl/traits.md @@ -192,7 +192,7 @@ Here’s the error: ```text error: type `std::fs::File` does not implement any method in scope named `write` -let result = f.write(b”whatever”); +let result = f.write(b"whatever"); ^~~~~~~~~~~~~~~~~~ ``` diff --git a/src/etc/CONFIGS.md b/src/etc/CONFIGS.md index 036a2f7d4365b..74837a06faecd 100644 --- a/src/etc/CONFIGS.md +++ b/src/etc/CONFIGS.md @@ -1,6 +1,8 @@ # Configs -Here are some links to repos with configs which ease the use of rust: +These are some links to repos with configs which ease the use of rust. + +## Officially Maintained Configs * [rust.vim](https://github.com/rust-lang/rust.vim) * [emacs rust-mode](https://github.com/rust-lang/rust-mode) @@ -8,3 +10,7 @@ Here are some links to repos with configs which ease the use of rust: * [kate-config](https://github.com/rust-lang/kate-config) * [nano-config](https://github.com/rust-lang/nano-config) * [zsh-config](https://github.com/rust-lang/zsh-config) + +## Community-maintained Configs + +* [.editorconfig](https://gist.github.com/derhuerst/c9d1b9309e308d9851fa) ([what is this?](http://editorconfig.org/)) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index ab7030bee1554..8c3c21a89023d 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -31,7 +31,7 @@ //! //! # Examples //! -//! Sharing some immutable data between tasks: +//! Sharing some immutable data between threads: //! //! ```no_run //! use std::sync::Arc; @@ -48,7 +48,7 @@ //! } //! ``` //! -//! Sharing mutable data safely between tasks with a `Mutex`: +//! Sharing mutable data safely between threads with a `Mutex`: //! //! ```no_run //! use std::sync::{Arc, Mutex}; @@ -89,9 +89,9 @@ use heap::deallocate; /// /// # Examples /// -/// In this example, a large vector of floats is shared between several tasks. +/// In this example, a large vector of floats is shared between several threads. /// With simple pipes, without `Arc`, a copy would have to be made for each -/// task. +/// thread. /// /// When you clone an `Arc`, it will create another pointer to the data and /// increase the reference counter. diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 86a04a0687a5b..83795a24c8160 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -95,7 +95,7 @@ pub const EMPTY: *mut () = 0x1 as *mut (); /// The allocator for unique pointers. #[cfg(not(test))] -#[lang="exchange_malloc"] +#[lang = "exchange_malloc"] #[inline] unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { if size == 0 { @@ -108,7 +108,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { } #[cfg(not(test))] -#[lang="exchange_free"] +#[lang = "exchange_free"] #[inline] unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) { deallocate(ptr, old_size, align); diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index c0974dcb2a0f0..473429b813c50 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -26,14 +26,14 @@ //! There can only be one owner of a `Box`, and the owner can decide to mutate //! the contents, which live on the heap. //! -//! This type can be sent among tasks efficiently as the size of a `Box` value +//! This type can be sent among threads efficiently as the size of a `Box` value //! is the same as that of a pointer. Tree-like data structures are often built //! with boxes because each node often has only one owner, the parent. //! //! ## Reference counted pointers //! //! The [`Rc`](rc/index.html) type is a non-threadsafe reference-counted pointer -//! type intended for sharing memory within a task. An `Rc` pointer wraps a +//! type intended for sharing memory within a thread. An `Rc` pointer wraps a //! type, `T`, and only allows access to `&T`, a shared reference. //! //! This type is useful when inherited mutability (such as using `Box`) is too diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 1271a6276aec9..17e937c5af257 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -644,6 +644,10 @@ impl BitVec { /// Splits the `BitVec` into two at the given bit, /// retaining the first half in-place and returning the second one. /// + /// # Panics + /// + /// Panics if `at` is out of bounds. + /// /// # Examples /// /// ``` diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 8eb7995c42218..b9e9800f7a0e7 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -80,7 +80,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use alloc::boxed::Box; -use core::convert::AsRef; use core::clone::Clone; use core::cmp::Ordering::{self, Greater, Less}; use core::cmp::{self, Ord, PartialEq}; @@ -1024,25 +1023,25 @@ pub trait SliceConcatExt { fn connect(&self, sep: &T) -> Self::Output; } -impl> SliceConcatExt for [V] { +impl> SliceConcatExt for [V] { type Output = Vec; fn concat(&self) -> Vec { - let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len()); + let size = self.iter().fold(0, |acc, v| acc + v.borrow().len()); let mut result = Vec::with_capacity(size); for v in self { - result.push_all(v.as_ref()) + result.push_all(v.borrow()) } result } fn connect(&self, sep: &T) -> Vec { - let size = self.iter().fold(0, |acc, v| acc + v.as_ref().len()); + let size = self.iter().fold(0, |acc, v| acc + v.borrow().len()); let mut result = Vec::with_capacity(size + self.len()); let mut first = true; for v in self { if first { first = false } else { result.push(sep.clone()) } - result.push_all(v.as_ref()) + result.push_all(v.borrow()) } result } diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index da1b4dcddfc38..baef6ba6f01f3 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -59,7 +59,6 @@ use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use rustc_unicode::str::{UnicodeStr, Utf16Encoder}; -use core::convert::AsRef; use vec_deque::VecDeque; use borrow::{Borrow, ToOwned}; use string::String; @@ -83,7 +82,7 @@ pub use core::str::pattern; Section: Creating a string */ -impl> SliceConcatExt for [S] { +impl> SliceConcatExt for [S] { type Output = String; fn concat(&self) -> String { @@ -92,11 +91,11 @@ impl> SliceConcatExt for [S] { } // `len` calculation may overflow but push_str will check boundaries - let len = self.iter().map(|s| s.as_ref().len()).sum(); + let len = self.iter().map(|s| s.borrow().len()).sum(); let mut result = String::with_capacity(len); for s in self { - result.push_str(s.as_ref()) + result.push_str(s.borrow()) } result @@ -115,7 +114,7 @@ impl> SliceConcatExt for [S] { // this is wrong without the guarantee that `self` is non-empty // `len` calculation may overflow but push_str but will check boundaries let len = sep.len() * (self.len() - 1) - + self.iter().map(|s| s.as_ref().len()).sum::(); + + self.iter().map(|s| s.borrow().len()).sum::(); let mut result = String::with_capacity(len); let mut first = true; @@ -125,7 +124,7 @@ impl> SliceConcatExt for [S] { } else { result.push_str(sep); } - result.push_str(s.as_ref()); + result.push_str(s.borrow()); } result } diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 3c668f7fe9bc6..28e476742911b 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1052,11 +1052,20 @@ impl ToString for T { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for String { + #[inline] fn as_ref(&self) -> &str { self } } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef<[u8]> for String { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&'a str> for String { #[cfg(not(test))] diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index bcbf31617eeb6..ec693f366912d 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -52,20 +52,20 @@ //! spinlock_clone.store(0, Ordering::SeqCst); //! }); //! -//! // Wait for the other task to release the lock +//! // Wait for the other thread to release the lock //! while spinlock.load(Ordering::SeqCst) != 0 {} //! } //! ``` //! -//! Keep a global count of live tasks: +//! Keep a global count of live threads: //! //! ``` //! use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; //! -//! static GLOBAL_TASK_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; +//! static GLOBAL_THREAD_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; //! -//! let old_task_count = GLOBAL_TASK_COUNT.fetch_add(1, Ordering::SeqCst); -//! println!("live tasks: {}", old_task_count + 1); +//! let old_thread_count = GLOBAL_THREAD_COUNT.fetch_add(1, Ordering::SeqCst); +//! println!("live threads: {}", old_thread_count + 1); //! ``` #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index c717b608a246e..bf5fdb973eb76 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -24,7 +24,8 @@ //! claim temporary, exclusive, mutable access to the inner value. Borrows for `RefCell`s are //! tracked 'at runtime', unlike Rust's native reference types which are entirely tracked //! statically, at compile time. Because `RefCell` borrows are dynamic it is possible to attempt -//! to borrow a value that is already mutably borrowed; when this happens it results in task panic. +//! to borrow a value that is already mutably borrowed; when this happens it results in thread +//! panic. //! //! # When to choose interior mutability //! @@ -100,7 +101,7 @@ //! // Recursive call to return the just-cached value. //! // Note that if we had not let the previous borrow //! // of the cache fall out of scope then the subsequent -//! // recursive borrow would cause a dynamic task panic. +//! // recursive borrow would cause a dynamic thread panic. //! // This is the major hazard of using `RefCell`. //! self.minimum_spanning_tree() //! } @@ -633,7 +634,7 @@ impl<'b, T: ?Sized> DerefMut for RefMut<'b, T> { /// /// **NOTE:** `UnsafeCell`'s fields are public to allow static initializers. It is not /// recommended to access its fields directly, `get` should be used instead. -#[lang="unsafe_cell"] +#[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] pub struct UnsafeCell { /// Wrapped value diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index dd59ceff577a8..dab549f784cf8 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -41,7 +41,7 @@ use option::Option::{self, Some, None}; /// PartialEq only requires the `eq` method to be implemented; `ne` is defined in terms of it by /// default. Any manual implementation of `ne` *must* respect the rule that `eq` is a strict /// inverse of `ne`; that is, `!(a == b)` if and only if `a != b`. -#[lang="eq"] +#[lang = "eq"] #[stable(feature = "rust1", since = "1.0.0")] pub trait PartialEq { /// This method tests for `self` and `other` values to be equal, and is used by `==`. @@ -222,7 +222,7 @@ impl PartialOrd for Ordering { /// However it remains possible to implement the others separately for types which do not have a /// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == /// false` (cf. IEEE 754-2008 section 5.11). -#[lang="ord"] +#[lang = "ord"] #[stable(feature = "rust1", since = "1.0.0")] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index d3de77a9241e3..da6ac6bd752bf 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -173,6 +173,7 @@ impl AsMut<[T]> for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for str { + #[inline] fn as_ref(&self) -> &str { self } diff --git a/src/libcore/fmt/float.rs b/src/libcore/fmt/float.rs deleted file mode 100644 index 4b75bd5f67e3d..0000000000000 --- a/src/libcore/fmt/float.rs +++ /dev/null @@ -1,289 +0,0 @@ -// Copyright 2013-2015 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub use self::ExponentFormat::*; -pub use self::SignificantDigits::*; - -use prelude::*; - -use char; -use fmt; -use num::Float; -use num::FpCategory as Fp; -use ops::{Div, Rem, Mul}; -use slice; -use str; - -/// A flag that specifies whether to use exponential (scientific) notation. -pub enum ExponentFormat { - /// Do not use exponential notation. - ExpNone, - /// Use exponential notation with the exponent having a base of 10 and the - /// exponent sign being `e` or `E`. For example, 1000 would be printed - /// 1e3. - ExpDec -} - -/// The number of digits used for emitting the fractional part of a number, if -/// any. -pub enum SignificantDigits { - /// At most the given number of digits will be printed, truncating any - /// trailing zeroes. - DigMax(usize), - - /// Precisely the given number of digits will be printed. - DigExact(usize) -} - -#[doc(hidden)] -pub trait MyFloat: Float + PartialEq + PartialOrd + Div + - Mul + Rem + Copy { - fn from_u32(u: u32) -> Self; - fn to_i32(&self) -> i32; -} - -macro_rules! doit { - ($($t:ident)*) => ($(impl MyFloat for $t { - fn from_u32(u: u32) -> $t { u as $t } - fn to_i32(&self) -> i32 { *self as i32 } - })*) -} -doit! { f32 f64 } - -/// Converts a float number to its string representation. -/// This is meant to be a common base implementation for various formatting styles. -/// The number is assumed to be non-negative, callers use `Formatter::pad_integral` -/// to add the right sign, if any. -/// -/// # Arguments -/// -/// - `num` - The number to convert (non-negative). Accepts any number that -/// implements the numeric traits. -/// - `digits` - The amount of digits to use for emitting the fractional -/// part, if any. See `SignificantDigits`. -/// - `exp_format` - Whether or not to use the exponential (scientific) notation. -/// See `ExponentFormat`. -/// - `exp_capital` - Whether or not to use a capital letter for the exponent sign, if -/// exponential notation is desired. -/// - `f` - A closure to invoke with the string representing the -/// float. -/// -/// # Panics -/// -/// - Panics if `num` is negative. -pub fn float_to_str_bytes_common( - num: T, - digits: SignificantDigits, - exp_format: ExponentFormat, - exp_upper: bool, - f: F -) -> U where - F: FnOnce(&str) -> U, -{ - let _0: T = T::zero(); - let _1: T = T::one(); - let radix: u32 = 10; - let radix_f = T::from_u32(radix); - - assert!(num.is_nan() || num >= _0, "float_to_str_bytes_common: number is negative"); - - match num.classify() { - Fp::Nan => return f("NaN"), - Fp::Infinite if num > _0 => { - return f("inf"); - } - Fp::Infinite if num < _0 => { - return f("-inf"); - } - _ => {} - } - - // For an f64 the (decimal) exponent is roughly in the range of [-307, 308], so - // we may have up to that many digits. We err on the side of caution and - // add 50% extra wiggle room. - let mut buf = [0; 462]; - let mut end = 0; - - let (num, exp) = match exp_format { - ExpDec if num != _0 => { - let exp = num.log10().floor(); - (num / radix_f.powf(exp), exp.to_i32()) - } - _ => (num, 0) - }; - - // First emit the non-fractional part, looping at least once to make - // sure at least a `0` gets emitted. - let mut deccum = num.trunc(); - loop { - let current_digit = deccum % radix_f; - - // Decrease the deccumulator one digit at a time - deccum = deccum / radix_f; - deccum = deccum.trunc(); - - let c = char::from_digit(current_digit.to_i32() as u32, radix); - buf[end] = c.unwrap() as u8; - end += 1; - - // No more digits to calculate for the non-fractional part -> break - if deccum == _0 { break; } - } - - // If limited digits, calculate one digit more for rounding. - let (limit_digits, digit_count, exact) = match digits { - DigMax(count) => (true, count + 1, false), - DigExact(count) => (true, count + 1, true) - }; - - buf[..end].reverse(); - - // Remember start of the fractional digits. - // Points one beyond end of buf if none get generated, - // or at the '.' otherwise. - let start_fractional_digits = end; - - // Now emit the fractional part, if any - deccum = num.fract(); - if deccum != _0 || (limit_digits && exact && digit_count > 0) { - buf[end] = b'.'; - end += 1; - let mut dig = 0; - - // calculate new digits while - // - there is no limit and there are digits left - // - or there is a limit, it's not reached yet and - // - it's exact - // - or it's a maximum, and there are still digits left - while (!limit_digits && deccum != _0) - || (limit_digits && dig < digit_count && ( - exact - || (!exact && deccum != _0) - ) - ) { - // Shift first fractional digit into the integer part - deccum = deccum * radix_f; - - let current_digit = deccum.trunc(); - - let c = char::from_digit(current_digit.to_i32() as u32, radix); - buf[end] = c.unwrap() as u8; - end += 1; - - // Decrease the deccumulator one fractional digit at a time - deccum = deccum.fract(); - dig += 1; - } - - // If digits are limited, and that limit has been reached, - // cut off the one extra digit, and depending on its value - // round the remaining ones. - if limit_digits && dig == digit_count { - let ascii2value = |chr: u8| { - (chr as char).to_digit(radix).unwrap() - }; - let value2ascii = |val: u32| { - char::from_digit(val, radix).unwrap() as u8 - }; - - let extra_digit = ascii2value(buf[end - 1]); - end -= 1; - if extra_digit >= radix / 2 { // -> need to round - let mut i: isize = end as isize - 1; - loop { - // If reached left end of number, have to - // insert additional digit: - if i < 0 - || buf[i as usize] == b'-' - || buf[i as usize] == b'+' { - for j in ((i + 1) as usize..end).rev() { - buf[j + 1] = buf[j]; - } - buf[(i + 1) as usize] = value2ascii(1); - end += 1; - break; - } - - // Skip the '.' - if buf[i as usize] == b'.' { i -= 1; continue; } - - // Either increment the digit, - // or set to 0 if max and carry the 1. - let current_digit = ascii2value(buf[i as usize]); - if current_digit < (radix - 1) { - buf[i as usize] = value2ascii(current_digit+1); - break; - } else { - buf[i as usize] = value2ascii(0); - i -= 1; - } - } - } - } - } - - // if number of digits is not exact, remove all trailing '0's up to - // and including the '.' - if !exact { - let buf_max_i = end - 1; - - // index to truncate from - let mut i = buf_max_i; - - // discover trailing zeros of fractional part - while i > start_fractional_digits && buf[i] == b'0' { - i -= 1; - } - - // Only attempt to truncate digits if buf has fractional digits - if i >= start_fractional_digits { - // If buf ends with '.', cut that too. - if buf[i] == b'.' { i -= 1 } - - // only resize buf if we actually remove digits - if i < buf_max_i { - end = i + 1; - } - } - } // If exact and trailing '.', just cut that - else { - let max_i = end - 1; - if buf[max_i] == b'.' { - end = max_i; - } - } - - match exp_format { - ExpNone => {}, - ExpDec => { - buf[end] = if exp_upper { b'E' } else { b'e' }; - end += 1; - - struct Filler<'a> { - buf: &'a mut [u8], - end: &'a mut usize, - } - - impl<'a> fmt::Write for Filler<'a> { - fn write_str(&mut self, s: &str) -> fmt::Result { - slice::bytes::copy_memory(s.as_bytes(), - &mut self.buf[(*self.end)..]); - *self.end += s.len(); - Ok(()) - } - } - - let mut filler = Filler { buf: &mut buf, end: &mut end }; - let _ = fmt::write(&mut filler, format_args!("{:-}", exp)); - } - } - - f(unsafe { str::from_utf8_unchecked(&buf[..end]) }) -} diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index f8a1ef96bcc33..a87f6619fe877 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -17,9 +17,9 @@ use prelude::*; use cell::{Cell, RefCell, Ref, RefMut, BorrowState}; use marker::PhantomData; use mem; +use num::flt2dec; use ops::Deref; use result; -use num::Float; use slice; use str; use self::rt::v1::Alignment; @@ -31,7 +31,6 @@ pub use self::num::RadixFmt; pub use self::builders::{DebugStruct, DebugTuple, DebugSet, DebugList, DebugMap}; mod num; -mod float; mod builders; #[unstable(feature = "core", reason = "internal to format_args!")] @@ -604,6 +603,83 @@ impl<'a> Formatter<'a> { Ok(()) } + /// Takes the formatted parts and applies the padding. + /// Assumes that the caller already has rendered the parts with required precision, + /// so that `self.precision` can be ignored. + fn pad_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { + if let Some(mut width) = self.width { + // for the sign-aware zero padding, we render the sign first and + // behave as if we had no sign from the beginning. + let mut formatted = formatted.clone(); + let mut align = self.align; + let old_fill = self.fill; + if self.flags & (1 << (FlagV1::SignAwareZeroPad as u32)) != 0 { + // a sign always goes first + let sign = unsafe { str::from_utf8_unchecked(formatted.sign) }; + try!(self.buf.write_str(sign)); + + // remove the sign from the formatted parts + formatted.sign = b""; + width = if width < sign.len() { 0 } else { width - sign.len() }; + align = Alignment::Right; + self.fill = '0'; + } + + // remaining parts go through the ordinary padding process. + let len = formatted.len(); + let ret = if width <= len { // no padding + self.write_formatted_parts(&formatted) + } else { + self.with_padding(width - len, align, |f| { + f.write_formatted_parts(&formatted) + }) + }; + self.fill = old_fill; + ret + } else { + // this is the common case and we take a shortcut + self.write_formatted_parts(formatted) + } + } + + fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { + fn write_bytes(buf: &mut Write, s: &[u8]) -> Result { + buf.write_str(unsafe { str::from_utf8_unchecked(s) }) + } + + if !formatted.sign.is_empty() { + try!(write_bytes(self.buf, formatted.sign)); + } + for part in formatted.parts { + match *part { + flt2dec::Part::Zero(mut nzeroes) => { + const ZEROES: &'static str = // 64 zeroes + "0000000000000000000000000000000000000000000000000000000000000000"; + while nzeroes > ZEROES.len() { + try!(self.buf.write_str(ZEROES)); + nzeroes -= ZEROES.len(); + } + if nzeroes > 0 { + try!(self.buf.write_str(&ZEROES[..nzeroes])); + } + } + flt2dec::Part::Num(mut v) => { + let mut s = [0; 5]; + let len = part.len(); + for c in s[..len].iter_mut().rev() { + *c = b'0' + (v % 10) as u8; + v /= 10; + } + try!(write_bytes(self.buf, &s[..len])); + } + flt2dec::Part::Copy(buf) => { + try!(write_bytes(self.buf, buf)); + } + } + } + Ok(()) + } + /// Writes some data to the underlying buffer contained within this /// formatter. #[stable(feature = "rust1", since = "1.0.0")] @@ -918,18 +994,50 @@ impl<'a, T> Pointer for &'a mut T { } // Common code of floating point Debug and Display. -fn float_to_str_common(num: &T, precision: Option, - post: F) -> Result - where F : FnOnce(&str) -> Result { - let digits = match precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), +fn float_to_decimal_common(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result + where T: flt2dec::DecodableFloat +{ + let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0; + let sign = match (force_sign, negative_zero) { + (false, false) => flt2dec::Sign::Minus, + (false, true) => flt2dec::Sign::MinusRaw, + (true, false) => flt2dec::Sign::MinusPlus, + (true, true) => flt2dec::Sign::MinusPlusRaw, + }; + + let mut buf = [0; 1024]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = if let Some(precision) = fmt.precision { + flt2dec::to_exact_fixed_str(flt2dec::strategy::grisu::format_exact, *num, sign, + precision, false, &mut buf, &mut parts) + } else { + flt2dec::to_shortest_str(flt2dec::strategy::grisu::format_shortest, *num, sign, + 0, false, &mut buf, &mut parts) + }; + fmt.pad_formatted_parts(&formatted) +} + +// Common code of floating point LowerExp and UpperExp. +fn float_to_exponential_common(fmt: &mut Formatter, num: &T, upper: bool) -> Result + where T: flt2dec::DecodableFloat +{ + let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0; + let sign = match force_sign { + false => flt2dec::Sign::Minus, + true => flt2dec::Sign::MinusPlus, }; - float::float_to_str_bytes_common(num.abs(), - digits, - float::ExpNone, - false, - post) + + let mut buf = [0; 1024]; // enough for f32 and f64 + let mut parts = [flt2dec::Part::Zero(0); 16]; + let formatted = if let Some(precision) = fmt.precision { + // 1 integral digit + `precision` fractional digits = `precision + 1` total digits + flt2dec::to_exact_exp_str(flt2dec::strategy::grisu::format_exact, *num, sign, + precision + 1, upper, &mut buf, &mut parts) + } else { + flt2dec::to_shortest_exp_str(flt2dec::strategy::grisu::format_shortest, *num, sign, + (0, 0), upper, &mut buf, &mut parts) + }; + fmt.pad_formatted_parts(&formatted) } macro_rules! floating { ($ty:ident) => { @@ -937,54 +1045,28 @@ macro_rules! floating { ($ty:ident) => { #[stable(feature = "rust1", since = "1.0.0")] impl Debug for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_str_common(self, fmt.precision, |absolute| { - // is_positive() counts -0.0 as negative - fmt.pad_integral(self.is_nan() || self.is_positive(), "", absolute) - }) + float_to_decimal_common(fmt, self, true) } } #[stable(feature = "rust1", since = "1.0.0")] impl Display for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - float_to_str_common(self, fmt.precision, |absolute| { - // simple comparison counts -0.0 as positive - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", absolute) - }) + float_to_decimal_common(fmt, self, false) } } #[stable(feature = "rust1", since = "1.0.0")] impl LowerExp for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - let digits = match fmt.precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), - }; - float::float_to_str_bytes_common(self.abs(), - digits, - float::ExpDec, - false, - |bytes| { - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes) - }) + float_to_exponential_common(fmt, self, false) } } #[stable(feature = "rust1", since = "1.0.0")] impl UpperExp for $ty { fn fmt(&self, fmt: &mut Formatter) -> Result { - let digits = match fmt.precision { - Some(i) => float::DigExact(i), - None => float::DigMax(6), - }; - float::float_to_str_bytes_common(self.abs(), - digits, - float::ExpDec, - true, - |bytes| { - fmt.pad_integral(self.is_nan() || *self >= 0.0, "", bytes) - }) + float_to_exponential_common(fmt, self, true) } } } } diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index a787d34f9145a..e4d2ab198630a 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -82,7 +82,7 @@ fn _assert_is_object_safe(_: &Iterator) {} /// is returned. A concrete Iterator implementation may choose to behave however /// it wishes, either by returning `None` infinitely, or by doing something /// else. -#[lang="iterator"] +#[lang = "iterator"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented = "`{Self}` is not an iterator; maybe try calling \ `.iter()` or a similar method"] @@ -137,7 +137,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4, 5]; - /// assert!(a.iter().last().unwrap() == &5); + /// assert_eq!(a.iter().last().unwrap(), &5); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -155,8 +155,8 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter(); - /// assert!(it.nth(2).unwrap() == &3); - /// assert!(it.nth(2) == None); + /// assert_eq!(it.nth(2).unwrap(), &3); + /// assert_eq!(it.nth(2), None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -545,8 +545,8 @@ pub trait Iterator { /// let mut it = 0..10; /// // sum the first five values /// let partial_sum = it.by_ref().take(5).fold(0, |a, b| a + b); - /// assert!(partial_sum == 10); - /// assert!(it.next() == Some(5)); + /// assert_eq!(partial_sum, 10); + /// assert_eq!(it.next(), Some(5)); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn by_ref(&mut self) -> &mut Self where Self: Sized { self } @@ -608,7 +608,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4, 5]; - /// assert!(a.iter().fold(0, |acc, &item| acc + item) == 15); + /// assert_eq!(a.iter().fold(0, |acc, &item| acc + item), 15); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -773,7 +773,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4, 5]; - /// assert!(a.iter().max().unwrap() == &5); + /// assert_eq!(a.iter().max().unwrap(), &5); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -796,7 +796,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4, 5]; - /// assert!(a.iter().min().unwrap() == &1); + /// assert_eq!(a.iter().min().unwrap(), &1); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -834,13 +834,13 @@ pub trait Iterator { /// assert_eq!(a.iter().min_max(), NoElements); /// /// let a = [1]; - /// assert!(a.iter().min_max() == OneElement(&1)); + /// assert_eq!(a.iter().min_max(), OneElement(&1)); /// /// let a = [1, 2, 3, 4, 5]; - /// assert!(a.iter().min_max() == MinMax(&1, &5)); + /// assert_eq!(a.iter().min_max(), MinMax(&1, &5)); /// /// let a = [1, 1, 1, 1]; - /// assert!(a.iter().min_max() == MinMax(&1, &1)); + /// assert_eq!(a.iter().min_max(), MinMax(&1, &1)); /// ``` #[unstable(feature = "core", reason = "return type may change")] fn min_max(mut self) -> MinMaxResult where Self: Sized, Self::Item: Ord @@ -1058,7 +1058,7 @@ pub trait Iterator { /// /// let a = [1, 2, 3, 4, 5]; /// let mut it = a.iter().cloned(); - /// assert!(it.sum::() == 15); + /// assert_eq!(it.sum::(), 15); /// ``` #[unstable(feature="core")] fn sum::Item>(self) -> S where @@ -1078,9 +1078,9 @@ pub trait Iterator { /// fn factorial(n: u32) -> u32 { /// (1..).take_while(|&i| i <= n).product() /// } - /// assert!(factorial(0) == 1); - /// assert!(factorial(1) == 1); - /// assert!(factorial(5) == 120); + /// assert_eq!(factorial(0), 1); + /// assert_eq!(factorial(1), 1); + /// assert_eq!(factorial(5), 120); /// ``` #[unstable(feature="core")] fn product::Item>(self) -> P where diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index ece419af95172..54877c070cbe4 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// Entry point of task panic, for details, see std::macros +/// Entry point of thread panic, for details, see std::macros #[macro_export] macro_rules! panic { () => ( diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 04839b12ac895..3aaedaeb813e3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -33,7 +33,7 @@ use hash::Hasher; /// Types able to be transferred across thread boundaries. #[stable(feature = "rust1", since = "1.0.0")] -#[lang="send"] +#[lang = "send"] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] pub unsafe trait Send { // empty. @@ -46,7 +46,7 @@ impl !Send for *mut T { } /// Types with a constant size known at compile-time. #[stable(feature = "rust1", since = "1.0.0")] -#[lang="sized"] +#[lang = "sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized { @@ -154,7 +154,7 @@ pub trait Sized { /// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking /// change: that second example would fail to compile if we made `Foo` non-`Copy`. #[stable(feature = "rust1", since = "1.0.0")] -#[lang="copy"] +#[lang = "copy"] pub trait Copy : Clone { // Empty. } @@ -201,7 +201,7 @@ pub trait Copy : Clone { /// reference; not doing this is undefined behaviour (for example, /// `transmute`-ing from `&T` to `&mut T` is illegal). #[stable(feature = "rust1", since = "1.0.0")] -#[lang="sync"] +#[lang = "sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] pub unsafe trait Sync { // Empty @@ -217,7 +217,7 @@ impl !Sync for *mut T { } /// ensure that they are never copied, even if they lack a destructor. #[unstable(feature = "core", reason = "likely to change with new variance strategy")] -#[lang="no_copy_bound"] +#[lang = "no_copy_bound"] #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct NoCopy; @@ -313,7 +313,7 @@ macro_rules! impls{ /// mismatches by enforcing types in the method implementations: /// /// ``` -/// # trait ResType { fn foo(&self); }; +/// # trait ResType { fn foo(&self); } /// # struct ParamType; /// # mod foreign_lib { /// # pub fn new(_: usize) -> *mut () { 42 as *mut () } @@ -359,7 +359,7 @@ macro_rules! impls{ /// better to use a reference type, like `PhantomData<&'a T>` /// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so /// as not to indicate ownership. -#[lang="phantom_data"] +#[lang = "phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 640703ca2f9c2..13b6468105dcf 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -31,7 +31,7 @@ unsafe impl Zeroable for u64 {} /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. -#[lang="non_zero"] +#[lang = "non_zero"] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] #[unstable(feature = "core")] pub struct NonZero(T); diff --git a/src/libcore/num/flt2dec/bignum.rs b/src/libcore/num/flt2dec/bignum.rs new file mode 100644 index 0000000000000..d6a5e44a1fb00 --- /dev/null +++ b/src/libcore/num/flt2dec/bignum.rs @@ -0,0 +1,357 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Custom arbitrary-precision number (bignum) implementation. +//! +//! This is designed to avoid the heap allocation at expense of stack memory. +//! The most used bignum type, `Big32x36`, is limited by 32 × 36 = 1,152 bits +//! and will take at most 152 bytes of stack memory. This is (barely) enough +//! for handling all possible finite `f64` values. +//! +//! In principle it is possible to have multiple bignum types for different +//! inputs, but we don't do so to avoid the code bloat. Each bignum is still +//! tracked for the actual usages, so it normally doesn't matter. + +#![macro_use] + +use prelude::*; +use mem; +use intrinsics; + +/// Arithmetic operations required by bignums. +pub trait FullOps { + /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`, + /// where `W` is the number of bits in `Self`. + fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self); + + /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`, + /// where `W` is the number of bits in `Self`. + fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self); + + /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`, + /// where `W` is the number of bits in `Self`. + fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self); + + /// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem` + /// and `0 <= rem < other`, where `W` is the number of bits in `Self`. + fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/); +} + +macro_rules! impl_full_ops { + ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => ( + $( + impl FullOps for $ty { + fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) { + // this cannot overflow, the output is between 0 and 2*2^nbits - 1 + // FIXME will LLVM optimize this into ADC or similar??? + let (v, carry1) = unsafe { $addfn(self, other) }; + let (v, carry2) = unsafe { $addfn(v, if carry {1} else {0}) }; + (carry1 || carry2, v) + } + + fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) { + // this cannot overflow, the output is between 0 and 2^nbits * (2^nbits - 1) + let nbits = mem::size_of::<$ty>() * 8; + let v = (self as $bigty) * (other as $bigty) + (carry as $bigty); + ((v >> nbits) as $ty, v as $ty) + } + + fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) { + // this cannot overflow, the output is between 0 and 2^(2*nbits) - 1 + let nbits = mem::size_of::<$ty>() * 8; + let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) + + (carry as $bigty); + ((v >> nbits) as $ty, v as $ty) + } + + fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) { + debug_assert!(borrow < other); + // this cannot overflow, the dividend is between 0 and other * 2^nbits - 1 + let nbits = mem::size_of::<$ty>() * 8; + let lhs = ((borrow as $bigty) << nbits) | (self as $bigty); + let rhs = other as $bigty; + ((lhs / rhs) as $ty, (lhs % rhs) as $ty) + } + } + )* + ) +} + +impl_full_ops! { + u8: add(intrinsics::u8_add_with_overflow), mul/div(u16); + u16: add(intrinsics::u16_add_with_overflow), mul/div(u32); + u32: add(intrinsics::u32_add_with_overflow), mul/div(u64); +// u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); // see RFC #521 for enabling this. +} + +macro_rules! define_bignum { + ($name:ident: type=$ty:ty, n=$n:expr) => ( + /// Stack-allocated arbitrary-precision (up to certain limit) integer. + /// + /// This is backed by an fixed-size array of given type ("digit"). + /// While the array is not very large (normally some hundred bytes), + /// copying it recklessly may result in the performance hit. + /// Thus this is intentionally not `Copy`. + /// + /// All operations available to bignums panic in the case of over/underflows. + /// The caller is responsible to use large enough bignum types. + pub struct $name { + /// One plus the offset to the maximum "digit" in use. + /// This does not decrease, so be aware of the computation order. + /// `base[size..]` should be zero. + size: usize, + /// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...` + /// where `W` is the number of bits in the digit type. + base: [$ty; $n] + } + + impl $name { + /// Makes a bignum from one digit. + pub fn from_small(v: $ty) -> $name { + let mut base = [0; $n]; + base[0] = v; + $name { size: 1, base: base } + } + + /// Makes a bignum from `u64` value. + pub fn from_u64(mut v: u64) -> $name { + use mem; + + let mut base = [0; $n]; + let mut sz = 0; + while v > 0 { + base[sz] = v as $ty; + v >>= mem::size_of::<$ty>() * 8; + sz += 1; + } + $name { size: sz, base: base } + } + + /// Returns true if the bignum is zero. + pub fn is_zero(&self) -> bool { + self.base[..self.size].iter().all(|&v| v == 0) + } + + /// Adds `other` to itself and returns its own mutable reference. + pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name { + use cmp; + use num::flt2dec::bignum::FullOps; + + let mut sz = cmp::max(self.size, other.size); + let mut carry = false; + for (a, b) in self.base[..sz].iter_mut().zip(other.base[..sz].iter()) { + let (c, v) = (*a).full_add(*b, carry); + *a = v; + carry = c; + } + if carry { + self.base[sz] = 1; + sz += 1; + } + self.size = sz; + self + } + + /// Subtracts `other` from itself and returns its own mutable reference. + pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name { + use cmp; + use num::flt2dec::bignum::FullOps; + + let sz = cmp::max(self.size, other.size); + let mut noborrow = true; + for (a, b) in self.base[..sz].iter_mut().zip(other.base[..sz].iter()) { + let (c, v) = (*a).full_add(!*b, noborrow); + *a = v; + noborrow = c; + } + assert!(noborrow); + self.size = sz; + self + } + + /// Multiplies itself by a digit-sized `other` and returns its own + /// mutable reference. + pub fn mul_small<'a>(&'a mut self, other: $ty) -> &'a mut $name { + use num::flt2dec::bignum::FullOps; + + let mut sz = self.size; + let mut carry = 0; + for a in self.base[..sz].iter_mut() { + let (c, v) = (*a).full_mul(other, carry); + *a = v; + carry = c; + } + if carry > 0 { + self.base[sz] = carry; + sz += 1; + } + self.size = sz; + self + } + + /// Multiplies itself by `2^bits` and returns its own mutable reference. + pub fn mul_pow2<'a>(&'a mut self, bits: usize) -> &'a mut $name { + use mem; + + let digitbits = mem::size_of::<$ty>() * 8; + let digits = bits / digitbits; + let bits = bits % digitbits; + + assert!(digits < $n); + debug_assert!(self.base[$n-digits..].iter().all(|&v| v == 0)); + debug_assert!(bits == 0 || (self.base[$n-digits-1] >> (digitbits - bits)) == 0); + + // shift by `digits * digitbits` bits + for i in (0..self.size).rev() { + self.base[i+digits] = self.base[i]; + } + for i in 0..digits { + self.base[i] = 0; + } + + // shift by `bits` bits + let mut sz = self.size + digits; + if bits > 0 { + let last = sz; + let overflow = self.base[last-1] >> (digitbits - bits); + if overflow > 0 { + self.base[last] = overflow; + sz += 1; + } + for i in (digits+1..last).rev() { + self.base[i] = (self.base[i] << bits) | + (self.base[i-1] >> (digitbits - bits)); + } + self.base[digits] <<= bits; + // self.base[..digits] is zero, no need to shift + } + + self.size = sz; + self + } + + /// Multiplies itself by a number described by `other[0] + other[1] * 2^W + + /// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type) + /// and returns its own mutable reference. + pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name { + // the internal routine. works best when aa.len() <= bb.len(). + fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize { + use num::flt2dec::bignum::FullOps; + + let mut retsz = 0; + for (i, &a) in aa.iter().enumerate() { + if a == 0 { continue; } + let mut sz = bb.len(); + let mut carry = 0; + for (j, &b) in bb.iter().enumerate() { + let (c, v) = a.full_mul_add(b, ret[i + j], carry); + ret[i + j] = v; + carry = c; + } + if carry > 0 { + ret[i + sz] = carry; + sz += 1; + } + if retsz < i + sz { + retsz = i + sz; + } + } + retsz + } + + let mut ret = [0; $n]; + let retsz = if self.size < other.len() { + mul_inner(&mut ret, &self.base[..self.size], other) + } else { + mul_inner(&mut ret, other, &self.base[..self.size]) + }; + self.base = ret; + self.size = retsz; + self + } + + /// Divides itself by a digit-sized `other` and returns its own + /// mutable reference *and* the remainder. + pub fn div_rem_small<'a>(&'a mut self, other: $ty) -> (&'a mut $name, $ty) { + use num::flt2dec::bignum::FullOps; + + assert!(other > 0); + + let sz = self.size; + let mut borrow = 0; + for a in self.base[..sz].iter_mut().rev() { + let (q, r) = (*a).full_div_rem(other, borrow); + *a = q; + borrow = r; + } + (self, borrow) + } + } + + impl ::cmp::PartialEq for $name { + fn eq(&self, other: &$name) -> bool { self.base[..] == other.base[..] } + } + + impl ::cmp::Eq for $name { + } + + impl ::cmp::PartialOrd for $name { + fn partial_cmp(&self, other: &$name) -> ::option::Option<::cmp::Ordering> { + ::option::Option::Some(self.cmp(other)) + } + } + + impl ::cmp::Ord for $name { + fn cmp(&self, other: &$name) -> ::cmp::Ordering { + use cmp::max; + use iter::order; + + let sz = max(self.size, other.size); + let lhs = self.base[..sz].iter().cloned().rev(); + let rhs = other.base[..sz].iter().cloned().rev(); + order::cmp(lhs, rhs) + } + } + + impl ::clone::Clone for $name { + fn clone(&self) -> $name { + $name { size: self.size, base: self.base } + } + } + + impl ::fmt::Debug for $name { + fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { + use mem; + + let sz = if self.size < 1 {1} else {self.size}; + let digitlen = mem::size_of::<$ty>() * 2; + + try!(write!(f, "{:#x}", self.base[sz-1])); + for &v in self.base[..sz-1].iter().rev() { + try!(write!(f, "_{:01$x}", v, digitlen)); + } + ::result::Result::Ok(()) + } + } + ) +} + +/// The digit type for `Big32x36`. +pub type Digit32 = u32; + +define_bignum!(Big32x36: type=Digit32, n=36); + +// this one is used for testing only. +#[doc(hidden)] +pub mod tests { + use prelude::*; + define_bignum!(Big8x3: type=u8, n=3); +} + diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs new file mode 100644 index 0000000000000..f98bc11a315f0 --- /dev/null +++ b/src/libcore/num/flt2dec/decoder.rs @@ -0,0 +1,105 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Decodes a floating-point value into individual parts and error ranges. + +use prelude::*; + +use {f32, f64}; +use num::{Float, FpCategory}; + +/// Decoded unsigned finite value, such that: +/// +/// - The original value equals to `mant * 2^exp`. +/// +/// - Any number from `(mant - minus) * 2^exp` to `(mant + plus) * 2^exp` will +/// round to the original value. The range is inclusive only when +/// `inclusive` is true. +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Decoded { + /// The scaled mantissa. + pub mant: u64, + /// The lower error range. + pub minus: u64, + /// The upper error range. + pub plus: u64, + /// The shared exponent in base 2. + pub exp: i16, + /// True when the error range is inclusive. + /// + /// In IEEE 754, this is true when the original mantissa was even. + pub inclusive: bool, +} + +/// Decoded unsigned value. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum FullDecoded { + /// Not-a-number. + Nan, + /// Infinities, either positive or negative. + Infinite, + /// Zero, either positive or negative. + Zero, + /// Finite numbers with further decoded fields. + Finite(Decoded), +} + +/// A floating point type which can be `decode`d. +pub trait DecodableFloat: Float + Copy { + /// Returns `x * 2^exp`. Almost same to `std::{f32,f64}::ldexp`. + /// This is used for testing. + fn ldexpi(f: i64, exp: isize) -> Self; + /// The minimum positive normalized value. + fn min_pos_norm_value() -> Self; +} + +impl DecodableFloat for f32 { + fn ldexpi(f: i64, exp: isize) -> Self { f as Self * (exp as Self).exp2() } + fn min_pos_norm_value() -> Self { f32::MIN_POSITIVE } +} + +impl DecodableFloat for f64 { + fn ldexpi(f: i64, exp: isize) -> Self { f as Self * (exp as Self).exp2() } + fn min_pos_norm_value() -> Self { f64::MIN_POSITIVE } +} + +/// Returns a sign (true when negative) and `FullDecoded` value +/// from given floating point number. +pub fn decode(v: T) -> (/*negative?*/ bool, FullDecoded) { + let (mant, exp, sign) = v.integer_decode(); + let even = (mant & 1) == 0; + let decoded = match v.classify() { + FpCategory::Nan => FullDecoded::Nan, + FpCategory::Infinite => FullDecoded::Infinite, + FpCategory::Zero => FullDecoded::Zero, + FpCategory::Subnormal => { + // neighbors: (mant - 2, exp) -- (mant, exp) -- (mant + 2, exp) + // Float::integer_decode always preserves the exponent, + // so the mantissa is scaled for subnormals. + FullDecoded::Finite(Decoded { mant: mant, minus: 1, plus: 1, + exp: exp, inclusive: even }) + } + FpCategory::Normal => { + let minnorm = ::min_pos_norm_value().integer_decode(); + if mant == minnorm.0 { + // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp) + // where maxmant = minnormmant * 2 - 1 + FullDecoded::Finite(Decoded { mant: mant << 2, minus: 1, plus: 2, + exp: exp - 2, inclusive: even }) + } else { + // neighbors: (mant - 1, exp) -- (mant, exp) -- (mant + 1, exp) + FullDecoded::Finite(Decoded { mant: mant << 1, minus: 1, plus: 1, + exp: exp - 1, inclusive: even }) + } + } + }; + (sign < 0, decoded) +} + diff --git a/src/libcore/num/flt2dec/estimator.rs b/src/libcore/num/flt2dec/estimator.rs new file mode 100644 index 0000000000000..d42e05a91f140 --- /dev/null +++ b/src/libcore/num/flt2dec/estimator.rs @@ -0,0 +1,25 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The exponent estimator. + +/// Finds `k_0` such that `10^(k_0-1) < mant * 2^exp <= 10^(k_0+1)`. +/// +/// This is used to approximate `k = ceil(log_10 (mant * 2^exp))`; +/// the true `k` is either `k_0` or `k_0+1`. +#[doc(hidden)] +pub fn estimate_scaling_factor(mant: u64, exp: i16) -> i16 { + // 2^(nbits-1) < mant <= 2^nbits if mant > 0 + let nbits = 64 - (mant - 1).leading_zeros() as i64; + // 1292913986 = floor(2^32 * log_10 2) + // therefore this always underestimates (or is exact), but not much. + (((nbits + exp as i64) * 1292913986) >> 32) as i16 +} + diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs new file mode 100644 index 0000000000000..f51dcf54a1959 --- /dev/null +++ b/src/libcore/num/flt2dec/mod.rs @@ -0,0 +1,661 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +Floating-point number to decimal conversion routines. + +# Problem statement + +We are given the floating-point number `v = f * 2^e` with an integer `f`, +and its bounds `minus` and `plus` such that any number between `v - minus` and +`v + plus` will be rounded to `v`. For the simplicity we assume that +this range is exclusive. Then we would like to get the unique decimal +representation `V = 0.d[0..n-1] * 10^k` such that: + +- `d[0]` is non-zero. + +- It's correctly rounded when parsed back: `v - minus < V < v + plus`. + Furthermore it is shortest such one, i.e. there is no representation + with less than `n` digits that is correctly rounded. + +- It's closest to the original value: `abs(V - v) <= 10^(k-n) / 2`. Note that + there might be two representations satisfying this uniqueness requirement, + in which case some tie-breaking mechanism is used. + +We will call this mode of operation as to the *shortest* mode. This mode is used +when there is no additional constraint, and can be thought as a "natural" mode +as it matches the ordinary intuition (it at least prints `0.1f32` as "0.1"). + +We have two more modes of operation closely related to each other. In these modes +we are given either the number of significant digits `n` or the last-digit +limitation `limit` (which determines the actual `n`), and we would like to get +the representation `V = 0.d[0..n-1] * 10^k` such that: + +- `d[0]` is non-zero, unless `n` was zero in which case only `k` is returned. + +- It's closest to the original value: `abs(V - v) <= 10^(k-n) / 2`. Again, + there might be some tie-breaking mechanism. + +When `limit` is given but not `n`, we set `n` such that `k - n = limit` +so that the last digit `d[n-1]` is scaled by `10^(k-n) = 10^limit`. +If such `n` is negative, we clip it to zero so that we will only get `k`. +We are also limited by the supplied buffer. This limitation is used to print +the number up to given number of fractional digits without knowing +the correct `k` beforehand. + +We will call the mode of operation requiring `n` as to the *exact* mode, +and one requiring `limit` as to the *fixed* mode. The exact mode is a subset of +the fixed mode: the sufficiently large last-digit limitation will eventually fill +the supplied buffer and let the algorithm to return. + +# Implementation overview + +It is easy to get the floating point printing correct but slow (Russ Cox has +[demonstrated](http://research.swtch.com/ftoa) how it's easy), or incorrect but +fast (naïve division and modulo). But it is surprisingly hard to print +floating point numbers correctly *and* efficiently. + +There are two classes of algorithms widely known to be correct. + +- The "Dragon" family of algorithm is first described by Guy L. Steele Jr. and + Jon L. White. They rely on the fixed-size big integer for their correctness. + A slight improvement was found later, which is posthumously described by + Robert G. Burger and R. Kent Dybvig. David Gay's `dtoa.c` routine is + a popular implementation of this strategy. + +- The "Grisu" family of algorithm is first described by Florian Loitsch. + They use very cheap integer-only procedure to determine the close-to-correct + representation which is at least guaranteed to be shortest. The variant, + Grisu3, actively detects if the resulting representation is incorrect. + +We implement both algorithms with necessary tweaks to suit our requirements. +In particular, published literatures are short of the actual implementation +difficulties like how to avoid arithmetic overflows. Each implementation, +available in `strategy::dragon` and `strategy::grisu` respectively, +extensively describes all necessary justifications and many proofs for them. +(It is still difficult to follow though. You have been warned.) + +Both implementations expose two public functions: + +- `format_shortest(decoded, buf)`, which always needs at least + `MAX_SIG_DIGITS` digits of buffer. Implements the shortest mode. + +- `format_exact(decoded, buf, limit)`, which accepts as small as + one digit of buffer. Implements exact and fixed modes. + +They try to fill the `u8` buffer with digits and returns the number of digits +written and the exponent `k`. They are total for all finite `f32` and `f64` +inputs (Grisu internally falls back to Dragon if necessary). + +The rendered digits are formatted into the actual string form with +four functions: + +- `to_shortest_str` prints the shortest representation, which can be padded by + zeroes to make *at least* given number of fractional digits. + +- `to_shortest_exp_str` prints the shortest representation, which can be + padded by zeroes when its exponent is in the specified ranges, + or can be printed in the exponential form such as `1.23e45`. + +- `to_exact_exp_str` prints the exact representation with given number of + digits in the exponential form. + +- `to_exact_fixed_str` prints the fixed representation with *exactly* + given number of fractional digits. + +They all return a slice of preallocated `Part` array, which corresponds to +the individual part of strings: a fixed string, a part of rendered digits, +a number of zeroes or a small (`u16`) number. The caller is expected to +provide a large enough buffer and `Part` array, and to assemble the final +string from resulting `Part`s itself. + +All algorithms and formatting functions are accompanied by extensive tests +in `coretest::num::flt2dec` module. It also shows how to use individual +functions. + +*/ + +// while this is extensively documented, this is in principle private which is +// only made public for testing. do not expose us. +#![doc(hidden)] + +use prelude::*; +use i16; +use num::Float; +use slice::bytes; +pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded}; + +pub mod estimator; +pub mod bignum; +pub mod decoder; + +/// Digit-generation algorithms. +pub mod strategy { + pub mod dragon; + pub mod grisu; +} + +/// The minimum size of buffer necessary for the shortest mode. +/// +/// It is a bit non-trivial to derive, but this is one plus the maximal number of +/// significant decimal digits from formatting algorithms with the shortest result. +/// The exact formula is `ceil(# bits in mantissa * log_10 2 + 1)`. +pub const MAX_SIG_DIGITS: usize = 17; + +/// When `d[..n]` contains decimal digits, increase the last digit and propagate carry. +/// Returns a next digit when it causes the length change. +#[doc(hidden)] +pub fn round_up(d: &mut [u8], n: usize) -> Option { + match d[..n].iter().rposition(|&c| c != b'9') { + Some(i) => { // d[i+1..n] is all nines + d[i] += 1; + for j in i+1..n { d[j] = b'0'; } + None + } + None if n > 0 => { // 999..999 rounds to 1000..000 with an increased exponent + d[0] = b'1'; + for j in 1..n { d[j] = b'0'; } + Some(b'0') + } + None => { // an empty buffer rounds up (a bit strange but reasonable) + Some(b'1') + } + } +} + +/// Formatted parts. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Part<'a> { + /// Given number of zero digits. + Zero(usize), + /// A literal number up to 5 digits. + Num(u16), + /// A verbatim copy of given bytes. + Copy(&'a [u8]), +} + +impl<'a> Part<'a> { + /// Returns the exact byte length of given part. + pub fn len(&self) -> usize { + match *self { + Part::Zero(nzeroes) => nzeroes, + Part::Num(v) => if v < 1_000 { if v < 10 { 1 } else if v < 100 { 2 } else { 3 } } + else { if v < 10_000 { 4 } else { 5 } }, + Part::Copy(buf) => buf.len(), + } + } + + /// Writes a part into the supplied buffer. + /// Returns the number of written bytes, or `None` if the buffer is not enough. + /// (It may still leave partially written bytes in the buffer; do not rely on that.) + pub fn write(&self, out: &mut [u8]) -> Option { + let len = self.len(); + if out.len() >= len { + match *self { + Part::Zero(nzeroes) => { + for c in &mut out[..nzeroes] { *c = b'0'; } + } + Part::Num(mut v) => { + for c in out[..len].iter_mut().rev() { + *c = b'0' + (v % 10) as u8; + v /= 10; + } + } + Part::Copy(buf) => { + bytes::copy_memory(buf, out); + } + } + Some(len) + } else { + None + } + } +} + +/// Formatted result containing one or more parts. +/// This can be written to the byte buffer or converted to the allocated string. +#[derive(Clone)] +pub struct Formatted<'a> { + /// A byte slice representing a sign, either `""`, `"-"` or `"+"`. + pub sign: &'static [u8], + /// Formatted parts to be rendered after a sign and optional zero padding. + pub parts: &'a [Part<'a>], +} + +impl<'a> Formatted<'a> { + /// Returns the exact byte length of combined formatted result. + pub fn len(&self) -> usize { + let mut len = self.sign.len(); + for part in self.parts { + len += part.len(); + } + len + } + + /// Writes all formatted parts into the supplied buffer. + /// Returns the number of written bytes, or `None` if the buffer is not enough. + /// (It may still leave partially written bytes in the buffer; do not rely on that.) + pub fn write(&self, out: &mut [u8]) -> Option { + if out.len() < self.sign.len() { return None; } + bytes::copy_memory(self.sign, out); + + let mut written = self.sign.len(); + for part in self.parts { + match part.write(&mut out[written..]) { + Some(len) => { written += len; } + None => { return None; } + } + } + Some(written) + } +} + +/// Formats given decimal digits `0.<...buf...> * 10^exp` into the decimal form +/// with at least given number of fractional digits. The result is stored to +/// the supplied parts array and a slice of written parts is returned. +/// +/// `frac_digits` can be less than the number of actual fractional digits in `buf`; +/// it will be ignored and full digits will be printed. It is only used to print +/// additional zeroes after rendered digits. Thus `frac_digits` of 0 means that +/// it will only print given digits and nothing else. +fn digits_to_dec_str<'a>(buf: &'a [u8], exp: i16, frac_digits: usize, + parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] { + assert!(!buf.is_empty()); + assert!(buf[0] > b'0'); + assert!(parts.len() >= 4); + + // if there is the restriction on the last digit position, `buf` is assumed to be + // left-padded with the virtual zeroes. the number of virtual zeroes, `nzeroes`, + // equals to `max(0, exp + frac_digits - buf.len())`, so that the position of + // the last digit `exp - buf.len() - nzeroes` is no more than `-frac_digits`: + // + // |<-virtual->| + // |<---- buf ---->| zeroes | exp + // 0. 1 2 3 4 5 6 7 8 9 _ _ _ _ _ _ x 10 + // | | | + // 10^exp 10^(exp-buf.len()) 10^(exp-buf.len()-nzeroes) + // + // `nzeroes` is individually calculated for each case in order to avoid overflow. + + if exp <= 0 { + // the decimal point is before rendered digits: [0.][000...000][1234][____] + let minus_exp = -(exp as i32) as usize; + parts[0] = Part::Copy(b"0."); + parts[1] = Part::Zero(minus_exp); + parts[2] = Part::Copy(buf); + if frac_digits > buf.len() && frac_digits - buf.len() > minus_exp { + parts[3] = Part::Zero((frac_digits - buf.len()) - minus_exp); + &parts[..4] + } else { + &parts[..3] + } + } else { + let exp = exp as usize; + if exp < buf.len() { + // the decimal point is inside rendered digits: [12][.][34][____] + parts[0] = Part::Copy(&buf[..exp]); + parts[1] = Part::Copy(b"."); + parts[2] = Part::Copy(&buf[exp..]); + if frac_digits > buf.len() - exp { + parts[3] = Part::Zero(frac_digits - (buf.len() - exp)); + &parts[..4] + } else { + &parts[..3] + } + } else { + // the decimal point is after rendered digits: [1234][____0000] or [1234][__][.][__]. + parts[0] = Part::Copy(buf); + parts[1] = Part::Zero(exp - buf.len()); + if frac_digits > 0 { + parts[2] = Part::Copy(b"."); + parts[3] = Part::Zero(frac_digits); + &parts[..4] + } else { + &parts[..2] + } + } + } +} + +/// Formats given decimal digits `0.<...buf...> * 10^exp` into the exponential form +/// with at least given number of significant digits. When `upper` is true, +/// the exponent will be prefixed by `E`; otherwise that's `e`. The result is +/// stored to the supplied parts array and a slice of written parts is returned. +/// +/// `min_digits` can be less than the number of actual significant digits in `buf`; +/// it will be ignored and full digits will be printed. It is only used to print +/// additional zeroes after rendered digits. Thus `min_digits` of 0 means that +/// it will only print given digits and nothing else. +fn digits_to_exp_str<'a>(buf: &'a [u8], exp: i16, min_ndigits: usize, upper: bool, + parts: &'a mut [Part<'a>]) -> &'a [Part<'a>] { + assert!(!buf.is_empty()); + assert!(buf[0] > b'0'); + assert!(parts.len() >= 6); + + let mut n = 0; + + parts[n] = Part::Copy(&buf[..1]); + n += 1; + + if buf.len() > 1 || min_ndigits > 1 { + parts[n] = Part::Copy(b"."); + parts[n + 1] = Part::Copy(&buf[1..]); + n += 2; + if min_ndigits > buf.len() { + parts[n] = Part::Zero(min_ndigits - buf.len()); + n += 1; + } + } + + // 0.1234 x 10^exp = 1.234 x 10^(exp-1) + let exp = exp as i32 - 1; // avoid underflow when exp is i16::MIN + if exp < 0 { + parts[n] = Part::Copy(if upper { b"E-" } else { b"e-" }); + parts[n + 1] = Part::Num(-exp as u16); + } else { + parts[n] = Part::Copy(if upper { b"E" } else { b"e" }); + parts[n + 1] = Part::Num(exp as u16); + } + &parts[..n + 2] +} + +/// Sign formatting options. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Sign { + /// Prints `-` only for the negative non-zero values. + Minus, // -inf -1 0 0 1 inf nan + /// Prints `-` only for any negative values (including the negative zero). + MinusRaw, // -inf -1 -0 0 1 inf nan + /// Prints `-` for the negative non-zero values, or `+` otherwise. + MinusPlus, // -inf -1 +0 +0 +1 +inf nan + /// Prints `-` for any negative values (including the negative zero), or `+` otherwise. + MinusPlusRaw, // -inf -1 -0 +0 +1 +inf nan +} + +/// Returns the static byte string corresponding to the sign to be formatted. +/// It can be either `b""`, `b"+"` or `b"-"`. +fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static [u8] { + match (*decoded, sign) { + (FullDecoded::Nan, _) => b"", + (FullDecoded::Zero, Sign::Minus) => b"", + (FullDecoded::Zero, Sign::MinusRaw) => if negative { b"-" } else { b"" }, + (FullDecoded::Zero, Sign::MinusPlus) => b"+", + (FullDecoded::Zero, Sign::MinusPlusRaw) => if negative { b"-" } else { b"+" }, + (_, Sign::Minus) | (_, Sign::MinusRaw) => if negative { b"-" } else { b"" }, + (_, Sign::MinusPlus) | (_, Sign::MinusPlusRaw) => if negative { b"-" } else { b"+" }, + } +} + +/// Formats given floating point number into the decimal form with at least +/// given number of fractional digits. The result is stored to the supplied parts +/// array while utilizing given byte buffer as a scratch. `upper` is currently +/// unused but left for the future decision to change the case of non-finite values, +/// i.e. `inf` and `nan`. The first part to be rendered is always a `Part::Sign` +/// (which can be an empty string if no sign is rendered). +/// +/// `format_shortest` should be the underlying digit-generation function. +/// You probably would want `strategy::grisu::format_shortest` for this. +/// +/// `frac_digits` can be less than the number of actual fractional digits in `v`; +/// it will be ignored and full digits will be printed. It is only used to print +/// additional zeroes after rendered digits. Thus `frac_digits` of 0 means that +/// it will only print given digits and nothing else. +/// +/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long. +/// There should be at least 5 parts available, due to the worst case like +/// `[+][0.][0000][45][0000]` with `frac_digits = 10`. +pub fn to_shortest_str<'a, T, F>(mut format_shortest: F, v: T, + sign: Sign, frac_digits: usize, _upper: bool, + buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + assert!(parts.len() >= 4); + assert!(buf.len() >= MAX_SIG_DIGITS); + + let (negative, full_decoded) = decode(v); + let sign = determine_sign(sign, &full_decoded, negative); + match full_decoded { + FullDecoded::Nan => { + parts[0] = Part::Copy(b"NaN"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Infinite => { + parts[0] = Part::Copy(b"inf"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Zero => { + if frac_digits > 0 { // [0.][0000] + parts[0] = Part::Copy(b"0."); + parts[1] = Part::Zero(frac_digits); + Formatted { sign: sign, parts: &parts[..2] } + } else { + parts[0] = Part::Copy(b"0"); + Formatted { sign: sign, parts: &parts[..1] } + } + } + FullDecoded::Finite(ref decoded) => { + let (len, exp) = format_shortest(decoded, buf); + Formatted { sign: sign, + parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) } + } + } +} + +/// Formats given floating point number into the decimal form or +/// the exponential form, depending on the resulting exponent. The result is +/// stored to the supplied parts array while utilizing given byte buffer +/// as a scratch. `upper` is used to determine the case of non-finite values +/// (`inf` and `nan`) or the case of the exponent prefix (`e` or `E`). +/// The first part to be rendered is always a `Part::Sign` (which can be +/// an empty string if no sign is rendered). +/// +/// `format_shortest` should be the underlying digit-generation function. +/// You probably would want `strategy::grisu::format_shortest` for this. +/// +/// The `dec_bounds` is a tuple `(lo, hi)` such that the number is formatted +/// as decimal only when `10^lo <= V < 10^hi`. Note that this is the *apparant* `V` +/// instead of the actual `v`! Thus any printed exponent in the exponential form +/// cannot be in this range, avoiding any confusion. +/// +/// The byte buffer should be at least `MAX_SIG_DIGITS` bytes long. +/// There should be at least 7 parts available, due to the worst case like +/// `[+][1][.][2345][e][-][67]`. +pub fn to_shortest_exp_str<'a, T, F>(mut format_shortest: F, v: T, + sign: Sign, dec_bounds: (i16, i16), upper: bool, + buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + assert!(parts.len() >= 6); + assert!(buf.len() >= MAX_SIG_DIGITS); + assert!(dec_bounds.0 <= dec_bounds.1); + + let (negative, full_decoded) = decode(v); + let sign = determine_sign(sign, &full_decoded, negative); + match full_decoded { + FullDecoded::Nan => { + parts[0] = Part::Copy(b"NaN"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Infinite => { + parts[0] = Part::Copy(b"inf"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Zero => { + parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 { + Part::Copy(b"0") + } else { + Part::Copy(if upper { b"0E0" } else { b"0e0" }) + }; + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Finite(ref decoded) => { + let (len, exp) = format_shortest(decoded, buf); + let vis_exp = exp as i32 - 1; + let parts = if dec_bounds.0 as i32 <= vis_exp && vis_exp < dec_bounds.1 as i32 { + digits_to_dec_str(&buf[..len], exp, 0, parts) + } else { + digits_to_exp_str(&buf[..len], exp, 0, upper, parts) + }; + Formatted { sign: sign, parts: parts } + } + } +} + +/// Returns rather crude approximation (upper bound) for the maximum buffer size +/// calculated from the given decoded exponent. +/// +/// The exact limit is: +/// +/// - when `exp < 0`, the maximum length is `ceil(log_10 (5^-exp * (2^64 - 1)))`. +/// - when `exp >= 0`, the maximum length is `ceil(log_10 (2^exp * (2^64 - 1)))`. +/// +/// `ceil(log_10 (x^exp * (2^64 - 1)))` is less than `ceil(log_10 (2^64 - 1)) + +/// ceil(exp * log_10 x)`, which is in turn less than `20 + (1 + exp * log_10 x)`. +/// We use the facts that `log_10 2 < 5/16` and `log_10 5 < 12/16`, which is +/// enough for our purposes. +/// +/// Why do we need this? `format_exact` functions will fill the entire buffer +/// unless limited by the last digit restriction, but it is possible that +/// the number of digits requested is ridiculously large (say, 30,000 digits). +/// The vast majority of buffer will be filled with zeroes, so we don't want to +/// allocate all the buffer beforehand. Consequently, for any given arguments, +/// 826 bytes of buffer should be sufficient for `f64`. Compare this with +/// the actual number for the worst case: 770 bytes (when `exp = -1074`). +fn estimate_max_buf_len(exp: i16) -> usize { + 21 + ((if exp < 0 { -12 } else { 5 } * exp as i32) as usize >> 4) +} + +/// Formats given floating point number into the exponential form with +/// exactly given number of significant digits. The result is stored to +/// the supplied parts array while utilizing given byte buffer as a scratch. +/// `upper` is used to determine the case of the exponent prefix (`e` or `E`). +/// The first part to be rendered is always a `Part::Sign` (which can be +/// an empty string if no sign is rendered). +/// +/// `format_exact` should be the underlying digit-generation function. +/// You probably would want `strategy::grisu::format_exact` for this. +/// +/// The byte buffer should be at least `ndigits` bytes long unless `ndigits` is +/// so large that only the fixed number of digits will be ever written. +/// (The tipping point for `f64` is about 800, so 1000 bytes should be enough.) +/// There should be at least 7 parts available, due to the worst case like +/// `[+][1][.][2345][e][-][67]`. +pub fn to_exact_exp_str<'a, T, F>(mut format_exact: F, v: T, + sign: Sign, ndigits: usize, upper: bool, + buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + assert!(parts.len() >= 6); + assert!(ndigits > 0); + + let (negative, full_decoded) = decode(v); + let sign = determine_sign(sign, &full_decoded, negative); + match full_decoded { + FullDecoded::Nan => { + parts[0] = Part::Copy(b"NaN"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Infinite => { + parts[0] = Part::Copy(b"inf"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Zero => { + if ndigits > 1 { // [0.][0000][e0] + parts[0] = Part::Copy(b"0."); + parts[1] = Part::Zero(ndigits - 1); + parts[2] = Part::Copy(if upper { b"E0" } else { b"e0" }); + Formatted { sign: sign, parts: &parts[..3] } + } else { + parts[0] = Part::Copy(if upper { b"0E0" } else { b"0e0" }); + Formatted { sign: sign, parts: &parts[..1] } + } + } + FullDecoded::Finite(ref decoded) => { + let maxlen = estimate_max_buf_len(decoded.exp); + assert!(buf.len() >= ndigits || buf.len() >= maxlen); + + let trunc = if ndigits < maxlen { ndigits } else { maxlen }; + let (len, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN); + Formatted { sign: sign, + parts: digits_to_exp_str(&buf[..len], exp, ndigits, upper, parts) } + } + } +} + +/// Formats given floating point number into the decimal form with exactly +/// given number of fractional digits. The result is stored to the supplied parts +/// array while utilizing given byte buffer as a scratch. `upper` is currently +/// unused but left for the future decision to change the case of non-finite values, +/// i.e. `inf` and `nan`. The first part to be rendered is always a `Part::Sign` +/// (which can be an empty string if no sign is rendered). +/// +/// `format_exact` should be the underlying digit-generation function. +/// You probably would want `strategy::grisu::format_exact` for this. +/// +/// The byte buffer should be enough for the output unless `frac_digits` is +/// so large that only the fixed number of digits will be ever written. +/// (The tipping point for `f64` is about 800, and 1000 bytes should be enough.) +/// There should be at least 5 parts available, due to the worst case like +/// `[+][0.][0000][45][0000]` with `frac_digits = 10`. +pub fn to_exact_fixed_str<'a, T, F>(mut format_exact: F, v: T, + sign: Sign, frac_digits: usize, _upper: bool, + buf: &'a mut [u8], parts: &'a mut [Part<'a>]) -> Formatted<'a> + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + assert!(parts.len() >= 4); + + let (negative, full_decoded) = decode(v); + let sign = determine_sign(sign, &full_decoded, negative); + match full_decoded { + FullDecoded::Nan => { + parts[0] = Part::Copy(b"NaN"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Infinite => { + parts[0] = Part::Copy(b"inf"); + Formatted { sign: sign, parts: &parts[..1] } + } + FullDecoded::Zero => { + if frac_digits > 0 { // [0.][0000] + parts[0] = Part::Copy(b"0."); + parts[1] = Part::Zero(frac_digits); + Formatted { sign: sign, parts: &parts[..2] } + } else { + parts[0] = Part::Copy(b"0"); + Formatted { sign: sign, parts: &parts[..1] } + } + } + FullDecoded::Finite(ref decoded) => { + let maxlen = estimate_max_buf_len(decoded.exp); + assert!(buf.len() >= maxlen); + + // it *is* possible that `frac_digits` is ridiculously large. + // `format_exact` will end rendering digits much earlier in this case, + // because we are strictly limited by `maxlen`. + let limit = if frac_digits < 0x8000 { -(frac_digits as i16) } else { i16::MIN }; + let (len, exp) = format_exact(decoded, &mut buf[..maxlen], limit); + if exp <= limit { + // the restriction couldn't been met, so this should render like zero no matter + // `exp` was. this does not include the case that the restriction has been met + // only after the final rounding-up; it's a regular case with `exp = limit + 1`. + debug_assert_eq!(len, 0); + if frac_digits > 0 { // [0.][0000] + parts[0] = Part::Copy(b"0."); + parts[1] = Part::Zero(frac_digits); + Formatted { sign: sign, parts: &parts[..2] } + } else { + parts[0] = Part::Copy(b"0"); + Formatted { sign: sign, parts: &parts[..1] } + } + } else { + Formatted { sign: sign, + parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) } + } + } + } +} + diff --git a/src/libcore/num/flt2dec/strategy/dragon.rs b/src/libcore/num/flt2dec/strategy/dragon.rs new file mode 100644 index 0000000000000..a819932525bd1 --- /dev/null +++ b/src/libcore/num/flt2dec/strategy/dragon.rs @@ -0,0 +1,331 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Almost direct (but slightly optimized) Rust translation of Figure 3 of [1]. + +[1] Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers + quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. +*/ + +use prelude::*; +use num::Float; +use cmp::Ordering; + +use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; +use num::flt2dec::estimator::estimate_scaling_factor; +use num::flt2dec::bignum::Digit32 as Digit; +use num::flt2dec::bignum::Big32x36 as Big; + +// FIXME(#22540) const ref to static array seems to ICE +static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000, + 1000000, 10000000, 100000000, 1000000000]; +static TWOPOW10: [Digit; 10] = [2, 20, 200, 2000, 20000, 200000, + 2000000, 20000000, 200000000, 2000000000]; + +// precalculated arrays of `Digit`s for 10^(2^n) +static POW10TO16: [Digit; 2] = [0x6fc10000, 0x2386f2]; +static POW10TO32: [Digit; 4] = [0, 0x85acef81, 0x2d6d415b, 0x4ee]; +static POW10TO64: [Digit; 7] = [0, 0, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed, 0xe93ff9f4, 0x184f03]; +static POW10TO128: [Digit; 14] = + [0, 0, 0, 0, 0x2e953e01, 0x3df9909, 0xf1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, + 0xbccdb0da, 0xa6337f19, 0xe91f2603, 0x24e]; +static POW10TO256: [Digit; 27] = + [0, 0, 0, 0, 0, 0, 0, 0, 0x982e7c01, 0xbed3875b, 0xd8d99f72, 0x12152f87, 0x6bde50c6, + 0xcf4a6e70, 0xd595d80f, 0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, + 0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x553f7]; + +#[doc(hidden)] +pub fn mul_pow10<'a>(x: &'a mut Big, n: usize) -> &'a mut Big { + debug_assert!(n < 512); + if n & 7 != 0 { x.mul_small(POW10[n & 7]); } + if n & 8 != 0 { x.mul_small(POW10[8]); } + if n & 16 != 0 { x.mul_digits(&POW10TO16); } + if n & 32 != 0 { x.mul_digits(&POW10TO32); } + if n & 64 != 0 { x.mul_digits(&POW10TO64); } + if n & 128 != 0 { x.mul_digits(&POW10TO128); } + if n & 256 != 0 { x.mul_digits(&POW10TO256); } + x +} + +fn div_2pow10<'a>(x: &'a mut Big, mut n: usize) -> &'a mut Big { + let largest = POW10.len() - 1; + while n > largest { + x.div_rem_small(POW10[largest]); + n -= largest; + } + x.div_rem_small(TWOPOW10[n]); + x +} + +// only usable when `x < 16 * scale`; `scaleN` should be `scale.mul_small(N)` +fn div_rem_upto_16<'a>(x: &'a mut Big, scale: &Big, + scale2: &Big, scale4: &Big, scale8: &Big) -> (u8, &'a mut Big) { + let mut d = 0; + if *x >= *scale8 { x.sub(scale8); d += 8; } + if *x >= *scale4 { x.sub(scale4); d += 4; } + if *x >= *scale2 { x.sub(scale2); d += 2; } + if *x >= *scale { x.sub(scale); d += 1; } + debug_assert!(*x < *scale); + (d, x) +} + +/// The shortest mode implementation for Dragon. +pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) { + // the number `v` to format is known to be: + // - equal to `mant * 2^exp`; + // - preceded by `(mant - 2 * minus) * 2^exp` in the original type; and + // - followed by `(mant + 2 * plus) * 2^exp` in the original type. + // + // obviously, `minus` and `plus` cannot be zero. (for infinities, we use out-of-range values.) + // also we assume that at least one digit is generated, i.e. `mant` cannot be zero too. + // + // this also means that any number between `low = (mant - minus) * 2^exp` and + // `high = (mant + plus) * 2^exp` will map to this exact floating point number, + // with bounds included when the original mantissa was even (i.e. `!mant_was_odd`). + + assert!(d.mant > 0); + assert!(d.minus > 0); + assert!(d.plus > 0); + assert!(d.mant.checked_add(d.plus).is_some()); + assert!(d.mant.checked_sub(d.minus).is_some()); + assert!(buf.len() >= MAX_SIG_DIGITS); + + // `a.cmp(&b) < rounding` is `if d.inclusive {a <= b} else {a < b}` + let rounding = if d.inclusive {Ordering::Greater} else {Ordering::Equal}; + + // estimate `k_0` from original inputs satisfying `10^(k_0-1) < high <= 10^(k_0+1)`. + // the tight bound `k` satisfying `10^(k-1) < high <= 10^k` is calculated later. + let mut k = estimate_scaling_factor(d.mant + d.plus, d.exp); + + // convert `{mant, plus, minus} * 2^exp` into the fractional form so that: + // - `v = mant / scale` + // - `low = (mant - minus) / scale` + // - `high = (mant + plus) / scale` + let mut mant = Big::from_u64(d.mant); + let mut minus = Big::from_u64(d.minus); + let mut plus = Big::from_u64(d.plus); + let mut scale = Big::from_small(1); + if d.exp < 0 { + scale.mul_pow2(-d.exp as usize); + } else { + mant.mul_pow2(d.exp as usize); + minus.mul_pow2(d.exp as usize); + plus.mul_pow2(d.exp as usize); + } + + // divide `mant` by `10^k`. now `scale / 10 < mant + plus <= scale * 10`. + if k >= 0 { + mul_pow10(&mut scale, k as usize); + } else { + mul_pow10(&mut mant, -k as usize); + mul_pow10(&mut minus, -k as usize); + mul_pow10(&mut plus, -k as usize); + } + + // fixup when `mant + plus > scale` (or `>=`). + // we are not actually modifying `scale`, since we can skip the initial multiplication instead. + // now `scale < mant + plus <= scale * 10` and we are ready to generate digits. + // + // note that `d[0]` *can* be zero, when `scale - plus < mant < scale`. + // in this case rounding-up condition (`up` below) will be triggered immediately. + if scale.cmp(mant.clone().add(&plus)) < rounding { + // equivalent to scaling `scale` by 10 + k += 1; + } else { + mant.mul_small(10); + minus.mul_small(10); + plus.mul_small(10); + } + + // cache `(2, 4, 8) * scale` for digit generation. + let mut scale2 = scale.clone(); scale2.mul_pow2(1); + let mut scale4 = scale.clone(); scale4.mul_pow2(2); + let mut scale8 = scale.clone(); scale8.mul_pow2(3); + + let mut down; + let mut up; + let mut i = 0; + loop { + // invariants, where `d[0..n-1]` are digits generated so far: + // - `v = mant / scale * 10^(k-n-1) + d[0..n-1] * 10^(k-n)` + // - `v - low = minus / scale * 10^(k-n-1)` + // - `high - v = plus / scale * 10^(k-n-1)` + // - `(mant + plus) / scale <= 10` (thus `mant / scale < 10`) + // where `d[i..j]` is a shorthand for `d[i] * 10^(j-i) + ... + d[j-1] * 10 + d[j]`. + + // generate one digit: `d[n] = floor(mant / scale) < 10`. + let (d, _) = div_rem_upto_16(&mut mant, &scale, &scale2, &scale4, &scale8); + debug_assert!(d < 10); + buf[i] = b'0' + d; + i += 1; + + // this is a simplified description of the modified Dragon algorithm. + // many intermediate derivations and completeness arguments are omitted for convenience. + // + // start with modified invariants, as we've updated `n`: + // - `v = mant / scale * 10^(k-n) + d[0..n-1] * 10^(k-n)` + // - `v - low = minus / scale * 10^(k-n)` + // - `high - v = plus / scale * 10^(k-n)` + // + // assume that `d[0..n-1]` is the shortest representation between `low` and `high`, + // i.e. `d[0..n-1]` satisfies both of the following but `d[0..n-2]` doesn't: + // - `low < d[0..n-1] * 10^(k-n) < high` (bijectivity: digits round to `v`); and + // - `abs(v / 10^(k-n) - d[0..n-1]) <= 1/2` (the last digit is correct). + // + // the second condition simplifies to `2 * mant <= scale`. + // solving invariants in terms of `mant`, `low` and `high` yields + // a simpler version of the first condition: `-plus < mant < minus`. + // since `-plus < 0 <= mant`, we have the correct shortest representation + // when `mant < minus` and `2 * mant <= scale`. + // (the former becomes `mant <= minus` when the original mantissa is even.) + // + // when the second doesn't hold (`2 * mant > scale`), we need to increase the last digit. + // this is enough for restoring that condition: we already know that + // the digit generation guarantees `0 <= v / 10^(k-n) - d[0..n-1] < 1`. + // in this case, the first condition becomes `-plus < mant - scale < minus`. + // since `mant < scale` after the generation, we have `scale < mant + plus`. + // (again, this becomes `scale <= mant + plus` when the original mantissa is even.) + // + // in short: + // - stop and round `down` (keep digits as is) when `mant < minus` (or `<=`). + // - stop and round `up` (increase the last digit) when `scale < mant + plus` (or `<=`). + // - keep generating otherwise. + down = mant.cmp(&minus) < rounding; + up = scale.cmp(mant.clone().add(&plus)) < rounding; + if down || up { break; } // we have the shortest representation, proceed to the rounding + + // restore the invariants. + // this makes the algorithm always terminating: `minus` and `plus` always increases, + // but `mant` is clipped modulo `scale` and `scale` is fixed. + mant.mul_small(10); + minus.mul_small(10); + plus.mul_small(10); + } + + // rounding up happens when + // i) only the rounding-up condition was triggered, or + // ii) both conditions were triggered and tie breaking prefers rounding up. + if up && (!down || *mant.mul_pow2(1) >= scale) { + // if rounding up changes the length, the exponent should also change. + // it seems that this condition is very hard to satisfy (possibly impossible), + // but we are just being safe and consistent here. + if let Some(c) = round_up(buf, i) { + buf[i] = c; + i += 1; + k += 1; + } + } + + (i, k) +} + +/// The exact and fixed mode implementation for Dragon. +pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) { + assert!(d.mant > 0); + assert!(d.minus > 0); + assert!(d.plus > 0); + assert!(d.mant.checked_add(d.plus).is_some()); + assert!(d.mant.checked_sub(d.minus).is_some()); + + // estimate `k_0` from original inputs satisfying `10^(k_0-1) < v <= 10^(k_0+1)`. + let mut k = estimate_scaling_factor(d.mant, d.exp); + + // `v = mant / scale`. + let mut mant = Big::from_u64(d.mant); + let mut scale = Big::from_small(1); + if d.exp < 0 { + scale.mul_pow2(-d.exp as usize); + } else { + mant.mul_pow2(d.exp as usize); + } + + // divide `mant` by `10^k`. now `scale / 10 < mant <= scale * 10`. + if k >= 0 { + mul_pow10(&mut scale, k as usize); + } else { + mul_pow10(&mut mant, -k as usize); + } + + // fixup when `mant + plus >= scale`, where `plus / scale = 10^-buf.len() / 2`. + // in order to keep the fixed-size bignum, we actually use `mant + floor(plus) >= scale`. + // we are not actually modifying `scale`, since we can skip the initial multiplication instead. + // again with the shortest algorithm, `d[0]` can be zero but will be eventually rounded up. + if *div_2pow10(&mut scale.clone(), buf.len()).add(&mant) >= scale { + // equivalent to scaling `scale` by 10 + k += 1; + } else { + mant.mul_small(10); + } + + // if we are working with the last-digit limitation, we need to shorten the buffer + // before the actual rendering in order to avoid double rounding. + // note that we have to enlarge the buffer again when rounding up happens! + let mut len = if k < limit { + // oops, we cannot even produce *one* digit. + // this is possible when, say, we've got something like 9.5 and it's being rounded to 10. + // we return an empty buffer, with an exception of the later rounding-up case + // which occurs when `k == limit` and has to produce exactly one digit. + 0 + } else if ((k as i32 - limit as i32) as usize) < buf.len() { + (k - limit) as usize + } else { + buf.len() + }; + + if len > 0 { + // cache `(2, 4, 8) * scale` for digit generation. + // (this can be expensive, so do not calculate them when the buffer is empty.) + let mut scale2 = scale.clone(); scale2.mul_pow2(1); + let mut scale4 = scale.clone(); scale4.mul_pow2(2); + let mut scale8 = scale.clone(); scale8.mul_pow2(3); + + for i in 0..len { + if mant.is_zero() { // following digits are all zeroes, we stop here + // do *not* try to perform rounding! rather, fill remaining digits. + for c in &mut buf[i..len] { *c = b'0'; } + return (len, k); + } + + let mut d = 0; + if mant >= scale8 { mant.sub(&scale8); d += 8; } + if mant >= scale4 { mant.sub(&scale4); d += 4; } + if mant >= scale2 { mant.sub(&scale2); d += 2; } + if mant >= scale { mant.sub(&scale); d += 1; } + debug_assert!(mant < scale); + debug_assert!(d < 10); + buf[i] = b'0' + d; + mant.mul_small(10); + } + } + + // rounding up if we stop in the middle of digits + // if the following digits are exactly 5000..., check the prior digit and try to + // round to even (i.e. avoid rounding up when the prior digit is even). + let order = mant.cmp(scale.mul_small(5)); + if order == Ordering::Greater || (order == Ordering::Equal && + (len == 0 || buf[len-1] & 1 == 1)) { + // if rounding up changes the length, the exponent should also change. + // but we've been requested a fixed number of digits, so do not alter the buffer... + if let Some(c) = round_up(buf, len) { + // ...unless we've been requested the fixed precision instead. + // we also need to check that, if the original buffer was empty, + // the additional digit can only be added when `k == limit` (edge case). + k += 1; + if k > limit && len < buf.len() { + buf[len] = c; + len += 1; + } + } + } + + (len, k) +} + diff --git a/src/libcore/num/flt2dec/strategy/grisu.rs b/src/libcore/num/flt2dec/strategy/grisu.rs new file mode 100644 index 0000000000000..220811e9985c3 --- /dev/null +++ b/src/libcore/num/flt2dec/strategy/grisu.rs @@ -0,0 +1,749 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +Rust adaptation of Grisu3 algorithm described in [1]. It uses about +1KB of precomputed table, and in turn, it's very quick for most inputs. + +[1] Florian Loitsch. 2010. Printing floating-point numbers quickly and + accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. +*/ + +use prelude::*; +use num::Float; + +use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; + +/// A custom 64-bit floating point type, representing `f * 2^e`. +#[derive(Copy, Clone, Debug)] +#[doc(hidden)] +pub struct Fp { + /// The integer mantissa. + pub f: u64, + /// The exponent in base 2. + pub e: i16, +} + +impl Fp { + /// Returns a correctly rounded product of itself and `other`. + fn mul(&self, other: &Fp) -> Fp { + const MASK: u64 = 0xffffffff; + let a = self.f >> 32; + let b = self.f & MASK; + let c = other.f >> 32; + let d = other.f & MASK; + let ac = a * c; + let bc = b * c; + let ad = a * d; + let bd = b * d; + let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */; + let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + let e = self.e + other.e + 64; + Fp { f: f, e: e } + } + + /// Normalizes itself so that the resulting mantissa is at least `2^63`. + fn normalize(&self) -> Fp { + let mut f = self.f; + let mut e = self.e; + if f >> (64 - 32) == 0 { f <<= 32; e -= 32; } + if f >> (64 - 16) == 0 { f <<= 16; e -= 16; } + if f >> (64 - 8) == 0 { f <<= 8; e -= 8; } + if f >> (64 - 4) == 0 { f <<= 4; e -= 4; } + if f >> (64 - 2) == 0 { f <<= 2; e -= 2; } + if f >> (64 - 1) == 0 { f <<= 1; e -= 1; } + debug_assert!(f >= (1 >> 63)); + Fp { f: f, e: e } + } + + /// Normalizes itself to have the shared exponent. + /// It can only decrease the exponent (and thus increase the mantissa). + fn normalize_to(&self, e: i16) -> Fp { + let edelta = self.e - e; + assert!(edelta >= 0); + let edelta = edelta as usize; + assert_eq!(self.f << edelta >> edelta, self.f); + Fp { f: self.f << edelta, e: e } + } +} + +// see the comments in `format_shortest_opt` for the rationale. +#[doc(hidden)] pub const ALPHA: i16 = -60; +#[doc(hidden)] pub const GAMMA: i16 = -32; + +/* +# the following Python code generates this table: +for i in xrange(-308, 333, 8): + if i >= 0: f = 10**i; e = 0 + else: f = 2**(80-4*i) // 10**-i; e = 4 * i - 80 + l = f.bit_length() + f = ((f << 64 >> (l-1)) + 1) >> 1; e += l - 64 + print ' (%#018x, %5d, %4d),' % (f, e, i) +*/ +// FIXME(#22540) const ref to static array seems to ICE +#[doc(hidden)] +pub static CACHED_POW10: [(u64, i16, i16); 81] = [ // (f, e, k) + (0xe61acf033d1a45df, -1087, -308), + (0xab70fe17c79ac6ca, -1060, -300), + (0xff77b1fcbebcdc4f, -1034, -292), + (0xbe5691ef416bd60c, -1007, -284), + (0x8dd01fad907ffc3c, -980, -276), + (0xd3515c2831559a83, -954, -268), + (0x9d71ac8fada6c9b5, -927, -260), + (0xea9c227723ee8bcb, -901, -252), + (0xaecc49914078536d, -874, -244), + (0x823c12795db6ce57, -847, -236), + (0xc21094364dfb5637, -821, -228), + (0x9096ea6f3848984f, -794, -220), + (0xd77485cb25823ac7, -768, -212), + (0xa086cfcd97bf97f4, -741, -204), + (0xef340a98172aace5, -715, -196), + (0xb23867fb2a35b28e, -688, -188), + (0x84c8d4dfd2c63f3b, -661, -180), + (0xc5dd44271ad3cdba, -635, -172), + (0x936b9fcebb25c996, -608, -164), + (0xdbac6c247d62a584, -582, -156), + (0xa3ab66580d5fdaf6, -555, -148), + (0xf3e2f893dec3f126, -529, -140), + (0xb5b5ada8aaff80b8, -502, -132), + (0x87625f056c7c4a8b, -475, -124), + (0xc9bcff6034c13053, -449, -116), + (0x964e858c91ba2655, -422, -108), + (0xdff9772470297ebd, -396, -100), + (0xa6dfbd9fb8e5b88f, -369, -92), + (0xf8a95fcf88747d94, -343, -84), + (0xb94470938fa89bcf, -316, -76), + (0x8a08f0f8bf0f156b, -289, -68), + (0xcdb02555653131b6, -263, -60), + (0x993fe2c6d07b7fac, -236, -52), + (0xe45c10c42a2b3b06, -210, -44), + (0xaa242499697392d3, -183, -36), + (0xfd87b5f28300ca0e, -157, -28), + (0xbce5086492111aeb, -130, -20), + (0x8cbccc096f5088cc, -103, -12), + (0xd1b71758e219652c, -77, -4), + (0x9c40000000000000, -50, 4), + (0xe8d4a51000000000, -24, 12), + (0xad78ebc5ac620000, 3, 20), + (0x813f3978f8940984, 30, 28), + (0xc097ce7bc90715b3, 56, 36), + (0x8f7e32ce7bea5c70, 83, 44), + (0xd5d238a4abe98068, 109, 52), + (0x9f4f2726179a2245, 136, 60), + (0xed63a231d4c4fb27, 162, 68), + (0xb0de65388cc8ada8, 189, 76), + (0x83c7088e1aab65db, 216, 84), + (0xc45d1df942711d9a, 242, 92), + (0x924d692ca61be758, 269, 100), + (0xda01ee641a708dea, 295, 108), + (0xa26da3999aef774a, 322, 116), + (0xf209787bb47d6b85, 348, 124), + (0xb454e4a179dd1877, 375, 132), + (0x865b86925b9bc5c2, 402, 140), + (0xc83553c5c8965d3d, 428, 148), + (0x952ab45cfa97a0b3, 455, 156), + (0xde469fbd99a05fe3, 481, 164), + (0xa59bc234db398c25, 508, 172), + (0xf6c69a72a3989f5c, 534, 180), + (0xb7dcbf5354e9bece, 561, 188), + (0x88fcf317f22241e2, 588, 196), + (0xcc20ce9bd35c78a5, 614, 204), + (0x98165af37b2153df, 641, 212), + (0xe2a0b5dc971f303a, 667, 220), + (0xa8d9d1535ce3b396, 694, 228), + (0xfb9b7cd9a4a7443c, 720, 236), + (0xbb764c4ca7a44410, 747, 244), + (0x8bab8eefb6409c1a, 774, 252), + (0xd01fef10a657842c, 800, 260), + (0x9b10a4e5e9913129, 827, 268), + (0xe7109bfba19c0c9d, 853, 276), + (0xac2820d9623bf429, 880, 284), + (0x80444b5e7aa7cf85, 907, 292), + (0xbf21e44003acdd2d, 933, 300), + (0x8e679c2f5e44ff8f, 960, 308), + (0xd433179d9c8cb841, 986, 316), + (0x9e19db92b4e31ba9, 1013, 324), + (0xeb96bf6ebadf77d9, 1039, 332), +]; + +#[doc(hidden)] pub const CACHED_POW10_FIRST_E: i16 = -1087; +#[doc(hidden)] pub const CACHED_POW10_LAST_E: i16 = 1039; + +#[doc(hidden)] +pub fn cached_power(alpha: i16, gamma: i16) -> (i16, Fp) { + let offset = CACHED_POW10_FIRST_E as i32; + let range = (CACHED_POW10.len() as i32) - 1; + let domain = (CACHED_POW10_LAST_E - CACHED_POW10_FIRST_E) as i32; + let idx = ((gamma as i32) - offset) * range / domain; + let (f, e, k) = CACHED_POW10[idx as usize]; + debug_assert!(alpha <= e && e <= gamma); + (k, Fp { f: f, e: e }) +} + +/// Given `x > 0`, returns `(k, 10^k)` such that `10^k <= x < 10^(k+1)`. +#[doc(hidden)] +pub fn max_pow10_no_more_than(x: u32) -> (u8, u32) { + debug_assert!(x > 0); + + const X9: u32 = 10_0000_0000; + const X8: u32 = 1_0000_0000; + const X7: u32 = 1000_0000; + const X6: u32 = 100_0000; + const X5: u32 = 10_0000; + const X4: u32 = 1_0000; + const X3: u32 = 1000; + const X2: u32 = 100; + const X1: u32 = 10; + + if x < X4 { + if x < X2 { if x < X1 {(0, 1)} else {(1, X1)} } + else { if x < X3 {(2, X2)} else {(3, X3)} } + } else { + if x < X6 { if x < X5 {(4, X4)} else {(5, X5)} } + else if x < X8 { if x < X7 {(6, X6)} else {(7, X7)} } + else { if x < X9 {(8, X8)} else {(9, X9)} } + } +} + +/// The shortest mode implementation for Grisu. +/// +/// It returns `None` when it would return an inexact representation otherwise. +pub fn format_shortest_opt(d: &Decoded, + buf: &mut [u8]) -> Option<(/*#digits*/ usize, /*exp*/ i16)> { + assert!(d.mant > 0); + assert!(d.minus > 0); + assert!(d.plus > 0); + assert!(d.mant.checked_add(d.plus).is_some()); + assert!(d.mant.checked_sub(d.minus).is_some()); + assert!(buf.len() >= MAX_SIG_DIGITS); + assert!(d.mant + d.plus < (1 << 61)); // we need at least three bits of additional precision + + // start with the normalized values with the shared exponent + let plus = Fp { f: d.mant + d.plus, e: d.exp }.normalize(); + let minus = Fp { f: d.mant - d.minus, e: d.exp }.normalize_to(plus.e); + let v = Fp { f: d.mant, e: d.exp }.normalize_to(plus.e); + + // find any `cached = 10^minusk` such that `ALPHA <= minusk + plus.e + 64 <= GAMMA`. + // since `plus` is normalized, this means `2^(62 + ALPHA) <= plus * cached < 2^(64 + GAMMA)`; + // given our choices of `ALPHA` and `GAMMA`, this puts `plus * cached` into `[4, 2^32)`. + // + // it is obviously desirable to maximize `GAMMA - ALPHA`, + // so that we don't need many cached powers of 10, but there are some considerations: + // + // 1. we want to keep `floor(plus * cached)` within `u32` since it needs a costly division. + // (this is not really avoidable, remainder is required for accuracy estimation.) + // 2. the remainder of `floor(plus * cached)` repeatedly gets multiplied by 10, + // and it should not overflow. + // + // the first gives `64 + GAMMA <= 32`, while the second gives `10 * 2^-ALPHA <= 2^64`; + // -60 and -32 is the maximal range with this constraint, and V8 also uses them. + let (minusk, cached) = cached_power(ALPHA - plus.e - 64, GAMMA - plus.e - 64); + + // scale fps. this gives the maximal error of 1 ulp (proved from Theorem 5.1). + let plus = plus.mul(&cached); + let minus = minus.mul(&cached); + let v = v.mul(&cached); + debug_assert_eq!(plus.e, minus.e); + debug_assert_eq!(plus.e, v.e); + + // +- actual range of minus + // | <---|---------------------- unsafe region --------------------------> | + // | | | + // | |<--->| | <--------------- safe region ---------------> | | + // | | | | | | + // |1 ulp|1 ulp| |1 ulp|1 ulp| |1 ulp|1 ulp| + // |<--->|<--->| |<--->|<--->| |<--->|<--->| + // |-----|-----|-------...-------|-----|-----|-------...-------|-----|-----| + // | minus | | v | | plus | + // minus1 minus0 v - 1 ulp v + 1 ulp plus0 plus1 + // + // above `minus`, `v` and `plus` are *quantized* approximations (error < 1 ulp). + // as we don't know the error is positive or negative, we use two approximations spaced equally + // and have the maximal error of 2 ulps. + // + // the "unsafe region" is a liberal interval which we initially generate. + // the "safe region" is a conservative interval which we only accept. + // we start with the correct repr within the unsafe region, and try to find the closest repr + // to `v` which is also within the safe region. if we can't, we give up. + let plus1 = plus.f + 1; +// let plus0 = plus.f - 1; // only for explanation +// let minus0 = minus.f + 1; // only for explanation + let minus1 = minus.f - 1; + let e = -plus.e as usize; // shared exponent + + // divide `plus1` into integral and fractional parts. + // integral parts are guaranteed to fit in u32, since cached power guarantees `plus < 2^32` + // and normalized `plus.f` is always less than `2^64 - 2^4` due to the precision requirement. + let plus1int = (plus1 >> e) as u32; + let plus1frac = plus1 & ((1 << e) - 1); + + // calculate the largest `10^max_kappa` no more than `plus1` (thus `plus1 < 10^(max_kappa+1)`). + // this is an upper bound of `kappa` below. + let (max_kappa, max_ten_kappa) = max_pow10_no_more_than(plus1int); + + let mut i = 0; + let exp = max_kappa as i16 - minusk + 1; + + // Theorem 6.2: if `k` is the greatest integer s.t. `0 <= y mod 10^k <= y - x`, + // then `V = floor(y / 10^k) * 10^k` is in `[x, y]` and one of the shortest + // representations (with the minimal number of significant digits) in that range. + // + // find the digit length `kappa` between `(minus1, plus1)` as per Theorem 6.2. + // Theorem 6.2 can be adopted to exclude `x` by requiring `y mod 10^k < y - x` instead. + // (e.g. `x` = 32000, `y` = 32777; `kappa` = 2 since `y mod 10^3 = 777 < y - x = 777`.) + // the algorithm relies on the later verification phase to exclude `y`. + let delta1 = plus1 - minus1; +// let delta1int = (delta1 >> e) as usize; // only for explanation + let delta1frac = delta1 & ((1 << e) - 1); + + // render integral parts, while checking for the accuracy at each step. + let mut kappa = max_kappa as i16; + let mut ten_kappa = max_ten_kappa; // 10^kappa + let mut remainder = plus1int; // digits yet to be rendered + loop { // we always have at least one digit to render, as `plus1 >= 10^kappa` + // invariants: + // - `delta1int <= remainder < 10^(kappa+1)` + // - `plus1int = d[0..n-1] * 10^(kappa+1) + remainder` + // (it follows that `remainder = plus1int % 10^(kappa+1)`) + + // divide `remainder` by `10^kappa`. both are scaled by `2^-e`. + let q = remainder / ten_kappa; + let r = remainder % ten_kappa; + debug_assert!(q < 10); + buf[i] = b'0' + q as u8; + i += 1; + + let plus1rem = ((r as u64) << e) + plus1frac; // == (plus1 % 10^kappa) * 2^e + if plus1rem < delta1 { + // `plus1 % 10^kappa < delta1 = plus1 - minus1`; we've found the correct `kappa`. + let ten_kappa = (ten_kappa as u64) << e; // scale 10^kappa back to the shared exponent + return round_and_weed(&mut buf[..i], exp, plus1rem, delta1, plus1 - v.f, ten_kappa, 1); + } + + // break the loop when we have rendered all integral digits. + // the exact number of digits is `max_kappa + 1` as `plus1 < 10^(max_kappa+1)`. + if i > max_kappa as usize { + debug_assert_eq!(ten_kappa, 1); + debug_assert_eq!(kappa, 0); + break; + } + + // restore invariants + kappa -= 1; + ten_kappa /= 10; + remainder = r; + } + + // render fractional parts, while checking for the accuracy at each step. + // this time we rely on repeated multiplications, as division will lose the precision. + let mut remainder = plus1frac; + let mut threshold = delta1frac; + let mut ulp = 1; + loop { // the next digit should be significant as we've tested that before breaking out + // invariants, where `m = max_kappa + 1` (# of digits in the integral part): + // - `remainder < 2^e` + // - `plus1frac * 10^(n-m) = d[m..n-1] * 2^e + remainder` + + remainder *= 10; // won't overflow, `2^e * 10 < 2^64` + threshold *= 10; + ulp *= 10; + + // divide `remainder` by `10^kappa`. + // both are scaled by `2^e / 10^kappa`, so the latter is implicit here. + let q = remainder >> e; + let r = remainder & ((1 << e) - 1); + debug_assert!(q < 10); + buf[i] = b'0' + q as u8; + i += 1; + + if r < threshold { + let ten_kappa = 1 << e; // implicit divisor + return round_and_weed(&mut buf[..i], exp, r, threshold, + (plus1 - v.f) * ulp, ten_kappa, ulp); + } + + // restore invariants + kappa -= 1; + remainder = r; + } + + // we've generated all significant digits of `plus1`, but not sure if it's the optimal one. + // for example, if `minus1` is 3.14153... and `plus1` is 3.14158..., there are 5 different + // shortest representation from 3.14154 to 3.14158 but we only have the greatest one. + // we have to successively decrease the last digit and check if this is the optimal repr. + // there are at most 9 candidates (..1 to ..9), so this is fairly quick. ("rounding" phase) + // + // the function checks if this "optimal" repr is actually within the ulp ranges, + // and also, it is possible that the "second-to-optimal" repr can actually be optimal + // due to the rounding error. in either cases this returns `None`. ("weeding" phase) + // + // all arguments here are scaled by the common (but implicit) value `k`, so that: + // - `remainder = (plus1 % 10^kappa) * k` + // - `threshold = (plus1 - minus1) * k` (and also, `remainder < threshold`) + // - `plus1v = (plus1 - v) * k` (and also, `threshold > plus1v` from prior invariants) + // - `ten_kappa = 10^kappa * k` + // - `ulp = 2^-e * k` + fn round_and_weed(buf: &mut [u8], exp: i16, remainder: u64, threshold: u64, plus1v: u64, + ten_kappa: u64, ulp: u64) -> Option<(usize, i16)> { + assert!(!buf.is_empty()); + + // produce two approximations to `v` (actually `plus1 - v`) within 1.5 ulps. + // the resulting representation should be the closest representation to both. + // + // here `plus1 - v` is used since calculations are done with respect to `plus1` + // in order to avoid overflow/underflow (hence the seemingly swapped names). + let plus1v_down = plus1v + ulp; // plus1 - (v - 1 ulp) + let plus1v_up = plus1v - ulp; // plus1 - (v + 1 ulp) + + // decrease the last digit and stop at the closest representation to `v + 1 ulp`. + let mut plus1w = remainder; // plus1w(n) = plus1 - w(n) + { + let last = buf.last_mut().unwrap(); + + // we work with the approximated digits `w(n)`, which is initially equal to `plus1 - + // plus1 % 10^kappa`. after running the loop body `n` times, `w(n) = plus1 - + // plus1 % 10^kappa - n * 10^kappa`. we set `plus1w(n) = plus1 - w(n) = + // plus1 % 10^kappa + n * 10^kappa` (thus `remainder = plus1w(0)`) to simplify checks. + // note that `plus1w(n)` is always increasing. + // + // we have three conditions to terminate. any of them will make the loop unable to + // proceed, but we then have at least one valid representation known to be closest to + // `v + 1 ulp` anyway. we will denote them as TC1 through TC3 for brevity. + // + // TC1: `w(n) <= v + 1 ulp`, i.e. this is the last repr that can be the closest one. + // this is equivalent to `plus1 - w(n) = plus1w(n) >= plus1 - (v + 1 ulp) = plus1v_up`. + // combined with TC2 (which checks if `w(n+1)` is valid), this prevents the possible + // overflow on the calculation of `plus1w(n)`. + // + // TC2: `w(n+1) < minus1`, i.e. the next repr definitely does not round to `v`. + // this is equivalent to `plus1 - w(n) + 10^kappa = plus1w(n) + 10^kappa > + // plus1 - minus1 = threshold`. the left hand side can overflow, but we know + // `threshold > plus1v`, so if TC1 is false, `threshold - plus1w(n) > + // threshold - (plus1v - 1 ulp) > 1 ulp` and we can safely test if + // `threshold - plus1w(n) < 10^kappa` instead. + // + // TC3: `abs(w(n) - (v + 1 ulp)) <= abs(w(n+1) - (v + 1 ulp))`, i.e. the next repr is + // no closer to `v + 1 ulp` than the current repr. given `z(n) = plus1v_up - plus1w(n)`, + // this becomes `abs(z(n)) <= abs(z(n+1))`. again assuming that TC1 is false, we have + // `z(n) > 0`. we have two cases to consider: + // + // - when `z(n+1) >= 0`: TC3 becomes `z(n) <= z(n+1)`. as `plus1w(n)` is increasing, + // `z(n)` should be decreasing and this is clearly false. + // - when `z(n+1) < 0`: + // - TC3a: the precondition is `plus1v_up < plus1w(n) + 10^kappa`. assuming TC2 is + // false, `threshold >= plus1w(n) + 10^kappa` so it cannot overflow. + // - TC3b: TC3 becomes `z(n) <= -z(n+1)`, i.e. `plus1v_up - plus1w(n) >= + // plus1w(n+1) - plus1v_up = plus1w(n) + 10^kappa - plus1v_up`. the negated TC1 + // gives `plus1v_up > plus1w(n)`, so it cannot overflow or underflow when + // combined with TC3a. + // + // consequently, we should stop when `TC1 || TC2 || (TC3a && TC3b)`. the following is + // equal to its inverse, `!TC1 && !TC2 && (!TC3a || !TC3b)`. + while plus1w < plus1v_up && + threshold - plus1w >= ten_kappa && + (plus1w + ten_kappa < plus1v_up || + plus1v_up - plus1w >= plus1w + ten_kappa - plus1v_up) { + *last -= 1; + debug_assert!(*last > b'0'); // the shortest repr cannot end with `0` + plus1w += ten_kappa; + } + } + + // check if this representation is also the closest representation to `v - 1 ulp`. + // + // this is simply same to the terminating conditions for `v + 1 ulp`, with all `plus1v_up` + // replaced by `plus1v_down` instead. overflow analysis equally holds. + if plus1w < plus1v_down && + threshold - plus1w >= ten_kappa && + (plus1w + ten_kappa < plus1v_down || + plus1v_down - plus1w >= plus1w + ten_kappa - plus1v_down) { + return None; + } + + // now we have the closest representation to `v` between `plus1` and `minus1`. + // this is too liberal, though, so we reject any `w(n)` not between `plus0` and `minus0`, + // i.e. `plus1 - plus1w(n) <= minus0` or `plus1 - plus1w(n) >= plus0`. we utilize the facts + // that `threshold = plus1 - minus1` and `plus1 - plus0 = minus0 - minus1 = 2 ulp`. + if 2 * ulp <= plus1w && plus1w <= threshold - 4 * ulp { + Some((buf.len(), exp)) + } else { + None + } + } +} + +/// The shortest mode implementation for Grisu with Dragon fallback. +/// +/// This should be used for most cases. +pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) { + use num::flt2dec::strategy::dragon::format_shortest as fallback; + match format_shortest_opt(d, buf) { + Some(ret) => ret, + None => fallback(d, buf), + } +} + +/// The exact and fixed mode implementation for Grisu. +/// +/// It returns `None` when it would return an inexact representation otherwise. +pub fn format_exact_opt(d: &Decoded, buf: &mut [u8], limit: i16) + -> Option<(/*#digits*/ usize, /*exp*/ i16)> { + assert!(d.mant > 0); + assert!(d.mant < (1 << 61)); // we need at least three bits of additional precision + assert!(!buf.is_empty()); + + // normalize and scale `v`. + let v = Fp { f: d.mant, e: d.exp }.normalize(); + let (minusk, cached) = cached_power(ALPHA - v.e - 64, GAMMA - v.e - 64); + let v = v.mul(&cached); + + // divide `v` into integral and fractional parts. + let e = -v.e as usize; + let vint = (v.f >> e) as u32; + let vfrac = v.f & ((1 << e) - 1); + + // both old `v` and new `v` (scaled by `10^-k`) has an error of < 1 ulp (Theorem 5.1). + // as we don't know the error is positive or negative, we use two approximations + // spaced equally and have the maximal error of 2 ulps (same to the shortest case). + // + // the goal is to find the exactly rounded series of digits that are common to + // both `v - 1 ulp` and `v + 1 ulp`, so that we are maximally confident. + // if this is not possible, we don't know which one is the correct output for `v`, + // so we give up and fall back. + // + // `err` is defined as `1 ulp * 2^e` here (same to the ulp in `vfrac`), + // and we will scale it whenever `v` gets scaled. + let mut err = 1; + + // calculate the largest `10^max_kappa` no more than `v` (thus `v < 10^(max_kappa+1)`). + // this is an upper bound of `kappa` below. + let (max_kappa, max_ten_kappa) = max_pow10_no_more_than(vint); + + let mut i = 0; + let exp = max_kappa as i16 - minusk + 1; + + // if we are working with the last-digit limitation, we need to shorten the buffer + // before the actual rendering in order to avoid double rounding. + // note that we have to enlarge the buffer again when rounding up happens! + let len = if exp <= limit { + // oops, we cannot even produce *one* digit. + // this is possible when, say, we've got something like 9.5 and it's being rounded to 10. + // + // in principle we can immediately call `possibly_round` with an empty buffer, + // but scaling `max_ten_kappa << e` by 10 can result in overflow. + // thus we are being sloppy here and widen the error range by a factor of 10. + // this will increase the false negative rate, but only very, *very* slightly; + // it can only matter noticably when the mantissa is bigger than 60 bits. + return possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e); + } else if ((exp as i32 - limit as i32) as usize) < buf.len() { + (exp - limit) as usize + } else { + buf.len() + }; + debug_assert!(len > 0); + + // render integral parts. + // the error is entirely fractional, so we don't need to check it in this part. + let mut kappa = max_kappa as i16; + let mut ten_kappa = max_ten_kappa; // 10^kappa + let mut remainder = vint; // digits yet to be rendered + loop { // we always have at least one digit to render + // invariants: + // - `remainder < 10^(kappa+1)` + // - `vint = d[0..n-1] * 10^(kappa+1) + remainder` + // (it follows that `remainder = vint % 10^(kappa+1)`) + + // divide `remainder` by `10^kappa`. both are scaled by `2^-e`. + let q = remainder / ten_kappa; + let r = remainder % ten_kappa; + debug_assert!(q < 10); + buf[i] = b'0' + q as u8; + i += 1; + + // is the buffer full? run the rounding pass with the remainder. + if i == len { + let vrem = ((r as u64) << e) + vfrac; // == (v % 10^kappa) * 2^e + return possibly_round(buf, len, exp, limit, vrem, (ten_kappa as u64) << e, err << e); + } + + // break the loop when we have rendered all integral digits. + // the exact number of digits is `max_kappa + 1` as `plus1 < 10^(max_kappa+1)`. + if i > max_kappa as usize { + debug_assert_eq!(ten_kappa, 1); + debug_assert_eq!(kappa, 0); + break; + } + + // restore invariants + kappa -= 1; + ten_kappa /= 10; + remainder = r; + } + + // render fractional parts. + // + // in principle we can continue to the last available digit and check for the accuracy. + // unfortunately we are working with the finite-sized integers, so we need some criterion + // to detect the overflow. V8 uses `remainder > err`, which becomes false when + // the first `i` significant digits of `v - 1 ulp` and `v` differ. however this rejects + // too many otherwise valid input. + // + // since the later phase has a correct overflow detection, we instead use tighter criterion: + // we continue til `err` exceeds `10^kappa / 2`, so that the range between `v - 1 ulp` and + // `v + 1 ulp` definitely contains two or more rounded representations. this is same to + // the first two comparisons from `possibly_round`, for the reference. + let mut remainder = vfrac; + let maxerr = 1 << (e - 1); + while err < maxerr { + // invariants, where `m = max_kappa + 1` (# of digits in the integral part): + // - `remainder < 2^e` + // - `vfrac * 10^(n-m) = d[m..n-1] * 2^e + remainder` + // - `err = 10^(n-m)` + + remainder *= 10; // won't overflow, `2^e * 10 < 2^64` + err *= 10; // won't overflow, `err * 10 < 2^e * 5 < 2^64` + + // divide `remainder` by `10^kappa`. + // both are scaled by `2^e / 10^kappa`, so the latter is implicit here. + let q = remainder >> e; + let r = remainder & ((1 << e) - 1); + debug_assert!(q < 10); + buf[i] = b'0' + q as u8; + i += 1; + + // is the buffer full? run the rounding pass with the remainder. + if i == len { + return possibly_round(buf, len, exp, limit, r, 1 << e, err); + } + + // restore invariants + remainder = r; + } + + // further calculation is useless (`possibly_round` definitely fails), so we give up. + return None; + + // we've generated all requested digits of `v`, which should be also same to corresponding + // digits of `v - 1 ulp`. now we check if there is a unique representation shared by + // both `v - 1 ulp` and `v + 1 ulp`; this can be either same to generated digits, or + // to the rounded-up version of those digits. if the range contains multiple representations + // of the same length, we cannot be sure and should return `None` instead. + // + // all arguments here are scaled by the common (but implicit) value `k`, so that: + // - `remainder = (v % 10^kappa) * k` + // - `ten_kappa = 10^kappa * k` + // - `ulp = 2^-e * k` + fn possibly_round(buf: &mut [u8], mut len: usize, mut exp: i16, limit: i16, + remainder: u64, ten_kappa: u64, ulp: u64) -> Option<(usize, i16)> { + debug_assert!(remainder < ten_kappa); + + // 10^kappa + // : : :<->: : + // : : : : : + // :|1 ulp|1 ulp| : + // :|<--->|<--->| : + // ----|-----|-----|---- + // | v | + // v - 1 ulp v + 1 ulp + // + // (for the reference, the dotted line indicates the exact value for + // possible representations in given number of digits.) + // + // error is too large that there are at least three possible representations + // between `v - 1 ulp` and `v + 1 ulp`. we cannot determine which one is correct. + if ulp >= ten_kappa { return None; } + + // 10^kappa + // :<------->: + // : : + // : |1 ulp|1 ulp| + // : |<--->|<--->| + // ----|-----|-----|---- + // | v | + // v - 1 ulp v + 1 ulp + // + // in fact, 1/2 ulp is enough to introduce two possible representations. + // (remember that we need a unique representation for both `v - 1 ulp` and `v + 1 ulp`.) + // this won't overflow, as `ulp < ten_kappa` from the first check. + if ten_kappa - ulp <= ulp { return None; } + + // remainder + // :<->| : + // : | : + // :<--------- 10^kappa ---------->: + // | : | : + // |1 ulp|1 ulp| : + // |<--->|<--->| : + // ----|-----|-----|------------------------ + // | v | + // v - 1 ulp v + 1 ulp + // + // if `v + 1 ulp` is closer to the rounded-down representation (which is already in `buf`), + // then we can safely return. note that `v - 1 ulp` *can* be less than the current + // representation, but as `1 ulp < 10^kappa / 2`, this condition is enough: + // the distance between `v - 1 ulp` and the current representation + // cannot exceed `10^kappa / 2`. + // + // the condition equals to `remainder + ulp < 10^kappa / 2`. + // since this can easily overflow, first check if `remainder < 10^kappa / 2`. + // we've already verified that `ulp < 10^kappa / 2`, so as long as + // `10^kappa` did not overflow after all, the second check is fine. + if ten_kappa - remainder > remainder && ten_kappa - 2 * remainder >= 2 * ulp { + return Some((len, exp)); + } + + // :<------- remainder ------>| : + // : | : + // :<--------- 10^kappa --------->: + // : | | : | + // : |1 ulp|1 ulp| + // : |<--->|<--->| + // -----------------------|-----|-----|----- + // | v | + // v - 1 ulp v + 1 ulp + // + // on the other hands, if `v - 1 ulp` is closer to the rounded-up representation, + // we should round up and return. for the same reason we don't need to check `v + 1 ulp`. + // + // the condition equals to `remainder - ulp >= 10^kappa / 2`. + // again we first check if `remainder > ulp` (note that this is not `remainder >= ulp`, + // as `10^kappa` is never zero). also note that `remainder - ulp <= 10^kappa`, + // so the second check does not overflow. + if remainder > ulp && ten_kappa - (remainder - ulp) <= remainder - ulp { + if let Some(c) = round_up(buf, len) { + // only add an additional digit when we've been requested the fixed precision. + // we also need to check that, if the original buffer was empty, + // the additional digit can only be added when `exp == limit` (edge case). + exp += 1; + if exp > limit && len < buf.len() { + buf[len] = c; + len += 1; + } + } + return Some((len, exp)); + } + + // otherwise we are doomed (i.e. some values between `v - 1 ulp` and `v + 1 ulp` are + // rounding down and others are rounding up) and give up. + None + } +} + +/// The exact and fixed mode implementation for Grisu with Dragon fallback. +/// +/// This should be used for most cases. +pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) { + use num::flt2dec::strategy::dragon::format_exact as fallback; + match format_exact_opt(d, buf, limit) { + Some(ret) => ret, + None => fallback(d, buf, limit), + } +} + diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 71c2b38287e0e..011830ddb7882 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -44,6 +44,9 @@ pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); #[unstable(feature = "core", reason = "may be removed or relocated")] pub mod wrapping; +#[unstable(feature = "core", reason = "internal routines only exposed for testing")] +pub mod flt2dec; + /// Types that have a "zero" value. /// /// This trait is intended for use in conjunction with `Add`, as an identity: diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index b7ca497db1863..69c2222949032 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -123,6 +123,7 @@ macro_rules! wrapping_impl { impl Not for Wrapping<$t> { type Output = Wrapping<$t>; + #[inline(always)] fn not(self) -> Wrapping<$t> { Wrapping(!self.0) } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 8a4f603ec4720..55c4264b10c70 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -91,7 +91,7 @@ use fmt; /// let _x = HasDrop; /// } /// ``` -#[lang="drop"] +#[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Drop { /// The `drop` method, called when the value goes out of scope. @@ -181,7 +181,7 @@ macro_rules! forward_ref_binop { /// Foo + Foo; /// } /// ``` -#[lang="add"] +#[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Add { /// The resulting type after applying the `+` operator @@ -235,7 +235,7 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo - Foo; /// } /// ``` -#[lang="sub"] +#[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Sub { /// The resulting type after applying the `-` operator @@ -289,7 +289,7 @@ sub_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo * Foo; /// } /// ``` -#[lang="mul"] +#[lang = "mul"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Mul { /// The resulting type after applying the `*` operator @@ -343,7 +343,7 @@ mul_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo / Foo; /// } /// ``` -#[lang="div"] +#[lang = "div"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Div { /// The resulting type after applying the `/` operator @@ -397,7 +397,7 @@ div_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Foo % Foo; /// } /// ``` -#[lang="rem"] +#[lang = "rem"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Rem { /// The resulting type after applying the `%` operator @@ -470,7 +470,7 @@ rem_float_impl! { f64, fmod } /// -Foo; /// } /// ``` -#[lang="neg"] +#[lang = "neg"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Neg { /// The resulting type after applying the `-` operator @@ -541,7 +541,7 @@ neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 } /// !Foo; /// } /// ``` -#[lang="not"] +#[lang = "not"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Not { /// The resulting type after applying the `!` operator @@ -595,7 +595,7 @@ not_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// Foo & Foo; /// } /// ``` -#[lang="bitand"] +#[lang = "bitand"] #[stable(feature = "rust1", since = "1.0.0")] pub trait BitAnd { /// The resulting type after applying the `&` operator @@ -649,7 +649,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// Foo | Foo; /// } /// ``` -#[lang="bitor"] +#[lang = "bitor"] #[stable(feature = "rust1", since = "1.0.0")] pub trait BitOr { /// The resulting type after applying the `|` operator @@ -703,7 +703,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// Foo ^ Foo; /// } /// ``` -#[lang="bitxor"] +#[lang = "bitxor"] #[stable(feature = "rust1", since = "1.0.0")] pub trait BitXor { /// The resulting type after applying the `^` operator @@ -757,7 +757,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// Foo << Foo; /// } /// ``` -#[lang="shl"] +#[lang = "shl"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Shl { /// The resulting type after applying the `<<` operator @@ -829,7 +829,7 @@ shl_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// Foo >> Foo; /// } /// ``` -#[lang="shr"] +#[lang = "shr"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Shr { /// The resulting type after applying the `>>` operator @@ -902,7 +902,7 @@ shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// Foo[Bar]; /// } /// ``` -#[lang="index"] +#[lang = "index"] #[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Index { @@ -949,7 +949,7 @@ pub trait Index { /// &mut Foo[Bar]; /// } /// ``` -#[lang="index_mut"] +#[lang = "index_mut"] #[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] #[stable(feature = "rust1", since = "1.0.0")] pub trait IndexMut: Index { @@ -960,7 +960,7 @@ pub trait IndexMut: Index { /// An unbounded range. #[derive(Copy, Clone, PartialEq, Eq)] -#[lang="range_full"] +#[lang = "range_full"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFull; @@ -973,7 +973,7 @@ impl fmt::Debug for RangeFull { /// A (half-open) range which is bounded at both ends. #[derive(Clone, PartialEq, Eq)] -#[lang="range"] +#[lang = "range"] #[stable(feature = "rust1", since = "1.0.0")] pub struct Range { /// The lower bound of the range (inclusive). @@ -993,7 +993,7 @@ impl fmt::Debug for Range { /// A range which is only bounded below. #[derive(Clone, PartialEq, Eq)] -#[lang="range_from"] +#[lang = "range_from"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeFrom { /// The lower bound of the range (inclusive). @@ -1010,7 +1010,7 @@ impl fmt::Debug for RangeFrom { /// A range which is only bounded above. #[derive(Copy, Clone, PartialEq, Eq)] -#[lang="range_to"] +#[lang = "range_to"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RangeTo { /// The upper bound of the range (exclusive). @@ -1053,7 +1053,7 @@ impl fmt::Debug for RangeTo { /// assert_eq!('a', *x); /// } /// ``` -#[lang="deref"] +#[lang = "deref"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Deref { /// The resulting type after dereferencing @@ -1114,7 +1114,7 @@ impl<'a, T: ?Sized> Deref for &'a mut T { /// assert_eq!('b', *x); /// } /// ``` -#[lang="deref_mut"] +#[lang = "deref_mut"] #[stable(feature = "rust1", since = "1.0.0")] pub trait DerefMut: Deref { /// The method called to mutably dereference a value @@ -1128,7 +1128,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { } /// A version of the call operator that takes an immutable receiver. -#[lang="fn"] +#[lang = "fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] #[fundamental] // so that regex can rely that `&str: !FnMut` @@ -1138,7 +1138,7 @@ pub trait Fn : FnMut { } /// A version of the call operator that takes a mutable receiver. -#[lang="fn_mut"] +#[lang = "fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] #[fundamental] // so that regex can rely that `&str: !FnMut` @@ -1148,7 +1148,7 @@ pub trait FnMut : FnOnce { } /// A version of the call operator that takes a by-value receiver. -#[lang="fn_once"] +#[lang = "fn_once"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] #[fundamental] // so that regex can rely that `&str: !FnMut` diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 0b8a52329dce6..635150c088688 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -33,7 +33,7 @@ use fmt; #[cold] #[inline(never)] // this is the slow path, always -#[lang="panic"] +#[lang = "panic"] pub fn panic(expr_file_line: &(&'static str, &'static str, u32)) -> ! { // Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially // reduce size overhead. The format_args! macro uses str's Display trait to @@ -46,7 +46,7 @@ pub fn panic(expr_file_line: &(&'static str, &'static str, u32)) -> ! { } #[cold] #[inline(never)] -#[lang="panic_bounds_check"] +#[lang = "panic_bounds_check"] fn panic_bounds_check(file_line: &(&'static str, u32), index: usize, len: usize) -> ! { panic_fmt(format_args!("index out of bounds: the len is {} but the index is {}", diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index c9bbcba31e9de..4d39607b16e92 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -21,6 +21,7 @@ use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use char::CharExt; use clone::Clone; use cmp::{self, Eq}; +use convert::AsRef; use default::Default; use fmt; use iter::ExactSizeIterator; @@ -1184,7 +1185,7 @@ fn eq_slice_(a: &str, b: &str) -> bool { /// Bytewise slice equality /// NOTE: This function is (ab)used in rustc::middle::trans::_match /// to compare &[u8] byte slices that are not necessarily valid UTF-8. -#[lang="str_eq"] +#[lang = "str_eq"] #[inline] fn eq_slice(a: &str, b: &str) -> bool { eq_slice_(a, b) @@ -1842,6 +1843,14 @@ impl StrExt for str { fn parse(&self) -> Result { FromStr::from_str(self) } } +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef<[u8]> for str { + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + /// Pluck a code point out of a UTF-8-like byte slice and return the /// index of the next code point. #[inline] diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 1566972275284..90c1e8b132e42 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -30,6 +30,7 @@ extern crate core; extern crate test; extern crate libc; extern crate rustc_unicode; +extern crate rand; mod any; mod atomic; diff --git a/src/libcoretest/num/flt2dec/bignum.rs b/src/libcoretest/num/flt2dec/bignum.rs new file mode 100644 index 0000000000000..09a1ed41dadd1 --- /dev/null +++ b/src/libcoretest/num/flt2dec/bignum.rs @@ -0,0 +1,160 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::prelude::v1::*; +use core::num::flt2dec::bignum::tests::Big8x3 as Big; + +#[test] +#[should_panic] +fn test_from_u64_overflow() { + Big::from_u64(0x1000000); +} + +#[test] +fn test_add() { + assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7)); + assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3)); + assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3)); + assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001)); + assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665)); + assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665)); +} + +#[test] +#[should_panic] +fn test_add_overflow_1() { + Big::from_small(1).add(&Big::from_u64(0xffffff)); +} + +#[test] +#[should_panic] +fn test_add_overflow_2() { + Big::from_u64(0xffffff).add(&Big::from_small(1)); +} + +#[test] +fn test_sub() { + assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1)); + assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0)); +} + +#[test] +#[should_panic] +fn test_sub_underflow_1() { + Big::from_u64(0x10665).sub(&Big::from_u64(0x10666)); +} + +#[test] +#[should_panic] +fn test_sub_underflow_2() { + Big::from_small(0).sub(&Big::from_u64(0x123456)); +} + +#[test] +fn test_mul_small() { + assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35)); + assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01)); + assert_eq!(*Big::from_u64(0xffffff/13).mul_small(13), Big::from_u64(0xffffff)); +} + +#[test] +#[should_panic] +fn test_mul_small_overflow() { + Big::from_u64(0x800000).mul_small(2); +} + +#[test] +fn test_mul_pow2() { + assert_eq!(*Big::from_small(0x7).mul_pow2(4), Big::from_small(0x70)); + assert_eq!(*Big::from_small(0xff).mul_pow2(1), Big::from_u64(0x1fe)); + assert_eq!(*Big::from_small(0xff).mul_pow2(12), Big::from_u64(0xff000)); + assert_eq!(*Big::from_small(0x1).mul_pow2(23), Big::from_u64(0x800000)); + assert_eq!(*Big::from_u64(0x123).mul_pow2(0), Big::from_u64(0x123)); + assert_eq!(*Big::from_u64(0x123).mul_pow2(7), Big::from_u64(0x9180)); + assert_eq!(*Big::from_u64(0x123).mul_pow2(15), Big::from_u64(0x918000)); + assert_eq!(*Big::from_small(0).mul_pow2(23), Big::from_small(0)); +} + +#[test] +#[should_panic] +fn test_mul_pow2_overflow_1() { + Big::from_u64(0x1).mul_pow2(24); +} + +#[test] +#[should_panic] +fn test_mul_pow2_overflow_2() { + Big::from_u64(0x123).mul_pow2(16); +} + +#[test] +fn test_mul_digits() { + assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15)); + assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01)); + assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2)); + assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3)); + assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e)); + assert_eq!(*Big::from_u64(0xffffff/13).mul_digits(&[13]), Big::from_u64(0xffffff)); + assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff)); +} + +#[test] +#[should_panic] +fn test_mul_digits_overflow_1() { + Big::from_u64(0x800000).mul_digits(&[2]); +} + +#[test] +#[should_panic] +fn test_mul_digits_overflow_2() { + Big::from_u64(0x1000).mul_digits(&[0, 0x10]); +} + +#[test] +fn test_div_rem_small() { + let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r); + assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0)); + assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15)); + assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3)); + assert_eq!(as_val(Big::from_u64(0xffffff).div_rem_small(123)), + (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8)); + assert_eq!(as_val(Big::from_u64(0x10000).div_rem_small(123)), + (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8)); +} + +#[test] +fn test_is_zero() { + assert!(Big::from_small(0).is_zero()); + assert!(!Big::from_small(3).is_zero()); + assert!(!Big::from_u64(0x123).is_zero()); + assert!(!Big::from_u64(0xffffff).sub(&Big::from_u64(0xfffffe)).is_zero()); + assert!(Big::from_u64(0xffffff).sub(&Big::from_u64(0xffffff)).is_zero()); +} + +#[test] +fn test_ord() { + assert!(Big::from_u64(0) < Big::from_u64(0xffffff)); + assert!(Big::from_u64(0x102) < Big::from_u64(0x201)); +} + +#[test] +fn test_fmt() { + assert_eq!(format!("{:?}", Big::from_u64(0)), "0x0"); + assert_eq!(format!("{:?}", Big::from_u64(0x1)), "0x1"); + assert_eq!(format!("{:?}", Big::from_u64(0x12)), "0x12"); + assert_eq!(format!("{:?}", Big::from_u64(0x123)), "0x1_23"); + assert_eq!(format!("{:?}", Big::from_u64(0x1234)), "0x12_34"); + assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45"); + assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56"); +} + diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcoretest/num/flt2dec/estimator.rs new file mode 100644 index 0000000000000..21260c520f623 --- /dev/null +++ b/src/libcoretest/num/flt2dec/estimator.rs @@ -0,0 +1,61 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::f64; +use core::num::flt2dec::estimator::*; + +#[test] +fn test_estimate_scaling_factor() { + macro_rules! assert_almost_eq { + ($actual:expr, $expected:expr) => ({ + let actual = $actual; + let expected = $expected; + println!("{} - {} = {} - {} = {}", stringify!($expected), stringify!($actual), + expected, actual, expected - actual); + assert!(expected == actual || expected == actual + 1, + "expected {}, actual {}", expected, actual); + }) + } + + assert_almost_eq!(estimate_scaling_factor(1, 0), 0); + assert_almost_eq!(estimate_scaling_factor(2, 0), 1); + assert_almost_eq!(estimate_scaling_factor(10, 0), 1); + assert_almost_eq!(estimate_scaling_factor(11, 0), 2); + assert_almost_eq!(estimate_scaling_factor(100, 0), 2); + assert_almost_eq!(estimate_scaling_factor(101, 0), 3); + assert_almost_eq!(estimate_scaling_factor(10000000000000000000, 0), 19); + assert_almost_eq!(estimate_scaling_factor(10000000000000000001, 0), 20); + + // 1/2^20 = 0.00000095367... + assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000, -20), -6); + assert_almost_eq!(estimate_scaling_factor(1 * 1048576 / 1000000 + 1, -20), -5); + assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000, -20), -5); + assert_almost_eq!(estimate_scaling_factor(10 * 1048576 / 1000000 + 1, -20), -4); + assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000, -20), -4); + assert_almost_eq!(estimate_scaling_factor(100 * 1048576 / 1000000 + 1, -20), -3); + assert_almost_eq!(estimate_scaling_factor(1048575, -20), 0); + assert_almost_eq!(estimate_scaling_factor(1048576, -20), 0); + assert_almost_eq!(estimate_scaling_factor(1048577, -20), 1); + assert_almost_eq!(estimate_scaling_factor(10485759999999999999, -20), 13); + assert_almost_eq!(estimate_scaling_factor(10485760000000000000, -20), 13); + assert_almost_eq!(estimate_scaling_factor(10485760000000000001, -20), 14); + + // extreme values: + // 2^-1074 = 4.94065... * 10^-324 + // (2^53-1) * 2^971 = 1.79763... * 10^308 + assert_almost_eq!(estimate_scaling_factor(1, -1074), -323); + assert_almost_eq!(estimate_scaling_factor(0x1fffffffffffff, 971), 309); + + for i in -1074..972 { + let expected = f64::ldexp(1.0, i).log10().ceil(); + assert_almost_eq!(estimate_scaling_factor(1, i as i16), expected as i16); + } +} + diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcoretest/num/flt2dec/mod.rs new file mode 100644 index 0000000000000..488cd3a779ca3 --- /dev/null +++ b/src/libcoretest/num/flt2dec/mod.rs @@ -0,0 +1,1178 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::prelude::v1::*; +use std::{str, mem, i16, f32, f64, fmt}; +use std::slice::bytes; +use std::__rand as rand; +use rand::{Rand, XorShiftRng}; +use rand::distributions::{IndependentSample, Range}; + +use core::num::flt2dec::{decode, DecodableFloat, FullDecoded, Decoded}; +use core::num::flt2dec::{MAX_SIG_DIGITS, round_up, Part, Formatted, Sign}; +use core::num::flt2dec::{to_shortest_str, to_shortest_exp_str, + to_exact_exp_str, to_exact_fixed_str}; + +pub use test::Bencher; + +mod estimator; +mod bignum; +mod strategy { + mod dragon; + mod grisu; +} + +pub fn decode_finite(v: T) -> Decoded { + match decode(v).1 { + FullDecoded::Finite(decoded) => decoded, + full_decoded => panic!("expected finite, got {:?} instead", full_decoded) + } +} + +macro_rules! check_shortest { + ($f:ident($v:expr) => $buf:expr, $exp:expr) => ( + check_shortest!($f($v) => $buf, $exp; + "shortest mismatch for v={v}: actual {actual:?}, expected {expected:?}", + v = stringify!($v)) + ); + + ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr) => ( + check_shortest!($f{$($k: $v),+} => $buf, $exp; + "shortest mismatch for {v:?}: actual {actual:?}, expected {expected:?}", + v = Decoded { $($k: $v),+ }) + ); + + ($f:ident($v:expr) => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ + let mut buf = [b'_'; MAX_SIG_DIGITS]; + let (len, k) = $f(&decode_finite($v), &mut buf); + assert!((&buf[..len], k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(&buf[..len]).unwrap(), k), + expected = (str::from_utf8($buf).unwrap(), $exp), + $($key = $val),*); + }); + + ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr; + $fmt:expr, $($key:ident = $val:expr),*) => ({ + let mut buf = [b'_'; MAX_SIG_DIGITS]; + let (len, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); + assert!((&buf[..len], k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(&buf[..len]).unwrap(), k), + expected = (str::from_utf8($buf).unwrap(), $exp), + $($key = $val),*); + }) +} + +macro_rules! try_exact { + ($f:ident($decoded:expr) => $buf:expr, $expected:expr, $expectedk:expr; + $fmt:expr, $($key:ident = $val:expr),*) => ({ + let (len, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); + assert!((&$buf[..len], k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(&$buf[..len]).unwrap(), k), + expected = (str::from_utf8($expected).unwrap(), $expectedk), + $($key = $val),*); + }) +} + +macro_rules! try_fixed { + ($f:ident($decoded:expr) => $buf:expr, $request:expr, $expected:expr, $expectedk:expr; + $fmt:expr, $($key:ident = $val:expr),*) => ({ + let (len, k) = $f($decoded, &mut $buf[..], $request); + assert!((&$buf[..len], k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(&$buf[..len]).unwrap(), k), + expected = (str::from_utf8($expected).unwrap(), $expectedk), + $($key = $val),*); + }) +} + +fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16) + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + // use a large enough buffer + let mut buf = [b'_'; 1024]; + let mut expected_ = [b'_'; 1024]; + + let decoded = decode_finite(v); + let cut = expected.iter().position(|&c| c == b' '); + + // check significant digits + for i in 1..cut.unwrap_or(expected.len() - 1) { + bytes::copy_memory(&expected[..i], &mut expected_); + let mut expectedk_ = expectedk; + if expected[i] >= b'5' { + // check if this is a rounding-to-even case. + // we avoid rounding ...x5000... (with infinite zeroes) to ...(x+1) when x is even. + if !(i+1 < expected.len() && expected[i-1] & 1 == 0 && + expected[i] == b'5' && + expected[i+1] == b' ') { + // if this returns true, expected_[..i] is all `9`s and being rounded up. + // we should always return `100..00` (`i` digits) instead, since that's + // what we can came up with `i` digits anyway. `round_up` assumes that + // the adjustment to the length is done by caller, which we simply ignore. + if let Some(_) = round_up(&mut expected_, i) { expectedk_ += 1; } + } + } + + try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk_; + "exact sigdigit mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + try_fixed!(f(&decoded) => &mut buf, expectedk_ - i as i16, &expected_[..i], expectedk_; + "fixed sigdigit mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + } + + // check exact rounding for zero- and negative-width cases + let start; + if expected[0] >= b'5' { + try_fixed!(f(&decoded) => &mut buf, expectedk, b"1", expectedk + 1; + "zero-width rounding-up mismatch for v={v}: \ + actual {actual:?}, expected {expected:?}", + v = vstr); + start = 1; + } else { + start = 0; + } + for i in start..-10 { + try_fixed!(f(&decoded) => &mut buf, expectedk - i, b"", expectedk; + "rounding-down mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = -i); + } + + // check infinite zero digits + if let Some(cut) = cut { + for i in cut..expected.len()-1 { + bytes::copy_memory(&expected[..cut], &mut expected_); + for c in &mut expected_[cut..i] { *c = b'0'; } + + try_exact!(f(&decoded) => &mut buf, &expected_[..i], expectedk; + "exact infzero mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + try_fixed!(f(&decoded) => &mut buf, expectedk - i as i16, &expected_[..i], expectedk; + "fixed infzero mismatch for v={v}, i={i}: \ + actual {actual:?}, expected {expected:?}", + v = vstr, i = i); + } + } +} + +fn check_exact_one(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16) + where T: DecodableFloat + fmt::Display, + F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + // use a large enough buffer + let mut buf = [b'_'; 1024]; + let v: T = DecodableFloat::ldexpi(x, e); + let decoded = decode_finite(v); + + try_exact!(f(&decoded) => &mut buf, &expected, expectedk; + "exact mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", + x = x, e = e, t = tstr); + try_fixed!(f(&decoded) => &mut buf, expectedk - expected.len() as i16, &expected, expectedk; + "fixed mismatch for v={x}p{e}{t}: actual {actual:?}, expected {expected:?}", + x = x, e = e, t = tstr); +} + +macro_rules! check_exact { + ($f:ident($v:expr) => $buf:expr, $exp:expr) => ( + check_exact(|d,b,k| $f(d,b,k), $v, stringify!($v), $buf, $exp) + ) +} + +macro_rules! check_exact_one { + ($f:ident($x:expr, $e:expr; $t:ty) => $buf:expr, $exp:expr) => ( + check_exact_one::<_, $t>(|d,b,k| $f(d,b,k), $x, $e, stringify!($t), $buf, $exp) + ) +} + +// in the following comments, three numbers are spaced by 1 ulp apart, +// and the second one is being formatted. +// +// some tests are derived from [1]. +// +// [1] Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion +// ftp://ftp.ee.lbl.gov/testbase-report.ps.Z + +pub fn f32_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + // 0.0999999940395355224609375 + // 0.100000001490116119384765625 + // 0.10000000894069671630859375 + check_shortest!(f(0.1f32) => b"1", 0); + + // 0.333333313465118408203125 + // 0.3333333432674407958984375 (1/3 in the default rounding) + // 0.33333337306976318359375 + check_shortest!(f(1.0f32/3.0) => b"33333334", 0); + + // 10^1 * 0.31415917873382568359375 + // 10^1 * 0.31415920257568359375 + // 10^1 * 0.31415922641754150390625 + check_shortest!(f(3.141592f32) => b"3141592", 1); + + // 10^18 * 0.31415916243714048 + // 10^18 * 0.314159196796878848 + // 10^18 * 0.314159231156617216 + check_shortest!(f(3.141592e17f32) => b"3141592", 18); + + // regression test for decoders + // 10^8 * 0.3355443 + // 10^8 * 0.33554432 + // 10^8 * 0.33554436 + check_shortest!(f(f32::ldexp(1.0, 25)) => b"33554432", 8); + + // 10^39 * 0.340282326356119256160033759537265639424 + // 10^39 * 0.34028234663852885981170418348451692544 + // 10^39 * 0.340282366920938463463374607431768211456 + check_shortest!(f(f32::MAX) => b"34028235", 39); + + // 10^-37 * 0.1175494210692441075487029444849287348827... + // 10^-37 * 0.1175494350822287507968736537222245677818... + // 10^-37 * 0.1175494490952133940450443629595204006810... + check_shortest!(f(f32::MIN_POSITIVE) => b"11754944", -37); + + // 10^-44 * 0 + // 10^-44 * 0.1401298464324817070923729583289916131280... + // 10^-44 * 0.2802596928649634141847459166579832262560... + let minf32 = f32::ldexp(1.0, -149); + check_shortest!(f(minf32) => b"1", -44); +} + +pub fn f32_exact_sanity_test(mut f: F) + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + let minf32 = f32::ldexp(1.0, -149); + + check_exact!(f(0.1f32) => b"100000001490116119384765625 ", 0); + check_exact!(f(0.5f32) => b"5 ", 0); + check_exact!(f(1.0f32/3.0) => b"3333333432674407958984375 ", 0); + check_exact!(f(3.141592f32) => b"31415920257568359375 ", 1); + check_exact!(f(3.141592e17f32) => b"314159196796878848 ", 18); + check_exact!(f(f32::MAX) => b"34028234663852885981170418348451692544 ", 39); + check_exact!(f(f32::MIN_POSITIVE) => b"1175494350822287507968736537222245677818", -37); + check_exact!(f(minf32) => b"1401298464324817070923729583289916131280", -44); + + // [1], Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP + check_exact_one!(f(12676506, -102; f32) => b"2", -23); + check_exact_one!(f(12676506, -103; f32) => b"12", -23); + check_exact_one!(f(15445013, 86; f32) => b"119", 34); + check_exact_one!(f(13734123, -138; f32) => b"3941", -34); + check_exact_one!(f(12428269, -130; f32) => b"91308", -32); + check_exact_one!(f(15334037, -146; f32) => b"171900", -36); + check_exact_one!(f(11518287, -41; f32) => b"5237910", -5); + check_exact_one!(f(12584953, -145; f32) => b"28216440", -36); + check_exact_one!(f(15961084, -125; f32) => b"375243281", -30); + check_exact_one!(f(14915817, -146; f32) => b"1672120916", -36); + check_exact_one!(f(10845484, -102; f32) => b"21388945814", -23); + check_exact_one!(f(16431059, -61; f32) => b"712583594561", -11); + + // [1], Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP + check_exact_one!(f(16093626, 69; f32) => b"1", 29); + check_exact_one!(f( 9983778, 25; f32) => b"34", 15); + check_exact_one!(f(12745034, 104; f32) => b"259", 39); + check_exact_one!(f(12706553, 72; f32) => b"6001", 29); + check_exact_one!(f(11005028, 45; f32) => b"38721", 21); + check_exact_one!(f(15059547, 71; f32) => b"355584", 29); + check_exact_one!(f(16015691, -99; f32) => b"2526831", -22); + check_exact_one!(f( 8667859, 56; f32) => b"62458507", 24); + check_exact_one!(f(14855922, -82; f32) => b"307213267", -17); + check_exact_one!(f(14855922, -83; f32) => b"1536066333", -17); + check_exact_one!(f(10144164, -110; f32) => b"78147796834", -26); + check_exact_one!(f(13248074, 95; f32) => b"524810279937", 36); +} + +pub fn f64_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + // 0.0999999999999999777955395074968691915273... + // 0.1000000000000000055511151231257827021181... + // 0.1000000000000000333066907387546962127089... + check_shortest!(f(0.1f64) => b"1", 0); + + // this example is explicitly mentioned in the paper. + // 10^3 * 0.0999999999999999857891452847979962825775... + // 10^3 * 0.1 (exact) + // 10^3 * 0.1000000000000000142108547152020037174224... + check_shortest!(f(100.0f64) => b"1", 3); + + // 0.3333333333333332593184650249895639717578... + // 0.3333333333333333148296162562473909929394... (1/3 in the default rounding) + // 0.3333333333333333703407674875052180141210... + check_shortest!(f(1.0f64/3.0) => b"3333333333333333", 0); + + // explicit test case for equally closest representations. + // Dragon has its own tie-breaking rule; Grisu should fall back. + // 10^1 * 0.1000007629394531027955395074968691915273... + // 10^1 * 0.100000762939453125 (exact) + // 10^1 * 0.1000007629394531472044604925031308084726... + check_shortest!(f(1.00000762939453125f64) => b"10000076293945313", 1); + + // 10^1 * 0.3141591999999999718085064159822650253772... + // 10^1 * 0.3141592000000000162174274009885266423225... + // 10^1 * 0.3141592000000000606263483859947882592678... + check_shortest!(f(3.141592f64) => b"3141592", 1); + + // 10^18 * 0.314159199999999936 + // 10^18 * 0.3141592 (exact) + // 10^18 * 0.314159200000000064 + check_shortest!(f(3.141592e17f64) => b"3141592", 18); + + // regression test for decoders + // 10^20 * 0.18446744073709549568 + // 10^20 * 0.18446744073709551616 + // 10^20 * 0.18446744073709555712 + check_shortest!(f(f64::ldexp(1.0, 64)) => b"18446744073709552", 20); + + // pathological case: high = 10^23 (exact). tie breaking should always prefer that. + // 10^24 * 0.099999999999999974834176 + // 10^24 * 0.099999999999999991611392 + // 10^24 * 0.100000000000000008388608 + check_shortest!(f(1.0e23f64) => b"1", 24); + + // 10^309 * 0.1797693134862315508561243283845062402343... + // 10^309 * 0.1797693134862315708145274237317043567980... + // 10^309 * 0.1797693134862315907729305190789024733617... + check_shortest!(f(f64::MAX) => b"17976931348623157", 309); + + // 10^-307 * 0.2225073858507200889024586876085859887650... + // 10^-307 * 0.2225073858507201383090232717332404064219... + // 10^-307 * 0.2225073858507201877155878558578948240788... + check_shortest!(f(f64::MIN_POSITIVE) => b"22250738585072014", -307); + + // 10^-323 * 0 + // 10^-323 * 0.4940656458412465441765687928682213723650... + // 10^-323 * 0.9881312916824930883531375857364427447301... + let minf64 = f64::ldexp(1.0, -1074); + check_shortest!(f(minf64) => b"5", -323); +} + +pub fn f64_exact_sanity_test(mut f: F) + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + let minf64 = f64::ldexp(1.0, -1074); + + check_exact!(f(0.1f64) => b"1000000000000000055511151231257827021181", 0); + check_exact!(f(0.45f64) => b"4500000000000000111022302462515654042363", 0); + check_exact!(f(0.5f64) => b"5 ", 0); + check_exact!(f(0.95f64) => b"9499999999999999555910790149937383830547", 0); + check_exact!(f(100.0f64) => b"1 ", 3); + check_exact!(f(999.5f64) => b"9995000000000000000000000000000000000000", 3); + check_exact!(f(1.0f64/3.0) => b"3333333333333333148296162562473909929394", 0); + check_exact!(f(3.141592f64) => b"3141592000000000162174274009885266423225", 1); + check_exact!(f(3.141592e17f64) => b"3141592 ", 18); + check_exact!(f(1.0e23f64) => b"99999999999999991611392 ", 23); + check_exact!(f(f64::MAX) => b"1797693134862315708145274237317043567980", 309); + check_exact!(f(f64::MIN_POSITIVE) => b"2225073858507201383090232717332404064219", -307); + check_exact!(f(minf64) => b"4940656458412465441765687928682213723650\ + 5980261432476442558568250067550727020875\ + 1865299836361635992379796564695445717730\ + 9266567103559397963987747960107818781263\ + 0071319031140452784581716784898210368871\ + 8636056998730723050006387409153564984387\ + 3124733972731696151400317153853980741262\ + 3856559117102665855668676818703956031062\ + 4931945271591492455329305456544401127480\ + 1297099995419319894090804165633245247571\ + 4786901472678015935523861155013480352649\ + 3472019379026810710749170333222684475333\ + 5720832431936092382893458368060106011506\ + 1698097530783422773183292479049825247307\ + 7637592724787465608477820373446969953364\ + 7017972677717585125660551199131504891101\ + 4510378627381672509558373897335989936648\ + 0994116420570263709027924276754456522908\ + 7538682506419718265533447265625 ", -323); + + // [1], Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP + check_exact_one!(f(8511030020275656, -342; f64) => b"9", -87); + check_exact_one!(f(5201988407066741, -824; f64) => b"46", -232); + check_exact_one!(f(6406892948269899, 237; f64) => b"141", 88); + check_exact_one!(f(8431154198732492, 72; f64) => b"3981", 38); + check_exact_one!(f(6475049196144587, 99; f64) => b"41040", 46); + check_exact_one!(f(8274307542972842, 726; f64) => b"292084", 235); + check_exact_one!(f(5381065484265332, -456; f64) => b"2891946", -121); + check_exact_one!(f(6761728585499734, -1057; f64) => b"43787718", -302); + check_exact_one!(f(7976538478610756, 376; f64) => b"122770163", 130); + check_exact_one!(f(5982403858958067, 377; f64) => b"1841552452", 130); + check_exact_one!(f(5536995190630837, 93; f64) => b"54835744350", 44); + check_exact_one!(f(7225450889282194, 710; f64) => b"389190181146", 230); + check_exact_one!(f(7225450889282194, 709; f64) => b"1945950905732", 230); + check_exact_one!(f(8703372741147379, 117; f64) => b"14460958381605", 52); + check_exact_one!(f(8944262675275217, -1001; f64) => b"417367747458531", -285); + check_exact_one!(f(7459803696087692, -707; f64) => b"1107950772878888", -196); + check_exact_one!(f(6080469016670379, -381; f64) => b"12345501366327440", -98); + check_exact_one!(f(8385515147034757, 721; f64) => b"925031711960365024", 233); + check_exact_one!(f(7514216811389786, -828; f64) => b"4198047150284889840", -233); + check_exact_one!(f(8397297803260511, -345; f64) => b"11716315319786511046", -87); + check_exact_one!(f(6733459239310543, 202; f64) => b"432810072844612493629", 77); + check_exact_one!(f(8091450587292794, -473; f64) => b"3317710118160031081518", -126); + + // [1], Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP + check_exact_one!(f(6567258882077402, 952; f64) => b"3", 303); + check_exact_one!(f(6712731423444934, 535; f64) => b"76", 177); + check_exact_one!(f(6712731423444934, 534; f64) => b"378", 177); + check_exact_one!(f(5298405411573037, -957; f64) => b"4350", -272); + check_exact_one!(f(5137311167659507, -144; f64) => b"23037", -27); + check_exact_one!(f(6722280709661868, 363; f64) => b"126301", 126); + check_exact_one!(f(5344436398034927, -169; f64) => b"7142211", -35); + check_exact_one!(f(8369123604277281, -853; f64) => b"13934574", -240); + check_exact_one!(f(8995822108487663, -780; f64) => b"141463449", -218); + check_exact_one!(f(8942832835564782, -383; f64) => b"4539277920", -99); + check_exact_one!(f(8942832835564782, -384; f64) => b"22696389598", -99); + check_exact_one!(f(8942832835564782, -385; f64) => b"113481947988", -99); + check_exact_one!(f(6965949469487146, -249; f64) => b"7700366561890", -59); + check_exact_one!(f(6965949469487146, -250; f64) => b"38501832809448", -59); + check_exact_one!(f(6965949469487146, -251; f64) => b"192509164047238", -59); + check_exact_one!(f(7487252720986826, 548; f64) => b"6898586531774201", 181); + check_exact_one!(f(5592117679628511, 164; f64) => b"13076622631878654", 66); + check_exact_one!(f(8887055249355788, 665; f64) => b"136052020756121240", 217); + check_exact_one!(f(6994187472632449, 690; f64) => b"3592810217475959676", 224); + check_exact_one!(f(8797576579012143, 588; f64) => b"89125197712484551899", 193); + check_exact_one!(f(7363326733505337, 272; f64) => b"558769757362301140950", 98); + check_exact_one!(f(8549497411294502, -448; f64) => b"1176257830728540379990", -118); +} + +pub fn more_shortest_sanity_test(mut f: F) where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, + exp: 0, inclusive: true} => b"1", 18); + check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, + exp: 0, inclusive: false} => b"99999999999999999", 17); +} + +fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + V: FnMut(usize) -> Decoded { + assert!(k <= 1024); + + let mut npassed = 0; // f(x) = Some(g(x)) + let mut nignored = 0; // f(x) = None + + for i in 0..n { + if (i & 0xfffff) == 0 { + println!("in progress, {:x}/{:x} (ignored={} passed={} failed={})", + i, n, nignored, npassed, i - nignored - npassed); + } + + let decoded = v(i); + let mut buf1 = [0; 1024]; + if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { + let mut buf2 = [0; 1024]; + let (len2, e2) = g(&decoded, &mut buf2[..k]); + if e1 == e2 && &buf1[..len1] == &buf2[..len2] { + npassed += 1; + } else { + println!("equivalence test failed, {:x}/{:x}: {:?} f(i)={}e{} g(i)={}e{}", + i, n, decoded, str::from_utf8(&buf1[..len1]).unwrap(), e1, + str::from_utf8(&buf2[..len2]).unwrap(), e2); + } + } else { + nignored += 1; + } + } + println!("{}({}): done, ignored={} passed={} failed={}", + func, k, nignored, npassed, n - nignored - npassed); + assert!(nignored + npassed == n, + "{}({}): {} out of {} values returns an incorrect value!", + func, k, n - nignored - npassed, n); + (npassed, nignored) +} + +pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); + iterate("f32_random_equivalence_test", k, n, f, g, |_| { + let i: u32 = f32_range.ind_sample(&mut rng); + let x: f32 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); + let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); + iterate("f64_random_equivalence_test", k, n, f, g, |_| { + let i: u64 = f64_range.ind_sample(&mut rng); + let x: f64 = unsafe {mem::transmute(i)}; + decode_finite(x) + }); +} + +pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) + where F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, + G: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, + // so why not simply testing all of them? + // + // this is of course very stressful (and thus should be behind an `#[ignore]` attribute), + // but with `-C opt-level=3 -C lto` this only takes about an hour or so. + + // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges + let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", + k, 0x7f7f_ffff, f, g, |i: usize| { + let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; + decode_finite(x) + }); + assert_eq!((npassed, nignored), (2121451881, 17643158)); +} + +fn to_string_with_parts(mut f: F) -> String + where F: for<'a> FnMut(&'a mut [u8], &'a mut [Part<'a>]) -> Formatted<'a> { + let mut buf = [0; 1024]; + let mut parts = [Part::Zero(0); 16]; + let formatted = f(&mut buf, &mut parts); + let mut ret = vec![0; formatted.len()]; + assert_eq!(formatted.write(&mut ret), Some(ret.len())); + String::from_utf8(ret).unwrap() +} + +pub fn to_shortest_str_test(mut f_: F) + where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize, upper: bool) -> String + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + to_string_with_parts(|buf, parts| to_shortest_str(|d,b| f(d,b), v, sign, + frac_digits, upper, buf, parts)) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0, false), "-0"); + assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); + + assert_eq!(to_string(f, 1.0/0.0, Minus, 0, false), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusRaw, 0, true), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlus, 0, false), "+inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, 0, true), "+inf"); + assert_eq!(to_string(f, 0.0/0.0, Minus, 0, false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusRaw, 1, true), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, 64, true), "NaN"); + assert_eq!(to_string(f, -1.0/0.0, Minus, 0, false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusRaw, 1, true), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlus, 8, false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, 64, true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0, false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3.14"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3.14"); + assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0, false), "-3.14"); + assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); + + assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 12, false), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 13, false), "0.0000000000750"); + + assert_eq!(to_string(f, 1.9971e20, Minus, 0, false), "199710000000000000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, 1, false), "199710000000000000000.0"); + assert_eq!(to_string(f, 1.9971e20, Minus, 8, false), "199710000000000000000.00000000"); + + assert_eq!(to_string(f, f32::MAX, Minus, 0, false), format!("34028235{:0>31}", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 1, false), format!("34028235{:0>31}.0", "")); + assert_eq!(to_string(f, f32::MAX, Minus, 8, false), format!("34028235{:0>31}.00000000", "")); + + let minf32 = f32::ldexp(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, 0, false), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 45, false), format!("0.{:0>44}1", "")); + assert_eq!(to_string(f, minf32, Minus, 46, false), format!("0.{:0>44}10", "")); + + assert_eq!(to_string(f, f64::MAX, Minus, 0, false), + format!("17976931348623157{:0>292}", "")); + assert_eq!(to_string(f, f64::MAX, Minus, 1, false), + format!("17976931348623157{:0>292}.0", "")); + assert_eq!(to_string(f, f64::MAX, Minus, 8, false), + format!("17976931348623157{:0>292}.00000000", "")); + + let minf64 = f64::ldexp(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, 0, false), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 324, false), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, 325, false), format!("0.{:0>323}50", "")); + + // very large output + assert_eq!(to_string(f, 1.1, Minus, 80000, false), format!("1.1{:0>79999}", "")); +} + +pub fn to_shortest_exp_str_test(mut f_: F) + where F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8]) -> (usize, i16) { + to_string_with_parts(|buf, parts| to_shortest_exp_str(|d,b| f(d,b), v, sign, + exp_bounds, upper, buf, parts)) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, (-4, 16), false), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (-4, 16), false), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, (-4, 16), false), "+0"); + assert_eq!(to_string(f, -0.0, Minus, (-4, 16), false), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, (-4, 16), false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (-4, 16), false), "+0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, (-4, 16), false), "-0"); + assert_eq!(to_string(f, 0.0, Minus, ( 0, 0), true), "0E0"); + assert_eq!(to_string(f, 0.0, MinusRaw, ( 0, 0), false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, (-9, -5), true), "+0E0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, ( 5, 9), false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, ( 0, 0), true), "0E0"); + assert_eq!(to_string(f, -0.0, MinusRaw, ( 0, 0), false), "-0e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, (-9, -5), true), "+0E0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, ( 5, 9), false), "-0e0"); + + assert_eq!(to_string(f, 1.0/0.0, Minus, (-4, 16), false), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusRaw, (-4, 16), true), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlus, (-4, 16), false), "+inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, (-4, 16), true), "+inf"); + assert_eq!(to_string(f, 0.0/0.0, Minus, ( 0, 0), false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusRaw, ( 0, 0), true), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlus, (-9, -5), false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, ( 5, 9), true), "NaN"); + assert_eq!(to_string(f, -1.0/0.0, Minus, ( 0, 0), false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusRaw, ( 0, 0), true), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlus, (-9, -5), false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, ( 5, 9), true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, (-4, 16), false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusRaw, (-4, 16), false), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, (-4, 16), false), "+3.14"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, (-4, 16), false), "+3.14"); + assert_eq!(to_string(f, -3.14, Minus, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusRaw, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlus, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, (-4, 16), false), "-3.14"); + assert_eq!(to_string(f, 3.14, Minus, ( 0, 0), true), "3.14E0"); + assert_eq!(to_string(f, 3.14, MinusRaw, ( 0, 0), false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, (-9, -5), true), "+3.14E0"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, ( 5, 9), false), "+3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, ( 0, 0), true), "-3.14E0"); + assert_eq!(to_string(f, -3.14, MinusRaw, ( 0, 0), false), "-3.14e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, (-9, -5), true), "-3.14E0"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, ( 5, 9), false), "-3.14e0"); + + assert_eq!(to_string(f, 0.1, Minus, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, MinusRaw, (-4, 16), false), "0.1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (-4, 16), false), "+0.1"); + assert_eq!(to_string(f, 0.1, MinusPlusRaw, (-4, 16), false), "+0.1"); + assert_eq!(to_string(f, -0.1, Minus, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, -0.1, MinusRaw, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, -0.1, MinusPlusRaw, (-4, 16), false), "-0.1"); + assert_eq!(to_string(f, 0.1, Minus, ( 0, 0), true), "1E-1"); + assert_eq!(to_string(f, 0.1, MinusRaw, ( 0, 0), false), "1e-1"); + assert_eq!(to_string(f, 0.1, MinusPlus, (-9, -5), true), "+1E-1"); + assert_eq!(to_string(f, 0.1, MinusPlusRaw, ( 5, 9), false), "+1e-1"); + assert_eq!(to_string(f, -0.1, Minus, ( 0, 0), true), "-1E-1"); + assert_eq!(to_string(f, -0.1, MinusRaw, ( 0, 0), false), "-1e-1"); + assert_eq!(to_string(f, -0.1, MinusPlus, (-9, -5), true), "-1E-1"); + assert_eq!(to_string(f, -0.1, MinusPlusRaw, ( 5, 9), false), "-1e-1"); + + assert_eq!(to_string(f, 7.5e-11, Minus, ( -4, 16), false), "7.5e-11"); + assert_eq!(to_string(f, 7.5e-11, Minus, (-11, 10), false), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, (-10, 11), false), "7.5e-11"); + + assert_eq!(to_string(f, 1.9971e20, Minus, ( -4, 16), false), "1.9971e20"); + assert_eq!(to_string(f, 1.9971e20, Minus, (-20, 21), false), "199710000000000000000"); + assert_eq!(to_string(f, 1.9971e20, Minus, (-21, 20), false), "1.9971e20"); + + // the true value of 1.0e23f64 is less than 10^23, but that shouldn't matter here + assert_eq!(to_string(f, 1.0e23, Minus, (22, 23), false), "1e23"); + assert_eq!(to_string(f, 1.0e23, Minus, (23, 24), false), "100000000000000000000000"); + assert_eq!(to_string(f, 1.0e23, Minus, (24, 25), false), "1e23"); + + assert_eq!(to_string(f, f32::MAX, Minus, ( -4, 16), false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-39, 38), false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, (-38, 39), false), format!("34028235{:0>31}", "")); + + let minf32 = f32::ldexp(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, ( -4, 16), false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, (-44, 45), false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, (-45, 44), false), format!("0.{:0>44}1", "")); + + assert_eq!(to_string(f, f64::MAX, Minus, ( -4, 16), false), + "1.7976931348623157e308"); + assert_eq!(to_string(f, f64::MAX, Minus, (-308, 309), false), + format!("17976931348623157{:0>292}", "")); + assert_eq!(to_string(f, f64::MAX, Minus, (-309, 308), false), + "1.7976931348623157e308"); + + let minf64 = f64::ldexp(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, ( -4, 16), false), "5e-324"); + assert_eq!(to_string(f, minf64, Minus, (-324, 323), false), format!("0.{:0>323}5", "")); + assert_eq!(to_string(f, minf64, Minus, (-323, 324), false), "5e-324"); + + assert_eq!(to_string(f, 1.1, Minus, (i16::MIN, i16::MAX), false), "1.1"); +} + +pub fn to_exact_exp_str_test(mut f_: F) + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + to_string_with_parts(|buf, parts| to_exact_exp_str(|d,b,l| f(d,b,l), v, sign, + ndigits, upper, buf, parts)) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, 1, true), "0E0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1, false), "0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0E0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, false), "+0e0"); + assert_eq!(to_string(f, -0.0, Minus, 1, true), "0E0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 1, false), "-0e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 1, true), "+0E0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 1, false), "-0e0"); + assert_eq!(to_string(f, 0.0, Minus, 2, true), "0.0E0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 2, false), "0.0e0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 2, true), "+0.0E0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 2, false), "+0.0e0"); + assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.0000000E0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8, false), "-0.0000000e0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.0000000E0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, false), "-0.0000000e0"); + + assert_eq!(to_string(f, 1.0/0.0, Minus, 1, false), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusRaw, 1, true), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlus, 1, false), "+inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, 1, true), "+inf"); + assert_eq!(to_string(f, 0.0/0.0, Minus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusRaw, 8, true), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, 8, true), "NaN"); + assert_eq!(to_string(f, -1.0/0.0, Minus, 64, false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusRaw, 64, true), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlus, 64, false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, 64, true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 1, true), "3E0"); + assert_eq!(to_string(f, 3.14, MinusRaw, 1, false), "3e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 1, true), "+3E0"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 1, false), "+3e0"); + assert_eq!(to_string(f, -3.14, Minus, 2, true), "-3.1E0"); + assert_eq!(to_string(f, -3.14, MinusRaw, 2, false), "-3.1e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 2, true), "-3.1E0"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 2, false), "-3.1e0"); + assert_eq!(to_string(f, 3.14, Minus, 3, true), "3.14E0"); + assert_eq!(to_string(f, 3.14, MinusRaw, 3, false), "3.14e0"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.14E0"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 3, false), "+3.14e0"); + assert_eq!(to_string(f, -3.14, Minus, 4, true), "-3.140E0"); + assert_eq!(to_string(f, -3.14, MinusRaw, 4, false), "-3.140e0"); + assert_eq!(to_string(f, -3.14, MinusPlus, 4, true), "-3.140E0"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 4, false), "-3.140e0"); + + assert_eq!(to_string(f, 0.195, Minus, 1, false), "2e-1"); + assert_eq!(to_string(f, 0.195, MinusRaw, 1, true), "2E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 1, false), "+2e-1"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 1, true), "+2E-1"); + assert_eq!(to_string(f, -0.195, Minus, 2, false), "-2.0e-1"); + assert_eq!(to_string(f, -0.195, MinusRaw, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 2, false), "-2.0e-1"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 2, true), "-2.0E-1"); + assert_eq!(to_string(f, 0.195, Minus, 3, false), "1.95e-1"); + assert_eq!(to_string(f, 0.195, MinusRaw, 3, true), "1.95E-1"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3, false), "+1.95e-1"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 3, true), "+1.95E-1"); + assert_eq!(to_string(f, -0.195, Minus, 4, false), "-1.950e-1"); + assert_eq!(to_string(f, -0.195, MinusRaw, 4, true), "-1.950E-1"); + assert_eq!(to_string(f, -0.195, MinusPlus, 4, false), "-1.950e-1"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 4, true), "-1.950E-1"); + + assert_eq!(to_string(f, 9.5, Minus, 1, false), "1e1"); + assert_eq!(to_string(f, 9.5, Minus, 2, false), "9.5e0"); + assert_eq!(to_string(f, 9.5, Minus, 3, false), "9.50e0"); + assert_eq!(to_string(f, 9.5, Minus, 30, false), "9.50000000000000000000000000000e0"); + + assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "1e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 2, false), "1.0e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 15, false), "1.00000000000000e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 16, false), "1.000000000000000e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 17, false), "1.0000000000000001e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 18, false), "1.00000000000000009e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 19, false), "1.000000000000000091e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 20, false), "1.0000000000000000906e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 21, false), "1.00000000000000009060e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 22, false), "1.000000000000000090597e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 23, false), "1.0000000000000000905970e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 24, false), "1.00000000000000009059697e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 25, false), "1.000000000000000090596966e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 26, false), "1.0000000000000000905969664e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 27, false), "1.00000000000000009059696640e25"); + assert_eq!(to_string(f, 1.0e25, Minus, 30, false), "1.00000000000000009059696640000e25"); + + assert_eq!(to_string(f, 1.0e-6, Minus, 1, false), "1e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 2, false), "1.0e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 16, false), "1.000000000000000e-6"); + assert_eq!(to_string(f, 1.0e-6, Minus, 17, false), "9.9999999999999995e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 18, false), "9.99999999999999955e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 19, false), "9.999999999999999547e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 20, false), "9.9999999999999995475e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 30, false), "9.99999999999999954748111825886e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 40, false), + "9.999999999999999547481118258862586856139e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 50, false), + "9.9999999999999995474811182588625868561393872369081e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 60, false), + "9.99999999999999954748111825886258685613938723690807819366455e-7"); + assert_eq!(to_string(f, 1.0e-6, Minus, 70, false), + "9.999999999999999547481118258862586856139387236908078193664550781250000e-7"); + + assert_eq!(to_string(f, f32::MAX, Minus, 1, false), "3e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 2, false), "3.4e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 4, false), "3.403e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 8, false), "3.4028235e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 16, false), "3.402823466385289e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 32, false), "3.4028234663852885981170418348452e38"); + assert_eq!(to_string(f, f32::MAX, Minus, 64, false), + "3.402823466385288598117041834845169254400000000000000000000000000e38"); + + let minf32 = f32::ldexp(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, 1, false), "1e-45"); + assert_eq!(to_string(f, minf32, Minus, 2, false), "1.4e-45"); + assert_eq!(to_string(f, minf32, Minus, 4, false), "1.401e-45"); + assert_eq!(to_string(f, minf32, Minus, 8, false), "1.4012985e-45"); + assert_eq!(to_string(f, minf32, Minus, 16, false), "1.401298464324817e-45"); + assert_eq!(to_string(f, minf32, Minus, 32, false), "1.4012984643248170709237295832899e-45"); + assert_eq!(to_string(f, minf32, Minus, 64, false), + "1.401298464324817070923729583289916131280261941876515771757068284e-45"); + assert_eq!(to_string(f, minf32, Minus, 128, false), + "1.401298464324817070923729583289916131280261941876515771757068283\ + 8897910826858606014866381883621215820312500000000000000000000000e-45"); + + assert_eq!(to_string(f, f64::MAX, Minus, 1, false), "2e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 2, false), "1.8e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 4, false), "1.798e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 8, false), "1.7976931e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 16, false), "1.797693134862316e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 32, false), "1.7976931348623157081452742373170e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 64, false), + "1.797693134862315708145274237317043567980705675258449965989174768e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 128, false), + "1.797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432133e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 256, false), + "1.797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978e308"); + assert_eq!(to_string(f, f64::MAX, Minus, 512, false), + "1.797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978\ + 2620414472316873817718091929988125040402618412485836800000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000e308"); + + // okay, this is becoming tough. fortunately for us, this is almost the worst case. + let minf64 = f64::ldexp(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, 1, false), "5e-324"); + assert_eq!(to_string(f, minf64, Minus, 2, false), "4.9e-324"); + assert_eq!(to_string(f, minf64, Minus, 4, false), "4.941e-324"); + assert_eq!(to_string(f, minf64, Minus, 8, false), "4.9406565e-324"); + assert_eq!(to_string(f, minf64, Minus, 16, false), "4.940656458412465e-324"); + assert_eq!(to_string(f, minf64, Minus, 32, false), "4.9406564584124654417656879286822e-324"); + assert_eq!(to_string(f, minf64, Minus, 64, false), + "4.940656458412465441765687928682213723650598026143247644255856825e-324"); + assert_eq!(to_string(f, minf64, Minus, 128, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671e-324"); + assert_eq!(to_string(f, minf64, Minus, 256, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671\ + 0355939796398774796010781878126300713190311404527845817167848982\ + 1036887186360569987307230500063874091535649843873124733972731696e-324"); + assert_eq!(to_string(f, minf64, Minus, 512, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671\ + 0355939796398774796010781878126300713190311404527845817167848982\ + 1036887186360569987307230500063874091535649843873124733972731696\ + 1514003171538539807412623856559117102665855668676818703956031062\ + 4931945271591492455329305456544401127480129709999541931989409080\ + 4165633245247571478690147267801593552386115501348035264934720193\ + 7902681071074917033322268447533357208324319360923828934583680601e-324"); + assert_eq!(to_string(f, minf64, Minus, 1024, false), + "4.940656458412465441765687928682213723650598026143247644255856825\ + 0067550727020875186529983636163599237979656469544571773092665671\ + 0355939796398774796010781878126300713190311404527845817167848982\ + 1036887186360569987307230500063874091535649843873124733972731696\ + 1514003171538539807412623856559117102665855668676818703956031062\ + 4931945271591492455329305456544401127480129709999541931989409080\ + 4165633245247571478690147267801593552386115501348035264934720193\ + 7902681071074917033322268447533357208324319360923828934583680601\ + 0601150616980975307834227731832924790498252473077637592724787465\ + 6084778203734469699533647017972677717585125660551199131504891101\ + 4510378627381672509558373897335989936648099411642057026370902792\ + 4276754456522908753868250641971826553344726562500000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000e-324"); + + // very large output + assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); + assert_eq!(to_string(f, 1.0e-1, Minus, 80000, false), + format!("1.000000000000000055511151231257827021181583404541015625{:0>79945}\ + e-1", "")); + assert_eq!(to_string(f, 1.0e-20, Minus, 80000, false), + format!("9.999999999999999451532714542095716517295037027873924471077157760\ + 66783064379706047475337982177734375{:0>79901}e-21", "")); +} + +pub fn to_exact_fixed_str_test(mut f_: F) + where F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + use core::num::flt2dec::Sign::*; + + fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize, upper: bool) -> String + where T: DecodableFloat, F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16) { + to_string_with_parts(|buf, parts| to_exact_fixed_str(|d,b,l| f(d,b,l), v, sign, + frac_digits, upper, buf, parts)) + } + + let f = &mut f_; + + assert_eq!(to_string(f, 0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 0, false), "0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 0, false), "+0"); + assert_eq!(to_string(f, -0.0, Minus, 0, false), "0"); + assert_eq!(to_string(f, -0.0, MinusRaw, 0, false), "-0"); + assert_eq!(to_string(f, -0.0, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 0, false), "-0"); + assert_eq!(to_string(f, 0.0, Minus, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusRaw, 1, true), "0.0"); + assert_eq!(to_string(f, 0.0, MinusPlus, 1, true), "+0.0"); + assert_eq!(to_string(f, 0.0, MinusPlusRaw, 1, true), "+0.0"); + assert_eq!(to_string(f, -0.0, Minus, 8, true), "0.00000000"); + assert_eq!(to_string(f, -0.0, MinusRaw, 8, true), "-0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlus, 8, true), "+0.00000000"); + assert_eq!(to_string(f, -0.0, MinusPlusRaw, 8, true), "-0.00000000"); + + assert_eq!(to_string(f, 1.0/0.0, Minus, 0, false), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusRaw, 1, true), "inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlus, 8, false), "+inf"); + assert_eq!(to_string(f, 1.0/0.0, MinusPlusRaw, 64, true), "+inf"); + assert_eq!(to_string(f, 0.0/0.0, Minus, 0, false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusRaw, 1, true), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlus, 8, false), "NaN"); + assert_eq!(to_string(f, 0.0/0.0, MinusPlusRaw, 64, true), "NaN"); + assert_eq!(to_string(f, -1.0/0.0, Minus, 0, false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusRaw, 1, true), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlus, 8, false), "-inf"); + assert_eq!(to_string(f, -1.0/0.0, MinusPlusRaw, 64, true), "-inf"); + + assert_eq!(to_string(f, 3.14, Minus, 0, false), "3"); + assert_eq!(to_string(f, 3.14, MinusRaw, 0, false), "3"); + assert_eq!(to_string(f, 3.14, MinusPlus, 0, false), "+3"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 0, false), "+3"); + assert_eq!(to_string(f, -3.14, Minus, 0, false), "-3"); + assert_eq!(to_string(f, -3.14, MinusRaw, 0, false), "-3"); + assert_eq!(to_string(f, -3.14, MinusPlus, 0, false), "-3"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 0, false), "-3"); + assert_eq!(to_string(f, 3.14, Minus, 1, true), "3.1"); + assert_eq!(to_string(f, 3.14, MinusRaw, 2, true), "3.14"); + assert_eq!(to_string(f, 3.14, MinusPlus, 3, true), "+3.140"); + assert_eq!(to_string(f, 3.14, MinusPlusRaw, 4, true), "+3.1400"); + assert_eq!(to_string(f, -3.14, Minus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusRaw, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlus, 8, true), "-3.14000000"); + assert_eq!(to_string(f, -3.14, MinusPlusRaw, 8, true), "-3.14000000"); + + assert_eq!(to_string(f, 0.195, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.195, MinusRaw, 0, false), "0"); + assert_eq!(to_string(f, 0.195, MinusPlus, 0, false), "+0"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 0, false), "+0"); + assert_eq!(to_string(f, -0.195, Minus, 0, false), "-0"); + assert_eq!(to_string(f, -0.195, MinusRaw, 0, false), "-0"); + assert_eq!(to_string(f, -0.195, MinusPlus, 0, false), "-0"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 0, false), "-0"); + assert_eq!(to_string(f, 0.195, Minus, 1, true), "0.2"); + assert_eq!(to_string(f, 0.195, MinusRaw, 2, true), "0.20"); + assert_eq!(to_string(f, 0.195, MinusPlus, 3, true), "+0.195"); + assert_eq!(to_string(f, 0.195, MinusPlusRaw, 4, true), "+0.1950"); + assert_eq!(to_string(f, -0.195, Minus, 5, true), "-0.19500"); + assert_eq!(to_string(f, -0.195, MinusRaw, 6, true), "-0.195000"); + assert_eq!(to_string(f, -0.195, MinusPlus, 7, true), "-0.1950000"); + assert_eq!(to_string(f, -0.195, MinusPlusRaw, 8, true), "-0.19500000"); + + assert_eq!(to_string(f, 999.5, Minus, 0, false), "1000"); + assert_eq!(to_string(f, 999.5, Minus, 1, false), "999.5"); + assert_eq!(to_string(f, 999.5, Minus, 2, false), "999.50"); + assert_eq!(to_string(f, 999.5, Minus, 3, false), "999.500"); + assert_eq!(to_string(f, 999.5, Minus, 30, false), "999.500000000000000000000000000000"); + + assert_eq!(to_string(f, 0.5, Minus, 0, false), "1"); + assert_eq!(to_string(f, 0.5, Minus, 1, false), "0.5"); + assert_eq!(to_string(f, 0.5, Minus, 2, false), "0.50"); + assert_eq!(to_string(f, 0.5, Minus, 3, false), "0.500"); + + assert_eq!(to_string(f, 0.95, Minus, 0, false), "1"); + assert_eq!(to_string(f, 0.95, Minus, 1, false), "0.9"); // because it really is less than 0.95 + assert_eq!(to_string(f, 0.95, Minus, 2, false), "0.95"); + assert_eq!(to_string(f, 0.95, Minus, 3, false), "0.950"); + assert_eq!(to_string(f, 0.95, Minus, 10, false), "0.9500000000"); + assert_eq!(to_string(f, 0.95, Minus, 30, false), "0.949999999999999955591079014994"); + + assert_eq!(to_string(f, 0.095, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.095, Minus, 1, false), "0.1"); + assert_eq!(to_string(f, 0.095, Minus, 2, false), "0.10"); + assert_eq!(to_string(f, 0.095, Minus, 3, false), "0.095"); + assert_eq!(to_string(f, 0.095, Minus, 4, false), "0.0950"); + assert_eq!(to_string(f, 0.095, Minus, 10, false), "0.0950000000"); + assert_eq!(to_string(f, 0.095, Minus, 30, false), "0.095000000000000001110223024625"); + + assert_eq!(to_string(f, 0.0095, Minus, 0, false), "0"); + assert_eq!(to_string(f, 0.0095, Minus, 1, false), "0.0"); + assert_eq!(to_string(f, 0.0095, Minus, 2, false), "0.01"); + assert_eq!(to_string(f, 0.0095, Minus, 3, false), "0.009"); // really is less than 0.0095 + assert_eq!(to_string(f, 0.0095, Minus, 4, false), "0.0095"); + assert_eq!(to_string(f, 0.0095, Minus, 5, false), "0.00950"); + assert_eq!(to_string(f, 0.0095, Minus, 10, false), "0.0095000000"); + assert_eq!(to_string(f, 0.0095, Minus, 30, false), "0.009499999999999999764077607267"); + + assert_eq!(to_string(f, 7.5e-11, Minus, 0, false), "0"); + assert_eq!(to_string(f, 7.5e-11, Minus, 3, false), "0.000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 10, false), "0.0000000001"); + assert_eq!(to_string(f, 7.5e-11, Minus, 11, false), "0.00000000007"); // ditto + assert_eq!(to_string(f, 7.5e-11, Minus, 12, false), "0.000000000075"); + assert_eq!(to_string(f, 7.5e-11, Minus, 13, false), "0.0000000000750"); + assert_eq!(to_string(f, 7.5e-11, Minus, 20, false), "0.00000000007500000000"); + assert_eq!(to_string(f, 7.5e-11, Minus, 30, false), "0.000000000074999999999999999501"); + + assert_eq!(to_string(f, 1.0e25, Minus, 0, false), "10000000000000000905969664"); + assert_eq!(to_string(f, 1.0e25, Minus, 1, false), "10000000000000000905969664.0"); + assert_eq!(to_string(f, 1.0e25, Minus, 3, false), "10000000000000000905969664.000"); + + assert_eq!(to_string(f, 1.0e-6, Minus, 0, false), "0"); + assert_eq!(to_string(f, 1.0e-6, Minus, 3, false), "0.000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 6, false), "0.000001"); + assert_eq!(to_string(f, 1.0e-6, Minus, 9, false), "0.000001000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 12, false), "0.000001000000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 22, false), "0.0000010000000000000000"); + assert_eq!(to_string(f, 1.0e-6, Minus, 23, false), "0.00000099999999999999995"); + assert_eq!(to_string(f, 1.0e-6, Minus, 24, false), "0.000000999999999999999955"); + assert_eq!(to_string(f, 1.0e-6, Minus, 25, false), "0.0000009999999999999999547"); + assert_eq!(to_string(f, 1.0e-6, Minus, 35, false), "0.00000099999999999999995474811182589"); + assert_eq!(to_string(f, 1.0e-6, Minus, 45, false), + "0.000000999999999999999954748111825886258685614"); + assert_eq!(to_string(f, 1.0e-6, Minus, 55, false), + "0.0000009999999999999999547481118258862586856139387236908"); + assert_eq!(to_string(f, 1.0e-6, Minus, 65, false), + "0.00000099999999999999995474811182588625868561393872369080781936646"); + assert_eq!(to_string(f, 1.0e-6, Minus, 75, false), + "0.000000999999999999999954748111825886258685613938723690807819366455078125000"); + + assert_eq!(to_string(f, f32::MAX, Minus, 0, false), + "340282346638528859811704183484516925440"); + assert_eq!(to_string(f, f32::MAX, Minus, 1, false), + "340282346638528859811704183484516925440.0"); + assert_eq!(to_string(f, f32::MAX, Minus, 2, false), + "340282346638528859811704183484516925440.00"); + + let minf32 = f32::ldexp(1.0, -149); + assert_eq!(to_string(f, minf32, Minus, 0, false), "0"); + assert_eq!(to_string(f, minf32, Minus, 1, false), "0.0"); + assert_eq!(to_string(f, minf32, Minus, 2, false), "0.00"); + assert_eq!(to_string(f, minf32, Minus, 4, false), "0.0000"); + assert_eq!(to_string(f, minf32, Minus, 8, false), "0.00000000"); + assert_eq!(to_string(f, minf32, Minus, 16, false), "0.0000000000000000"); + assert_eq!(to_string(f, minf32, Minus, 32, false), "0.00000000000000000000000000000000"); + assert_eq!(to_string(f, minf32, Minus, 64, false), + "0.0000000000000000000000000000000000000000000014012984643248170709"); + assert_eq!(to_string(f, minf32, Minus, 128, false), + "0.0000000000000000000000000000000000000000000014012984643248170709\ + 2372958328991613128026194187651577175706828388979108268586060149"); + assert_eq!(to_string(f, minf32, Minus, 256, false), + "0.0000000000000000000000000000000000000000000014012984643248170709\ + 2372958328991613128026194187651577175706828388979108268586060148\ + 6638188362121582031250000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000"); + + assert_eq!(to_string(f, f64::MAX, Minus, 0, false), + "1797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978\ + 26204144723168738177180919299881250404026184124858368"); + assert_eq!(to_string(f, f64::MAX, Minus, 10, false), + "1797693134862315708145274237317043567980705675258449965989174768\ + 0315726078002853876058955863276687817154045895351438246423432132\ + 6889464182768467546703537516986049910576551282076245490090389328\ + 9440758685084551339423045832369032229481658085593321233482747978\ + 26204144723168738177180919299881250404026184124858368.0000000000"); + + let minf64 = f64::ldexp(1.0, -1074); + assert_eq!(to_string(f, minf64, Minus, 0, false), "0"); + assert_eq!(to_string(f, minf64, Minus, 1, false), "0.0"); + assert_eq!(to_string(f, minf64, Minus, 10, false), "0.0000000000"); + assert_eq!(to_string(f, minf64, Minus, 100, false), + "0.0000000000000000000000000000000000000000000000000000000000000000\ + 000000000000000000000000000000000000"); + assert_eq!(to_string(f, minf64, Minus, 1000, false), + "0.0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0000000000000000000000000000000000000000000000000000000000000000\ + 0004940656458412465441765687928682213723650598026143247644255856\ + 8250067550727020875186529983636163599237979656469544571773092665\ + 6710355939796398774796010781878126300713190311404527845817167848\ + 9821036887186360569987307230500063874091535649843873124733972731\ + 6961514003171538539807412623856559117102665855668676818703956031\ + 0624931945271591492455329305456544401127480129709999541931989409\ + 0804165633245247571478690147267801593552386115501348035264934720\ + 1937902681071074917033322268447533357208324319360923828934583680\ + 6010601150616980975307834227731832924790498252473077637592724787\ + 4656084778203734469699533647017972677717585125660551199131504891\ + 1014510378627381672509558373897335989937"); + + // very large output + assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("10.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>80000}", "")); + assert_eq!(to_string(f, 1.0e-1, Minus, 80000, false), + format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "")); + assert_eq!(to_string(f, 1.0e-20, Minus, 80000, false), + format!("0.0000000000000000000099999999999999994515327145420957165172950370\ + 2787392447107715776066783064379706047475337982177734375{:0>79881}", "")); +} + diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcoretest/num/flt2dec/strategy/dragon.rs new file mode 100644 index 0000000000000..f2397f6b48037 --- /dev/null +++ b/src/libcoretest/num/flt2dec/strategy/dragon.rs @@ -0,0 +1,117 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::prelude::v1::*; +use std::{i16, f64}; +use super::super::*; +use core::num::flt2dec::*; +use core::num::flt2dec::bignum::Big32x36 as Big; +use core::num::flt2dec::strategy::dragon::*; + +#[test] +fn test_mul_pow10() { + let mut prevpow10 = Big::from_small(1); + for i in 1..340 { + let mut curpow10 = Big::from_small(1); + mul_pow10(&mut curpow10, i); + assert_eq!(curpow10, *prevpow10.clone().mul_small(10)); + prevpow10 = curpow10; + } +} + +#[test] +fn shortest_sanity_test() { + f64_shortest_sanity_test(format_shortest); + f32_shortest_sanity_test(format_shortest); + more_shortest_sanity_test(format_shortest); +} + +#[test] +fn exact_sanity_test() { + f64_exact_sanity_test(format_exact); + f32_exact_sanity_test(format_exact); +} + +#[bench] +fn bench_small_shortest(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; MAX_SIG_DIGITS]; + b.iter(|| format_shortest(&decoded, &mut buf)); +} + +#[bench] +fn bench_big_shortest(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; MAX_SIG_DIGITS]; + b.iter(|| format_shortest(&decoded, &mut buf)); +} + +#[bench] +fn bench_small_exact_3(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; 3]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_big_exact_3(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; 3]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_small_exact_12(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; 12]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_big_exact_12(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; 12]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_small_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; 1024]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_big_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; 1024]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[test] +fn test_to_shortest_str() { + to_shortest_str_test(format_shortest); +} + +#[test] +fn test_to_shortest_exp_str() { + to_shortest_exp_str_test(format_shortest); +} + +#[test] +fn test_to_exact_exp_str() { + to_exact_exp_str_test(format_exact); +} + +#[test] +fn test_to_exact_fixed_str() { + to_exact_fixed_str_test(format_exact); +} + diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcoretest/num/flt2dec/strategy/grisu.rs new file mode 100644 index 0000000000000..e5b8a9dcc38fc --- /dev/null +++ b/src/libcoretest/num/flt2dec/strategy/grisu.rs @@ -0,0 +1,177 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{i16, f64}; +use super::super::*; +use core::num::flt2dec::*; +use core::num::flt2dec::strategy::grisu::*; + +#[test] +fn test_cached_power() { + assert_eq!(CACHED_POW10.first().unwrap().1, CACHED_POW10_FIRST_E); + assert_eq!(CACHED_POW10.last().unwrap().1, CACHED_POW10_LAST_E); + + for e in -1137..961 { // full range for f64 + let low = ALPHA - e - 64; + let high = GAMMA - e - 64; + let (_k, cached) = cached_power(low, high); + assert!(low <= cached.e && cached.e <= high, + "cached_power({}, {}) = {:?} is incorrect", low, high, cached); + } +} + +#[test] +fn test_max_pow10_no_more_than() { + let mut prevtenk = 1; + for k in 1..10 { + let tenk = prevtenk * 10; + assert_eq!(max_pow10_no_more_than(tenk - 1), (k - 1, prevtenk)); + assert_eq!(max_pow10_no_more_than(tenk), (k, tenk)); + prevtenk = tenk; + } +} + + +#[test] +fn shortest_sanity_test() { + f64_shortest_sanity_test(format_shortest); + f32_shortest_sanity_test(format_shortest); + more_shortest_sanity_test(format_shortest); +} + +#[test] +fn shortest_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); + f32_random_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS, 10_000); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f32_exhaustive_equivalence_test() { + // it is hard to directly test the optimality of the output, but we can at least test if + // two different algorithms agree to each other. + // + // this reports the progress and the number of f32 values returned `None`. + // with `--nocapture` (and plenty of time and appropriate rustc flags), this should print: + // `done, ignored=17643158 passed=2121451881 failed=0`. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f32_exhaustive_equivalence_test(format_shortest_opt, fallback, MAX_SIG_DIGITS); +} + +#[test] #[ignore] // it is too expensive +fn shortest_f64_hard_random_equivalence_test() { + // this again probably has to use appropriate rustc flags. + + use core::num::flt2dec::strategy::dragon::format_shortest as fallback; + f64_random_equivalence_test(format_shortest_opt, fallback, + MAX_SIG_DIGITS, 100_000_000); +} + +#[test] +fn exact_sanity_test() { + f64_exact_sanity_test(format_exact); + f32_exact_sanity_test(format_exact); +} + +#[test] +fn exact_f32_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f32_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} + +#[test] +fn exact_f64_random_equivalence_test() { + use core::num::flt2dec::strategy::dragon::format_exact as fallback; + for k in 1..21 { + f64_random_equivalence_test(|d, buf| format_exact_opt(d, buf, i16::MIN), + |d, buf| fallback(d, buf, i16::MIN), k, 1_000); + } +} + +#[bench] +fn bench_small_shortest(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; MAX_SIG_DIGITS]; + b.iter(|| format_shortest(&decoded, &mut buf)); +} + +#[bench] +fn bench_big_shortest(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; MAX_SIG_DIGITS]; + b.iter(|| format_shortest(&decoded, &mut buf)); +} + +#[bench] +fn bench_small_exact_3(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; 3]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_big_exact_3(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; 3]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_small_exact_12(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; 12]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_big_exact_12(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; 12]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_small_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(3.141592f64); + let mut buf = [0; 1024]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[bench] +fn bench_big_exact_inf(b: &mut Bencher) { + let decoded = decode_finite(f64::MAX); + let mut buf = [0; 1024]; + b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); +} + +#[test] +fn test_to_shortest_str() { + to_shortest_str_test(format_shortest); +} + +#[test] +fn test_to_shortest_exp_str() { + to_shortest_exp_str_test(format_shortest); +} + +#[test] +fn test_to_exact_exp_str() { + to_exact_exp_str_test(format_exact); +} + +#[test] +fn test_to_exact_fixed_str() { + to_exact_fixed_str_test(format_exact); +} + diff --git a/src/libcoretest/num/mod.rs b/src/libcoretest/num/mod.rs index 0ea9f8afb4e53..998f4b21ece7f 100644 --- a/src/libcoretest/num/mod.rs +++ b/src/libcoretest/num/mod.rs @@ -29,6 +29,8 @@ mod u16; mod u32; mod u64; +mod flt2dec; + /// Helper function for testing numeric operations pub fn test_num(ten: T, two: T) where T: PartialEq diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index 4cbc3b4725d3b..55934da00a37c 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -12,7 +12,8 @@ #![cfg_attr(stage0, feature(custom_attribute))] #![crate_name = "libc"] #![crate_type = "rlib"] -#![cfg_attr(not(feature = "cargo-build"), unstable(feature = "libc"))] +#![cfg_attr(not(feature = "cargo-build"), unstable(feature = "libc", + reason = "use `libc` from crates.io"))] #![cfg_attr(not(feature = "cargo-build"), feature(staged_api, core, no_std))] #![cfg_attr(not(feature = "cargo-build"), staged_api)] #![cfg_attr(not(feature = "cargo-build"), no_std)] @@ -3624,6 +3625,30 @@ pub mod consts { pub const IPV6_DROP_MEMBERSHIP: c_int = 21; pub const TCP_NODELAY: c_int = 1; + pub const TCP_MAXSEG: c_int = 2; + pub const TCP_CORK: c_int = 3; + pub const TCP_KEEPIDLE: c_int = 4; + pub const TCP_KEEPINTVL: c_int = 5; + pub const TCP_KEEPCNT: c_int = 6; + pub const TCP_SYNCNT: c_int = 7; + pub const TCP_LINGER2: c_int = 8; + pub const TCP_DEFER_ACCEPT: c_int = 9; + pub const TCP_WINDOW_CLAMP: c_int = 10; + pub const TCP_INFO: c_int = 11; + pub const TCP_QUICKACK: c_int = 12; + pub const TCP_CONGESTION: c_int = 13; + pub const TCP_MD5SIG: c_int = 14; + pub const TCP_COOKIE_TRANSACTIONS: c_int = 15; + pub const TCP_THIN_LINEAR_TIMEOUTS: c_int = 16; + pub const TCP_THIN_DUPACK: c_int = 17; + pub const TCP_USER_TIMEOUT: c_int = 18; + pub const TCP_REPAIR: c_int = 19; + pub const TCP_REPAIR_QUEUE: c_int = 20; + pub const TCP_QUEUE_SEQ: c_int = 21; + pub const TCP_REPAIR_OPTIONS: c_int = 22; + pub const TCP_FASTOPEN: c_int = 23; + pub const TCP_TIMESTAMP: c_int = 24; + pub const SOL_SOCKET: c_int = 65535; pub const SO_DEBUG: c_int = 0x0001; diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 453d087196b13..4280a88f724a2 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -228,7 +228,7 @@ thread_local! { } } -/// A trait used to represent an interface to a task-local logger. Each task +/// A trait used to represent an interface to a thread-local logger. Each thread /// can have its own custom logger which can respond to logging messages /// however it likes. pub trait Logger { @@ -324,7 +324,7 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { #[inline(always)] pub fn log_level() -> u32 { unsafe { LOG_LEVEL } } -/// Replaces the task-local logger with the specified logger, returning the old +/// Replaces the thread-local logger with the specified logger, returning the old /// logger. pub fn set_logger(logger: Box) -> Option> { let mut l = Some(logger); diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 53ea28f0c11d3..1359894b4dd72 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -26,7 +26,8 @@ html_playground_url = "http://play.rust-lang.org/")] #![no_std] #![staged_api] -#![unstable(feature = "rand")] +#![unstable(feature = "rand", + reason = "use `rand` from crates.io")] #![feature(core)] #![feature(no_std)] #![feature(staged_api)] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 88112b4b90cbe..aaf615ee40409 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -271,6 +271,12 @@ fn main() { See also http://doc.rust-lang.org/book/unsafe.html "##, +E0137: r##" +This error indicates that the compiler found multiple functions with the +#[main] attribute. This is an error because there must be a unique entry point +into a Rust program. +"##, + E0152: r##" Lang items are already implemented in the standard library. Unless you are writing a free-standing application (e.g. a kernel), you do not need to provide @@ -419,6 +425,142 @@ of a loop. Without a loop to break out of or continue in, no sensible action can be taken. "##, +E0271: r##" +This is because of a type mismatch between the associated type of some +trait (e.g. T::Bar, where T implements trait Quux { type Bar; }) +and another type U that is required to be equal to T::Bar, but is not. +Examples follow. + +Here is a basic example: + +``` +trait Trait { type AssociatedType; } +fn foo(t: T) where T: Trait { + println!("in foo"); +} +impl Trait for i8 { type AssociatedType = &'static str; } +foo(3_i8); +``` + +Here is that same example again, with some explanatory comments: + +``` +trait Trait { type AssociatedType; } + +fn foo(t: T) where T: Trait { +// ~~~~~~~~ ~~~~~~~~~~~~~~~~~~ +// | | +// This says `foo` can | +// only be used with | +// some type that | +// implements `Trait`. | +// | +// This says not only must +// `T` be an impl of `Trait` +// but also that the impl +// must assign the type `u32` +// to the associated type. + println!("in foo"); +} + +impl Trait for i8 { type AssociatedType = &'static str; } +~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// | | +// `i8` does have | +// implementation | +// of `Trait`... | +// ... but it is an implementation +// that assigns `&'static str` to +// the associated type. + +foo(3_i8); +// Here, we invoke `foo` with an `i8`, which does not satisfy +// the constraint `::AssociatedType=32`, and +// therefore the type-checker complains with this error code. +``` + +Here is a more subtle instance of the same problem, that can +arise with for-loops in Rust: + +``` +let vs: Vec = vec![1, 2, 3, 4]; +for v in &vs { + match v { + 1 => {} + _ => {} + } +} +``` + +The above fails because of an analogous type mismatch, +though may be harder to see. Again, here are some +explanatory comments for the same example: + +``` +{ + let vs = vec![1, 2, 3, 4]; + + // `for`-loops use a protocol based on the `Iterator` + // trait. Each item yielded in a `for` loop has the + // type `Iterator::Item` -- that is,I `Item` is the + // associated type of the concrete iterator impl. + for v in &vs { +// ~ ~~~ +// | | +// | We borrow `vs`, iterating over a sequence of +// | *references* of type `&Elem` (where `Elem` is +// | vector's element type). Thus, the associated +// | type `Item` must be a reference `&`-type ... +// | +// ... and `v` has the type `Iterator::Item`, as dictated by +// the `for`-loop protocol ... + + match v { + 1 => {} +// ~ +// | +// ... but *here*, `v` is forced to have some integral type; +// only types like `u8`,`i8`,`u16`,`i16`, et cetera can +// match the pattern `1` ... + + _ => {} + } + +// ... therefore, the compiler complains, because it sees +// an attempt to solve the equations +// `some integral-type` = type-of-`v` +// = `Iterator::Item` +// = `&Elem` (i.e. `some reference type`) +// +// which cannot possibly all be true. + + } +} +``` + +To avoid those issues, you have to make the types match correctly. +So we can fix the previous examples like this: + +``` +// Basic Example: +trait Trait { type AssociatedType; } +fn foo(t: T) where T: Trait { + println!("in foo"); +} +impl Trait for i8 { type AssociatedType = &'static str; } +foo(3_i8); + +// For-Loop Example: +let vs = vec![1, 2, 3, 4]; +for v in &vs { + match v { + &1 => {} + _ => {} + } +} +``` +"##, + E0282: r##" This error indicates that type inference did not result in one unique possible type, and extra information is required. In most cases this can be provided @@ -664,7 +806,6 @@ register_diagnostics! { E0134, E0135, E0136, - E0137, E0138, E0139, E0261, // use of undeclared lifetime name @@ -674,7 +815,6 @@ register_diagnostics! { E0266, // expected item E0269, // not all control paths return a value E0270, // computation may converge in a function marked as diverging - E0271, // type mismatch resolving E0272, // rustc_on_unimplemented attribute refers to non-existent type parameter E0273, // rustc_on_unimplemented must have named format arguments E0274, // rustc_on_unimplemented must have a value diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 29f718fd09769..500255db330c5 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -273,7 +273,6 @@ impl VecPerParamSpace { /// `t` is the type space. /// `s` is the self space. - /// `a` is the assoc space. /// `f` is the fn space. pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { let type_limit = t.len(); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5298c9682b48c..cb069acdfd2f0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4630,7 +4630,7 @@ pub fn expr_ty_opt<'tcx>(cx: &ctxt<'tcx>, expr: &ast::Expr) -> Option> /// require serializing and deserializing the type and, although that's not /// hard to do, I just hate that code so much I didn't want to touch it /// unless it was to fix it properly, which seemed a distraction from the -/// task at hand! -nmatsakis +/// thread at hand! -nmatsakis pub fn expr_ty_adjusted<'tcx>(cx: &ctxt<'tcx>, expr: &ast::Expr) -> Ty<'tcx> { adjust_ty(cx, expr.span, expr.id, expr_ty(cx, expr), cx.adjustments.borrow().get(&expr.id), diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs index 752e71bc19131..4ea331f68987e 100644 --- a/src/librustc/plugin/load.rs +++ b/src/librustc/plugin/load.rs @@ -131,7 +131,7 @@ impl<'a> PluginLoader<'a> { // Intentionally leak the dynamic library. We can't ever unload it // since the library can make things that will live arbitrarily long - // (e.g. an @-box cycle or a task). + // (e.g. an @-box cycle or a thread). mem::forget(lib); registrar diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 45d81ff0f6529..0073c0b061039 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -872,11 +872,8 @@ pub fn collect_crate_types(session: &Session, None } _ => { - session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES, - ast::CRATE_NODE_ID, - a.span, - "`crate_type` requires a \ - value".to_string()); + session.span_err(a.span, "`crate_type` requires a value"); + session.note("for example: `#![crate_type=\"lib\"]`"); None } } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 488a4a8082f9d..a10ff71a8f689 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -86,8 +86,8 @@ struct Diagnostic { } // We use an Arc instead of just returning a list of diagnostics from the -// child task because we need to make sure that the messages are seen even -// if the child task panics (for example, when `fatal` is called). +// child thread because we need to make sure that the messages are seen even +// if the child thread panics (for example, when `fatal` is called). #[derive(Clone)] struct SharedEmitter { buffer: Arc>>, @@ -637,7 +637,7 @@ pub fn run_passes(sess: &Session, metadata_config.set_flags(sess, trans); - // Populate a buffer with a list of codegen tasks. Items are processed in + // Populate a buffer with a list of codegen threads. Items are processed in // LIFO order, just because it's a tiny bit simpler that way. (The order // doesn't actually matter.) let mut work_items = Vec::with_capacity(1 + trans.modules.len()); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 2ba963a42efbe..03dda57e5689f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -147,7 +147,7 @@ pub fn type_is_fat_ptr<'tcx>(cx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } // Some things don't need cleanups during unwinding because the -// task can free them all at once later. Currently only things +// thread can free them all at once later. Currently only things // that only contain scalars and shared boxes can avoid unwind // cleanups. pub fn type_needs_unwind_cleanup<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool { diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 8545e73c4f932..fd90d662bd141 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -396,19 +396,24 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( } }; - let opt_type_did = match typ.sty { - ty::ty_struct(struct_did, _) => Some(struct_did), - ty::ty_enum(enum_did, _) => Some(enum_did), - _ => None, + let dtor_kind = match typ.sty { + ty::ty_enum(def_id, _) | + ty::ty_struct(def_id, _) => { + match destructor_for_type.get(&def_id) { + Some(def_id) => DtorKind::KnownDropMethod(*def_id), + None => DtorKind::PureRecur, + } + } + ty::ty_trait(ref ty_trait) => { + DtorKind::Unknown(ty_trait.bounds.clone()) + } + _ => DtorKind::PureRecur, }; - let opt_dtor = - opt_type_did.and_then(|did| destructor_for_type.get(&did)); - debug!("iterate_over_potentially_unsafe_regions_in_type \ - {}typ: {} scope: {:?} opt_dtor: {:?} xref: {}", + {}typ: {} scope: {:?} xref: {}", (0..depth).map(|_| ' ').collect::(), - typ.repr(rcx.tcx()), scope, opt_dtor, xref_depth); + typ.repr(rcx.tcx()), scope, xref_depth); // If `typ` has a destructor, then we must ensure that all // borrowed data reachable via `typ` must outlive the parent @@ -439,102 +444,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( // simply skip the `type_must_outlive` call entirely (but // resume the recursive checking of the type-substructure). - let has_dtor_of_interest; - - if let Some(&dtor_method_did) = opt_dtor { - let impl_did = ty::impl_of_method(rcx.tcx(), dtor_method_did) - .unwrap_or_else(|| { - rcx.tcx().sess.span_bug( - span, "no Drop impl found for drop method") - }); - - let dtor_typescheme = ty::lookup_item_type(rcx.tcx(), impl_did); - let dtor_generics = dtor_typescheme.generics; - - let mut has_pred_of_interest = false; - - let mut seen_items = Vec::new(); - let mut items_to_inspect = vec![impl_did]; - 'items: while let Some(item_def_id) = items_to_inspect.pop() { - if seen_items.contains(&item_def_id) { - continue; - } - - for pred in ty::lookup_predicates(rcx.tcx(), item_def_id).predicates { - let result = match pred { - ty::Predicate::Equate(..) | - ty::Predicate::RegionOutlives(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::Projection(..) => { - // For now, assume all these where-clauses - // may give drop implementation capabilty - // to access borrowed data. - true - } - - ty::Predicate::Trait(ty::Binder(ref t_pred)) => { - let def_id = t_pred.trait_ref.def_id; - if ty::trait_items(rcx.tcx(), def_id).len() != 0 { - // If trait has items, assume it adds - // capability to access borrowed data. - true - } else { - // Trait without items is itself - // uninteresting from POV of dropck. - // - // However, may have parent w/ items; - // so schedule checking of predicates, - items_to_inspect.push(def_id); - // and say "no capability found" for now. - false - } - } - }; - - if result { - has_pred_of_interest = true; - debug!("typ: {} has interesting dtor due to generic preds, e.g. {}", - typ.repr(rcx.tcx()), pred.repr(rcx.tcx())); - break 'items; - } - } - - seen_items.push(item_def_id); - } - - // In `impl<'a> Drop ...`, we automatically assume - // `'a` is meaningful and thus represents a bound - // through which we could reach borrowed data. - // - // FIXME (pnkfelix): In the future it would be good to - // extend the language to allow the user to express, - // in the impl signature, that a lifetime is not - // actually used (something like `where 'a: ?Live`). - let has_region_param_of_interest = - dtor_generics.has_region_params(subst::TypeSpace); - - has_dtor_of_interest = - has_region_param_of_interest || - has_pred_of_interest; - - if has_dtor_of_interest { - debug!("typ: {} has interesting dtor, due to \ - region params: {} or pred: {}", - typ.repr(rcx.tcx()), - has_region_param_of_interest, - has_pred_of_interest); - } else { - debug!("typ: {} has dtor, but it is uninteresting", - typ.repr(rcx.tcx())); - } - - } else { - debug!("typ: {} has no dtor, and thus is uninteresting", - typ.repr(rcx.tcx())); - has_dtor_of_interest = false; - } - - if has_dtor_of_interest { + if has_dtor_of_interest(rcx.tcx(), dtor_kind, typ, span) { // If `typ` has a destructor, then we must ensure that all // borrowed data reachable via `typ` must outlive the // parent of `scope`. (It does not suffice for it to @@ -620,7 +530,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( ty::ty_rptr(..) | ty::ty_ptr(_) | ty::ty_bare_fn(..) => { // Don't recurse, since references, pointers, - // boxes, and bare functions don't own instances + // and bare functions don't own instances // of the types appearing within them. walker.skip_current_subtree(); } @@ -639,3 +549,140 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>( return Ok(()); } + +enum DtorKind<'tcx> { + // Type has an associated drop method with this def id + KnownDropMethod(ast::DefId), + + // Type has no destructor (or its dtor is known to be pure + // with respect to lifetimes), though its *substructure* + // may carry a destructor. + PureRecur, + + // Type may have impure destructor that is unknown; + // e.g. `Box` + Unknown(ty::ExistentialBounds<'tcx>), +} + +fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>, + dtor_kind: DtorKind, + typ: ty::Ty<'tcx>, + span: Span) -> bool { + let has_dtor_of_interest: bool; + + match dtor_kind { + DtorKind::PureRecur => { + has_dtor_of_interest = false; + debug!("typ: {} has no dtor, and thus is uninteresting", + typ.repr(tcx)); + } + DtorKind::Unknown(bounds) => { + match bounds.region_bound { + ty::ReStatic => { + debug!("trait: {} has 'static bound, and thus is uninteresting", + typ.repr(tcx)); + has_dtor_of_interest = false; + } + ty::ReEmpty => { + debug!("trait: {} has empty region bound, and thus is uninteresting", + typ.repr(tcx)); + has_dtor_of_interest = false; + } + r => { + debug!("trait: {} has non-static bound: {}; assumed interesting", + typ.repr(tcx), r.repr(tcx)); + has_dtor_of_interest = true; + } + } + } + DtorKind::KnownDropMethod(dtor_method_did) => { + let impl_did = ty::impl_of_method(tcx, dtor_method_did) + .unwrap_or_else(|| { + tcx.sess.span_bug( + span, "no Drop impl found for drop method") + }); + + let dtor_typescheme = ty::lookup_item_type(tcx, impl_did); + let dtor_generics = dtor_typescheme.generics; + + let mut has_pred_of_interest = false; + + let mut seen_items = Vec::new(); + let mut items_to_inspect = vec![impl_did]; + 'items: while let Some(item_def_id) = items_to_inspect.pop() { + if seen_items.contains(&item_def_id) { + continue; + } + + for pred in ty::lookup_predicates(tcx, item_def_id).predicates { + let result = match pred { + ty::Predicate::Equate(..) | + ty::Predicate::RegionOutlives(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::Projection(..) => { + // For now, assume all these where-clauses + // may give drop implementation capabilty + // to access borrowed data. + true + } + + ty::Predicate::Trait(ty::Binder(ref t_pred)) => { + let def_id = t_pred.trait_ref.def_id; + if ty::trait_items(tcx, def_id).len() != 0 { + // If trait has items, assume it adds + // capability to access borrowed data. + true + } else { + // Trait without items is itself + // uninteresting from POV of dropck. + // + // However, may have parent w/ items; + // so schedule checking of predicates, + items_to_inspect.push(def_id); + // and say "no capability found" for now. + false + } + } + }; + + if result { + has_pred_of_interest = true; + debug!("typ: {} has interesting dtor due to generic preds, e.g. {}", + typ.repr(tcx), pred.repr(tcx)); + break 'items; + } + } + + seen_items.push(item_def_id); + } + + // In `impl<'a> Drop ...`, we automatically assume + // `'a` is meaningful and thus represents a bound + // through which we could reach borrowed data. + // + // FIXME (pnkfelix): In the future it would be good to + // extend the language to allow the user to express, + // in the impl signature, that a lifetime is not + // actually used (something like `where 'a: ?Live`). + let has_region_param_of_interest = + dtor_generics.has_region_params(subst::TypeSpace); + + has_dtor_of_interest = + has_region_param_of_interest || + has_pred_of_interest; + + if has_dtor_of_interest { + debug!("typ: {} has interesting dtor, due to \ + region params: {} or pred: {}", + typ.repr(tcx), + has_region_param_of_interest, + has_pred_of_interest); + } else { + debug!("typ: {} has dtor, but it is uninteresting", + typ.repr(tcx)); + } + } + } + + return has_dtor_of_interest; +} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 154d824e67846..026ba3d08b42b 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -12,6 +12,57 @@ register_long_diagnostics! { +E0046: r##" +When trying to make some type implement a trait `Foo`, you must, at minimum, +provide implementations for all of `Foo`'s required methods (meaning the +methods that do not have default implementations), as well as any required +trait items like associated types or constants. +"##, + +E0054: r##" +It is not allowed to cast to a bool. If you are trying to cast a numeric type +to a bool, you can compare it with zero instead: + +``` +let x = 5; + +// Ok +let x_is_nonzero = x != 0; + +// Not allowed, won't compile +let x_is_nonzero = x as bool; +``` +"##, + +E0062: r##" +This error indicates that during an attempt to build a struct or struct-like +enum variant, one of the fields was specified more than once. Each field should +be specified exactly one time. +"##, + +E0063: r##" +This error indicates that during an attempt to build a struct or struct-like +enum variant, one of the fields was not provided. Each field should be specified +exactly once. +"##, + +E0067: r##" +The left-hand side of an assignment operator must be an lvalue expression. An +lvalue expression represents a memory location and includes item paths (ie, +namespaced variables), dereferences, indexing expressions, and field references. + +``` +use std::collections::LinkedList; + +// Good +let mut list = LinkedList::new(); + + +// Bad: assignment to non-lvalue expression +LinkedList::new() += 1; +``` +"##, + E0081: r##" Enum discriminants are used to differentiate enum variants stored in memory. This error indicates that the same value was used for two or more variants, @@ -85,6 +136,20 @@ construct an instance of the following type using only safe code: ``` enum Empty {} ``` +"##, + +E0131: r##" +It is not possible to define `main` with type parameters, or even with function +parameters. When `main` is present, it must take no arguments and return `()`. +"##, + +E0132: r##" +It is not possible to declare type parameters on a function that has the `start` +attribute. Such a function must have the following type signature: + +``` +fn(isize, *const *const u8) -> isize +``` "## } @@ -106,20 +171,15 @@ register_diagnostics! { E0040, // explicit use of destructor method E0044, E0045, - E0046, E0049, E0050, E0053, - E0054, E0055, E0057, E0059, E0060, E0061, - E0062, - E0063, E0066, - E0067, E0068, E0069, E0070, @@ -159,8 +219,6 @@ register_diagnostics! { E0128, E0129, E0130, - E0131, - E0132, E0141, E0159, E0163, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 17053e4f10ad3..66c5a4e0db236 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -477,7 +477,7 @@ impl LangString { /// By default this markdown renderer generates anchors for each header in the /// rendered document. The anchor name is the contents of the header separated -/// by hyphens, and a task-local map is used to disambiguate among duplicate +/// by hyphens, and a thread-local map is used to disambiguate among duplicate /// headers (numbers are appended). /// /// This method will reset the local table for these headers. This is typically diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0642daeeb3a87..08792044c2a77 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -17,10 +17,10 @@ //! //! The rendering process is largely driven by the `Context` and `Cache` //! structures. The cache is pre-populated by crawling the crate in question, -//! and then it is shared among the various rendering tasks. The cache is meant +//! and then it is shared among the various rendering threads. The cache is meant //! to be a fairly large structure not implementing `Clone` (because it's shared -//! among tasks). The context, however, should be a lightweight structure. This -//! is cloned per-task and contains information about what is currently being +//! among threads). The context, however, should be a lightweight structure. This +//! is cloned per-thread and contains information about what is currently being //! rendered. //! //! In order to speed up rendering (mostly because of markdown rendering), the @@ -30,7 +30,7 @@ //! //! In addition to rendering the crate itself, this module is also responsible //! for creating the corresponding search index and source file renderings. -//! These tasks are not parallelized (they haven't been a bottleneck yet), and +//! These threads are not parallelized (they haven't been a bottleneck yet), and //! both occur before the crate is rendered. pub use self::ExternalLocation::*; @@ -154,7 +154,7 @@ impl Impl { /// This structure purposefully does not implement `Clone` because it's intended /// to be a fairly large and expensive structure to clone. Instead this adheres /// to `Send` so it may be stored in a `Arc` instance and shared among the various -/// rendering tasks. +/// rendering threads. #[derive(Default)] pub struct Cache { /// Mapping of typaram ids to the name of the type parameter. This is used @@ -688,7 +688,7 @@ fn write(dst: PathBuf, contents: &[u8]) -> io::Result<()> { try!(File::create(&dst)).write_all(contents) } -/// Makes a directory on the filesystem, failing the task if an error occurs and +/// Makes a directory on the filesystem, failing the thread if an error occurs and /// skipping if the directory already exists. fn mkdir(path: &Path) -> io::Result<()> { if !path.exists() { @@ -1643,7 +1643,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, clean::ExternCrateItem(ref name, ref src) => { match *src { Some(ref src) => { - try!(write!(w, "{}extern crate \"{}\" as {};", + try!(write!(w, "{}extern crate {} as {};", VisSpace(myitem.visibility), src, name)) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 4bed38e74fc10..f8c2626d09e31 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -180,9 +180,9 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths, // an explicit handle into rustc to collect output messages, but we also // want to catch the error message that rustc prints when it fails. // - // We take our task-local stderr (likely set by the test runner) and replace + // We take our thread-local stderr (likely set by the test runner) and replace // it with a sink that is also passed to rustc itself. When this function - // returns the output of the sink is copied onto the output of our own task. + // returns the output of the sink is copied onto the output of our own thread. // // The basic idea is to not use a default_handler() for rustc, and then also // not print things by default to the actual stderr. diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index baa6493533d29..adc4f69334f17 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -3011,9 +3011,9 @@ mod tests { let v: i64 = super::decode("9223372036854775807").unwrap(); assert_eq!(v, i64::MAX); - let res: DecodeResult = super::decode("765.25252"); + let res: DecodeResult = super::decode("765.25"); assert_eq!(res, Err(ExpectedError("Integer".to_string(), - "765.25252".to_string()))); + "765.25".to_string()))); } #[test] diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index eedda3cf4371a..48f65a5abfd45 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -205,7 +205,7 @@ fn test_resize_policy() { /// A hash map implementation which uses linear probing with Robin /// Hood bucket stealing. /// -/// The hashes are all keyed by the task-local random number generator +/// The hashes are all keyed by the thread-local random number generator /// on creation by default. This means that the ordering of the keys is /// randomized, but makes the tables more resistant to /// denial-of-service attacks (Hash DoS). This behaviour can be @@ -916,6 +916,24 @@ impl HashMap } /// Gets the given key's corresponding entry in the map for in-place manipulation. + /// + /// # Examples + /// + /// ``` + /// use std::collections::HashMap; + /// + /// let mut letters = HashMap::new(); + /// + /// for ch in "a short treatise on fungi".chars() { + /// let counter = letters.entry(ch).or_insert(0); + /// *counter += 1; + /// } + /// + /// assert_eq!(letters[&'s'], 2); + /// assert_eq!(letters[&'t'], 3); + /// assert_eq!(letters[&'u'], 1); + /// assert_eq!(letters.get(&'y'), None); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry { // Gotta resize now. diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs index 48b95ce6439c9..1099bf108f1db 100644 --- a/src/libstd/collections/mod.rs +++ b/src/libstd/collections/mod.rs @@ -271,7 +271,7 @@ //! ``` //! //! Iterators also provide a series of *adapter* methods for performing common -//! tasks to sequences. Among the adapters are functional favorites like `map`, +//! threads to sequences. Among the adapters are functional favorites like `map`, //! `fold`, `skip`, and `take`. Of particular interest to collections is the //! `rev` adapter, that reverses any iterator that supports this operation. Most //! collections provide reversible iterators as the way to iterate over them in diff --git a/src/libstd/env.rs b/src/libstd/env.rs index fe379208774a5..82999a47e5637 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -457,8 +457,8 @@ static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT; /// Sets the process exit code /// -/// Sets the exit code returned by the process if all supervised tasks -/// terminate successfully (without panicking). If the current root task panics +/// Sets the exit code returned by the process if all supervised threads +/// terminate successfully (without panicking). If the current root thread panics /// and is supervised by the scheduler then any user-specified exit status is /// ignored and the process exits with the default panic status. /// diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index a9dab8191fd9c..a14c472333c6e 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -355,13 +355,13 @@ impl<'a> Write for StderrLock<'a> { } } -/// Resets the task-local stderr handle to the specified writer +/// Resets the thread-local stderr handle to the specified writer /// -/// This will replace the current task's stderr handle, returning the old +/// This will replace the current thread's stderr handle, returning the old /// handle. All future calls to `panic!` and friends will emit their output to /// this specified handle. /// -/// Note that this does not need to be called for all new tasks; the default +/// Note that this does not need to be called for all new threads; the default /// output handle is to the process's stderr stream. #[unstable(feature = "set_stdio", reason = "this function may disappear completely or be replaced \ @@ -378,13 +378,13 @@ pub fn set_panic(sink: Box) -> Option> { }) } -/// Resets the task-local stdout handle to the specified writer +/// Resets the thread-local stdout handle to the specified writer /// -/// This will replace the current task's stdout handle, returning the old +/// This will replace the current thread's stdout handle, returning the old /// handle. All future calls to `print!` and friends will emit their output to /// this specified handle. /// -/// Note that this does not need to be called for all new tasks; the default +/// Note that this does not need to be called for all new threads; the default /// output handle is to the process's stdout stream. #[unstable(feature = "set_stdio", reason = "this function may disappear completely or be replaced \ diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6a5e46e9ed062..32193b4089d30 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -16,10 +16,10 @@ #![unstable(feature = "std_misc")] -/// The entry point for panic of Rust tasks. +/// The entry point for panic of Rust threads. /// -/// This macro is used to inject panic into a Rust task, causing the task to -/// unwind and panic entirely. Each task's panic can be reaped as the +/// This macro is used to inject panic into a Rust thread, causing the thread to +/// unwind and panic entirely. Each thread's panic can be reaped as the /// `Box` type, and the single-argument form of the `panic!` macro will be /// the value which is transmitted. /// @@ -38,10 +38,10 @@ #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable] -/// The entry point for panic of Rust tasks. +/// The entry point for panic of Rust threads. /// -/// This macro is used to inject panic into a Rust task, causing the task to -/// unwind and panic entirely. Each task's panic can be reaped as the +/// This macro is used to inject panic into a Rust thread, causing the thread to +/// unwind and panic entirely. Each thread's panic can be reaped as the /// `Box` type, and the single-argument form of the `panic!` macro will be /// the value which is transmitted. /// @@ -143,17 +143,17 @@ macro_rules! try { /// use std::sync::mpsc; /// /// // two placeholder functions for now -/// fn long_running_task() {} +/// fn long_running_thread() {} /// fn calculate_the_answer() -> u32 { 42 } /// /// let (tx1, rx1) = mpsc::channel(); /// let (tx2, rx2) = mpsc::channel(); /// -/// thread::spawn(move|| { long_running_task(); tx1.send(()).unwrap(); }); +/// thread::spawn(move|| { long_running_thread(); tx1.send(()).unwrap(); }); /// thread::spawn(move|| { tx2.send(calculate_the_answer()).unwrap(); }); /// /// select! { -/// _ = rx1.recv() => println!("the long running task finished first"), +/// _ = rx1.recv() => println!("the long running thread finished first"), /// answer = rx2.recv() => { /// println!("the answer was: {}", answer.unwrap()); /// } diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs index 88cfc5a7b2d8d..69f40d7e7befe 100644 --- a/src/libstd/net/parser.rs +++ b/src/libstd/net/parser.rs @@ -61,7 +61,7 @@ impl<'a> Parser<'a> { } // Return result of first successful parser - fn read_or(&mut self, parsers: &mut [Box Option>]) + fn read_or(&mut self, parsers: &mut [Box Option + 'static>]) -> Option { for pf in parsers.iter_mut() { match self.read_atomically(|p: &mut Parser| pf(p)) { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index db2cdb7319880..28063c1edb3f7 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -444,7 +444,7 @@ mod tests { let _t = thread::spawn(move|| { let acceptor = acceptor; for (i, stream) in acceptor.incoming().enumerate().take(MAX) { - // Start another task to handle the connection + // Start another thread to handle the connection let _t = thread::spawn(move|| { let mut stream = t!(stream); let mut buf = [0]; @@ -478,7 +478,7 @@ mod tests { let _t = thread::spawn(move|| { for stream in acceptor.incoming().take(MAX) { - // Start another task to handle the connection + // Start another thread to handle the connection let _t = thread::spawn(move|| { let mut stream = t!(stream); let mut buf = [0]; @@ -738,7 +738,7 @@ mod tests { assert_eq!(t!(s2.read(&mut [0])), 0); tx.send(()).unwrap(); }); - // this should wake up the child task + // this should wake up the child thread t!(s.shutdown(Shutdown::Read)); // this test will never finish if the child doesn't wake up @@ -752,7 +752,7 @@ mod tests { each_ip(&mut |addr| { let accept = t!(TcpListener::bind(&addr)); - // Enqueue a task to write to a socket + // Enqueue a thread to write to a socket let (tx, rx) = channel(); let (txdone, rxdone) = channel(); let txdone2 = txdone.clone(); diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index adce5f22ebc10..9589f4cf099b2 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -60,8 +60,8 @@ mod arch { #[cfg(any(target_arch = "mips", target_arch = "mipsel"))] mod arch { - use super::{dev_t, mode_t}; - use os::raw::c_long; + use super::mode_t; + use os::raw::{c_long, c_ulong}; use os::unix::raw::{gid_t, uid_t}; pub type blkcnt_t = i32; diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 09fa10dacf98c..4a8cceb202f5d 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -19,7 +19,7 @@ //! ``` //! //! This means that the contents of std can be accessed from any context -//! with the `std::` path prefix, as in `use std::vec`, `use std::task::spawn`, +//! with the `std::` path prefix, as in `use std::vec`, `use std::thread::spawn`, //! etc. //! //! Additionally, `std` contains a `prelude` module that reexports many of the diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index a04bb6705b321..3c36f0f1d490c 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -374,7 +374,7 @@ mod tests { txs.push(tx); thread::spawn(move|| { - // wait until all the tasks are ready to go. + // wait until all the threads are ready to go. rx.recv().unwrap(); // deschedule to attempt to interleave things as much @@ -394,7 +394,7 @@ mod tests { }); } - // start all the tasks + // start all the threads for tx in &txs { tx.send(()).unwrap(); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index a764b99e2805d..b24099505ed89 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -238,7 +238,7 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] + #[lang = "eh_personality"] #[no_mangle] // referenced from rust_try.ll #[allow(private_no_mangle_fns)] extern fn rust_eh_personality( @@ -292,7 +292,7 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] + #[lang = "eh_personality"] #[no_mangle] // referenced from rust_try.ll pub extern "C" fn rust_eh_personality( version: c_int, @@ -345,7 +345,7 @@ pub mod eabi { -> uw::_Unwind_Reason_Code; } - #[lang="eh_personality"] + #[lang = "eh_personality"] #[no_mangle] // referenced from rust_try.ll #[allow(private_no_mangle_fns)] extern "C" fn rust_eh_personality( @@ -432,7 +432,7 @@ pub mod eabi { ) -> EXCEPTION_DISPOSITION; } - #[lang="eh_personality"] + #[lang = "eh_personality"] #[no_mangle] // referenced from rust_try.ll #[allow(private_no_mangle_fns)] extern "C" fn rust_eh_personality( @@ -590,7 +590,7 @@ fn begin_unwind_inner(msg: Box, /// This is an unsafe and experimental API which allows for an arbitrary /// callback to be invoked when a thread panics. This callback is invoked on both /// the initial unwinding and a double unwinding if one occurs. Additionally, -/// the local `Task` will be in place for the duration of the callback, and +/// the local `Thread` will be in place for the duration of the callback, and /// the callback must ensure that it remains in place once the callback returns. /// /// Only a limited number of callbacks can be registered, and this function diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs index 34fcf6cdadd30..8360620c3453b 100644 --- a/src/libstd/sync/barrier.rs +++ b/src/libstd/sync/barrier.rs @@ -10,7 +10,7 @@ use sync::{Mutex, Condvar}; -/// A barrier enables multiple tasks to synchronize the beginning +/// A barrier enables multiple threads to synchronize the beginning /// of some computation. /// /// ``` @@ -128,7 +128,7 @@ mod tests { }); } - // At this point, all spawned tasks should be blocked, + // At this point, all spawned threads should be blocked, // so we shouldn't get anything from the port assert!(match rx.try_recv() { Err(TryRecvError::Empty) => true, diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index 965ad74fb60a1..77aeeca796809 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -107,7 +107,7 @@ //! //! let (tx, rx) = sync_channel::(0); //! thread::spawn(move|| { -//! // This will wait for the parent task to start receiving +//! // This will wait for the parent thread to start receiving //! tx.send(53).unwrap(); //! }); //! rx.recv().unwrap(); @@ -253,7 +253,7 @@ // blocking. The implementation is essentially the entire blocking procedure // followed by an increment as soon as its woken up. The cancellation procedure // involves an increment and swapping out of to_wake to acquire ownership of the -// task to unblock. +// thread to unblock. // // Sadly this current implementation requires multiple allocations, so I have // seen the throughput of select() be much worse than it should be. I do not @@ -289,7 +289,7 @@ mod mpsc_queue; mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by -/// one task +/// one thread #[stable(feature = "rust1", since = "1.0.0")] pub struct Receiver { inner: UnsafeCell>, @@ -316,7 +316,7 @@ pub struct IntoIter { } /// The sending-half of Rust's asynchronous channel type. This half can only be -/// owned by one task, but it can be cloned to send to other tasks. +/// owned by one thread, but it can be cloned to send to other threads. #[stable(feature = "rust1", since = "1.0.0")] pub struct Sender { inner: UnsafeCell>, @@ -327,7 +327,7 @@ pub struct Sender { unsafe impl Send for Sender { } /// The sending-half of Rust's synchronous channel type. This half can only be -/// owned by one task, but it can be cloned to send to other tasks. +/// owned by one thread, but it can be cloned to send to other threads. #[stable(feature = "rust1", since = "1.0.0")] pub struct SyncSender { inner: Arc>>, @@ -421,7 +421,7 @@ impl UnsafeFlavor for Receiver { /// Creates a new asynchronous channel, returning the sender/receiver halves. /// /// All data sent on the sender will become available on the receiver, and no -/// send will block the calling task (this channel has an "infinite buffer"). +/// send will block the calling thread (this channel has an "infinite buffer"). /// /// # Examples /// @@ -1596,7 +1596,7 @@ mod tests { drop(rx); // destroy a shared tx2.send(()).unwrap(); }); - // make sure the other task has gone to sleep + // make sure the other thread has gone to sleep for _ in 0..5000 { thread::yield_now(); } // upgrade to a shared chan and send a message @@ -1604,7 +1604,7 @@ mod tests { drop(tx); t.send(()).unwrap(); - // wait for the child task to exit before we exit + // wait for the child thread to exit before we exit rx2.recv().unwrap(); } } @@ -2060,7 +2060,7 @@ mod sync_tests { drop(rx); // destroy a shared tx2.send(()).unwrap(); }); - // make sure the other task has gone to sleep + // make sure the other thread has gone to sleep for _ in 0..5000 { thread::yield_now(); } // upgrade to a shared chan and send a message @@ -2068,7 +2068,7 @@ mod sync_tests { drop(tx); t.send(()).unwrap(); - // wait for the child task to exit before we exit + // wait for the child thread to exit before we exit rx2.recv().unwrap(); } diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 4ab5a796fcb43..2c0da938cbf8b 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -28,7 +28,7 @@ //! A mostly lock-free multi-producer, single consumer queue. //! //! This module contains an implementation of a concurrent MPSC queue. This -//! queue can be used to share data between tasks, and is also used as the +//! queue can be used to share data between threads, and is also used as the //! building block of channels in rust. //! //! Note that the current implementation of this queue has a caveat of the `pop` diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index ab45b722c4523..7e9c017617d8a 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -23,7 +23,7 @@ /// # Implementation /// /// Oneshots are implemented around one atomic usize variable. This variable -/// indicates both the state of the port/chan but also contains any tasks +/// indicates both the state of the port/chan but also contains any threads /// blocked on the port. All atomic operations happen on this one word. /// /// In order to upgrade a oneshot channel, an upgrade is considered a disconnect @@ -55,7 +55,7 @@ const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded // whoever changed the state. pub struct Packet { - // Internal state of the chan/port pair (stores the blocked task as well) + // Internal state of the chan/port pair (stores the blocked thread as well) state: AtomicUsize, // One-shot data slot location data: Option, @@ -139,7 +139,7 @@ impl Packet { } pub fn recv(&mut self) -> Result> { - // Attempt to not block the task (it's a little expensive). If it looks + // Attempt to not block the thread (it's a little expensive). If it looks // like we're not empty, then immediately go through to `try_recv`. if self.state.load(Ordering::SeqCst) == EMPTY { let (wait_token, signal_token) = blocking::tokens(); @@ -317,8 +317,8 @@ impl Packet { } } - // Remove a previous selecting task from this port. This ensures that the - // blocked task will no longer be visible to any other threads. + // Remove a previous selecting thread from this port. This ensures that the + // blocked thread will no longer be visible to any other threads. // // The return value indicates whether there's data on this port. pub fn abort_selection(&mut self) -> Result> { @@ -329,7 +329,7 @@ impl Packet { s @ DATA | s @ DISCONNECTED => s, - // If we've got a blocked task, then use an atomic to gain ownership + // If we've got a blocked thread, then use an atomic to gain ownership // of it (may fail) ptr => self.state.compare_and_swap(ptr, EMPTY, Ordering::SeqCst) }; @@ -338,7 +338,7 @@ impl Packet { // about it. match state { EMPTY => unreachable!(), - // our task used for select was stolen + // our thread used for select was stolen DATA => Ok(true), // If the other end has hung up, then we have complete ownership diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index 2d91581192c6f..679cc550454fa 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -229,7 +229,7 @@ impl Select { // woken us up (although the wakeup is guaranteed to fail). // // This situation happens in the window of where a sender invokes - // increment(), sees -1, and then decides to wake up the task. After + // increment(), sees -1, and then decides to wake up the thread. After // all this is done, the sending thread will set `selecting` to // `false`. Until this is done, we cannot return. If we were to // return, then a sender could wake up a receiver which has gone diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index 09a02923f140c..41c79dd52c85a 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -91,8 +91,8 @@ impl Packet { } // This function is used at the creation of a shared packet to inherit a - // previously blocked task. This is done to prevent spurious wakeups of - // tasks in select(). + // previously blocked thread. This is done to prevent spurious wakeups of + // threads in select(). // // This can only be called at channel-creation time pub fn inherit_blocker(&mut self, @@ -424,7 +424,7 @@ impl Packet { } } - // Cancels a previous task waiting on this port, returning whether there's + // Cancels a previous thread waiting on this port, returning whether there's // data on the port. // // This is similar to the stream implementation (hence fewer comments), but diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index f4b9c7d45fd2e..b72da91c0a075 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -30,7 +30,7 @@ //! A single-producer single-consumer concurrent queue //! //! This module contains the implementation of an SPSC queue which can be used -//! concurrently between two tasks. This data structure is safe to use and +//! concurrently between two threads. This data structure is safe to use and //! enforces the semantics that there is one pusher and one popper. #![unstable(feature = "std_misc")] diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 1200e71d9afed..404814b4cd4bb 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -181,7 +181,7 @@ impl Packet { data => return data, } - // Welp, our channel has no data. Deschedule the current task and + // Welp, our channel has no data. Deschedule the current thread and // initiate the blocking protocol. let (wait_token, signal_token) = blocking::tokens(); if self.decrement(signal_token).is_ok() { @@ -385,7 +385,7 @@ impl Packet { } } - // Removes a previous task from being blocked in this port + // Removes a previous thread from being blocked in this port pub fn abort_selection(&mut self, was_upgrade: bool) -> Result> { // If we're aborting selection after upgrading from a oneshot, then @@ -414,7 +414,7 @@ impl Packet { let prev = self.bump(steals + 1); // If we were previously disconnected, then we know for sure that there - // is no task in to_wake, so just keep going + // is no thread in to_wake, so just keep going let has_data = if prev == DISCONNECTED { assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); true // there is data, that data is that we're disconnected @@ -428,7 +428,7 @@ impl Packet { // // If the previous count was positive then we're in a tougher // situation. A possible race is that a sender just incremented - // through -1 (meaning it's going to try to wake a task up), but it + // through -1 (meaning it's going to try to wake a thread up), but it // hasn't yet read the to_wake. In order to prevent a future recv() // from waking up too early (this sender picking up the plastered // over to_wake), we spin loop here waiting for to_wake to be 0. diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 4687df107f6b1..904eab1fd7efd 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -19,7 +19,7 @@ /// which means that every successful send is paired with a successful recv. /// /// This flavor of channels defines a new `send_opt` method for channels which -/// is the method by which a message is sent but the task does not panic if it +/// is the method by which a message is sent but the thread does not panic if it /// cannot be delivered. /// /// Another major difference is that send() will *always* return back the data @@ -62,12 +62,12 @@ unsafe impl Sync for Packet { } struct State { disconnected: bool, // Is the channel disconnected yet? queue: Queue, // queue of senders waiting to send data - blocker: Blocker, // currently blocked task on this channel + blocker: Blocker, // currently blocked thread on this channel buf: Buffer, // storage for buffered messages cap: usize, // capacity of this channel /// A curious flag used to indicate whether a sender failed or succeeded in - /// blocking. This is used to transmit information back to the task that it + /// blocking. This is used to transmit information back to the thread that it /// must dequeue its message from the buffer because it was not received. /// This is only relevant in the 0-buffer case. This obviously cannot be /// safely constructed, but it's guaranteed to always have a valid pointer @@ -84,7 +84,7 @@ enum Blocker { NoneBlocked } -/// Simple queue for threading tasks together. Nodes are stack-allocated, so +/// Simple queue for threading threads together. Nodes are stack-allocated, so /// this structure is not safe at all struct Queue { head: *mut Node, @@ -130,7 +130,7 @@ fn wait<'a, 'b, T>(lock: &'a Mutex>, /// Wakes up a thread, dropping the lock at the correct time fn wakeup(token: SignalToken, guard: MutexGuard>) { - // We need to be careful to wake up the waiting task *outside* of the mutex + // We need to be careful to wake up the waiting thread *outside* of the mutex // in case it incurs a context switch. drop(guard); token.signal(); @@ -298,7 +298,7 @@ impl Packet { }; mem::drop(guard); - // only outside of the lock do we wake up the pending tasks + // only outside of the lock do we wake up the pending threads pending_sender1.map(|t| t.signal()); pending_sender2.map(|t| t.signal()); } @@ -394,8 +394,8 @@ impl Packet { } } - // Remove a previous selecting task from this port. This ensures that the - // blocked task will no longer be visible to any other threads. + // Remove a previous selecting thread from this port. This ensures that the + // blocked thread will no longer be visible to any other threads. // // The return value indicates whether there's data on this port. pub fn abort_selection(&self) -> bool { @@ -446,7 +446,7 @@ impl Buffer { } //////////////////////////////////////////////////////////////////////////////// -// Queue, a simple queue to enqueue tasks with (stack-allocated nodes) +// Queue, a simple queue to enqueue threads with (stack-allocated nodes) //////////////////////////////////////////////////////////////////////////////// impl Queue { diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 222aff9188a6a..febf5f1b18322 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -30,7 +30,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// /// The mutexes in this module implement a strategy called "poisoning" where a /// mutex is considered poisoned whenever a thread panics while holding the -/// lock. Once a mutex is poisoned, all other tasks are unable to access the +/// lock. Once a mutex is poisoned, all other threads are unable to access the /// data by default as it is likely tainted (some invariant is not being /// upheld). /// @@ -56,7 +56,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// // Spawn a few threads to increment a shared variable (non-atomically), and /// // let the main thread know once all increments are done. /// // -/// // Here we're using an Arc to share memory among tasks, and the data inside +/// // Here we're using an Arc to share memory among threads, and the data inside /// // the Arc is protected with a mutex. /// let data = Arc::new(Mutex::new(0)); /// @@ -69,7 +69,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult}; /// // which can access the shared state when the lock is held. /// // /// // We unwrap() the return value to assert that we are not expecting -/// // tasks to ever fail while holding the lock. +/// // threads to ever fail while holding the lock. /// let mut data = data.lock().unwrap(); /// *data += 1; /// if *data == N { @@ -195,10 +195,10 @@ impl Mutex { } impl Mutex { - /// Acquires a mutex, blocking the current task until it is able to do so. + /// Acquires a mutex, blocking the current thread until it is able to do so. /// - /// This function will block the local task until it is available to acquire - /// the mutex. Upon returning, the task is the only task with the mutex + /// This function will block the local thread until it is available to acquire + /// the mutex. Upon returning, the thread is the only thread with the mutex /// held. An RAII guard is returned to allow scoped unlock of the lock. When /// the guard goes out of scope, the mutex will be unlocked. /// diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs index 2d7123692289d..57baedaad9c8e 100644 --- a/src/libstd/sync/once.rs +++ b/src/libstd/sync/once.rs @@ -55,13 +55,13 @@ impl Once { /// will be executed if this is the first time `call_once` has been called, /// and otherwise the routine will *not* be invoked. /// - /// This method will block the calling task if another initialization + /// This method will block the calling thread if another initialization /// routine is currently running. /// /// When this function returns, it is guaranteed that some initialization /// has run and completed (it may not be the closure specified). It is also /// guaranteed that any memory writes performed by the executed closure can - /// be reliably observed by other tasks at this point (there is a + /// be reliably observed by other threads at this point (there is a /// happens-before relation between the closure and code executing after the /// return). #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index d70c0a4b43836..625377df7d6dd 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -25,7 +25,7 @@ use sys_common::rwlock as sys; /// typically allows for read-only access (shared access). /// /// The type parameter `T` represents the data that this lock protects. It is -/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to +/// required that `T` satisfies `Send` to be shared across threads and `Sync` to /// allow concurrent access through readers. The RAII guards returned from the /// locking methods implement `Deref` (and `DerefMut` for the `write` methods) /// to allow access to the contained of the lock. diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys/common/poison.rs index 6c59231c23a89..67679c11a9858 100644 --- a/src/libstd/sys/common/poison.rs +++ b/src/libstd/sys/common/poison.rs @@ -55,7 +55,7 @@ pub struct Guard { /// A type of error which can be returned whenever a lock is acquired. /// -/// Both Mutexes and RwLocks are poisoned whenever a task fails while the lock +/// Both Mutexes and RwLocks are poisoned whenever a thread fails while the lock /// is held. The precise semantics for when a lock is poisoned is documented on /// each lock, but once a lock is poisoned then all future acquisitions will /// return this error. @@ -68,7 +68,7 @@ pub struct PoisonError { /// `try_lock` method. #[stable(feature = "rust1", since = "1.0.0")] pub enum TryLockError { - /// The lock could not be acquired because another task failed while holding + /// The lock could not be acquired because another thread failed while holding /// the lock. #[stable(feature = "rust1", since = "1.0.0")] Poisoned(PoisonError), diff --git a/src/libstd/sys/common/stack.rs b/src/libstd/sys/common/stack.rs index 8dc3407db77a2..fadeebc815001 100644 --- a/src/libstd/sys/common/stack.rs +++ b/src/libstd/sys/common/stack.rs @@ -11,13 +11,13 @@ //! Rust stack-limit management //! //! Currently Rust uses a segmented-stack-like scheme in order to detect stack -//! overflow for rust tasks. In this scheme, the prologue of all functions are +//! overflow for rust threads. In this scheme, the prologue of all functions are //! preceded with a check to see whether the current stack limits are being //! exceeded. //! //! This module provides the functionality necessary in order to manage these //! stack limits (which are stored in platform-specific locations). The -//! functions here are used at the borders of the task lifetime in order to +//! functions here are used at the borders of the thread lifetime in order to //! manage these limits. //! //! This function is an unstable module because this scheme for stack overflow diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index ca805ad02422a..135ae1bf9163b 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -22,7 +22,7 @@ /// getting both accurate backtraces and accurate symbols across platforms. /// This route was not chosen in favor of the next option, however. /// -/// * We're already using libgcc_s for exceptions in rust (triggering task +/// * We're already using libgcc_s for exceptions in rust (triggering thread /// unwinding and running destructors on the stack), and it turns out that it /// conveniently comes with a function that also gives us a backtrace. All of /// these functions look like _Unwind_*, but it's not quite the full @@ -116,7 +116,7 @@ pub fn write(w: &mut Write) -> io::Result<()> { // while it doesn't requires lock for work as everything is // local, it still displays much nicer backtraces when a - // couple of tasks panic simultaneously + // couple of threads panic simultaneously static LOCK: StaticMutex = MUTEX_INIT; let _g = LOCK.lock(); diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index cbabab8acb780..ea5af3f2830e8 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -32,7 +32,7 @@ pub type Dtor = unsafe extern fn(*mut u8); // somewhere to run arbitrary code on thread termination. With this in place // we'll be able to run anything we like, including all TLS destructors! // -// To accomplish this feat, we perform a number of tasks, all contained +// To accomplish this feat, we perform a number of threads, all contained // within this module: // // * All TLS destructors are tracked by *us*, not the windows runtime. This diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index bb2832b874657..41bdf034705d3 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -32,7 +32,7 @@ pub mod __impl { /// primary method is the `with` method. /// /// The `with` method yields a reference to the contained value which cannot be -/// sent across tasks or escape the given closure. +/// sent across threads or escape the given closure. /// /// # Initialization and Destruction /// diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index bcc70c2b8163e..f480147b93ee7 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -873,8 +873,8 @@ mod tests { #[test] fn test_child_doesnt_ref_parent() { - // If the child refcounts the parent task, this will stack overflow when - // climbing the task tree to dereference each ancestor. (See #1789) + // If the child refcounts the parent thread, this will stack overflow when + // climbing the thread tree to dereference each ancestor. (See #1789) // (well, it would if the constant were 8000+ - I lowered it to be more // valgrind-friendly. try this at home, instead..!) const GENERATIONS: u32 = 16; @@ -983,6 +983,6 @@ mod tests { thread::sleep_ms(2); } - // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due + // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due // to the test harness apparently interfering with stderr configuration. } diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index 339e535cdcd9f..e36631210d4da 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -77,7 +77,7 @@ //! //! The `cs_...` functions ("combine substructure) are designed to //! make life easier by providing some pre-made recipes for common -//! tasks; mostly calling the function being derived on all the +//! threads; mostly calling the function being derived on all the //! arguments and then combining them back together in some way (or //! letting the user chose that). They are not meant to be the only //! way to handle the structures that this code creates. diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4ea2d4e5c686c..c3f1b9748155f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -986,9 +986,10 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P { let fm = fresh_mark(); let marked_before = mark_tts(&tts[..], fm); let mac_span = fld.cx.original_span(); - let expanded = match expander.expand(fld.cx, - mac_span, - &marked_before[..]).make_pat() { + let pat = expander.expand(fld.cx, + mac_span, + &marked_before[..]).make_pat(); + let expanded = match pat { Some(e) => e, None => { fld.cx.span_err( diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0106de913bb87..53ed4f351d356 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -601,7 +601,7 @@ pub type IdentInterner = StrInterner; // if an interner exists in TLS, return it. Otherwise, prepare a // fresh one. -// FIXME(eddyb) #8726 This should probably use a task-local reference. +// FIXME(eddyb) #8726 This should probably use a thread-local reference. pub fn get_ident_interner() -> Rc { thread_local!(static KEY: Rc<::parse::token::IdentInterner> = { Rc::new(mk_fresh_ident_interner()) @@ -615,14 +615,14 @@ pub fn reset_ident_interner() { interner.reset(mk_fresh_ident_interner()); } -/// Represents a string stored in the task-local interner. Because the -/// interner lives for the life of the task, this can be safely treated as an -/// immortal string, as long as it never crosses between tasks. +/// Represents a string stored in the thread-local interner. Because the +/// interner lives for the life of the thread, this can be safely treated as an +/// immortal string, as long as it never crosses between threads. /// /// FIXME(pcwalton): You must be careful about what you do in the destructors /// of objects stored in TLS, because they may run after the interner is /// destroyed. In particular, they must not access string contents. This can -/// be fixed in the future by just leaking all strings until task death +/// be fixed in the future by just leaking all strings until thread death /// somehow. #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] pub struct InternedString { @@ -697,14 +697,14 @@ impl Encodable for InternedString { } } -/// Returns the string contents of a name, using the task-local interner. +/// Returns the string contents of a name, using the thread-local interner. #[inline] pub fn get_name(name: ast::Name) -> InternedString { let interner = get_ident_interner(); InternedString::new_from_rc_str(interner.get(name)) } -/// Returns the string contents of an identifier, using the task-local +/// Returns the string contents of an identifier, using the thread-local /// interner. #[inline] pub fn get_ident(ident: ast::Ident) -> InternedString { @@ -712,7 +712,7 @@ pub fn get_ident(ident: ast::Ident) -> InternedString { } /// Interns and returns the string contents of an identifier, using the -/// task-local interner. +/// thread-local interner. #[inline] pub fn intern_and_get_ident(s: &str) -> InternedString { get_name(intern(s)) diff --git a/src/libsyntax/util/parser_testing.rs b/src/libsyntax/util/parser_testing.rs index d016eb39239f6..929f2a6abd6b8 100644 --- a/src/libsyntax/util/parser_testing.rs +++ b/src/libsyntax/util/parser_testing.rs @@ -73,7 +73,11 @@ pub fn string_to_stmt(source_str : String) -> P { /// Parse a string, return a pat. Uses "irrefutable"... which doesn't /// (currently) affect parsing. pub fn string_to_pat(source_str: String) -> P { - string_to_parser(&new_parse_sess(), source_str).parse_pat() + // Binding `sess` and `parser` works around dropck-injected + // region-inference issues; see #25212, #22323, #22321. + let sess = new_parse_sess(); + let mut parser = string_to_parser(&sess, source_str); + parser.parse_pat() } /// Convert a vector of strings to a vector of ast::Ident's diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index 9cbfe283cbddc..4d0b746c60c75 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -146,7 +146,7 @@ pub trait TDynBenchFn: Send { // A function that runs a test. If the function returns successfully, // the test succeeds; if the function panics then the test fails. We // may need to come up with a more clever definition of test in order -// to support isolation of tests into tasks. +// to support isolation of tests into threads. pub enum TestFn { StaticTestFn(fn()), StaticBenchFn(fn(&mut Bencher)), diff --git a/src/test/auxiliary/crateresolve3-1.rs b/src/test/auxiliary/crateresolve3-1.rs deleted file mode 100644 index 0e02a8d96a3b2..0000000000000 --- a/src/test/auxiliary/crateresolve3-1.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="crateresolve3#0.1"] - -#![crate_type = "lib"] - -pub fn f() -> isize { 10 } diff --git a/src/test/auxiliary/crateresolve3-2.rs b/src/test/auxiliary/crateresolve3-2.rs deleted file mode 100644 index 6a11465b27ca0..0000000000000 --- a/src/test/auxiliary/crateresolve3-2.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="crateresolve3#0.2"] - -#![crate_type = "lib"] - -pub fn g() -> isize { 20 } diff --git a/src/test/auxiliary/crateresolve4a-1.rs b/src/test/auxiliary/crateresolve4a-1.rs deleted file mode 100644 index 579e93aa059c6..0000000000000 --- a/src/test/auxiliary/crateresolve4a-1.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="crateresolve4a#0.1"] -#![crate_type = "lib"] - -pub fn f() -> isize { 10 } diff --git a/src/test/auxiliary/crateresolve4b-1.rs b/src/test/auxiliary/crateresolve4b-1.rs deleted file mode 100644 index 9e4b0d158ecb9..0000000000000 --- a/src/test/auxiliary/crateresolve4b-1.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:crateresolve4a-1.rs -// aux-build:crateresolve4a-2.rs -#![crate_name="crateresolve4b#0.1"] -#![crate_type = "lib"] - -extern crate "crateresolve4a#0.2" as crateresolve4a; - -pub fn f() -> isize { crateresolve4a::g() } diff --git a/src/test/auxiliary/crateresolve4b-2.rs b/src/test/auxiliary/crateresolve4b-2.rs deleted file mode 100644 index a50b8dbf957ea..0000000000000 --- a/src/test/auxiliary/crateresolve4b-2.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:crateresolve4a-1.rs -// aux-build:crateresolve4a-2.rs -#![crate_name="crateresolve4b#0.2"] -#![crate_type = "lib"] - -extern crate "crateresolve4a#0.1" as crateresolve4a; - -pub fn g() -> isize { crateresolve4a::f() } diff --git a/src/test/auxiliary/crateresolve5-1.rs b/src/test/auxiliary/crateresolve5-1.rs deleted file mode 100644 index eaec37ed417d0..0000000000000 --- a/src/test/auxiliary/crateresolve5-1.rs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="crateresolve5#0.1"] - -#![crate_type = "lib"] - -pub struct NameVal { pub name: String, pub val: isize } - -pub fn struct_nameval() -> NameVal { - NameVal { name: "crateresolve5".to_string(), val: 10 } -} - -pub enum e { - e_val -} - -pub fn nominal() -> e { e_val } - -pub fn nominal_eq(_e1: e, _e2: e) -> bool { true } - -impl PartialEq for e { - fn eq(&self, other: &e) -> bool { nominal_eq(*self, *other) } - fn ne(&self, other: &e) -> bool { !nominal_eq(*self, *other) } -} - -pub fn f() -> isize { 10 } diff --git a/src/test/auxiliary/crateresolve5-2.rs b/src/test/auxiliary/crateresolve5-2.rs deleted file mode 100644 index 14d28c709cdb5..0000000000000 --- a/src/test/auxiliary/crateresolve5-2.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="crateresolve5#0.2"] - -#![crate_type = "lib"] - -pub struct NameVal { pub name: String, pub val: isize } -pub fn struct_nameval() -> NameVal { - NameVal { name: "crateresolve5".to_string(), val: 10 } -} - -pub enum e { - e_val -} - -impl PartialEq for e { - fn eq(&self, other: &e) -> bool { !nominal_neq(*self, *other) } - fn ne(&self, other: &e) -> bool { nominal_neq(*self, *other) } -} - -pub fn nominal() -> e { e_val } - -pub fn nominal_neq(_e1: e, _e2: e) -> bool { false } - -pub fn f() -> isize { 20 } diff --git a/src/test/auxiliary/crateresolve7x.rs b/src/test/auxiliary/crateresolve7x.rs deleted file mode 100644 index c05d292eaea47..0000000000000 --- a/src/test/auxiliary/crateresolve7x.rs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2012-2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:crateresolve_calories-1.rs -// aux-build:crateresolve_calories-2.rs - -// These both have the same version but differ in other metadata -pub mod a { - extern crate cr_1 (name = "crateresolve_calories", vers = "0.1", calories="100"); - pub fn f() -> isize { cr_1::f() } -} - -pub mod b { - extern crate cr_2 (name = "crateresolve_calories", vers = "0.1", calories="200"); - pub fn f() -> isize { cr_2::f() } -} diff --git a/src/test/auxiliary/crateresolve8-1.rs b/src/test/auxiliary/crateresolve8-1.rs deleted file mode 100644 index bc2a2d83bfec1..0000000000000 --- a/src/test/auxiliary/crateresolve8-1.rs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// default link meta for 'package_id' will be equal to filestem -#![crate_name="crateresolve8#0.1"] - -#![crate_type = "lib"] - -pub fn f() -> isize { 20 } diff --git a/src/test/auxiliary/crateresolve_calories-1.rs b/src/test/auxiliary/crateresolve_calories-1.rs deleted file mode 100644 index c1705d687abb0..0000000000000 --- a/src/test/auxiliary/crateresolve_calories-1.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="crateresolve_calories#0.1"] -#![crate_type = "lib"] - -pub fn f() -> isize { 100 } diff --git a/src/test/auxiliary/crateresolve_calories-2.rs b/src/test/auxiliary/crateresolve_calories-2.rs deleted file mode 100644 index 2ae87daab4e29..0000000000000 --- a/src/test/auxiliary/crateresolve_calories-2.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="crateresolve_calories#0.1"] -#![crate_type = "lib"] - -pub fn f() -> isize { 200 } diff --git a/src/test/auxiliary/inherit_struct_lib.rs b/src/test/auxiliary/inherit_struct_lib.rs deleted file mode 100644 index 6f5ddfd37a5c2..0000000000000 --- a/src/test/auxiliary/inherit_struct_lib.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2014 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test struct inheritance on structs from another crate. -#![feature(struct_inherit)] - -pub virtual struct S1 { - pub f1: isize, -} - -pub struct S2 : S1 { - pub f2: isize, -} - -pub fn test_s2(s2: S2) { - assert!(s2.f1 == 115); - assert!(s2.f2 == 113); -} - -pub static glob_s: S2 = S2 { f1: 32, f2: -45 }; diff --git a/src/test/auxiliary/issue_2242_a.rs b/src/test/auxiliary/issue_2242_a.rs deleted file mode 100644 index 33b6d116c8a2d..0000000000000 --- a/src/test/auxiliary/issue_2242_a.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="a#0.1"] -#![crate_type = "lib"] - -trait to_strz { - fn to_strz() -> String; -} - -impl to_strz for String { - fn to_strz() -> String { self.clone() } -} diff --git a/src/test/auxiliary/issue_2242_c.rs b/src/test/auxiliary/issue_2242_c.rs deleted file mode 100644 index 31d119b20beaa..0000000000000 --- a/src/test/auxiliary/issue_2242_c.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![crate_name="c#0.1"] -#![crate_type = "lib"] - -extern crate a; - -use a::to_strz; - -impl to_strz for bool { - fn to_strz() -> String { fmt!("%b", self) } -} diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index 8048f3dde9682..07174de88a3d0 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This test creates a bunch of tasks that simultaneously send to each +// This test creates a bunch of threads that simultaneously send to each // other in a ring. The messages should all be basically // independent. // This is like msgsend-ring-pipes but adapted to use Arcs. @@ -52,7 +52,7 @@ fn thread_ring(i: usize, count: usize, num_chan: pipe, num_port: pipe) { let mut num_port = Some(num_port); // Send/Receive lots of messages. for j in 0..count { - //println!("task %?, iter %?", i, j); + //println!("thread %?, iter %?", i, j); let num_chan2 = num_chan.take().unwrap(); let num_port2 = num_port.take().unwrap(); send(&num_chan2, i * j); diff --git a/src/test/bench/rt-messaging-ping-pong.rs b/src/test/bench/rt-messaging-ping-pong.rs index b9512324e42d6..9be13101aa8a1 100644 --- a/src/test/bench/rt-messaging-ping-pong.rs +++ b/src/test/bench/rt-messaging-ping-pong.rs @@ -21,14 +21,14 @@ use std::sync::mpsc::channel; use std::env; use std::thread; -// This is a simple bench that creates M pairs of tasks. These -// tasks ping-pong back and forth over a pair of streams. This is a +// This is a simple bench that creates M pairs of threads. These +// threads ping-pong back and forth over a pair of streams. This is a // canonical message-passing benchmark as it heavily strains message // passing and almost nothing else. fn ping_pong_bench(n: usize, m: usize) { - // Create pairs of tasks that pingpong back and forth. + // Create pairs of threads that pingpong back and forth. fn run_pair(n: usize) { // Create a channel: A->B let (atx, arx) = channel(); diff --git a/src/test/bench/rt-parfib.rs b/src/test/bench/rt-parfib.rs index d420023cf0059..2c5c0ea27c760 100644 --- a/src/test/bench/rt-parfib.rs +++ b/src/test/bench/rt-parfib.rs @@ -13,7 +13,7 @@ use std::env; use std::thread; // A simple implementation of parfib. One subtree is found in a new -// task and communicated over a oneshot pipe, the other is found +// thread and communicated over a oneshot pipe, the other is found // locally. There is no sequential-mode threshold. fn parfib(n: u64) -> u64 { diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 17e8f88c5689d..365a86464e2d3 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -11,7 +11,7 @@ // ignore-android: FIXME(#10393) hangs without output // ignore-pretty very bad with line comments -// multi tasking k-nucleotide +// multi threading k-nucleotide use std::ascii::AsciiExt; use std::cmp::Ordering::{self, Less, Greater, Equal}; diff --git a/src/test/bench/task-perf-jargon-metal-smoke.rs b/src/test/bench/task-perf-jargon-metal-smoke.rs index 4798e317ac840..6e3db3d01960e 100644 --- a/src/test/bench/task-perf-jargon-metal-smoke.rs +++ b/src/test/bench/task-perf-jargon-metal-smoke.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test performance of a task "spawn ladder", in which children task have -// many ancestor taskgroups, but with only a few such groups alive at a time. -// Each child task has to enlist as a descendant in each of its ancestor +// Test performance of a thread "spawn ladder", in which children thread have +// many ancestor threadgroups, but with only a few such groups alive at a time. +// Each child thread has to enlist as a descendant in each of its ancestor // groups, but that shouldn't have to happen for already-dead groups. // // The filename is a song reference; google it in quotes. @@ -23,7 +23,7 @@ use std::thread; fn child_generation(gens_left: usize, tx: Sender<()>) { // This used to be O(n^2) in the number of generations that ever existed. - // With this code, only as many generations are alive at a time as tasks + // With this code, only as many generations are alive at a time as threads // alive at a time, thread::spawn(move|| { if gens_left & 1 == 1 { diff --git a/src/test/compile-fail/dropck_trait_cycle_checked.rs b/src/test/compile-fail/dropck_trait_cycle_checked.rs new file mode 100644 index 0000000000000..6e543d017f260 --- /dev/null +++ b/src/test/compile-fail/dropck_trait_cycle_checked.rs @@ -0,0 +1,131 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Reject mixing cyclic structure and Drop when using trait +// objects to hide the the cross-references. +// +// (Compare against compile-fail/dropck_vec_cycle_checked.rs) + +use std::cell::Cell; +use id::Id; + +mod s { + use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; + + static S_COUNT: AtomicUsize = ATOMIC_USIZE_INIT; + + pub fn next_count() -> usize { + S_COUNT.fetch_add(1, Ordering::SeqCst) + 1 + } +} + +mod id { + use s; + #[derive(Debug)] + pub struct Id { + orig_count: usize, + count: usize, + } + + impl Id { + pub fn new() -> Id { + let c = s::next_count(); + println!("building Id {}", c); + Id { orig_count: c, count: c } + } + pub fn count(&self) -> usize { + println!("Id::count on {} returns {}", self.orig_count, self.count); + self.count + } + } + + impl Drop for Id { + fn drop(&mut self) { + println!("dropping Id {}", self.count); + self.count = 0; + } + } +} + +trait HasId { + fn count(&self) -> usize; +} + +#[derive(Debug)] +struct CheckId { + v: T +} + +#[allow(non_snake_case)] +fn CheckId(t: T) -> CheckId { CheckId{ v: t } } + +impl Drop for CheckId { + fn drop(&mut self) { + assert!(self.v.count() > 0); + } +} + +trait Obj<'a> : HasId { + fn set0(&self, b: &'a Box>); + fn set1(&self, b: &'a Box>); +} + +struct O<'a> { + id: Id, + obj0: CheckId>>>>, + obj1: CheckId>>>>, +} + +impl<'a> HasId for O<'a> { + fn count(&self) -> usize { self.id.count() } +} + +impl<'a> O<'a> { + fn new() -> Box> { + Box::new(O { + id: Id::new(), + obj0: CheckId(Cell::new(None)), + obj1: CheckId(Cell::new(None)), + }) + } +} + +impl<'a> HasId for Cell>>> { + fn count(&self) -> usize { + match self.get() { + None => 1, + Some(c) => c.count(), + } + } +} + +impl<'a> Obj<'a> for O<'a> { + fn set0(&self, b: &'a Box>) { + self.obj0.v.set(Some(b)) + } + fn set1(&self, b: &'a Box>) { + self.obj1.v.set(Some(b)) + } +} + + +fn f() { + let (o1, o2, o3): (Box, Box, Box) = (O::new(), O::new(), O::new()); + o1.set0(&o2); //~ ERROR `o2` does not live long enough + o1.set1(&o3); //~ ERROR `o3` does not live long enough + o2.set0(&o2); //~ ERROR `o2` does not live long enough + o2.set1(&o3); //~ ERROR `o3` does not live long enough + o3.set0(&o1); //~ ERROR `o1` does not live long enough + o3.set1(&o2); //~ ERROR `o2` does not live long enough +} + +fn main() { + f(); +} diff --git a/src/test/auxiliary/crateresolve4a-2.rs b/src/test/compile-fail/invalid_crate_type_syntax.rs similarity index 69% rename from src/test/auxiliary/crateresolve4a-2.rs rename to src/test/compile-fail/invalid_crate_type_syntax.rs index 7da96e07b3f05..6d42515704ea1 100644 --- a/src/test/auxiliary/crateresolve4a-2.rs +++ b/src/test/compile-fail/invalid_crate_type_syntax.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![crate_name="crateresolve4a#0.2"] -#![crate_type = "lib"] +// regression test for issue 16974 +#![crate_type(lib)] //~ ERROR `crate_type` requires a value -pub fn g() -> isize { 20 } +fn my_lib_fn() {} diff --git a/src/test/compile-fail/issue-25199.rs b/src/test/compile-fail/issue-25199.rs new file mode 100644 index 0000000000000..74ea1ca2947f2 --- /dev/null +++ b/src/test/compile-fail/issue-25199.rs @@ -0,0 +1,83 @@ +// Copyright 2015 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Regression test for Issue 25199: Check that one cannot hide a +// destructor's access to borrowed data behind a boxed trait object. +// +// Prior to fixing Issue 25199, this example was able to be compiled +// with rustc, and thus when you ran it, you would see the `Drop` impl +// for `Test` accessing state that had already been dropping (which is +// marked explicitly here with checking code within the `Drop` impl +// for `VecHolder`, but in the general case could just do unsound +// things like accessing memory that has been freed). +// +// Note that I would have liked to encode my go-to example of cyclic +// structure that accesses its neighbors in drop (and thus is +// fundamentally unsound) via this trick, but the closest I was able +// to come was dropck_trait_cycle_checked.rs, which is not quite as +// "good" as this regression test because the encoding of that example +// was forced to attach a lifetime to the trait definition itself +// (`trait Obj<'a>`) while *this* example is solely + +use std::cell::RefCell; + +trait Obj { } + +struct VecHolder { + v: Vec<(bool, &'static str)>, +} + +impl Drop for VecHolder { + fn drop(&mut self) { + println!("Dropping Vec"); + self.v[30].0 = false; + self.v[30].1 = "invalid access: VecHolder dropped already"; + } +} + +struct Container<'a> { + v: VecHolder, + d: RefCell>>, +} + +impl<'a> Container<'a> { + fn new() -> Container<'a> { + Container { + d: RefCell::new(Vec::new()), + v: VecHolder { + v: vec![(true, "valid"); 100] + } + } + } + + fn store(&'a self, val: T) { + self.d.borrow_mut().push(Box::new(val)); + } +} + +struct Test<'a> { + test: &'a Container<'a>, +} + +impl<'a> Obj for Test<'a> { } +impl<'a> Drop for Test<'a> { + fn drop(&mut self) { + for e in &self.test.v.v { + assert!(e.0, e.1); + } + } +} + +fn main() { + let container = Container::new(); + let test = Test{test: &container}; //~ ERROR `container` does not live long enough + println!("container.v[30]: {:?}", container.v.v[30]); + container.store(test); //~ ERROR `container` does not live long enough +} diff --git a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs index 7398e6f1089bc..f73b06653012a 100644 --- a/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs +++ b/src/test/compile-fail/unboxed-closures-failed-recursive-fn-1.rs @@ -22,12 +22,24 @@ fn a() { let mut factorial: Option u32>> = None; let f = |x: u32| -> u32 { + //~^ ERROR `factorial` does not live long enough + let g = factorial.as_ref().unwrap(); + if x == 0 {1} else {x * g(x-1)} + }; + + factorial = Some(Box::new(f)); +} + +fn b() { + let mut factorial: Option u32 + 'static>> = None; + + let f = |x: u32| -> u32 { + //~^ ERROR closure may outlive the current function, but it borrows `factorial` let g = factorial.as_ref().unwrap(); if x == 0 {1} else {x * g(x-1)} }; factorial = Some(Box::new(f)); - //~^ ERROR cannot assign to `factorial` because it is borrowed } fn main() { } diff --git a/src/test/run-fail/issue-2061.rs b/src/test/run-fail/issue-2061.rs index 7213d3ef7c5f0..252ac9bcac0d5 100644 --- a/src/test/run-fail/issue-2061.rs +++ b/src/test/run-fail/issue-2061.rs @@ -9,7 +9,7 @@ // except according to those terms. // ignore-test -// error-pattern: task '
' has overflowed its stack +// error-pattern: thread '
' has overflowed its stack struct R { b: isize, diff --git a/src/test/run-fail/rt-set-exit-status.rs b/src/test/run-fail/rt-set-exit-status.rs index c33a8d2d03227..f5da020181546 100644 --- a/src/test/run-fail/rt-set-exit-status.rs +++ b/src/test/run-fail/rt-set-exit-status.rs @@ -17,7 +17,7 @@ use std::env; fn main() { error!("whatever"); - // 101 is the code the runtime uses on task panic and the value + // 101 is the code the runtime uses on thread panic and the value // compiletest expects run-fail tests to return. env::set_exit_status(101); } diff --git a/src/test/run-fail/task-spawn-barefn.rs b/src/test/run-fail/task-spawn-barefn.rs index 406f7dbcb67fe..ede055acd61ff 100644 --- a/src/test/run-fail/task-spawn-barefn.rs +++ b/src/test/run-fail/task-spawn-barefn.rs @@ -8,12 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:Ensure that the child task runs by panicking +// error-pattern:Ensure that the child thread runs by panicking use std::thread; fn main() { - // the purpose of this test is to make sure that task::spawn() + // the purpose of this test is to make sure that thread::spawn() // works when provided with a bare function: let r = thread::spawn(startfn).join(); if r.is_err() { @@ -22,5 +22,5 @@ fn main() { } fn startfn() { - assert!("Ensure that the child task runs by panicking".is_empty()); + assert!("Ensure that the child thread runs by panicking".is_empty()); } diff --git a/src/test/run-fail/too-much-recursion-unwinding.rs b/src/test/run-fail/too-much-recursion-unwinding.rs index 2ec670c3306db..6e5a9b2f2ac02 100644 --- a/src/test/run-fail/too-much-recursion-unwinding.rs +++ b/src/test/run-fail/too-much-recursion-unwinding.rs @@ -11,7 +11,7 @@ // ignore-test leaks // error-pattern:ran out of stack -// Test that the task panicks after hitting the recursion limit +// Test that the thread panicks after hitting the recursion limit // during unwinding fn recurse() { diff --git a/src/test/run-pass/extern-call-deep2.rs b/src/test/run-pass/extern-call-deep2.rs index b35095171ece0..252086ad014da 100644 --- a/src/test/run-pass/extern-call-deep2.rs +++ b/src/test/run-pass/extern-call-deep2.rs @@ -40,7 +40,7 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { } pub fn main() { - // Make sure we're on a task with small Rust stacks (main currently + // Make sure we're on a thread with small Rust stacks (main currently // has a large stack) thread::spawn(move|| { let result = count(1000); diff --git a/src/test/run-pass/extern-call-scrub.rs b/src/test/run-pass/extern-call-scrub.rs index 3993868068197..9a39b1773e533 100644 --- a/src/test/run-pass/extern-call-scrub.rs +++ b/src/test/run-pass/extern-call-scrub.rs @@ -44,7 +44,7 @@ fn count(n: libc::uintptr_t) -> libc::uintptr_t { } pub fn main() { - // Make sure we're on a task with small Rust stacks (main currently + // Make sure we're on a thread with small Rust stacks (main currently // has a large stack) thread::spawn(move|| { let result = count(12); diff --git a/src/test/run-pass/foreign-dupe.rs b/src/test/run-pass/foreign-dupe.rs index fd779d665071d..11de5ac70f4fe 100644 --- a/src/test/run-pass/foreign-dupe.rs +++ b/src/test/run-pass/foreign-dupe.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// calling pin_task and that's having weird side-effects. +// calling pin_thread and that's having weird side-effects. // pretty-expanded FIXME #23616 diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 5c96aaf4bd890..4dae1131c6d91 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -68,7 +68,7 @@ mod map_reduce { pub fn map_reduce(inputs: Vec) { let (tx, rx) = channel(); - // This task becomes the master control task. It spawns others + // This thread becomes the master control thread. It spawns others // to do the rest. let mut reducers: HashMap; diff --git a/src/test/run-pass/issue-11205.rs b/src/test/run-pass/issue-11205.rs index 41b54727b662f..679d494a47302 100644 --- a/src/test/run-pass/issue-11205.rs +++ b/src/test/run-pass/issue-11205.rs @@ -21,7 +21,7 @@ fn foos(_: &[&Foo]) {} fn foog(_: &[T], _: &[T]) {} fn bar(_: [Box; 2]) {} -fn bars(_: &[Box]) {} +fn bars(_: &[Box]) {} fn main() { let x: [&Foo; 2] = [&1, &2]; @@ -45,11 +45,11 @@ fn main() { bar(x); bar([Box::new(1), Box::new(2)]); - let x: &[Box] = &[Box::new(1), Box::new(2)]; + let x: &[Box] = &[Box::new(1), Box::new(2)]; bars(x); bars(&[Box::new(1), Box::new(2)]); - let x: &[Box] = &[Box::new(1), Box::new(2)]; + let x: &[Box] = &[Box::new(1), Box::new(2)]; foog(x, &[Box::new(1)]); struct T<'a> { diff --git a/src/test/run-pass/task-comm-12.rs b/src/test/run-pass/task-comm-12.rs index f8d608d31689c..a3dfa361cecd6 100644 --- a/src/test/run-pass/task-comm-12.rs +++ b/src/test/run-pass/task-comm-12.rs @@ -22,14 +22,14 @@ fn test00() { start(i) }); - // Sleep long enough for the task to finish. + // Sleep long enough for the thread to finish. let mut i = 0_usize; while i < 10000 { thread::yield_now(); i += 1; } - // Try joining tasks that have already finished. + // Try joining threads that have already finished. result.join(); println!("Joined task."); diff --git a/src/test/run-pass/task-comm-14.rs b/src/test/run-pass/task-comm-14.rs index 0048d7d2d7321..90f68deb303e8 100644 --- a/src/test/run-pass/task-comm-14.rs +++ b/src/test/run-pass/task-comm-14.rs @@ -16,7 +16,7 @@ use std::thread; pub fn main() { let (tx, rx) = channel(); - // Spawn 10 tasks each sending us back one isize. + // Spawn 10 threads each sending us back one isize. let mut i = 10; while (i > 0) { println!("{}", i); @@ -25,7 +25,7 @@ pub fn main() { i = i - 1; } - // Spawned tasks are likely killed before they get a chance to send + // Spawned threads are likely killed before they get a chance to send // anything back, so we deadlock here. i = 10; diff --git a/src/test/run-pass/task-comm-15.rs b/src/test/run-pass/task-comm-15.rs index 1d853b3e67ffc..2994b9c538490 100644 --- a/src/test/run-pass/task-comm-15.rs +++ b/src/test/run-pass/task-comm-15.rs @@ -24,7 +24,7 @@ fn start(tx: &Sender, i0: isize) { } pub fn main() { - // Spawn a task that sends us back messages. The parent task + // Spawn a thread that sends us back messages. The parent thread // is likely to terminate before the child completes, so from // the child's point of view the receiver may die. We should // drop messages on the floor in this case, and not crash! diff --git a/src/test/run-pass/task-comm-3.rs b/src/test/run-pass/task-comm-3.rs index 25f40757b7b8a..890107998ccb7 100644 --- a/src/test/run-pass/task-comm-3.rs +++ b/src/test/run-pass/task-comm-3.rs @@ -38,7 +38,7 @@ fn test00() { let mut i: isize = 0; - // Create and spawn tasks... + // Create and spawn threads... let mut results = Vec::new(); while i < number_of_tasks { let tx = tx.clone(); @@ -51,7 +51,7 @@ fn test00() { i = i + 1; } - // Read from spawned tasks... + // Read from spawned threads... let mut sum = 0; for _r in &results { i = 0; @@ -62,12 +62,12 @@ fn test00() { } } - // Join spawned tasks... + // Join spawned threads... for r in results { r.join(); } println!("Completed: Final number is: "); println!("{}", sum); - // assert (sum == (((number_of_tasks * (number_of_tasks - 1)) / 2) * + // assert (sum == (((number_of_threads * (number_of_threads - 1)) / 2) * // number_of_messages)); assert_eq!(sum, 480); } diff --git a/src/test/run-pass/trait-bounds-in-arc.rs b/src/test/run-pass/trait-bounds-in-arc.rs index 21205a2d7fa59..250ed58a8ef4c 100644 --- a/src/test/run-pass/trait-bounds-in-arc.rs +++ b/src/test/run-pass/trait-bounds-in-arc.rs @@ -9,7 +9,7 @@ // except according to those terms. // Tests that a heterogeneous list of existential types can be put inside an Arc -// and shared between tasks as long as all types fulfill Send. +// and shared between threads as long as all types fulfill Send. // ignore-pretty