Add a bunch of small hashtypes for cheap'n'collidey hashtables

This commit is contained in:
Andrew Poelstra 2014-08-22 11:32:42 -07:00
parent 1522ab841d
commit 611b1f57c9
4 changed files with 116 additions and 33 deletions

View File

@ -34,7 +34,7 @@ use network::encodable::ConsensusEncodable;
use network::serialize::BitcoinHash; use network::serialize::BitcoinHash;
/// A transaction input, which defines old coins to be consumed /// A transaction input, which defines old coins to be consumed
#[deriving(Clone, PartialEq, Show)] #[deriving(Clone, PartialEq, Eq, Show)]
pub struct TxIn { pub struct TxIn {
/// The hash of the transaction whose output is being used an an input /// The hash of the transaction whose output is being used an an input
pub prev_hash: Sha256dHash, pub prev_hash: Sha256dHash,
@ -51,7 +51,7 @@ pub struct TxIn {
} }
/// A transaction output, which defines new coins to be created from old ones. /// A transaction output, which defines new coins to be created from old ones.
#[deriving(Clone, PartialEq, Show)] #[deriving(Clone, PartialEq, Eq, Show)]
pub struct TxOut { pub struct TxOut {
/// The value of the output, in satoshis /// The value of the output, in satoshis
pub value: u64, pub value: u64,
@ -67,7 +67,7 @@ impl Default for TxOut {
} }
/// A Bitcoin transaction, which describes an authenticated movement of coins /// A Bitcoin transaction, which describes an authenticated movement of coins
#[deriving(Clone, PartialEq, Show)] #[deriving(Clone, PartialEq, Eq, Show)]
pub struct Transaction { pub struct Transaction {
/// The protocol version, should always be 1. /// The protocol version, should always be 1.
pub version: u32, pub version: u32,

View File

@ -36,6 +36,25 @@ macro_rules! impl_consensus_encoding(
); );
) )
macro_rules! impl_newtype_consensus_encoding(
($thing:ident) => (
impl<S: ::network::serialize::SimpleEncoder<E>, E> ::network::encodable::ConsensusEncodable<S, E> for $thing {
#[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), E> {
let &$thing(ref data) = self;
data.consensus_encode(s)
}
}
impl<D: ::network::serialize::SimpleDecoder<E>, E> ::network::encodable::ConsensusDecodable<D, E> for $thing {
#[inline]
fn consensus_decode(d: &mut D) -> Result<$thing, E> {
Ok($thing(try!(ConsensusDecodable::consensus_decode(d))))
}
}
);
)
macro_rules! impl_json( macro_rules! impl_json(
($thing:ident, $($field:ident),+) => ( ($thing:ident, $($field:ident),+) => (
impl ::serialize::json::ToJson for $thing { impl ::serialize::json::ToJson for $thing {

View File

@ -319,23 +319,33 @@ impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for CheckedData {
} }
// Tuples // Tuples
impl<S:SimpleEncoder<E>, E, T: ConsensusEncodable<S, E>, U: ConsensusEncodable<S, E>> ConsensusEncodable<S, E> for (T, U) { macro_rules! tuple_encode(
($($x:ident),*) => (
impl <SS:SimpleEncoder<EE>, EE, $($x: ConsensusEncodable<SS, EE>),*> ConsensusEncodable<SS, EE> for ($($x),*) {
#[inline] #[inline]
fn consensus_encode(&self, s: &mut S) -> Result<(), E> { #[allow(uppercase_variables)]
let &(ref s1, ref s2) = self; fn consensus_encode(&self, s: &mut SS) -> Result<(), EE> {
try!(s1.consensus_encode(s)); let &($(ref $x),*) = self;
try!(s2.consensus_encode(s)); $( try!($x.consensus_encode(s)); )*
Ok(()) Ok(())
} }
} }
impl<D:SimpleDecoder<E>, E, T: ConsensusDecodable<D, E>, U: ConsensusDecodable<D, E>> ConsensusDecodable<D, E> for (T, U) { impl<DD:SimpleDecoder<EE>, EE, $($x: ConsensusDecodable<DD, EE>),*> ConsensusDecodable<DD, EE> for ($($x),*) {
#[inline] #[inline]
fn consensus_decode(d: &mut D) -> Result<(T, U), E> { #[allow(uppercase_variables)]
Ok((try!(ConsensusDecodable::consensus_decode(d)), fn consensus_decode(d: &mut DD) -> Result<($($x),*), EE> {
try!(ConsensusDecodable::consensus_decode(d)))) Ok(($(try!({let $x = ConsensusDecodable::consensus_decode(d); $x })),*))
} }
} }
);
)
tuple_encode!(A, B)
tuple_encode!(A, B, C, D)
tuple_encode!(A, B, C, D, E, F)
tuple_encode!(A, B, C, D, E, F, G, H)
// References // References
impl<S:SimpleEncoder<E>, E, T: ConsensusEncodable<S, E>> ConsensusEncodable<S, E> for Box<T> { impl<S:SimpleEncoder<E>, E, T: ConsensusEncodable<S, E>> ConsensusEncodable<S, E> for Box<T> {

View File

@ -28,7 +28,7 @@ use crypto::digest::Digest;
use crypto::sha2; use crypto::sha2;
use network::encodable::{ConsensusDecodable, ConsensusEncodable}; use network::encodable::{ConsensusDecodable, ConsensusEncodable};
use network::serialize::{RawEncoder, BitcoinHash, SimpleDecoder, SimpleEncoder}; use network::serialize::{RawEncoder, BitcoinHash, SimpleDecoder};
use util::uint::Uint128; use util::uint::Uint128;
use util::uint::Uint256; use util::uint::Uint256;
@ -44,6 +44,19 @@ pub struct Ripemd160Hash([u8, ..20]);
/// A "hasher" which just truncates /// A "hasher" which just truncates
pub struct DumbHasher; pub struct DumbHasher;
/// A 32-bit hash obtained by truncating a real hash
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct Hash32((u8, u8, u8, u8));
/// A 48-bit hash obtained by truncating a real hash
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct Hash48((u8, u8, u8, u8, u8, u8));
/// A 64-bit hash obtained by truncating a real hash
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct Hash64((u8, u8, u8, u8, u8, u8, u8, u8));
// Allow these to be used as a key for Rust's HashMap et. al. // Allow these to be used as a key for Rust's HashMap et. al.
impl hash::Hash<u64> for Sha256dHash { impl hash::Hash<u64> for Sha256dHash {
#[inline] #[inline]
@ -72,6 +85,32 @@ impl hash::Hash<u64> for Uint128 {
} }
} }
impl hash::Hash<u64> for Hash32 {
#[inline]
fn hash(&self, state: &mut u64) {
let &Hash32((a, b, c, d)) = self;
*state = a as u64 + (b as u64 << 8) + (c as u64 << 16) + (d as u64 << 24);
}
}
impl hash::Hash<u64> for Hash48 {
#[inline]
fn hash(&self, state: &mut u64) {
let &Hash48((a, b, c, d, e, f)) = self;
*state = a as u64 + (b as u64 << 8) + (c as u64 << 16) + (d as u64 << 24) +
(e as u64 << 32) + (f as u64 << 40);
}
}
impl hash::Hash<u64> for Hash64 {
#[inline]
fn hash(&self, state: &mut u64) {
let &Hash64((a, b, c, d, e, f, g, h)) = self;
*state = a as u64 + (b as u64 << 8) + (c as u64 << 16) + (d as u64 << 24) +
(e as u64 << 32) + (f as u64 << 40) + (g as u64 << 48) + (h as u64 << 56);
}
}
impl hash::Hasher<u64> for DumbHasher { impl hash::Hasher<u64> for DumbHasher {
#[inline] #[inline]
fn hash<T: hash::Hash<u64>>(&self, value: &T) -> u64 { fn hash<T: hash::Hash<u64>>(&self, value: &T) -> u64 {
@ -122,6 +161,30 @@ impl Sha256dHash {
data[31]])) } data[31]])) }
} }
/// Converts a hash to a Hash32 by truncation
#[inline]
pub fn into_hash32(self) -> Hash32 {
let Sha256dHash(data) = self;
unsafe { transmute([data[0], data[8], data[16], data[24]]) }
}
/// Converts a hash to a Hash48 by truncation
#[inline]
pub fn into_hash48(self) -> Hash48 {
let Sha256dHash(data) = self;
unsafe { transmute([data[0], data[6], data[12], data[18], data[24], data[30]]) }
}
/// Human-readable hex output
/// Converts a hash to a Hash64 by truncation
#[inline]
pub fn into_hash64(self) -> Hash64 {
let Sha256dHash(data) = self;
unsafe { transmute([data[0], data[4], data[8], data[12],
data[16], data[20], data[24], data[28]]) }
}
/// Human-readable hex output /// Human-readable hex output
pub fn le_hex_string(&self) -> String { pub fn le_hex_string(&self) -> String {
let &Sha256dHash(data) = self; let &Sha256dHash(data) = self;
@ -214,19 +277,10 @@ impl<D: ::serialize::Decoder<E>, E> ::serialize::Decodable<D, E> for Sha256dHash
} }
// Consensus encoding (little-endian) // Consensus encoding (little-endian)
impl<S:SimpleEncoder<E>, E> ConsensusEncodable<S, E> for Sha256dHash { impl_newtype_consensus_encoding!(Hash32)
#[inline] impl_newtype_consensus_encoding!(Hash48)
fn consensus_encode(&self, s: &mut S) -> Result<(), E> { impl_newtype_consensus_encoding!(Hash64)
self.into_uint256().consensus_encode(s) impl_newtype_consensus_encoding!(Sha256dHash)
}
}
impl<D:SimpleDecoder<E>, E> ConsensusDecodable<D, E> for Sha256dHash {
#[inline]
fn consensus_decode(d: &mut D) -> Result<Sha256dHash, E> {
Ok(Sha256dHash(try!(ConsensusDecodable::consensus_decode(d))))
}
}
impl fmt::LowerHex for Sha256dHash { impl fmt::LowerHex for Sha256dHash {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {