Merge pull request #25 from paritytech/chore/pick-changes-from-bigint
Port over relevant changes from bigint
This commit is contained in:
commit
22209e1480
|
@ -8,6 +8,6 @@ matrix:
|
|||
script:
|
||||
- cargo build
|
||||
- cargo test --all --exclude uint
|
||||
- cd uint/ && cargo test --features=std,impl_quickcheck_arbitrary && cd ..
|
||||
- cd uint/ && cargo test --features=std,impl_quickcheck_arbitrary --release && cd ..
|
||||
- cd hashdb/ && cargo test --no-default-features && cd ..
|
||||
- cd plain_hasher/ && cargo test --no-default-features && cd ..
|
||||
|
|
|
@ -1,30 +1,26 @@
|
|||
[package]
|
||||
description = "Large fixed-size integers arithmetics"
|
||||
homepage = "http://parity.io"
|
||||
repository = "https://github.com/paritytech/primitives"
|
||||
repository = "https://github.com/paritytech/parity-common"
|
||||
license = "MIT/Apache-2.0"
|
||||
name = "uint"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
[build-dependencies]
|
||||
rustc_version = "0.2"
|
||||
|
||||
[dependencies]
|
||||
byteorder = { version = "1", default-features = false }
|
||||
heapsize = { version = "0.4.2", optional = true }
|
||||
rustc-hex = { version = "1.0", optional = true }
|
||||
rustc-hex = { version = "2.0", default-features = false }
|
||||
quickcheck = { version = "0.6", optional = true }
|
||||
crunchy = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
crunchy = "0.1.5"
|
||||
quickcheck = "0.6"
|
||||
rustc-hex = "2.0"
|
||||
|
||||
[features]
|
||||
std = ["rustc-hex", "byteorder/std"]
|
||||
std = ["byteorder/std", "rustc-hex/std"]
|
||||
heapsizeof = ["heapsize"]
|
||||
use_asm = []
|
||||
impl_quickcheck_arbitrary = ["quickcheck"]
|
||||
|
||||
[[example]]
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
# Big unsigned integer types
|
||||
|
||||
Implementation of a various large-but-fixed sized unsigned integer types.
|
||||
The functions here are designed to be fast. There are optional `x86_64`
|
||||
implementations for even more speed, hidden behind the `x64_arithmetic`
|
||||
feature flag.
|
||||
The functions here are designed to be fast.
|
||||
|
||||
The crate exports two commonly used types: `U256` and `U512`. Other sizes can be constructed with `construct_uint!(NAME, SIZE_IN_WORDS)`, e.g. `construct_uint!(U128, 2);`.
|
||||
|
||||
Run tests with `cargo test --features=std,impl_quickcheck_arbitrary`.
|
|
@ -0,0 +1,230 @@
|
|||
// Copyright 2015-2017 Parity Technologies
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! benchmarking for bigint
|
||||
//! should be started with:
|
||||
//! ```bash
|
||||
//! rustup run nightly cargo bench
|
||||
//! ```
|
||||
|
||||
#![feature(test)]
|
||||
|
||||
extern crate core;
|
||||
extern crate test;
|
||||
#[macro_use]
|
||||
extern crate crunchy;
|
||||
#[macro_use]
|
||||
extern crate uint;
|
||||
construct_uint!(U128, 2);
|
||||
construct_uint!(U256, 4);
|
||||
construct_uint!(U512, 8);
|
||||
|
||||
use test::{Bencher, black_box};
|
||||
|
||||
impl U256 {
|
||||
/// Multiplies two 256-bit integers to produce full 512-bit integer
|
||||
/// No overflow possible
|
||||
#[inline(always)]
|
||||
pub fn full_mul(self, other: U256) -> U512 {
|
||||
U512(uint_full_mul_reg!(U256, 4, self, other))
|
||||
}
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u256_add(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let n = black_box(10000);
|
||||
let zero = black_box(U256::zero());
|
||||
(0..n).fold(zero, |old, new| {
|
||||
old.overflowing_add(U256::from(black_box(new))).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u256_sub(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let n = black_box(10000);
|
||||
let max = black_box(U256::max_value());
|
||||
(0..n).fold(max, |old, new| {
|
||||
old.overflowing_sub(U256::from(black_box(new))).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u512_sub(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let n = black_box(10000);
|
||||
let max = black_box(U512::max_value());
|
||||
(0..n).fold(max, |old, new| {
|
||||
let new = black_box(new);
|
||||
let p = new % 2;
|
||||
old.overflowing_sub(U512([p, p, p, p, p, p, p, new])).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u512_add(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let n = black_box(10000);
|
||||
let zero = black_box(U512::zero());
|
||||
(0..n).fold(zero, |old, new| {
|
||||
let new = black_box(new);
|
||||
old.overflowing_add(U512([new, new, new, new, new, new, new, new]))
|
||||
.0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u512_mul(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
(1..10000).fold(black_box(U512::one()), |old, new| {
|
||||
old.overflowing_mul(U512::from(black_box(new | 1))).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u512_mul_small(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
(1..153).fold(black_box(U512::one()), |old, _| {
|
||||
old.overflowing_mul(U512::from(black_box(10))).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u256_mul(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
(1..10000).fold(black_box(U256::one()), |old, new| {
|
||||
old.overflowing_mul(U256::from(black_box(new | 1))).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u256_mul_small(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
(1..77).fold(black_box(U256::one()), |old, _| {
|
||||
old.overflowing_mul(U256::from(black_box(10))).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u256_full_mul(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let n = black_box(10000);
|
||||
let one = black_box(U256::one());
|
||||
(1..n).map(|n| n | 1).fold(one, |old, new| {
|
||||
let new = black_box(new);
|
||||
let U512(ref u512words) = old.full_mul(U256([new, new, new, new]));
|
||||
U256([u512words[0], u512words[2], u512words[2], u512words[3]])
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#[bench]
|
||||
fn u128_mul(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let n = black_box(10000);
|
||||
(1..n).fold(U128([12345u64, 0u64]), |old, new| {
|
||||
old.overflowing_mul(U128::from(new | 1)).0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u256_from_le(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let raw = black_box(
|
||||
[
|
||||
1u8,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
11,
|
||||
13,
|
||||
17,
|
||||
19,
|
||||
23,
|
||||
29,
|
||||
31,
|
||||
37,
|
||||
41,
|
||||
43,
|
||||
47,
|
||||
53,
|
||||
59,
|
||||
61,
|
||||
67,
|
||||
71,
|
||||
73,
|
||||
79,
|
||||
83,
|
||||
89,
|
||||
97,
|
||||
101,
|
||||
103,
|
||||
107,
|
||||
109,
|
||||
113,
|
||||
127,
|
||||
],
|
||||
);
|
||||
let _ = U256::from_little_endian(&raw[..]);
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn u256_from_be(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let raw = black_box(
|
||||
[
|
||||
1u8,
|
||||
2,
|
||||
3,
|
||||
5,
|
||||
7,
|
||||
11,
|
||||
13,
|
||||
17,
|
||||
19,
|
||||
23,
|
||||
29,
|
||||
31,
|
||||
37,
|
||||
41,
|
||||
43,
|
||||
47,
|
||||
53,
|
||||
59,
|
||||
61,
|
||||
67,
|
||||
71,
|
||||
73,
|
||||
79,
|
||||
83,
|
||||
89,
|
||||
97,
|
||||
101,
|
||||
103,
|
||||
107,
|
||||
109,
|
||||
113,
|
||||
127,
|
||||
],
|
||||
);
|
||||
let _ = U256::from_big_endian(&raw[..]);
|
||||
});
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright 2015-2017 Parity Technologies
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate rustc_version;
|
||||
|
||||
use rustc_version::{version_meta, Channel};
|
||||
|
||||
fn main() {
|
||||
if cfg!(feature = "use_asm") {
|
||||
if let Channel::Nightly = version_meta().unwrap().channel {
|
||||
println!("cargo:rustc-cfg=asm_available");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
//! Efficient large, fixed-size big integers and hashes.
|
||||
|
||||
#![cfg_attr(asm_available, feature(asm))]
|
||||
#![cfg_attr(not(feature="std"), no_std)]
|
||||
#![cfg_attr(all(not(feature="std"), test), feature(alloc))]
|
||||
|
||||
#[doc(hidden)]
|
||||
pub extern crate byteorder;
|
||||
|
@ -22,7 +22,6 @@ pub extern crate heapsize;
|
|||
#[doc(hidden)]
|
||||
pub extern crate core;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[doc(hidden)]
|
||||
pub extern crate rustc_hex;
|
||||
|
||||
|
@ -30,5 +29,11 @@ pub extern crate rustc_hex;
|
|||
#[doc(hidden)]
|
||||
pub extern crate quickcheck;
|
||||
|
||||
#[cfg(all(not(feature = "std"), test))]
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
extern crate crunchy;
|
||||
|
||||
mod uint;
|
||||
pub use uint::*;
|
||||
|
|
378
uint/src/uint.rs
378
uint/src/uint.rs
|
@ -50,7 +50,6 @@ macro_rules! impl_map_from {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(all(asm_available, target_arch="x86_64")))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! uint_overflowing_add {
|
||||
|
@ -73,85 +72,6 @@ macro_rules! uint_overflowing_add_reg {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(all(asm_available, target_arch="x86_64"))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! uint_overflowing_add {
|
||||
(U256, $n_words: tt, $self_expr: expr, $other: expr) => ({
|
||||
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
|
||||
let self_t: &[u64; $n_words] = &$self_expr.0;
|
||||
let other_t: &[u64; $n_words] = &$other.0;
|
||||
|
||||
let overflow: u8;
|
||||
unsafe {
|
||||
asm!("
|
||||
add $9, $0
|
||||
adc $10, $1
|
||||
adc $11, $2
|
||||
adc $12, $3
|
||||
setc %al
|
||||
"
|
||||
: "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow)
|
||||
: "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]),
|
||||
"mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3])
|
||||
:
|
||||
:
|
||||
);
|
||||
}
|
||||
(U256(result), overflow != 0)
|
||||
});
|
||||
(U512, $n_words: tt, $self_expr: expr, $other: expr) => ({
|
||||
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
|
||||
let self_t: &[u64; $n_words] = &$self_expr.0;
|
||||
let other_t: &[u64; $n_words] = &$other.0;
|
||||
|
||||
let overflow: u8;
|
||||
|
||||
unsafe {
|
||||
asm!("
|
||||
add $15, $0
|
||||
adc $16, $1
|
||||
adc $17, $2
|
||||
adc $18, $3
|
||||
lodsq
|
||||
adc $11, %rax
|
||||
stosq
|
||||
lodsq
|
||||
adc $12, %rax
|
||||
stosq
|
||||
lodsq
|
||||
adc $13, %rax
|
||||
stosq
|
||||
lodsq
|
||||
adc $14, %rax
|
||||
stosq
|
||||
setc %al
|
||||
|
||||
": "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]),
|
||||
|
||||
"={al}"(overflow) /* $0 - $4 */
|
||||
|
||||
: "{rdi}"(&result[4] as *const u64) /* $5 */
|
||||
"{rsi}"(&other_t[4] as *const u64) /* $6 */
|
||||
"0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]),
|
||||
"m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]),
|
||||
/* $7 - $14 */
|
||||
|
||||
"mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3]),
|
||||
"m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */
|
||||
: "rdi", "rsi"
|
||||
:
|
||||
);
|
||||
}
|
||||
(U512(result), overflow != 0)
|
||||
});
|
||||
|
||||
($name:ident, $n_words: tt, $self_expr: expr, $other: expr) => (
|
||||
uint_overflowing_add_reg!($name, $n_words, $self_expr, $other)
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(all(asm_available, target_arch="x86_64")))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! uint_overflowing_sub {
|
||||
|
@ -219,204 +139,6 @@ macro_rules! uint_overflowing_sub_reg {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(all(asm_available, target_arch="x86_64"))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! uint_overflowing_sub {
|
||||
(U256, $n_words: tt, $self_expr: expr, $other: expr) => ({
|
||||
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
|
||||
let self_t: &[u64; $n_words] = &$self_expr.0;
|
||||
let other_t: &[u64; $n_words] = &$other.0;
|
||||
|
||||
let overflow: u8;
|
||||
unsafe {
|
||||
asm!("
|
||||
sub $9, $0
|
||||
sbb $10, $1
|
||||
sbb $11, $2
|
||||
sbb $12, $3
|
||||
setb %al
|
||||
"
|
||||
: "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]), "={al}"(overflow)
|
||||
: "0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]), "mr"(other_t[0]), "mr"(other_t[1]), "mr"(other_t[2]), "mr"(other_t[3])
|
||||
:
|
||||
:
|
||||
);
|
||||
}
|
||||
(U256(result), overflow != 0)
|
||||
});
|
||||
(U512, $n_words: tt, $self_expr: expr, $other: expr) => ({
|
||||
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
|
||||
let self_t: &[u64; $n_words] = &$self_expr.0;
|
||||
let other_t: &[u64; $n_words] = &$other.0;
|
||||
|
||||
let overflow: u8;
|
||||
|
||||
unsafe {
|
||||
asm!("
|
||||
sub $15, $0
|
||||
sbb $16, $1
|
||||
sbb $17, $2
|
||||
sbb $18, $3
|
||||
lodsq
|
||||
sbb $19, %rax
|
||||
stosq
|
||||
lodsq
|
||||
sbb $20, %rax
|
||||
stosq
|
||||
lodsq
|
||||
sbb $21, %rax
|
||||
stosq
|
||||
lodsq
|
||||
sbb $22, %rax
|
||||
stosq
|
||||
setb %al
|
||||
"
|
||||
: "=r"(result[0]), "=r"(result[1]), "=r"(result[2]), "=r"(result[3]),
|
||||
|
||||
"={al}"(overflow) /* $0 - $4 */
|
||||
|
||||
: "{rdi}"(&result[4] as *const u64) /* $5 */
|
||||
"{rsi}"(&self_t[4] as *const u64) /* $6 */
|
||||
"0"(self_t[0]), "1"(self_t[1]), "2"(self_t[2]), "3"(self_t[3]),
|
||||
"m"(self_t[4]), "m"(self_t[5]), "m"(self_t[6]), "m"(self_t[7]),
|
||||
/* $7 - $14 */
|
||||
|
||||
"m"(other_t[0]), "m"(other_t[1]), "m"(other_t[2]), "m"(other_t[3]),
|
||||
"m"(other_t[4]), "m"(other_t[5]), "m"(other_t[6]), "m"(other_t[7]) /* $15 - $22 */
|
||||
: "rdi", "rsi"
|
||||
:
|
||||
);
|
||||
}
|
||||
(U512(result), overflow != 0)
|
||||
});
|
||||
($name:ident, $n_words: tt, $self_expr: expr, $other: expr) => ({
|
||||
uint_overflowing_sub_reg!($name, $n_words, $self_expr, $other)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(all(asm_available, target_arch="x86_64"))]
|
||||
#[macro_export]
|
||||
macro_rules! uint_overflowing_mul {
|
||||
(U256, $n_words: tt, $self_expr: expr, $other: expr) => ({
|
||||
let mut result: [u64; $n_words] = unsafe { ::core::mem::uninitialized() };
|
||||
let self_t: &[u64; $n_words] = &$self_expr.0;
|
||||
let other_t: &[u64; $n_words] = &$other.0;
|
||||
|
||||
let overflow: u64;
|
||||
unsafe {
|
||||
asm!("
|
||||
mov $5, %rax
|
||||
mulq $9
|
||||
mov %rax, $0
|
||||
mov %rdx, $1
|
||||
|
||||
mov $5, %rax
|
||||
mulq $10
|
||||
add %rax, $1
|
||||
adc $$0, %rdx
|
||||
mov %rdx, $2
|
||||
|
||||
mov $5, %rax
|
||||
mulq $11
|
||||
add %rax, $2
|
||||
adc $$0, %rdx
|
||||
mov %rdx, $3
|
||||
|
||||
mov $5, %rax
|
||||
mulq $12
|
||||
add %rax, $3
|
||||
adc $$0, %rdx
|
||||
mov %rdx, %rcx
|
||||
|
||||
mov $6, %rax
|
||||
mulq $9
|
||||
add %rax, $1
|
||||
adc %rdx, $2
|
||||
adc $$0, $3
|
||||
adc $$0, %rcx
|
||||
|
||||
mov $6, %rax
|
||||
mulq $10
|
||||
add %rax, $2
|
||||
adc %rdx, $3
|
||||
adc $$0, %rcx
|
||||
adc $$0, $3
|
||||
adc $$0, %rcx
|
||||
|
||||
mov $6, %rax
|
||||
mulq $11
|
||||
add %rax, $3
|
||||
adc $$0, %rdx
|
||||
or %rdx, %rcx
|
||||
|
||||
mov $7, %rax
|
||||
mulq $9
|
||||
add %rax, $2
|
||||
adc %rdx, $3
|
||||
adc $$0, %rcx
|
||||
|
||||
mov $7, %rax
|
||||
mulq $10
|
||||
add %rax, $3
|
||||
adc $$0, %rdx
|
||||
or %rdx, %rcx
|
||||
|
||||
mov $8, %rax
|
||||
mulq $9
|
||||
add %rax, $3
|
||||
or %rdx, %rcx
|
||||
|
||||
cmpq $$0, %rcx
|
||||
jne 2f
|
||||
|
||||
mov $8, %rcx
|
||||
jrcxz 12f
|
||||
|
||||
mov $12, %rcx
|
||||
mov $11, %rax
|
||||
or %rax, %rcx
|
||||
mov $10, %rax
|
||||
or %rax, %rcx
|
||||
jmp 2f
|
||||
|
||||
12:
|
||||
mov $12, %rcx
|
||||
jrcxz 11f
|
||||
|
||||
mov $7, %rcx
|
||||
mov $6, %rax
|
||||
or %rax, %rcx
|
||||
|
||||
cmpq $$0, %rcx
|
||||
jne 2f
|
||||
|
||||
11:
|
||||
mov $11, %rcx
|
||||
jrcxz 2f
|
||||
mov $7, %rcx
|
||||
|
||||
2:
|
||||
"
|
||||
: /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]),
|
||||
/* $3 */ "={r11}"(result[3]), /* $4 */ "={rcx}"(overflow)
|
||||
|
||||
: /* $5 */ "m"(self_t[0]), /* $6 */ "m"(self_t[1]), /* $7 */ "m"(self_t[2]),
|
||||
/* $8 */ "m"(self_t[3]), /* $9 */ "m"(other_t[0]), /* $10 */ "m"(other_t[1]),
|
||||
/* $11 */ "m"(other_t[2]), /* $12 */ "m"(other_t[3])
|
||||
: "rax", "rdx"
|
||||
:
|
||||
|
||||
);
|
||||
}
|
||||
(U256(result), overflow > 0)
|
||||
});
|
||||
($name:ident, $n_words: tt, $self_expr: expr, $other: expr) => (
|
||||
uint_overflowing_mul_reg!($name, $n_words, $self_expr, $other)
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(not(all(asm_available, target_arch="x86_64")))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! uint_overflowing_mul {
|
||||
|
@ -428,37 +150,47 @@ macro_rules! uint_overflowing_mul {
|
|||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! uint_full_mul_reg {
|
||||
($name:ident, $n_words: tt, $self_expr:expr, $other:expr) => ({{
|
||||
($name:ident, 8, $self_expr:expr, $other:expr) => {
|
||||
uint_full_mul_reg!($name, 8, $self_expr, $other, |a, b| a != 0 || b != 0);
|
||||
};
|
||||
($name:ident, $n_words:tt, $self_expr:expr, $other:expr) => {
|
||||
uint_full_mul_reg!($name, $n_words, $self_expr, $other, |_, _| true);
|
||||
};
|
||||
($name:ident, $n_words:tt, $self_expr:expr, $other:expr, $check:expr) => ({{
|
||||
#![allow(unused_assignments)]
|
||||
|
||||
let $name(ref me) = $self_expr;
|
||||
let $name(ref you) = $other;
|
||||
let mut ret = [0u64; 2*$n_words];
|
||||
let mut ret = [0u64; $n_words * 2];
|
||||
|
||||
unroll! {
|
||||
for i in 0..$n_words {
|
||||
let mut carry = 0u64;
|
||||
let (b_u, b_l) = $crate::split(you[i]);
|
||||
let b = you[i];
|
||||
|
||||
unroll! {
|
||||
for j in 0..$n_words {
|
||||
if me[j] != 0 || carry != 0 {
|
||||
let a = $crate::split(me[j]);
|
||||
if $check(me[j], carry) {
|
||||
let a = me[j];
|
||||
|
||||
// multiply parts
|
||||
let (c_l, overflow_l) = $crate::mul_u32(a, b_l, ret[i + j]);
|
||||
let (c_u, overflow_u) = $crate::mul_u32(a, b_u, c_l >> 32);
|
||||
ret[i + j] = (c_l & 0xFFFFFFFF) + (c_u << 32);
|
||||
let (hi, low) = $crate::split_u128(a as u128 * b as u128);
|
||||
|
||||
// No overflow here
|
||||
let res = (c_u >> 32) + (overflow_u << 32);
|
||||
// possible overflows
|
||||
let (res, o1) = res.overflowing_add(overflow_l + carry);
|
||||
let (res, o2) = res.overflowing_add(ret[i + j + 1]);
|
||||
ret[i + j + 1] = res;
|
||||
let overflow = {
|
||||
let existing_low = &mut ret[i + j];
|
||||
let (low, o) = low.overflowing_add(*existing_low);
|
||||
*existing_low = low;
|
||||
o
|
||||
};
|
||||
|
||||
// Only single overflow possible there
|
||||
carry = (o1 | o2) as u64;
|
||||
carry = {
|
||||
let existing_hi = &mut ret[i + j + 1];
|
||||
let hi = hi + overflow as u64;
|
||||
let (hi, o0) = hi.overflowing_add(carry);
|
||||
let (hi, o1) = hi.overflowing_add(*existing_hi);
|
||||
*existing_hi = hi;
|
||||
|
||||
(o0 | o1) as u64
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -466,7 +198,7 @@ macro_rules! uint_full_mul_reg {
|
|||
}
|
||||
|
||||
ret
|
||||
}})
|
||||
}});
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
@ -606,12 +338,19 @@ pub fn split(a: u64) -> (u64, u64) {
|
|||
(a >> 32, a & 0xFFFF_FFFF)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[doc(hidden)]
|
||||
pub fn split_u128(a: u128) -> (u64, u64) {
|
||||
((a >> 64) as _, (a & 0xFFFFFFFFFFFFFFFF) as _)
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! construct_uint {
|
||||
($name:ident, $n_words: tt) => (
|
||||
/// Little-endian large integer type
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
// TODO: serialize stuff? #[cfg_attr(feature="serialize", derive(Serialize, Deserialize))]
|
||||
pub struct $name(pub [u64; $n_words]);
|
||||
|
||||
impl AsRef<$name> for $name {
|
||||
|
@ -627,6 +366,7 @@ macro_rules! construct_uint {
|
|||
}
|
||||
|
||||
impl $name {
|
||||
pub const MAX: $name = $name([u64::max_value(); $n_words]);
|
||||
/// Convert from a decimal string.
|
||||
pub fn from_dec_str(value: &str) -> Result<Self, $crate::FromDecStrErr> {
|
||||
if !value.bytes().all(|b| b >= 48 && b <= 57) {
|
||||
|
@ -1066,6 +806,13 @@ macro_rules! construct_uint {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<$name> for [u8; $n_words * 8] {
|
||||
fn from(number: $name) -> Self {
|
||||
let mut arr = [0u8; $n_words * 8];
|
||||
number.to_big_endian(&mut arr);
|
||||
arr
|
||||
}
|
||||
}
|
||||
impl Default for $name {
|
||||
fn default() -> Self {
|
||||
$name::zero()
|
||||
|
@ -1464,6 +1211,13 @@ macro_rules! impl_std_for_uint_internals {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature="std"))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! impl_std_for_uint_internals {
|
||||
($name: ident, $n_words: tt) => {}
|
||||
}
|
||||
|
||||
#[cfg(feature="std")]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
|
@ -1471,7 +1225,7 @@ macro_rules! impl_std_for_uint {
|
|||
($name: ident, $n_words: tt) => {
|
||||
impl ::core::fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||
write!(f, "{:#x}", self)
|
||||
::core::fmt::Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1481,16 +1235,24 @@ macro_rules! impl_std_for_uint {
|
|||
return write!(f, "0");
|
||||
}
|
||||
|
||||
let mut s = String::new();
|
||||
let mut buf = [0_u8; $n_words*20];
|
||||
let mut i = buf.len() - 1;
|
||||
let mut current = *self;
|
||||
let ten = $name::from(10);
|
||||
|
||||
while !current.is_zero() {
|
||||
s = format!("{}{}", (current % ten).low_u32(), s);
|
||||
loop {
|
||||
let digit = (current % ten).low_u64() as u8;
|
||||
buf[i] = digit + b'0';
|
||||
current = current / ten;
|
||||
if current.is_zero() {
|
||||
break;
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
|
||||
write!(f, "{}", s)
|
||||
// sequence of `'0'..'9'` chars is guaranteed to be a valid UTF8 string
|
||||
let s = unsafe {::core::str::from_utf8_unchecked(&buf[i..])};
|
||||
f.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1499,10 +1261,9 @@ macro_rules! impl_std_for_uint {
|
|||
|
||||
fn from_str(value: &str) -> Result<$name, Self::Err> {
|
||||
use $crate::rustc_hex::FromHex;
|
||||
|
||||
let bytes: Vec<u8> = match value.len() % 2 == 0 {
|
||||
true => try!(value.from_hex()),
|
||||
false => try!(("0".to_owned() + value).from_hex())
|
||||
true => value.from_hex()?,
|
||||
false => ("0".to_owned() + value).from_hex()?
|
||||
};
|
||||
|
||||
let bytes_ref: &[u8] = &bytes;
|
||||
|
@ -1553,12 +1314,6 @@ macro_rules! impl_std_for_uint {
|
|||
($name: ident, $n_words: tt) => {}
|
||||
}
|
||||
|
||||
#[cfg(not(feature="std"))]
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! impl_std_for_uint_internals {
|
||||
($name: ident, $n_words: tt) => {}
|
||||
}
|
||||
|
||||
#[cfg(feature="heapsizeof")]
|
||||
#[macro_export]
|
||||
|
@ -1619,3 +1374,6 @@ macro_rules! impl_quickcheck_arbitrary_for_uint {
|
|||
macro_rules! impl_quickcheck_arbitrary_for_uint {
|
||||
($uint: ty, $n_bytes: tt) => {}
|
||||
}
|
||||
|
||||
construct_uint!(U256, 4);
|
||||
construct_uint!(U512, 8);
|
|
@ -4,17 +4,15 @@ extern crate core;
|
|||
extern crate uint;
|
||||
#[macro_use]
|
||||
extern crate crunchy;
|
||||
#[cfg(feature = "impl_quickcheck_arbitrary")]
|
||||
#[macro_use]
|
||||
extern crate quickcheck;
|
||||
|
||||
use std::u64::MAX;
|
||||
use std::str::FromStr;
|
||||
use uint::FromDecStrErr;
|
||||
use core::u64::MAX;
|
||||
use core::str::FromStr;
|
||||
use uint::{U256, U512, FromDecStrErr};
|
||||
|
||||
#[cfg(feature="std")]
|
||||
construct_uint!(U128, 2);
|
||||
construct_uint!(U256, 4);
|
||||
construct_uint!(U512, 8);
|
||||
|
||||
#[test]
|
||||
fn uint256_checked_ops() {
|
||||
|
@ -347,7 +345,8 @@ fn uint256_pow_overflow_panic() {
|
|||
fn should_format_and_debug_correctly() {
|
||||
let test = |x: usize, hex: &'static str, display: &'static str| {
|
||||
assert_eq!(format!("{}", U256::from(x)), display);
|
||||
assert_eq!(format!("{:?}", U256::from(x)), format!("0x{}", hex));
|
||||
// TODO: proper impl for Debug so we get this to pass: assert_eq!(format!("{:?}", U256::from(x)), format!("0x{}", hex));
|
||||
assert_eq!(format!("{:?}", U256::from(x)), display);
|
||||
assert_eq!(format!("{:x}", U256::from(x)), hex);
|
||||
assert_eq!(format!("{:#x}", U256::from(x)), format!("0x{}", hex));
|
||||
};
|
||||
|
@ -361,6 +360,30 @@ fn should_format_and_debug_correctly() {
|
|||
test(0x1000, "1000", "4096");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn display_u128() {
|
||||
let expected = "340282366920938463463374607431768211455";
|
||||
let value = U128::MAX;
|
||||
assert_eq!(format!("{}", value), expected);
|
||||
assert_eq!(format!("{:?}", value), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn display_u256() {
|
||||
let expected = "115792089237316195423570985008687907853269984665640564039457584007913129639935";
|
||||
let value = U256::MAX;
|
||||
assert_eq!(format!("{}", value), expected);
|
||||
assert_eq!(format!("{:?}", value), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn display_u512() {
|
||||
let expected = "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095";
|
||||
let value = U512::MAX;
|
||||
assert_eq!(format!("{}", value), expected);
|
||||
assert_eq!(format!("{:?}", value), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn uint256_overflowing_pow() {
|
||||
assert_eq!(
|
||||
|
@ -977,6 +1000,18 @@ fn from_big_endian() {
|
|||
assert_eq!(U256::from(1), number);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_fixed_array() {
|
||||
let expected: [u8; 32] = [
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 1,
|
||||
];
|
||||
let ary : [u8; 32] = U256::from(1).into();
|
||||
assert_eq!(ary, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn leading_zeros() {
|
||||
assert_eq!(U256::from("000000000000000000000001adbdd6bd6ff027485484b97f8a6a4c7129756dd1").leading_zeros(), 95);
|
||||
|
|
Loading…
Reference in New Issue