lexical_parse_float/
lib.rs

1//! Fast lexical string-to-float conversion routines.
2//!
3//! The default implementations are highly optimized both for simple
4//! strings, as well as input with large numbers of digits. In order to
5//! keep performance optimal for simple strings, we avoid overly branching
6//! to minimize the number of branches (and therefore optimization checks).
7//! Most of the branches in the code are resolved at compile-time, and
8//! the resulting ASM as well as comprehensive benchmarks are monitored
9//! to ensure there are no regressions.
10//!
11//! For simple floats, we use an optimized digit parser with multiple-digit
12//! optimizations (parsing 8 digits in 3 multiplication instructions),
13//! and then use machine floats to create an exact representation with
14//! high throughput. In more complex cases, we use the Eisel-Lemire
15//! algorithm, described in "Number Parsing at a Gigabyte per Second",
16//! available online [here](https://arxiv.org/abs/2101.11408). The
17//! Eisel-Lemire algorithm creates an extended representation using a
18//! 128-bit (or a fallback 192-bit representation) of the significant
19//! digits of the float, scaled to the proper exponent using pre-computed
20//! powers-of-5.
21//!
22//! If the Eisel-Lemire algorithm is unable to unambiguously round the float,
23//! we fallback to using optimized, big-integer algorithms, which are
24//! described in [Algorithm Approach](#algorithm-approach) below.
25//!
26//! # Features
27//!
28//! * `std` - Use the standard library.
29//! * `power-of-two` - Add support for parsing power-of-two integer strings.
30//! * `radix` - Add support for strings of any radix.
31//! * `format` - Add support for parsing custom integer formats.
32//! * `compact` - Reduce code size at the cost of performance.
33//!
34//! # Note
35//!
36//! Only documented functionality is considered part of the public API:
37//! any of the modules, internal functions, or structs may change
38//! release-to-release without major or minor version changes. Use
39//! internal implementation details at your own risk.
40//!
41//! lexical-parse-float mainly exists as an implementation detail for
42//! lexical-core, although its API is stable. If you would like to use
43//! a high-level API that writes to and parses from `String` and `&str`,
44//! respectively, please look at [lexical](https://crates.io/crates/lexical)
45//! instead. If you would like an API that supports multiple numeric
46//! conversions, please look at [lexical-core](https://crates.io/crates/lexical-core)
47//! instead.
48//!
49//! # Machine Float-Only Algorithm
50//!
51//! We also support an algorithm that uses only machine floats for the
52//! fast-path algorithm, however, this may be slower for floats with large
53//! exponents since it uses an iterative algorithm. A code sample
54//! using this is:
55//!
56//! ```rust
57//! use lexical_parse_float::Options;
58//! use lexical_parse_float::format::STANDARD;
59//! use lexical_parse_float::parse::ParseFloat;
60//!
61//! let options = Options::new();
62//! let result = f64::fast_path_complete::<{ STANDARD }>(b"1.34000", &options);
63//! assert_eq!(result, Ok(1.34000));
64//! ```
65//!
66//! # Version Support
67//!
68//! The minimum, standard, required version is 1.63.0, for const generic
69//! support. Older versions of lexical support older Rust versions.
70//!
71//! # Safety
72//!
73//! The primary use of unsafe code is in the big integer implementation, which
74//! for performance reasons requires unchecked indexing at certain points, where
75//! rust cannot elide the index check. The use of unsafe code can be found in
76//! the calculation of the [hi] bits, however, every invocation requires the
77//! buffer to be of sufficient [length][longbits]. The other major source is the
78//! implementation of methods such as [push_unchecked], however, the safety
79//! invariants for each caller to create a safe API are documented and has
80//! similar safety guarantees to a regular vector. All other invocations of
81//! unsafe code are indexing a buffer where the index is proven to be within
82//! bounds within a few lines of code of the unsafe index.
83//!
84//! # Design
85//!
86//! - [Algorithm Approach](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/Algorithm.md)
87//! - [Benchmarks](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/Benchmarks.md)
88//! - [Comprehensive Benchmarks](https://github.com/Alexhuszagh/lexical-benchmarks)
89//! - [Big Integer Implementation](https://github.com/Alexhuszagh/rust-lexical/blob/main/lexical-parse-float/docs/BigInteger.md)
90//!
91//! [hi]: <https://github.com/Alexhuszagh/rust-lexical/blob/15d4c8c92d70b1fb9bd6d33f582ffe27e0e74f99/lexical-parse-float/src/bigint.rs#L266>
92//! [longbits]: <https://github.com/Alexhuszagh/rust-lexical/blob/15d4c8c92d70b1fb9bd6d33f582ffe27e0e74f99/lexical-parse-float/src/bigint.rs#L550-L557>
93//! [push_unchecked]: <https://github.com/Alexhuszagh/rust-lexical/blob/15d4c8c92d70b1fb9bd6d33f582ffe27e0e74f99/lexical-parse-float/src/bigint.rs#L377-L386>
94
95// FIXME: Implement clippy/allow reasons once we drop support for 1.80.0 and below
96// Clippy reasons were stabilized in 1.81.0.
97
98// We want to have the same safety guarantees as Rust core,
99// so we allow unused unsafe to clearly document safety guarantees.
100#![allow(unused_unsafe)]
101#![cfg_attr(feature = "lint", warn(unsafe_op_in_unsafe_fn))]
102#![cfg_attr(not(feature = "std"), no_std)]
103#![deny(
104    clippy::doc_markdown,
105    clippy::unnecessary_safety_comment,
106    clippy::semicolon_if_nothing_returned,
107    clippy::unwrap_used,
108    clippy::as_underscore,
109    clippy::doc_markdown
110)]
111#![allow(
112    // used when concepts are logically separate
113    clippy::match_same_arms,
114    // loss of precision is intentional
115    clippy::integer_division,
116    // mathematical names use 1-character identifiers
117    clippy::min_ident_chars,
118    // these are not cryptographically secure contexts
119    clippy::integer_division_remainder_used,
120    // this can be intentional
121    clippy::module_name_repetitions,
122    // this is intentional: already passing a pointer and need performance
123    clippy::needless_pass_by_value,
124    // we use this for inline formatting for unsafe blocks
125    clippy::semicolon_inside_block,
126)]
127
128#[macro_use]
129pub mod shared;
130
131pub mod bellerophon;
132pub mod bigint;
133pub mod binary;
134pub mod float;
135pub mod fpu;
136pub mod lemire;
137pub mod libm;
138pub mod limits;
139pub mod mask;
140pub mod number;
141pub mod options;
142pub mod parse;
143pub mod slow;
144pub mod table;
145
146mod api;
147mod table_bellerophon_decimal;
148mod table_bellerophon_radix;
149mod table_binary;
150mod table_decimal;
151mod table_large;
152mod table_lemire;
153mod table_radix;
154mod table_small;
155
156#[macro_use(parse_sign)]
157extern crate lexical_parse_integer;
158
159// Re-exports
160#[cfg(feature = "f16")]
161pub use lexical_util::bf16::bf16;
162pub use lexical_util::error::Error;
163#[cfg(feature = "f16")]
164pub use lexical_util::f16::f16;
165pub use lexical_util::format::{self, NumberFormatBuilder};
166pub use lexical_util::options::ParseOptions;
167pub use lexical_util::result::Result;
168
169pub use self::api::{FromLexical, FromLexicalWithOptions};
170#[doc(inline)]
171pub use self::options::{Options, OptionsBuilder};