Merge branch 'master' into mining

This commit is contained in:
Gav Wood 2016-03-01 16:59:39 +01:00
commit f705f6957a
13 changed files with 734 additions and 34 deletions

3
.gitignore vendored
View File

@ -27,3 +27,6 @@
# jetbrains ide stuff
.idea
*.iml
# Build artifacts
out/

View File

@ -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:

View File

@ -447,7 +447,7 @@ impl BlockChain {
let mut write_details = self.block_details.write().unwrap();
for (hash, details) in update.block_details.into_iter() {
batch.put_extras(&hash, &details);
batch.put_extras(&hash, &details);
write_details.insert(hash, details);
}
@ -572,7 +572,7 @@ impl BlockChain {
/// This function returns modified transaction addresses.
fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, TransactionAddress> {
let block = BlockView::new(block_bytes);
let transaction_hashes = block.transaction_hashes();
let transaction_hashes = block.transaction_hashes();
transaction_hashes.into_iter()
.enumerate()
@ -587,20 +587,20 @@ impl BlockChain {
/// This functions returns modified blocks blooms.
///
/// To accelerate blooms lookups, blomms are stored in multiple
/// layers (BLOOM_LEVELS, currently 3).
/// To accelerate blooms lookups, blomms are stored in multiple
/// layers (BLOOM_LEVELS, currently 3).
/// ChainFilter is responsible for building and rebuilding these layers.
/// It returns them in HashMap, where values are Blooms and
/// keys are BloomIndexes. BloomIndex represents bloom location on one
/// of these layers.
///
///
/// To reduce number of queries to databse, block blooms are stored
/// in BlocksBlooms structure which contains info about several
/// in BlocksBlooms structure which contains info about several
/// (BLOOM_INDEX_SIZE, currently 16) consecutive blocks blooms.
///
///
/// Later, BloomIndexer is used to map bloom location on filter layer (BloomIndex)
/// to bloom location in database (BlocksBloomLocation).
///
///
fn prepare_block_blooms_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap<H256, BlocksBlooms> {
let block = BlockView::new(block_bytes);
let header = block.header_view();
@ -766,32 +766,33 @@ 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());
assert_eq!(bc.block_hash(0), Some(genesis_hash.clone()));
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());
@ -961,7 +962,7 @@ mod tests {
let temp = RandomTempPath::new();
let bc = BlockChain::new(BlockChainConfig::default(), &genesis, temp.as_path());
bc.insert_block(&b1, vec![]);
let transactions = bc.transactions(&b1_hash).unwrap();
assert_eq!(transactions.len(), 7);
for t in transactions {
@ -981,7 +982,7 @@ mod tests {
// prepare for fork (b1a, child of genesis)
let b1a = "f902ccf901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004001832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
// fork (b2a, child of b1a, with higher total difficulty)
let b2a = "f902ccf901f9a0626b0774a7cbdad7bdce07b87d74b6fa91c1c359d725076215d76348f8399f56a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0c70a5dc56146e5ef025e4e5726a6373c6f12fd2f6784093a19ead0a7d17fb292a040645cbce4fd399e7bb9160b4c30c40d7ee616a030d4e18ef0ed3b02bdb65911a086e608555f63628417032a011d107b36427af37d153f0da02ce3f90fdd5e8c08b90100000000000000000000000000000000000000000000000200000008000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000080000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302004002832fefd882c0e384562791e880a0e3cc39ff775cc0a32f175995b92e84b729e5c9a3563ff899e3555b908bc21d75887c3cde283f4846a6f8cdf8cb01018304cb2f8080b87e6060604052606e8060106000396000f360606040526000357c010000000000000000000000000000000000000000000000000000000090048063c0406226146037576035565b005b60406004506056565b6040518082815260200191505060405180910390f35b6000600560006000508190555060059050606b565b90561ba05258615c63503c0a600d6994b12ea5750d45b3c69668e2a371b4fbfb9eeff6b8a0a11be762bc90491231274a2945be35a43f23c27775b1ff24dd521702fe15f73ec0".from_hex().unwrap();
@ -1001,7 +1002,7 @@ mod tests {
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
assert_eq!(blocks_b1, vec![]);
assert_eq!(blocks_b2, vec![]);
bc.insert_block(&b1, vec![]);
let blocks_b1 = bc.blocks_with_bloom(&bloom_b1, 0, 5);
let blocks_b2 = bc.blocks_with_bloom(&bloom_b2, 0, 5);
@ -1041,6 +1042,4 @@ mod tests {
assert_eq!(blocks_b2, vec![2]);
assert_eq!(blocks_ba, vec![3]);
}
}

View 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());
}
}

View 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;

View File

@ -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;

View File

@ -117,7 +117,7 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!();
}
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry> {
fn logs(&self, _filter: Filter) -> Vec<LocalizedLogEntry> {
unimplemented!();
}

View File

@ -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(|| {

View File

@ -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);

View File

@ -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::*;

View File

@ -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);
}
}
@ -418,7 +418,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
}
Some(addr) => NodeEndpoint { address: addr, udp_port: udp_port }
};
// Setup the server socket
*tcp_listener = Some(TcpListener::bind(&listen_address).unwrap());
self.info.write().unwrap().public_endpoint = public_endpoint.clone();
@ -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
View 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);
}
}

View File

@ -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);
}
}