Merge branch 'master' into mining
This commit is contained in:
commit
f705f6957a
3
.gitignore
vendored
3
.gitignore
vendored
@ -27,3 +27,6 @@
|
||||
# jetbrains ide stuff
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
# Build artifacts
|
||||
out/
|
||||
|
@ -19,7 +19,7 @@ First (if you don't already have it) get multirust:
|
||||
|
||||
- Linux:
|
||||
```bash
|
||||
curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes
|
||||
curl -sf https://raw.githubusercontent.com/brson/multirust/master/quick-install.sh | sudo sh -s -- --yes
|
||||
```
|
||||
|
||||
- OSX with Homebrew:
|
||||
|
@ -766,19 +766,24 @@ mod tests {
|
||||
use std::str::FromStr;
|
||||
use rustc_serialize::hex::FromHex;
|
||||
use util::hash::*;
|
||||
use util::sha3::Hashable;
|
||||
use blockchain::{BlockProvider, BlockChain, BlockChainConfig};
|
||||
use tests::helpers::*;
|
||||
use devtools::*;
|
||||
use blockchain::helpers::generators::ChainGenerator;
|
||||
use views::BlockView;
|
||||
|
||||
#[test]
|
||||
fn valid_tests_extra32() {
|
||||
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0925002c3260b44e44c3edebad1cc442142b03020209df1ab8bb86752edbd2cd7a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a0363659b251bf8b819179874c8cce7b9b983d7f3704cbb58a3b334431f7032871889032d09c281e1236c0c0".from_hex().unwrap();
|
||||
fn basic_blockchain_insert() {
|
||||
let mut canon_chain = ChainGenerator::default();
|
||||
let genesis = canon_chain.next().unwrap();
|
||||
let first = canon_chain.next().unwrap();
|
||||
let genesis_hash = BlockView::new(&genesis).header_view().sha3();
|
||||
let first_hash = BlockView::new(&first).header_view().sha3();
|
||||
|
||||
let temp = RandomTempPath::new();
|
||||
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
|
||||
|
||||
let genesis_hash = H256::from_str("3caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942").unwrap();
|
||||
|
||||
assert_eq!(bc.genesis_hash(), genesis_hash.clone());
|
||||
assert_eq!(bc.best_block_number(), 0);
|
||||
assert_eq!(bc.best_block_hash(), genesis_hash.clone());
|
||||
@ -786,12 +791,8 @@ mod tests {
|
||||
assert_eq!(bc.block_hash(1), None);
|
||||
assert_eq!(bc.block_details(&genesis_hash).unwrap().children, vec![]);
|
||||
|
||||
let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap();
|
||||
|
||||
bc.insert_block(&first, vec![]);
|
||||
|
||||
let first_hash = H256::from_str("a940e5af7d146b3b917c953a82e1966b906dace3a4e355b5b0a4560190357ea1").unwrap();
|
||||
|
||||
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
|
||||
assert_eq!(bc.best_block_number(), 1);
|
||||
assert_eq!(bc.best_block_hash(), first_hash.clone());
|
||||
@ -1041,6 +1042,4 @@ mod tests {
|
||||
assert_eq!(blocks_b2, vec![2]);
|
||||
assert_eq!(blocks_ba, vec![3]);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
154
ethcore/src/blockchain/helpers/generators.rs
Normal file
154
ethcore/src/blockchain/helpers/generators.rs
Normal file
@ -0,0 +1,154 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use util::rlp::*;
|
||||
use util::hash::{H256, H2048};
|
||||
use util::uint::{U256};
|
||||
use util::bytes::Bytes;
|
||||
use header::{BlockNumber, Header};
|
||||
use transaction::SignedTransaction;
|
||||
|
||||
/// Chain iterator interface.
|
||||
pub trait ChainIterator: Iterator {
|
||||
/// Should be called to create a fork of current iterator.
|
||||
/// Blocks generated by fork will have lower difficulty than current chain.
|
||||
fn fork(&mut self) -> Self;
|
||||
/// Should be called to create new block with given bloom.
|
||||
fn next_with_bloom(&mut self, bloom: H2048) -> Option<Self::Item>;
|
||||
}
|
||||
|
||||
/// Helper structure, used for encoding blocks.
|
||||
#[derive(Default)]
|
||||
struct Block {
|
||||
header: Header,
|
||||
transactions: Vec<SignedTransaction>,
|
||||
uncles: Vec<Header>
|
||||
}
|
||||
|
||||
impl Encodable for Block {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(3);
|
||||
s.append(&self.header);
|
||||
s.append(&self.transactions);
|
||||
s.append(&self.uncles);
|
||||
}
|
||||
}
|
||||
|
||||
/// Blockchain generator.
|
||||
pub struct ChainGenerator {
|
||||
/// Next block number.
|
||||
number: BlockNumber,
|
||||
/// Next block parent hash.
|
||||
parent_hash: H256,
|
||||
/// Next block difficulty.
|
||||
difficulty: U256,
|
||||
/// Number of forks of current block.
|
||||
number_of_forks: usize,
|
||||
}
|
||||
|
||||
impl ChainGenerator {
|
||||
fn prepare_block(&self) -> Block {
|
||||
let mut block = Block::default();
|
||||
block.header.parent_hash = self.parent_hash.clone();
|
||||
block.header.number = self.number;
|
||||
block.header.difficulty = self.difficulty;
|
||||
block
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ChainGenerator {
|
||||
fn default() -> Self {
|
||||
ChainGenerator {
|
||||
number: 0,
|
||||
parent_hash: H256::default(),
|
||||
difficulty: U256::from(1000),
|
||||
number_of_forks: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for ChainGenerator {
|
||||
type Item = Bytes;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let block = self.prepare_block();
|
||||
self.number += 1;
|
||||
self.parent_hash = block.header.hash();
|
||||
self.number_of_forks = 0;
|
||||
Some(encode(&block).to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainIterator for ChainGenerator {
|
||||
fn fork(&mut self) -> Self {
|
||||
self.number_of_forks += 1;
|
||||
ChainGenerator {
|
||||
number: self.number,
|
||||
parent_hash: self.parent_hash.clone(),
|
||||
difficulty: self.difficulty - U256::from(self.number_of_forks),
|
||||
number_of_forks: 0
|
||||
}
|
||||
}
|
||||
|
||||
fn next_with_bloom(&mut self, bloom: H2048) -> Option<Self::Item> {
|
||||
let mut block = self.prepare_block();
|
||||
block.header.log_bloom = bloom;
|
||||
self.number += 1;
|
||||
self.parent_hash = block.header.hash();
|
||||
self.number_of_forks = 0;
|
||||
Some(encode(&block).to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use util::hash::H256;
|
||||
use util::sha3::Hashable;
|
||||
use views::BlockView;
|
||||
use super::{ChainIterator, ChainGenerator};
|
||||
|
||||
#[test]
|
||||
fn canon_chain_generator() {
|
||||
let mut canon_chain = ChainGenerator::default();
|
||||
|
||||
let genesis_rlp = canon_chain.next().unwrap();
|
||||
let genesis = BlockView::new(&genesis_rlp);
|
||||
|
||||
assert_eq!(genesis.header_view().parent_hash(), H256::default());
|
||||
assert_eq!(genesis.header_view().number(), 0);
|
||||
|
||||
let b1_rlp = canon_chain.next().unwrap();
|
||||
let b1 = BlockView::new(&b1_rlp);
|
||||
|
||||
assert_eq!(b1.header_view().parent_hash(), genesis.header_view().sha3());
|
||||
assert_eq!(b1.header_view().number(), 1);
|
||||
|
||||
let mut fork_chain = canon_chain.fork();
|
||||
|
||||
let b2_rlp_fork = fork_chain.next().unwrap();
|
||||
let b2_fork = BlockView::new(&b2_rlp_fork);
|
||||
|
||||
assert_eq!(b2_fork.header_view().parent_hash(), b1.header_view().sha3());
|
||||
assert_eq!(b2_fork.header_view().number(), 2);
|
||||
|
||||
let b2_rlp = canon_chain.next().unwrap();
|
||||
let b2 = BlockView::new(&b2_rlp);
|
||||
|
||||
assert_eq!(b2.header_view().parent_hash(), b1.header_view().sha3());
|
||||
assert_eq!(b2.header_view().number(), 2);
|
||||
assert!(b2.header_view().difficulty() > b2_fork.header_view().difficulty());
|
||||
}
|
||||
}
|
17
ethcore/src/blockchain/helpers/mod.rs
Normal file
17
ethcore/src/blockchain/helpers/mod.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
pub mod generators;
|
@ -23,6 +23,8 @@ mod bloom_indexer;
|
||||
mod cache;
|
||||
mod tree_route;
|
||||
mod update;
|
||||
#[cfg(test)]
|
||||
mod helpers;
|
||||
|
||||
pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig};
|
||||
pub use self::cache::CacheSize;
|
||||
|
@ -117,7 +117,7 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||
fn logs(&self, _filter: Filter) -> Vec<LocalizedLogEntry> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
|
@ -74,6 +74,19 @@ fn u256_mul(b: &mut Bencher) {
|
||||
}
|
||||
|
||||
|
||||
#[bench]
|
||||
fn u256_full_mul(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let n = black_box(10000);
|
||||
(0..n).fold(U256([rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>()]),
|
||||
|old, new| {
|
||||
let U512(ref u512words) = old.full_mul(U256([rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>(), rand::random::<u64>()]));
|
||||
U256([u512words[0], u512words[2], u512words[2], u512words[3]])
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#[bench]
|
||||
fn u128_mul(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
|
@ -46,14 +46,14 @@ pub fn enumerate_geth_keys(path: &Path) -> Result<Vec<(Address, String)>, io::Er
|
||||
#[derive(Debug)]
|
||||
pub enum ImportError {
|
||||
/// Io error reading geth file
|
||||
IoError(io::Error),
|
||||
Io(io::Error),
|
||||
/// format error
|
||||
FormatError,
|
||||
Format,
|
||||
}
|
||||
|
||||
impl From<io::Error> for ImportError {
|
||||
fn from (err: io::Error) -> ImportError {
|
||||
ImportError::IoError(err)
|
||||
ImportError::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,15 +65,15 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path)
|
||||
|
||||
let mut json_result = Json::from_str(&buf);
|
||||
let mut json = match json_result {
|
||||
Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::FormatError)),
|
||||
Err(_) => { return Err(ImportError::FormatError); }
|
||||
Ok(ref mut parsed_json) => try!(parsed_json.as_object_mut().ok_or(ImportError::Format)),
|
||||
Err(_) => { return Err(ImportError::Format); }
|
||||
};
|
||||
let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::FormatError)).clone();
|
||||
let crypto_object = try!(json.get("Crypto").and_then(|crypto| crypto.as_object()).ok_or(ImportError::Format)).clone();
|
||||
json.insert("crypto".to_owned(), Json::Object(crypto_object));
|
||||
json.remove("Crypto");
|
||||
match KeyFileContent::load(&Json::Object(json.clone())) {
|
||||
Ok(key_file) => try!(secret_store.import_key(key_file)),
|
||||
Err(_) => { return Err(ImportError::FormatError); }
|
||||
Err(_) => { return Err(ImportError::Format); }
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
@ -82,7 +82,7 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path)
|
||||
pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> {
|
||||
use std::path::PathBuf;
|
||||
let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory));
|
||||
for &(ref address, ref file_path) in geth_files.iter() {
|
||||
for &(ref address, ref file_path) in &geth_files {
|
||||
let mut path = PathBuf::new();
|
||||
path.push(geth_keyfiles_directory);
|
||||
path.push(file_path);
|
||||
|
@ -144,6 +144,7 @@ pub mod network;
|
||||
pub mod log;
|
||||
pub mod panics;
|
||||
pub mod keys;
|
||||
pub mod table;
|
||||
|
||||
pub use common::*;
|
||||
pub use misc::*;
|
||||
|
@ -376,7 +376,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
||||
let entry = NodeEntry { endpoint: n.endpoint.clone(), id: n.id.clone() };
|
||||
self.pinned_nodes.push(n.id.clone());
|
||||
self.nodes.write().unwrap().add_node(n);
|
||||
if let &mut Some(ref mut discovery) = self.discovery.lock().unwrap().deref_mut() {
|
||||
if let Some(ref mut discovery) = *self.discovery.lock().unwrap().deref_mut() {
|
||||
discovery.add_node(entry);
|
||||
}
|
||||
}
|
||||
@ -697,7 +697,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
|
||||
let entry = NodeEntry { id: session.id().clone(), endpoint: NodeEndpoint { address: address, udp_port: address.port() } };
|
||||
self.nodes.write().unwrap().add_node(Node::new(entry.id.clone(), entry.endpoint.clone()));
|
||||
let mut discovery = self.discovery.lock().unwrap();
|
||||
if let &mut Some(ref mut discovery) = discovery.deref_mut() {
|
||||
if let Some(ref mut discovery) = *discovery.deref_mut() {
|
||||
discovery.add_node(entry);
|
||||
}
|
||||
}
|
||||
|
254
util/src/table.rs
Normal file
254
util/src/table.rs
Normal file
@ -0,0 +1,254 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! A collection associating pair of keys (row and column) with a single value.
|
||||
|
||||
use std::hash::Hash;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Structure to hold double-indexed values
|
||||
///
|
||||
/// You can obviously use `HashMap<(Row,Col), Val>`, but this structure gives
|
||||
/// you better access to all `Columns` in Specific `Row`. Namely you can get sub-hashmap
|
||||
/// `HashMap<Col, Val>` for specific `Row`
|
||||
pub struct Table<Row, Col, Val>
|
||||
where Row: Eq + Hash + Clone,
|
||||
Col: Eq + Hash {
|
||||
map: HashMap<Row, HashMap<Col, Val>>,
|
||||
}
|
||||
|
||||
impl<Row, Col, Val> Table<Row, Col, Val>
|
||||
where Row: Eq + Hash + Clone,
|
||||
Col: Eq + Hash {
|
||||
/// Creates new Table
|
||||
pub fn new() -> Table<Row, Col, Val> {
|
||||
Table {
|
||||
map: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all elements from this Table
|
||||
pub fn clear(&mut self) {
|
||||
self.map.clear();
|
||||
}
|
||||
|
||||
/// Returns length of the Table (number of (row, col, val) tuples)
|
||||
pub fn len(&self) -> usize {
|
||||
self.map.values().fold(0, |acc, v| acc + v.len())
|
||||
}
|
||||
|
||||
/// Check if there is any element in this Table
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.map.is_empty() || self.map.values().all(|v| v.is_empty())
|
||||
}
|
||||
|
||||
/// Get mutable reference for single Table row.
|
||||
pub fn row_mut(&mut self, row: &Row) -> Option<&mut HashMap<Col, Val>> {
|
||||
self.map.get_mut(row)
|
||||
}
|
||||
|
||||
/// Checks if row is defined for that table (note that even if defined it might be empty)
|
||||
pub fn has_row(&self, row: &Row) -> bool {
|
||||
self.map.contains_key(row)
|
||||
}
|
||||
|
||||
/// Get immutable reference for single row in this Table
|
||||
pub fn row(&self, row: &Row) -> Option<&HashMap<Col, Val>> {
|
||||
self.map.get(row)
|
||||
}
|
||||
|
||||
/// Get element in cell described by `(row, col)`
|
||||
pub fn get(&self, row: &Row, col: &Col) -> Option<&Val> {
|
||||
self.map.get(row).and_then(|r| r.get(col))
|
||||
}
|
||||
|
||||
/// Remove value from specific cell
|
||||
///
|
||||
/// It will remove the row if it's the last value in it
|
||||
pub fn remove(&mut self, row: &Row, col: &Col) -> Option<Val> {
|
||||
let (val, is_empty) = {
|
||||
let row_map = self.map.get_mut(row);
|
||||
if let None = row_map {
|
||||
return None;
|
||||
}
|
||||
let mut row_map = row_map.unwrap();
|
||||
let val = row_map.remove(col);
|
||||
(val, row_map.is_empty())
|
||||
};
|
||||
// Clean row
|
||||
if is_empty {
|
||||
self.map.remove(row);
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
/// Remove given row from Table if there are no values defined in it
|
||||
///
|
||||
/// When using `#row_mut` it may happen that all values from some row are drained.
|
||||
/// Table however will not be aware that row is empty.
|
||||
/// You can use this method to explicitly remove row entry from the Table.
|
||||
pub fn clear_if_empty(&mut self, row: &Row) {
|
||||
let is_empty = self.map.get(row).map_or(false, |m| m.is_empty());
|
||||
if is_empty {
|
||||
self.map.remove(row);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts new value to specified cell
|
||||
///
|
||||
/// Returns previous value (if any)
|
||||
pub fn insert(&mut self, row: Row, col: Col, val: Val) -> Option<Val> {
|
||||
self.map.entry(row).or_insert_with(|| HashMap::new()).insert(col, val)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn should_create_empty_table() {
|
||||
// when
|
||||
let table : Table<usize, usize, bool> = Table::new();
|
||||
|
||||
// then
|
||||
assert!(table.is_empty());
|
||||
assert_eq!(table.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_insert_elements_and_return_previous_if_any() {
|
||||
// given
|
||||
let mut table = Table::new();
|
||||
|
||||
// when
|
||||
let r1 = table.insert(5, 4, true);
|
||||
let r2 = table.insert(10, 4, true);
|
||||
let r3 = table.insert(10, 10, true);
|
||||
let r4 = table.insert(10, 10, false);
|
||||
|
||||
// then
|
||||
assert!(r1.is_none());
|
||||
assert!(r2.is_none());
|
||||
assert!(r3.is_none());
|
||||
assert!(r4.is_some());
|
||||
assert!(!table.is_empty());
|
||||
assert_eq!(r4.unwrap(), true);
|
||||
assert_eq!(table.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_remove_element() {
|
||||
// given
|
||||
let mut table = Table::new();
|
||||
table.insert(5, 4, true);
|
||||
assert!(!table.is_empty());
|
||||
assert_eq!(table.len(), 1);
|
||||
|
||||
// when
|
||||
let r = table.remove(&5, &4);
|
||||
|
||||
// then
|
||||
assert!(table.is_empty());
|
||||
assert_eq!(table.len() ,0);
|
||||
assert_eq!(r.unwrap(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_none_if_trying_to_remove_non_existing_element() {
|
||||
// given
|
||||
let mut table : Table<usize, usize, usize> = Table::new();
|
||||
assert!(table.is_empty());
|
||||
|
||||
// when
|
||||
let r = table.remove(&5, &4);
|
||||
|
||||
// then
|
||||
assert!(r.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_clear_row_if_removing_last_element() {
|
||||
// given
|
||||
let mut table = Table::new();
|
||||
table.insert(5, 4, true);
|
||||
assert!(table.has_row(&5));
|
||||
|
||||
// when
|
||||
let r = table.remove(&5, &4);
|
||||
|
||||
// then
|
||||
assert!(r.is_some());
|
||||
assert!(!table.has_row(&5));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_element_given_row_and_col() {
|
||||
// given
|
||||
let mut table = Table::new();
|
||||
table.insert(1551, 1234, 123);
|
||||
|
||||
// when
|
||||
let r1 = table.get(&1551, &1234);
|
||||
let r2 = table.get(&5, &4);
|
||||
|
||||
// then
|
||||
assert!(r1.is_some());
|
||||
assert!(r2.is_none());
|
||||
assert_eq!(r1.unwrap(), &123);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_clear_table() {
|
||||
// given
|
||||
let mut table = Table::new();
|
||||
table.insert(1, 1, true);
|
||||
table.insert(1, 2, false);
|
||||
table.insert(2, 2, false);
|
||||
assert_eq!(table.len(), 3);
|
||||
|
||||
// when
|
||||
table.clear();
|
||||
|
||||
// then
|
||||
assert!(table.is_empty());
|
||||
assert_eq!(table.len(), 0);
|
||||
assert_eq!(table.has_row(&1), false);
|
||||
assert_eq!(table.has_row(&2), false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_mutable_row() {
|
||||
// given
|
||||
let mut table = Table::new();
|
||||
table.insert(1, 1, true);
|
||||
table.insert(1, 2, false);
|
||||
table.insert(2, 2, false);
|
||||
|
||||
// when
|
||||
{
|
||||
let mut row = table.row_mut(&1).unwrap();
|
||||
row.remove(&1);
|
||||
row.remove(&2);
|
||||
}
|
||||
assert!(table.has_row(&1));
|
||||
table.clear_if_empty(&1);
|
||||
|
||||
// then
|
||||
assert!(!table.has_row(&1));
|
||||
assert_eq!(table.len(), 1);
|
||||
}
|
||||
}
|
257
util/src/uint.rs
257
util/src/uint.rs
@ -1097,6 +1097,157 @@ construct_uint!(U512, 8);
|
||||
construct_uint!(U256, 4);
|
||||
construct_uint!(U128, 2);
|
||||
|
||||
impl U256 {
|
||||
/// Multiplies two 256-bit integers to produce full 512-bit integer
|
||||
/// No overflow possible
|
||||
#[cfg(all(x64asm, target_arch="x86_64"))]
|
||||
pub fn full_mul(self, other: U256) -> U512 {
|
||||
let self_t: &[u64; 4] = unsafe { &mem::transmute(self) };
|
||||
let other_t: &[u64; 4] = unsafe { &mem::transmute(other) };
|
||||
let mut result: [u64; 8] = unsafe { mem::uninitialized() };
|
||||
unsafe {
|
||||
asm!("
|
||||
mov $8, %rax
|
||||
mulq $12
|
||||
mov %rax, $0
|
||||
mov %rdx, $1
|
||||
|
||||
mov $8, %rax
|
||||
mulq $13
|
||||
add %rax, $1
|
||||
adc $$0, %rdx
|
||||
mov %rdx, $2
|
||||
|
||||
mov $8, %rax
|
||||
mulq $14
|
||||
add %rax, $2
|
||||
adc $$0, %rdx
|
||||
mov %rdx, $3
|
||||
|
||||
mov $8, %rax
|
||||
mulq $15
|
||||
add %rax, $3
|
||||
adc $$0, %rdx
|
||||
mov %rdx, $4
|
||||
|
||||
mov $9, %rax
|
||||
mulq $12
|
||||
add %rax, $1
|
||||
adc %rdx, $2
|
||||
adc $$0, $3
|
||||
adc $$0, $4
|
||||
xor $5, $5
|
||||
adc $$0, $5
|
||||
xor $6, $6
|
||||
adc $$0, $6
|
||||
xor $7, $7
|
||||
adc $$0, $7
|
||||
|
||||
mov $9, %rax
|
||||
mulq $13
|
||||
add %rax, $2
|
||||
adc %rdx, $3
|
||||
adc $$0, $4
|
||||
adc $$0, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $9, %rax
|
||||
mulq $14
|
||||
add %rax, $3
|
||||
adc %rdx, $4
|
||||
adc $$0, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $9, %rax
|
||||
mulq $15
|
||||
add %rax, $4
|
||||
adc %rdx, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $10, %rax
|
||||
mulq $12
|
||||
add %rax, $2
|
||||
adc %rdx, $3
|
||||
adc $$0, $4
|
||||
adc $$0, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $10, %rax
|
||||
mulq $13
|
||||
add %rax, $3
|
||||
adc %rdx, $4
|
||||
adc $$0, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $10, %rax
|
||||
mulq $14
|
||||
add %rax, $4
|
||||
adc %rdx, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $10, %rax
|
||||
mulq $15
|
||||
add %rax, $5
|
||||
adc %rdx, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $11, %rax
|
||||
mulq $12
|
||||
add %rax, $3
|
||||
adc %rdx, $4
|
||||
adc $$0, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $11, %rax
|
||||
mulq $13
|
||||
add %rax, $4
|
||||
adc %rdx, $5
|
||||
adc $$0, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $11, %rax
|
||||
mulq $14
|
||||
add %rax, $5
|
||||
adc %rdx, $6
|
||||
adc $$0, $7
|
||||
|
||||
mov $11, %rax
|
||||
mulq $15
|
||||
add %rax, $6
|
||||
adc %rdx, $7
|
||||
"
|
||||
: /* $0 */ "={r8}"(result[0]), /* $1 */ "={r9}"(result[1]), /* $2 */ "={r10}"(result[2]),
|
||||
/* $3 */ "={r11}"(result[3]), /* $4 */ "={r12}"(result[4]), /* $5 */ "={r13}"(result[5]),
|
||||
/* $6 */ "={r14}"(result[6]), /* $7 */ "={r15}"(result[7])
|
||||
|
||||
: /* $8 */ "m"(self_t[0]), /* $9 */ "m"(self_t[1]), /* $10 */ "m"(self_t[2]),
|
||||
/* $11 */ "m"(self_t[3]), /* $12 */ "m"(other_t[0]), /* $13 */ "m"(other_t[1]),
|
||||
/* $14 */ "m"(other_t[2]), /* $15 */ "m"(other_t[3])
|
||||
: "rax", "rdx"
|
||||
:
|
||||
);
|
||||
}
|
||||
U512(result)
|
||||
}
|
||||
|
||||
/// Multiplies two 256-bit integers to produce full 512-bit integer
|
||||
/// No overflow possible
|
||||
#[cfg(not(all(x64asm, target_arch="x86_64")))]
|
||||
pub fn full_mul(self, other: U256) -> U512 {
|
||||
let self_512 = U512::from(self);
|
||||
let other_512 = U512::from(other);
|
||||
let (result, _) = self_512.overflowing_mul(other_512);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl From<U256> for U512 {
|
||||
fn from(value: U256) -> U512 {
|
||||
let U256(ref arr) = value;
|
||||
@ -1855,5 +2006,111 @@ mod tests {
|
||||
let (_, overflow) = U256([0, 0, 8, 0]).overflowing_mul(U256([0, 0, 7, 0]));
|
||||
assert!(overflow);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn u256_multi_full_mul() {
|
||||
let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0]));
|
||||
assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([1, 0, 0, 0]).full_mul(U256([1, 0, 0, 0]));
|
||||
assert_eq!(U512([1, 0, 0, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([5, 0, 0, 0]).full_mul(U256([5, 0, 0, 0]));
|
||||
assert_eq!(U512([25, 0, 0, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([0, 5, 0, 0]).full_mul(U256([0, 5, 0, 0]));
|
||||
assert_eq!(U512([0, 0, 25, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([0, 0, 0, 4]).full_mul(U256([4, 0, 0, 0]));
|
||||
assert_eq!(U512([0, 0, 0, 16, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([0, 0, 0, 5]).full_mul(U256([2, 0, 0, 0]));
|
||||
assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([0, 0, 2, 0]).full_mul(U256([0, 5, 0, 0]));
|
||||
assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([0, 3, 0, 0]).full_mul(U256([0, 0, 3, 0]));
|
||||
assert_eq!(U512([0, 0, 0, 9, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([0, 0, 8, 0]).full_mul(U256([0, 0, 6, 0]));
|
||||
assert_eq!(U512([0, 0, 0, 0, 48, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([9, 0, 0, 0]).full_mul(U256([0, 3, 0, 0]));
|
||||
assert_eq!(U512([0, 27, 0, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||
assert_eq!(U512([1, ::std::u64::MAX-1, 0, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([0, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||
assert_eq!(U512([0, 1, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||
assert_eq!(U512([1, 0, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, 0, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, 0, 0, 0]));
|
||||
assert_eq!(U512([1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]));
|
||||
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, 0, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||
assert_eq!(U512([1, 0, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||
assert_eq!(U512([1, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||
assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, 0]));
|
||||
assert_eq!(U512([1, 0, 0, ::std::u64::MAX, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, 0]), result);
|
||||
|
||||
let result = U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]).full_mul(U256([::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]));
|
||||
assert_eq!(U512([1, 0, 0, 0, ::std::u64::MAX-1, ::std::u64::MAX, ::std::u64::MAX, ::std::u64::MAX]), result);
|
||||
|
||||
let result = U256([0, 0, 0, ::std::u64::MAX]).full_mul(U256([0, 0, 0, ::std::u64::MAX]));
|
||||
assert_eq!(U512([0, 0, 0, 0, 0, 0, 1, ::std::u64::MAX-1]), result);
|
||||
|
||||
let result = U256([1, 0, 0, 0]).full_mul(U256([0, 0, 0, ::std::u64::MAX]));
|
||||
assert_eq!(U512([0, 0, 0, ::std::u64::MAX, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([1, 2, 3, 4]).full_mul(U256([5, 0, 0, 0]));
|
||||
assert_eq!(U512([5, 10, 15, 20, 0, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 6, 0, 0]));
|
||||
assert_eq!(U512([0, 6, 12, 18, 24, 0, 0, 0]), result);
|
||||
|
||||
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 7, 0]));
|
||||
assert_eq!(U512([0, 0, 7, 14, 21, 28, 0, 0]), result);
|
||||
|
||||
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 0, 8]));
|
||||
assert_eq!(U512([0, 0, 0, 8, 16, 24, 32, 0]), result);
|
||||
|
||||
let result = U256([1, 2, 3, 4]).full_mul(U256([5, 6, 7, 8]));
|
||||
assert_eq!(U512([5, 16, 34, 60, 61, 52, 32, 0]), result);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user