Implement serde and equality traits for SecondaryMap

This commit is contained in:
Artur Jamro
2019-08-22 10:11:41 -07:00
committed by Dan Gohman
parent e736367b8c
commit d3815a0399
5 changed files with 112 additions and 17 deletions

View File

@@ -33,7 +33,7 @@ pub type CodeOffset = u32;
pub type Addend = i64; pub type Addend = i64;
/// Relocation kinds for every ISA /// Relocation kinds for every ISA
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub enum Reloc { pub enum Reloc {
/// absolute 4-byte /// absolute 4-byte

View File

@@ -101,7 +101,7 @@ impl fmt::Display for StackSlotKind {
} }
/// Contents of a stack slot. /// Contents of a stack slot.
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct StackSlotData { pub struct StackSlotData {
/// The kind of stack slot. /// The kind of stack slot.
@@ -154,7 +154,7 @@ impl fmt::Display for StackSlotData {
/// Stack frame manager. /// Stack frame manager.
/// ///
/// Keep track of all the stack slots used by a function. /// 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))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct StackSlots { pub struct StackSlots {
/// All allocated stack slots. /// All allocated stack slots.

View File

@@ -12,7 +12,7 @@ use std::vec::Vec;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Value location range. /// Value location range.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct ValueLocRange { pub struct ValueLocRange {
/// The ValueLoc containing a ValueLabel during this range. /// The ValueLoc containing a ValueLabel during this range.

View File

@@ -6,6 +6,13 @@ use crate::EntityRef;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::ops::{Index, IndexMut}; use core::ops::{Index, IndexMut};
use core::slice; 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; use std::vec::Vec;
/// A mapping `K -> V` for densely indexed entity references. /// 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. /// Get the element at `k` if it exists.
pub fn get(&self, k: K) -> Option<&V> { pub fn get(&self, k: K) -> Option<&V> {
self.elems.get(k.index()) self.elems.get(k.index())
} }
/// Get the default value.
pub fn get_default(&self) -> &V {
&self.default
}
/// Is this map completely empty? /// Is this map completely empty?
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.elems.is_empty() self.elems.is_empty()
@@ -148,6 +143,106 @@ where
} }
} }
impl<K, V> PartialEq for SecondaryMap<K, V>
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<K, V> Eq for SecondaryMap<K, V>
where
K: EntityRef,
V: Clone + PartialEq + Eq,
{
}
#[cfg(feature = "enable-serde")]
impl<K, V> Serialize for SecondaryMap<K, V>
where
K: EntityRef,
V: Clone + PartialEq + Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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<K, V>
where
K: EntityRef,
V: Clone + Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use std::fmt;
struct SecondaryMapVisitor<K, V> {
unused: PhantomData<fn(K) -> V>,
}
impl<'de, K, V> Visitor<'de> for SecondaryMapVisitor<K, V>
where
K: EntityRef,
V: Clone + Deserialize<'de>,
{
type Value = SecondaryMap<K, V>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct SecondaryMap")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@@ -27,7 +27,7 @@ use std::vec::Vec;
/// that it only allows indexing with the distinct `EntityRef` key type, so converting to a /// 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 /// plain slice would make it easier to use incorrectly. To make a slice of a `PrimaryMap`, use
/// `into_boxed_slice`. /// `into_boxed_slice`.
#[derive(Debug, Clone, Hash)] #[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
pub struct PrimaryMap<K, V> pub struct PrimaryMap<K, V>
where where