From d3815a0399a83a9c649a843e85485d0f979b6305 Mon Sep 17 00:00:00 2001 From: Artur Jamro Date: Thu, 22 Aug 2019 10:11:41 -0700 Subject: [PATCH] Implement serde and equality traits for SecondaryMap --- cranelift/codegen/src/binemit/mod.rs | 2 +- cranelift/codegen/src/ir/stackslot.rs | 4 +- cranelift/codegen/src/value_label.rs | 2 +- cranelift/entity/src/map.rs | 119 +++++++++++++++++++++++--- cranelift/entity/src/primary.rs | 2 +- 5 files changed, 112 insertions(+), 17 deletions(-) diff --git a/cranelift/codegen/src/binemit/mod.rs b/cranelift/codegen/src/binemit/mod.rs index 996f2e4494..ce9321ec19 100644 --- a/cranelift/codegen/src/binemit/mod.rs +++ b/cranelift/codegen/src/binemit/mod.rs @@ -33,7 +33,7 @@ pub type CodeOffset = u32; pub type Addend = i64; /// Relocation kinds for every ISA -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub enum Reloc { /// absolute 4-byte diff --git a/cranelift/codegen/src/ir/stackslot.rs b/cranelift/codegen/src/ir/stackslot.rs index 0101b54f2e..0e1ec4777a 100644 --- a/cranelift/codegen/src/ir/stackslot.rs +++ b/cranelift/codegen/src/ir/stackslot.rs @@ -101,7 +101,7 @@ impl fmt::Display for StackSlotKind { } /// Contents of a stack slot. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct StackSlotData { /// The kind of stack slot. @@ -154,7 +154,7 @@ impl fmt::Display for StackSlotData { /// Stack frame manager. /// /// Keep track of all the stack slots used by a function. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct StackSlots { /// All allocated stack slots. diff --git a/cranelift/codegen/src/value_label.rs b/cranelift/codegen/src/value_label.rs index c31067cc24..60ea7b342a 100644 --- a/cranelift/codegen/src/value_label.rs +++ b/cranelift/codegen/src/value_label.rs @@ -12,7 +12,7 @@ use std::vec::Vec; use serde::{Deserialize, Serialize}; /// Value location range. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct ValueLocRange { /// The ValueLoc containing a ValueLabel during this range. diff --git a/cranelift/entity/src/map.rs b/cranelift/entity/src/map.rs index a0d31a4309..bb1b94aeca 100644 --- a/cranelift/entity/src/map.rs +++ b/cranelift/entity/src/map.rs @@ -6,6 +6,13 @@ use crate::EntityRef; use core::marker::PhantomData; use core::ops::{Index, IndexMut}; use core::slice; +#[cfg(feature = "enable-serde")] +use serde::{ + de::{Deserializer, SeqAccess, Visitor}, + ser::{SerializeSeq, Serializer}, + Deserialize, Serialize, +}; +use std::cmp::min; use std::vec::Vec; /// A mapping `K -> V` for densely indexed entity references. @@ -56,23 +63,11 @@ where } } - /// Returns the number of elements in the underlying vector. - /// - /// The number is not necessarily the same as the length of the corresponding PrimaryMap. - pub fn len(&self) -> usize { - self.elems.len() - } - /// Get the element at `k` if it exists. pub fn get(&self, k: K) -> Option<&V> { self.elems.get(k.index()) } - /// Get the default value. - pub fn get_default(&self) -> &V { - &self.default - } - /// Is this map completely empty? pub fn is_empty(&self) -> bool { self.elems.is_empty() @@ -148,6 +143,106 @@ where } } +impl PartialEq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + let min_size = min(self.elems.len(), other.elems.len()); + self.default == other.default + && self.elems[..min_size] == other.elems[..min_size] + && self.elems[min_size..].iter().all(|e| *e == self.default) + && other.elems[min_size..].iter().all(|e| *e == other.default) + } +} + +impl Eq for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Eq, +{ +} + +#[cfg(feature = "enable-serde")] +impl Serialize for SecondaryMap +where + K: EntityRef, + V: Clone + PartialEq + Serialize, +{ + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // TODO: bincode encodes option as "byte for Some/None" and then optionally the content + // TODO: we can actually optimize it by encoding manually bitmask, then elements + let mut elems_cnt = self.elems.len(); + while elems_cnt > 0 && self.elems[elems_cnt - 1] == self.default { + elems_cnt -= 1; + } + let mut seq = serializer.serialize_seq(Some(1 + elems_cnt))?; + seq.serialize_element(&Some(self.default.clone()))?; + for e in self.elems.iter().take(elems_cnt) { + let some_e = Some(e); + seq.serialize_element(if *e == self.default { &None } else { &some_e })?; + } + seq.end() + } +} + +#[cfg(feature = "enable-serde")] +impl<'de, K, V> Deserialize<'de> for SecondaryMap +where + K: EntityRef, + V: Clone + Deserialize<'de>, +{ + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + use std::fmt; + struct SecondaryMapVisitor { + unused: PhantomData V>, + } + + impl<'de, K, V> Visitor<'de> for SecondaryMapVisitor + where + K: EntityRef, + V: Clone + Deserialize<'de>, + { + type Value = SecondaryMap; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct SecondaryMap") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + match seq.next_element()? { + Some(Some(default_val)) => { + let default_val: V = default_val; // compiler can't infer the type + let mut m = SecondaryMap::with_default(default_val.clone()); + let mut idx = 0; + while let Some(val) = seq.next_element()? { + let val: Option<_> = val; // compiler can't infer the type + m[K::new(idx)] = val.unwrap_or_else(|| default_val.clone()); + idx += 1; + } + Ok(m) + } + _ => Err(serde::de::Error::custom("Default value required")), + } + } + } + + deserializer.deserialize_seq(SecondaryMapVisitor { + unused: PhantomData {}, + }) + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/cranelift/entity/src/primary.rs b/cranelift/entity/src/primary.rs index 6734a1f5e5..9cde5e779d 100644 --- a/cranelift/entity/src/primary.rs +++ b/cranelift/entity/src/primary.rs @@ -27,7 +27,7 @@ use std::vec::Vec; /// that it only allows indexing with the distinct `EntityRef` key type, so converting to a /// plain slice would make it easier to use incorrectly. To make a slice of a `PrimaryMap`, use /// `into_boxed_slice`. -#[derive(Debug, Clone, Hash)] +#[derive(Debug, Clone, Hash, PartialEq, Eq)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] pub struct PrimaryMap where