Skip to content

Commit

Permalink
Finish.
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Nov 6, 2023
1 parent 547023e commit a4ace19
Show file tree
Hide file tree
Showing 14 changed files with 1,811 additions and 911 deletions.
762 changes: 395 additions & 367 deletions src/symbols/analyzer.rs

Large diffs are not rendered by default.

162 changes: 118 additions & 44 deletions src/symbols/collections.rs
Original file line number Diff line number Diff line change
@@ -1,64 +1,129 @@
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.

#![allow(dead_code)]

use indexmap::IndexMap;
use std::cell::UnsafeCell;
use std::collections::HashMap;

/// A hash map that supports inserting data while holding references to
/// the underlying data at another key. Due to this property, the values
/// in the hashmap can never be replaced or removed. Inserting data at a
/// previously inserted to key will cause a panic.
pub struct AdditiveOnlyMap<K, V> {
// store the values in a box to ensure the references are always stored
// in the same place. Uses an UnsafeCell for faster performance.
data: UnsafeCell<HashMap<K, Box<V>>>,
}
macro_rules! define_map {
($name:ident, $kind:ident) => {
/// A map that supports inserting data while holding references to
/// the underlying data at another key. Due to this property, the values
/// in the hashmap can never be replaced or removed. Inserting data at a
/// previously inserted to key will cause a panic.
pub struct $name<K, V> {
// store the values in a box to ensure the references are always stored
// in the same place. Uses an UnsafeCell for faster performance.
data: UnsafeCell<$kind<K, Box<V>>>,
}

impl<K, V> Default for AdditiveOnlyMap<K, V> {
fn default() -> Self {
Self {
data: Default::default(),
impl<K, V> Default for $name<K, V> {
fn default() -> Self {
Self {
data: Default::default(),
}
}
}
}
}

impl<K, V> AdditiveOnlyMap<K, V> {
#[cfg(test)]
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: UnsafeCell::new(HashMap::with_capacity(capacity)),
impl<K, V> $name<K, V> {
#[cfg(test)]
pub fn with_capacity(capacity: usize) -> Self {
Self {
data: UnsafeCell::new($kind::with_capacity(capacity)),
}
}

pub fn len(&self) -> usize {
let data = unsafe { &*self.data.get() };
data.len()
}
}
}

pub fn len(&self) -> usize {
let data = unsafe { &*self.data.get() };
data.len()
}
impl<K: Eq + std::hash::Hash, V> $name<K, V> {
pub fn take(self) -> $kind<K, Box<V>> {
self.data.into_inner()
}

pub fn contains_key(&self, key: &K) -> bool {
let data = unsafe { &*self.data.get() };
data.contains_key(key)
}

pub fn insert(&self, key: K, value: V) {
let data = unsafe { &mut *self.data.get() };
// assert that we never replace any data
assert!(data.insert(key, Box::new(value)).is_none());
}

pub fn get<'a>(&'a self, key: &K) -> Option<&'a V> {
unsafe {
let data = &*self.data.get();
// this is ok because we never remove from the map
data
.get(key)
.map(|value_box| value_box.as_ref() as *const V)
.map(|raw| &*raw)
}
}
}
};
}

impl<K: Eq + std::hash::Hash, V> AdditiveOnlyMap<K, V> {
pub fn contains_key(&self, key: &K) -> bool {
let data = unsafe { &*self.data.get() };
data.contains_key(key)
}
define_map!(AdditiveOnlyMap, HashMap);
define_map!(AdditiveOnlyIndexMap, IndexMap);

pub fn insert(&self, key: K, value: V) {
let data = unsafe { &mut *self.data.get() };
// assert that we never replace any data
assert!(data.insert(key, Box::new(value)).is_none());
}
macro_rules! define_map_for_copy_values {
($name:ident, $kind:ident) => {
/// An additive hash map for data that is `Copy`. This is slightly more
/// optimized than `AdditiveOnlyMap` because it won't copy the value.
pub struct $name<K, V: Copy> {
data: UnsafeCell<$kind<K, V>>,
}

pub fn get<'a>(&'a self, key: &K) -> Option<&'a V> {
unsafe {
let data = &*self.data.get();
// this is ok because we never remove from the map
data
.get(key)
.map(|value_box| value_box.as_ref() as *const V)
.map(|raw| &*raw)
impl<K, V: Copy> Default for $name<K, V> {
fn default() -> Self {
Self {
data: Default::default(),
}
}
}
}

impl<K, V: Copy> $name<K, V> {
pub fn len(&self) -> usize {
let data = unsafe { &*self.data.get() };
data.len()
}

pub fn take(self) -> $kind<K, V> {
self.data.into_inner()
}
}

impl<K: Eq + std::hash::Hash, V: Copy> $name<K, V> {
pub fn contains_key(&self, key: &K) -> bool {
let data = unsafe { &*self.data.get() };
data.contains_key(key)
}

pub fn insert(&self, key: K, value: V) {
let data = unsafe { &mut *self.data.get() };
data.insert(key, value);
}

pub fn get(&self, key: &K) -> Option<V> {
unsafe {
let data = &*self.data.get();
data.get(key).copied()
}
}
}
};
}

define_map_for_copy_values!(AdditiveOnlyMapForCopyValues, HashMap);
define_map_for_copy_values!(AdditiveOnlyIndexMapForCopyValues, IndexMap);

#[cfg(test)]
mod test {
use super::*;
Expand All @@ -82,4 +147,13 @@ mod test {
assert!(map.contains_key(&99));
assert!(!map.contains_key(&100));
}

#[test]
fn support_copy_map() {
let map: AdditiveOnlyMapForCopyValues<usize, usize> =
AdditiveOnlyMapForCopyValues::default();
map.insert(1, 2);
assert_eq!(map.get(&1), Some(2));
assert_eq!(map.get(&0), None);
}
}
Loading

0 comments on commit a4ace19

Please sign in to comment.