Merge pull request #4074 from roc-lang/dict-umentation

document why Dict is the way it is
This commit is contained in:
Brian Hicks 2022-09-20 09:58:35 -05:00 committed by GitHub
commit 74552f0bac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -5,6 +5,16 @@ use core::{
mem::{align_of, ManuallyDrop},
};
/// At the moment, Roc's Dict is just an association list. Its lookups are O(n) but
/// we haven't grown such big programs that it's a problem yet!
///
/// We do some things in this data structure that only make sense because the
/// memory is managed in Roc:
///
/// 1. We don't implement an [`IntoIterator`] that iterates over owned values,
/// since Roc owns the memory, not rust.
/// 2. We use a union for [`RocDictItem`] instead of just a struct. See the
/// comment on that data structure for why.
#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct RocDict<K, V>(RocList<RocDictItem<K, V>>);
@ -108,6 +118,26 @@ impl<K: Debug, V: Debug> Debug for RocDict<K, V> {
}
}
/// Roc is constructing these values according to its memory layout rules.
/// Specifically:
///
/// 1. fields with the highest alignment go first
/// 2. then fields are sorted alphabetically
///
/// Taken together, these mean that if we have a value with higher alignment
/// than the key, it'll be first in memory. Otherwise, the key will be first.
/// Fortunately, the total amount of memory doesn't change, so we can use a
/// union and disambiguate by examining the alignment of the key and value.
///
/// However, note that this only makes sense while we're storing KV pairs
/// contiguously in memory. If we separate them at some point, we'll need to
/// change this implementation drastically!
#[derive(Eq)]
union RocDictItem<K, V> {
key_first: ManuallyDrop<KeyFirst<K, V>>,
value_first: ManuallyDrop<ValueFirst<K, V>>,
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(C)]
struct KeyFirst<K, V> {
@ -122,12 +152,6 @@ struct ValueFirst<K, V> {
key: K,
}
#[derive(Eq)]
union RocDictItem<K, V> {
key_first: ManuallyDrop<KeyFirst<K, V>>,
value_first: ManuallyDrop<ValueFirst<K, V>>,
}
impl<K, V> RocDictItem<K, V> {
fn key(&self) -> &K {
if align_of::<K>() >= align_of::<V>() {