This is an automated email from the ASF dual-hosted git repository.
dheres pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-ballista.git
The following commit(s) were added to refs/heads/main by this push:
new b8bd8fc0 Refactor cache mod, remove linked_hash_map (#918)
b8bd8fc0 is described below
commit b8bd8fc03cafaac09a10dd75cadf3032c2b4afff
Author: Chojan Shang <[email protected]>
AuthorDate: Mon Nov 27 22:13:36 2023 +0800
Refactor cache mod, remove linked_hash_map (#918)
Signed-off-by: Chojan Shang <[email protected]>
---
ballista/cache/Cargo.toml | 1 +
.../backend/policy/lru/hashlink/linked_hash_map.rs | 2215 --------------------
.../cache/src/backend/policy/lru/hashlink/mod.rs | 20 -
.../backend/policy/lru/{hashlink => }/lru_cache.rs | 11 +-
ballista/cache/src/backend/policy/lru/mod.rs | 2 +-
ballista/cache/src/loading_cache/driver.rs | 2 +-
ballista/cache/src/metrics/loading_cache.rs | 2 +-
ballista/core/src/cache_layer/policy/file.rs | 2 +-
8 files changed, 8 insertions(+), 2247 deletions(-)
diff --git a/ballista/cache/Cargo.toml b/ballista/cache/Cargo.toml
index e8ad7552..be89453e 100644
--- a/ballista/cache/Cargo.toml
+++ b/ballista/cache/Cargo.toml
@@ -26,6 +26,7 @@ edition = "2021"
async-trait = "0.1.64"
futures = "0.3"
hashbrown = "0.14"
+hashlink = "0.8.4"
log = "0.4"
parking_lot = "0.12"
tokio = { version = "1.25", features = ["macros", "parking_lot",
"rt-multi-thread", "sync", "time"] }
diff --git a/ballista/cache/src/backend/policy/lru/hashlink/linked_hash_map.rs
b/ballista/cache/src/backend/policy/lru/hashlink/linked_hash_map.rs
deleted file mode 100644
index c7a0c36f..00000000
--- a/ballista/cache/src/backend/policy/lru/hashlink/linked_hash_map.rs
+++ /dev/null
@@ -1,2215 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-/// It's a fork version of hashlink[https://github.com/triplehex/hashlink]
mainly to deal with version
-/// issue of hashbrown. Later we will propose PR to the original hashlink to
update the hashbrown version
-use std::{
- alloc::Layout,
- borrow::Borrow,
- cmp::Ordering,
- fmt,
- hash::{BuildHasher, Hash, Hasher},
- iter::FromIterator,
- marker::PhantomData,
- mem::{self, MaybeUninit},
- ops::{Index, IndexMut},
- ptr::{self, NonNull},
-};
-
-use hashbrown::{hash_map, HashMap};
-
-pub enum TryReserveError {
- CapacityOverflow,
- AllocError { layout: Layout },
-}
-
-/// A version of `HashMap` that has a user controllable order for its entries.
-///
-/// It achieves this by keeping its entries in an internal linked list and
using a `HashMap` to
-/// point at nodes in this linked list.
-///
-/// The order of entries defaults to "insertion order", but the user can also
modify the order of
-/// existing entries by manually moving them to the front or back.
-///
-/// There are two kinds of methods that modify the order of the internal list:
-///
-/// * Methods that have names like `to_front` and `to_back` will
unsurprisingly move an existing
-/// entry to the front or back
-/// * Methods that have the word `insert` will insert a new entry ot the back
of the list, and if
-/// that method might replace an entry, that method will *also move that
existing entry to the
-/// back*.
-pub struct LinkedHashMap<K, V, S = hash_map::DefaultHashBuilder> {
- map: HashMap<NonNull<Node<K, V>>, (), NullHasher>,
- // We need to keep any custom hash builder outside of the HashMap so we
can access it alongside
- // the entry API without mutable aliasing.
- hash_builder: S,
- // Circular linked list of nodes. If `values` is non-null, it will point
to a "guard node"
- // which will never have an initialized key or value, `values.prev` will
contain the last key /
- // value in the list, `values.next` will contain the first key / value in
the list.
- values: Option<NonNull<Node<K, V>>>,
- // *Singly* linked list of free nodes. The `prev` pointers in the free
list should be assumed
- // invalid.
- free: Option<NonNull<Node<K, V>>>,
-}
-
-impl<K, V> LinkedHashMap<K, V> {
- #[inline]
- pub fn new() -> Self {
- Self {
- hash_builder: hash_map::DefaultHashBuilder::default(),
- map: HashMap::with_hasher(NullHasher),
- values: None,
- free: None,
- }
- }
-
- #[inline]
- pub fn with_capacity(capacity: usize) -> Self {
- Self {
- hash_builder: hash_map::DefaultHashBuilder::default(),
- map: HashMap::with_capacity_and_hasher(capacity, NullHasher),
- values: None,
- free: None,
- }
- }
-}
-
-impl<K, V, S> LinkedHashMap<K, V, S> {
- #[inline]
- pub fn with_hasher(hash_builder: S) -> Self {
- Self {
- hash_builder,
- map: HashMap::with_hasher(NullHasher),
- values: None,
- free: None,
- }
- }
-
- #[inline]
- pub fn with_capacity_and_hasher(capacity: usize, hash_builder: S) -> Self {
- Self {
- hash_builder,
- map: HashMap::with_capacity_and_hasher(capacity, NullHasher),
- values: None,
- free: None,
- }
- }
-
- #[inline]
- pub fn reserve(&mut self, additional: usize) {
- self.map.reserve(additional);
- }
-
- #[inline]
- pub fn try_reserve(&mut self, additional: usize) -> Result<(),
TryReserveError> {
- self.map.try_reserve(additional).map_err(|e| match e {
- hashbrown::TryReserveError::CapacityOverflow => {
- TryReserveError::CapacityOverflow
- }
- hashbrown::TryReserveError::AllocError { layout } => {
- TryReserveError::AllocError { layout }
- }
- })
- }
-
- #[inline]
- pub fn len(&self) -> usize {
- self.map.len()
- }
-
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.len() == 0
- }
-
- #[inline]
- pub fn clear(&mut self) {
- self.map.clear();
- if let Some(mut values) = self.values {
- unsafe {
- drop_value_nodes(values);
- values.as_mut().links.value = ValueLinks {
- prev: values,
- next: values,
- };
- }
- }
- }
-
- #[inline]
- pub fn iter(&self) -> Iter<K, V> {
- let (head, tail) = if let Some(values) = self.values {
- unsafe {
- let ValueLinks { next, prev } = values.as_ref().links.value;
- (next.as_ptr(), prev.as_ptr())
- }
- } else {
- (ptr::null_mut(), ptr::null_mut())
- };
-
- Iter {
- head,
- tail,
- remaining: self.len(),
- marker: PhantomData,
- }
- }
-
- #[inline]
- pub fn iter_mut(&mut self) -> IterMut<K, V> {
- let (head, tail) = if let Some(values) = self.values {
- unsafe {
- let ValueLinks { next, prev } = values.as_ref().links.value;
- (Some(next), Some(prev))
- }
- } else {
- (None, None)
- };
-
- IterMut {
- head,
- tail,
- remaining: self.len(),
- marker: PhantomData,
- }
- }
-
- #[inline]
- pub fn drain(&mut self) -> Drain<'_, K, V> {
- unsafe {
- let (head, tail) = if let Some(mut values) = self.values {
- let ValueLinks { next, prev } = values.as_ref().links.value;
- values.as_mut().links.value = ValueLinks {
- next: values,
- prev: values,
- };
- (Some(next), Some(prev))
- } else {
- (None, None)
- };
- let len = self.len();
-
- self.map.clear();
-
- Drain {
- free: (&mut self.free).into(),
- head,
- tail,
- remaining: len,
- marker: PhantomData,
- }
- }
- }
-
- #[inline]
- pub fn keys(&self) -> Keys<K, V> {
- Keys { inner: self.iter() }
- }
-
- #[inline]
- pub fn values(&self) -> Values<K, V> {
- Values { inner: self.iter() }
- }
-
- #[inline]
- pub fn values_mut(&mut self) -> ValuesMut<K, V> {
- ValuesMut {
- inner: self.iter_mut(),
- }
- }
-
- #[inline]
- pub fn front(&self) -> Option<(&K, &V)> {
- if self.is_empty() {
- return None;
- }
- unsafe {
- let front = (*self.values.as_ptr()).links.value.next.as_ptr();
- let (key, value) = (*front).entry_ref();
- Some((key, value))
- }
- }
-
- #[inline]
- pub fn back(&self) -> Option<(&K, &V)> {
- if self.is_empty() {
- return None;
- }
- unsafe {
- let back = &*(*self.values.as_ptr()).links.value.prev.as_ptr();
- let (key, value) = (*back).entry_ref();
- Some((key, value))
- }
- }
-
- #[inline]
- pub fn retain<F>(&mut self, mut f: F)
- where
- F: FnMut(&K, &mut V) -> bool,
- {
- let free = self.free;
- let mut drop_filtered_values = DropFilteredValues {
- free: &mut self.free,
- cur_free: free,
- };
-
- self.map.retain(|&node, _| unsafe {
- let (k, v) = (*node.as_ptr()).entry_mut();
- if f(k, v) {
- true
- } else {
- drop_filtered_values.drop_later(node);
- false
- }
- });
- }
-
- #[inline]
- pub fn hasher(&self) -> &S {
- &self.hash_builder
- }
-
- #[inline]
- pub fn capacity(&self) -> usize {
- self.map.capacity()
- }
-}
-
-impl<K, V, S> LinkedHashMap<K, V, S>
-where
- K: Eq + Hash,
- S: BuildHasher,
-{
- #[inline]
- pub fn entry(&mut self, key: K) -> Entry<'_, K, V, S> {
- match self.raw_entry_mut().from_key(&key) {
- RawEntryMut::Occupied(occupied) => Entry::Occupied(OccupiedEntry {
- key,
- raw_entry: occupied,
- }),
- RawEntryMut::Vacant(vacant) => Entry::Vacant(VacantEntry {
- key,
- raw_entry: vacant,
- }),
- }
- }
-
- #[inline]
- pub fn get<Q>(&self, k: &Q) -> Option<&V>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- self.raw_entry().from_key(k).map(|(_, v)| v)
- }
-
- #[inline]
- pub fn get_key_value<Q>(&self, k: &Q) -> Option<(&K, &V)>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- self.raw_entry().from_key(k)
- }
-
- #[inline]
- pub fn contains_key<Q>(&self, k: &Q) -> bool
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- self.get(k).is_some()
- }
-
- #[inline]
- pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- match self.raw_entry_mut().from_key(k) {
- RawEntryMut::Occupied(occupied) => Some(occupied.into_mut()),
- RawEntryMut::Vacant(_) => None,
- }
- }
-
- /// Inserts the given key / value pair at the *back* of the internal
linked list.
- ///
- /// Returns the previously set value, if one existed prior to this call.
After this call,
- /// calling `LinkedHashMap::back` will return a reference to this key /
value pair.
- #[inline]
- pub fn insert(&mut self, k: K, v: V) -> Option<V> {
- match self.raw_entry_mut().from_key(&k) {
- RawEntryMut::Occupied(mut occupied) => {
- occupied.to_back();
- Some(occupied.replace_value(v))
- }
- RawEntryMut::Vacant(vacant) => {
- vacant.insert(k, v);
- None
- }
- }
- }
-
- /// If the given key is not in this map, inserts the key / value pair at
the *back* of the
- /// internal linked list and returns `None`, otherwise, replaces the
existing value with the
- /// given value *without* moving the entry in the internal linked list and
returns the previous
- /// value.
- #[inline]
- pub fn replace(&mut self, k: K, v: V) -> Option<V> {
- match self.raw_entry_mut().from_key(&k) {
- RawEntryMut::Occupied(mut occupied) =>
Some(occupied.replace_value(v)),
- RawEntryMut::Vacant(vacant) => {
- vacant.insert(k, v);
- None
- }
- }
- }
-
- #[inline]
- pub fn remove<Q>(&mut self, k: &Q) -> Option<V>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- match self.raw_entry_mut().from_key(k) {
- RawEntryMut::Occupied(occupied) => Some(occupied.remove()),
- RawEntryMut::Vacant(_) => None,
- }
- }
-
- #[inline]
- pub fn remove_entry<Q>(&mut self, k: &Q) -> Option<(K, V)>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- match self.raw_entry_mut().from_key(k) {
- RawEntryMut::Occupied(occupied) => Some(occupied.remove_entry()),
- RawEntryMut::Vacant(_) => None,
- }
- }
-
- #[inline]
- pub fn pop_front(&mut self) -> Option<(K, V)> {
- if self.is_empty() {
- return None;
- }
- unsafe {
- let front = (*self.values.as_ptr()).links.value.next;
- match self.map.raw_entry_mut().from_hash(
- hash_key(&self.hash_builder, front.as_ref().key_ref()),
- |k| (*k).as_ref().key_ref().eq(front.as_ref().key_ref()),
- ) {
- hash_map::RawEntryMut::Occupied(occupied) => {
- Some(remove_node(&mut self.free,
occupied.remove_entry().0))
- }
- hash_map::RawEntryMut::Vacant(_) => None,
- }
- }
- }
-
- #[inline]
- pub fn pop_back(&mut self) -> Option<(K, V)> {
- if self.is_empty() {
- return None;
- }
- unsafe {
- let back = (*self.values.as_ptr()).links.value.prev;
- match self
- .map
- .raw_entry_mut()
- .from_hash(hash_key(&self.hash_builder,
back.as_ref().key_ref()), |k| {
- (*k).as_ref().key_ref().eq(back.as_ref().key_ref())
- }) {
- hash_map::RawEntryMut::Occupied(occupied) => {
- Some(remove_node(&mut self.free,
occupied.remove_entry().0))
- }
- hash_map::RawEntryMut::Vacant(_) => None,
- }
- }
- }
-
- /// If an entry with this key exists, move it to the front of the list and
return a reference to
- /// the value.
- #[inline]
- pub fn to_front<Q>(&mut self, k: &Q) -> Option<&mut V>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- match self.raw_entry_mut().from_key(k) {
- RawEntryMut::Occupied(mut occupied) => {
- occupied.to_front();
- Some(occupied.into_mut())
- }
- RawEntryMut::Vacant(_) => None,
- }
- }
-
- /// If an entry with this key exists, move it to the back of the list and
return a reference to
- /// the value.
- #[inline]
- pub fn to_back<Q>(&mut self, k: &Q) -> Option<&mut V>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- match self.raw_entry_mut().from_key(k) {
- RawEntryMut::Occupied(mut occupied) => {
- occupied.to_back();
- Some(occupied.into_mut())
- }
- RawEntryMut::Vacant(_) => None,
- }
- }
-
- #[inline]
- pub fn shrink_to_fit(&mut self) {
- unsafe {
- let len = self.map.len();
- if len != self.map.capacity() {
- self.map = HashMap::with_hasher(NullHasher);
- self.map.reserve(len);
-
- if let Some(guard) = self.values {
- let mut cur = guard.as_ref().links.value.next;
- while cur != guard {
- let hash = hash_key(&self.hash_builder,
cur.as_ref().key_ref());
- match self.map.raw_entry_mut().from_hash(hash, |k| {
- (*k).as_ref().key_ref().eq(cur.as_ref().key_ref())
- }) {
- hash_map::RawEntryMut::Occupied(_) =>
unreachable!(),
- hash_map::RawEntryMut::Vacant(vacant) => {
- let hash_builder = &self.hash_builder;
- vacant.insert_with_hasher(hash, cur, (), |k| {
- hash_key(hash_builder,
(*k).as_ref().key_ref())
- });
- }
- }
- cur = cur.as_ref().links.value.next;
- }
- }
- }
-
- drop_free_nodes(self.free);
- self.free = None;
- }
- }
-
- pub fn retain_with_order<F>(&mut self, mut f: F)
- where
- F: FnMut(&K, &mut V) -> bool,
- {
- let free = self.free;
- let mut drop_filtered_values = DropFilteredValues {
- free: &mut self.free,
- cur_free: free,
- };
-
- if let Some(values) = self.values {
- unsafe {
- let mut cur = values.as_ref().links.value.next;
- while cur != values {
- let next = cur.as_ref().links.value.next;
- let filter = {
- let (k, v) = (*cur.as_ptr()).entry_mut();
- !f(k, v)
- };
- if filter {
- let k = (*cur.as_ptr()).key_ref();
- let hash = hash_key(&self.hash_builder, k);
- match self
- .map
- .raw_entry_mut()
- .from_hash(hash, |o| (*o).as_ref().key_ref().eq(k))
- {
- hash_map::RawEntryMut::Occupied(entry) => {
- entry.remove();
- drop_filtered_values.drop_later(cur);
- }
- hash_map::RawEntryMut::Vacant(_) => unreachable!(),
- }
- }
- cur = next;
- }
- }
- }
- }
-}
-
-impl<K, V, S> LinkedHashMap<K, V, S>
-where
- S: BuildHasher,
-{
- #[inline]
- pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> {
- RawEntryBuilder {
- hash_builder: &self.hash_builder,
- entry: self.map.raw_entry(),
- }
- }
-
- #[inline]
- pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> {
- RawEntryBuilderMut {
- hash_builder: &self.hash_builder,
- values: &mut self.values,
- free: &mut self.free,
- entry: self.map.raw_entry_mut(),
- }
- }
-}
-
-impl<K, V, S> Default for LinkedHashMap<K, V, S>
-where
- S: Default,
-{
- #[inline]
- fn default() -> Self {
- Self::with_hasher(S::default())
- }
-}
-
-impl<K: Hash + Eq, V, S: BuildHasher + Default> FromIterator<(K, V)>
- for LinkedHashMap<K, V, S>
-{
- #[inline]
- fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
- let iter = iter.into_iter();
- let mut map = Self::with_capacity_and_hasher(iter.size_hint().0,
S::default());
- map.extend(iter);
- map
- }
-}
-
-impl<K, V, S> fmt::Debug for LinkedHashMap<K, V, S>
-where
- K: fmt::Debug,
- V: fmt::Debug,
-{
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.debug_map().entries(self).finish()
- }
-}
-
-impl<K: Hash + Eq, V: PartialEq, S: BuildHasher> PartialEq for
LinkedHashMap<K, V, S> {
- #[inline]
- fn eq(&self, other: &Self) -> bool {
- self.len() == other.len() && self.iter().eq(other)
- }
-}
-
-impl<K: Hash + Eq, V: Eq, S: BuildHasher> Eq for LinkedHashMap<K, V, S> {}
-
-impl<K: Hash + Eq + PartialOrd, V: PartialOrd, S: BuildHasher> PartialOrd
- for LinkedHashMap<K, V, S>
-{
- #[inline]
- fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- self.iter().partial_cmp(other)
- }
-
- #[inline]
- fn lt(&self, other: &Self) -> bool {
- self.iter().lt(other)
- }
-
- #[inline]
- fn le(&self, other: &Self) -> bool {
- self.iter().le(other)
- }
-
- #[inline]
- fn ge(&self, other: &Self) -> bool {
- self.iter().ge(other)
- }
-
- #[inline]
- fn gt(&self, other: &Self) -> bool {
- self.iter().gt(other)
- }
-}
-
-impl<K: Hash + Eq + Ord, V: Ord, S: BuildHasher> Ord for LinkedHashMap<K, V,
S> {
- #[inline]
- fn cmp(&self, other: &Self) -> Ordering {
- self.iter().cmp(other)
- }
-}
-
-impl<K: Hash + Eq, V: Hash, S: BuildHasher> Hash for LinkedHashMap<K, V, S> {
- #[inline]
- fn hash<H: Hasher>(&self, h: &mut H) {
- for e in self.iter() {
- e.hash(h);
- }
- }
-}
-
-impl<K, V, S> Drop for LinkedHashMap<K, V, S> {
- #[inline]
- fn drop(&mut self) {
- unsafe {
- if let Some(values) = self.values {
- drop_value_nodes(values);
- let _ = Box::from_raw(values.as_ptr());
- }
- drop_free_nodes(self.free);
- }
- }
-}
-
-unsafe impl<K: Send, V: Send, S: Send> Send for LinkedHashMap<K, V, S> {}
-unsafe impl<K: Sync, V: Sync, S: Sync> Sync for LinkedHashMap<K, V, S> {}
-
-impl<'a, K, V, S, Q> Index<&'a Q> for LinkedHashMap<K, V, S>
-where
- K: Hash + Eq + Borrow<Q>,
- S: BuildHasher,
- Q: Eq + Hash + ?Sized,
-{
- type Output = V;
-
- #[inline]
- fn index(&self, index: &'a Q) -> &V {
- self.get(index).expect("no entry found for key")
- }
-}
-
-impl<'a, K, V, S, Q> IndexMut<&'a Q> for LinkedHashMap<K, V, S>
-where
- K: Hash + Eq + Borrow<Q>,
- S: BuildHasher,
- Q: Eq + Hash + ?Sized,
-{
- #[inline]
- fn index_mut(&mut self, index: &'a Q) -> &mut V {
- self.get_mut(index).expect("no entry found for key")
- }
-}
-
-impl<K: Hash + Eq + Clone, V: Clone, S: BuildHasher + Clone> Clone
- for LinkedHashMap<K, V, S>
-{
- #[inline]
- fn clone(&self) -> Self {
- let mut map = Self::with_hasher(self.hash_builder.clone());
- map.extend(self.iter().map(|(k, v)| (k.clone(), v.clone())));
- map
- }
-}
-
-impl<K: Hash + Eq, V, S: BuildHasher> Extend<(K, V)> for LinkedHashMap<K, V,
S> {
- #[inline]
- fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
- for (k, v) in iter {
- self.insert(k, v);
- }
- }
-}
-
-impl<'a, K, V, S> Extend<(&'a K, &'a V)> for LinkedHashMap<K, V, S>
-where
- K: 'a + Hash + Eq + Copy,
- V: 'a + Copy,
- S: BuildHasher,
-{
- #[inline]
- fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
- for (&k, &v) in iter {
- self.insert(k, v);
- }
- }
-}
-
-pub enum Entry<'a, K, V, S> {
- Occupied(OccupiedEntry<'a, K, V>),
- Vacant(VacantEntry<'a, K, V, S>),
-}
-
-impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for Entry<'_, K, V, S> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- Entry::Vacant(ref v) => f.debug_tuple("Entry").field(v).finish(),
- Entry::Occupied(ref o) => f.debug_tuple("Entry").field(o).finish(),
- }
- }
-}
-
-impl<'a, K, V, S> Entry<'a, K, V, S> {
- /// If this entry is vacant, inserts a new entry with the given value and
returns a reference to
- /// it.
- ///
- /// If this entry is occupied, this method *moves the occupied entry to
the back of the internal
- /// linked list* and returns a reference to the existing value.
- #[inline]
- pub fn or_insert(self, default: V) -> &'a mut V
- where
- K: Hash,
- S: BuildHasher,
- {
- match self {
- Entry::Occupied(mut entry) => {
- entry.to_back();
- entry.into_mut()
- }
- Entry::Vacant(entry) => entry.insert(default),
- }
- }
-
- /// Similar to `Entry::or_insert`, but accepts a function to construct a
new value if this entry
- /// is vacant.
- #[inline]
- pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V
- where
- K: Hash,
- S: BuildHasher,
- {
- match self {
- Entry::Occupied(mut entry) => {
- entry.to_back();
- entry.into_mut()
- }
- Entry::Vacant(entry) => entry.insert(default()),
- }
- }
-
- #[inline]
- pub fn key(&self) -> &K {
- match *self {
- Entry::Occupied(ref entry) => entry.key(),
- Entry::Vacant(ref entry) => entry.key(),
- }
- }
-
- #[inline]
- pub fn and_modify<F>(self, f: F) -> Self
- where
- F: FnOnce(&mut V),
- {
- match self {
- Entry::Occupied(mut entry) => {
- f(entry.get_mut());
- Entry::Occupied(entry)
- }
- Entry::Vacant(entry) => Entry::Vacant(entry),
- }
- }
-}
-
-pub struct OccupiedEntry<'a, K, V> {
- key: K,
- raw_entry: RawOccupiedEntryMut<'a, K, V>,
-}
-
-impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for OccupiedEntry<'_, K, V> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("OccupiedEntry")
- .field("key", self.key())
- .field("value", self.get())
- .finish()
- }
-}
-
-impl<'a, K, V> OccupiedEntry<'a, K, V> {
- #[inline]
- pub fn key(&self) -> &K {
- self.raw_entry.key()
- }
-
- #[inline]
- pub fn remove_entry(self) -> (K, V) {
- self.raw_entry.remove_entry()
- }
-
- #[inline]
- pub fn get(&self) -> &V {
- self.raw_entry.get()
- }
-
- #[inline]
- pub fn get_mut(&mut self) -> &mut V {
- self.raw_entry.get_mut()
- }
-
- #[inline]
- pub fn into_mut(self) -> &'a mut V {
- self.raw_entry.into_mut()
- }
-
- #[inline]
- pub fn to_back(&mut self) {
- self.raw_entry.to_back()
- }
-
- #[inline]
- pub fn to_front(&mut self) {
- self.raw_entry.to_front()
- }
-
- /// Replaces this entry's value with the provided value.
- ///
- /// Similarly to `LinkedHashMap::insert`, this moves the existing entry to
the back of the
- /// internal linked list.
- #[inline]
- pub fn insert(&mut self, value: V) -> V {
- self.raw_entry.to_back();
- self.raw_entry.replace_value(value)
- }
-
- #[inline]
- pub fn remove(self) -> V {
- self.raw_entry.remove()
- }
-
- /// Similar to `OccupiedEntry::replace_entry`, but *does* move the entry
to the back of the
- /// internal linked list.
- #[inline]
- pub fn insert_entry(mut self, value: V) -> (K, V) {
- self.raw_entry.to_back();
- self.replace_entry(value)
- }
-
- /// Replaces the entry's key with the key provided to
`LinkedHashMap::entry`, and replaces the
- /// entry's value with the given `value` parameter.
- ///
- /// Does *not* move the entry to the back of the internal linked list.
- pub fn replace_entry(mut self, value: V) -> (K, V) {
- let old_key = mem::replace(self.raw_entry.key_mut(), self.key);
- let old_value = mem::replace(self.raw_entry.get_mut(), value);
- (old_key, old_value)
- }
-
- /// Replaces this entry's key with the key provided to
`LinkedHashMap::entry`.
- ///
- /// Does *not* move the entry to the back of the internal linked list.
- #[inline]
- pub fn replace_key(mut self) -> K {
- mem::replace(self.raw_entry.key_mut(), self.key)
- }
-}
-
-pub struct VacantEntry<'a, K, V, S> {
- key: K,
- raw_entry: RawVacantEntryMut<'a, K, V, S>,
-}
-
-impl<K: fmt::Debug, V, S> fmt::Debug for VacantEntry<'_, K, V, S> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_tuple("VacantEntry").field(self.key()).finish()
- }
-}
-
-impl<'a, K, V, S> VacantEntry<'a, K, V, S> {
- #[inline]
- pub fn key(&self) -> &K {
- &self.key
- }
-
- #[inline]
- pub fn into_key(self) -> K {
- self.key
- }
-
- /// Insert's the key for this vacant entry paired with the given value as
a new entry at the
- /// *back* of the internal linked list.
- #[inline]
- pub fn insert(self, value: V) -> &'a mut V
- where
- K: Hash,
- S: BuildHasher,
- {
- self.raw_entry.insert(self.key, value).1
- }
-}
-
-pub struct RawEntryBuilder<'a, K, V, S> {
- hash_builder: &'a S,
- entry: hash_map::RawEntryBuilder<'a, NonNull<Node<K, V>>, (), NullHasher>,
-}
-
-impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S>
-where
- S: BuildHasher,
-{
- #[inline]
- pub fn from_key<Q>(self, k: &Q) -> Option<(&'a K, &'a V)>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- let hash = hash_key(self.hash_builder, k);
- self.from_key_hashed_nocheck(hash, k)
- }
-
- #[inline]
- pub fn from_key_hashed_nocheck<Q>(self, hash: u64, k: &Q) -> Option<(&'a
K, &'a V)>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- self.from_hash(hash, move |o| k.eq(o.borrow()))
- }
-
- #[inline]
- pub fn from_hash(
- self,
- hash: u64,
- mut is_match: impl FnMut(&K) -> bool,
- ) -> Option<(&'a K, &'a V)> {
- unsafe {
- let node = *self
- .entry
- .from_hash(hash, move |k| is_match((*k).as_ref().key_ref()))?
- .0;
-
- let (key, value) = (*node.as_ptr()).entry_ref();
- Some((key, value))
- }
- }
-}
-
-unsafe impl<'a, K, V, S> Send for RawEntryBuilder<'a, K, V, S>
-where
- K: Send,
- V: Send,
- S: Send,
-{
-}
-
-unsafe impl<'a, K, V, S> Sync for RawEntryBuilder<'a, K, V, S>
-where
- K: Sync,
- V: Sync,
- S: Sync,
-{
-}
-
-pub struct RawEntryBuilderMut<'a, K, V, S> {
- hash_builder: &'a S,
- values: &'a mut Option<NonNull<Node<K, V>>>,
- free: &'a mut Option<NonNull<Node<K, V>>>,
- entry: hash_map::RawEntryBuilderMut<'a, NonNull<Node<K, V>>, (),
NullHasher>,
-}
-
-impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S>
-where
- S: BuildHasher,
-{
- #[inline]
- pub fn from_key<Q>(self, k: &Q) -> RawEntryMut<'a, K, V, S>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- let hash = hash_key(self.hash_builder, k);
- self.from_key_hashed_nocheck(hash, k)
- }
-
- #[inline]
- pub fn from_key_hashed_nocheck<Q>(self, hash: u64, k: &Q) ->
RawEntryMut<'a, K, V, S>
- where
- K: Borrow<Q>,
- Q: Hash + Eq + ?Sized,
- {
- self.from_hash(hash, move |o| k.eq(o.borrow()))
- }
-
- #[inline]
- pub fn from_hash(
- self,
- hash: u64,
- mut is_match: impl FnMut(&K) -> bool,
- ) -> RawEntryMut<'a, K, V, S> {
- let entry = self
- .entry
- .from_hash(hash, move |k| is_match(unsafe {
(*k).as_ref().key_ref() }));
-
- match entry {
- hash_map::RawEntryMut::Occupied(occupied) => {
- RawEntryMut::Occupied(RawOccupiedEntryMut {
- free: self.free,
- values: self.values,
- entry: occupied,
- })
- }
- hash_map::RawEntryMut::Vacant(vacant) => {
- RawEntryMut::Vacant(RawVacantEntryMut {
- hash_builder: self.hash_builder,
- values: self.values,
- free: self.free,
- entry: vacant,
- })
- }
- }
- }
-}
-
-unsafe impl<'a, K, V, S> Send for RawEntryBuilderMut<'a, K, V, S>
-where
- K: Send,
- V: Send,
- S: Send,
-{
-}
-
-unsafe impl<'a, K, V, S> Sync for RawEntryBuilderMut<'a, K, V, S>
-where
- K: Sync,
- V: Sync,
- S: Sync,
-{
-}
-
-pub enum RawEntryMut<'a, K, V, S> {
- Occupied(RawOccupiedEntryMut<'a, K, V>),
- Vacant(RawVacantEntryMut<'a, K, V, S>),
-}
-
-impl<'a, K, V, S> RawEntryMut<'a, K, V, S> {
- /// Similarly to `Entry::or_insert`, if this entry is occupied, it will
move the existing entry
- /// to the back of the internal linked list.
- #[inline]
- pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a
mut V)
- where
- K: Hash,
- S: BuildHasher,
- {
- match self {
- RawEntryMut::Occupied(mut entry) => {
- entry.to_back();
- entry.into_key_value()
- }
- RawEntryMut::Vacant(entry) => entry.insert(default_key,
default_val),
- }
- }
-
- /// Similarly to `Entry::or_insert_with`, if this entry is occupied, it
will move the existing
- /// entry to the back of the internal linked list.
- #[inline]
- pub fn or_insert_with<F>(self, default: F) -> (&'a mut K, &'a mut V)
- where
- F: FnOnce() -> (K, V),
- K: Hash,
- S: BuildHasher,
- {
- match self {
- RawEntryMut::Occupied(mut entry) => {
- entry.to_back();
- entry.into_key_value()
- }
- RawEntryMut::Vacant(entry) => {
- let (k, v) = default();
- entry.insert(k, v)
- }
- }
- }
-
- #[inline]
- pub fn and_modify<F>(self, f: F) -> Self
- where
- F: FnOnce(&mut K, &mut V),
- {
- match self {
- RawEntryMut::Occupied(mut entry) => {
- {
- let (k, v) = entry.get_key_value_mut();
- f(k, v);
- }
- RawEntryMut::Occupied(entry)
- }
- RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry),
- }
- }
-}
-
-pub struct RawOccupiedEntryMut<'a, K, V> {
- free: &'a mut Option<NonNull<Node<K, V>>>,
- values: &'a mut Option<NonNull<Node<K, V>>>,
- entry: hash_map::RawOccupiedEntryMut<'a, NonNull<Node<K, V>>, (),
NullHasher>,
-}
-
-impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> {
- #[inline]
- pub fn key(&self) -> &K {
- self.get_key_value().0
- }
-
- #[inline]
- pub fn key_mut(&mut self) -> &mut K {
- self.get_key_value_mut().0
- }
-
- #[inline]
- pub fn into_key(self) -> &'a mut K {
- self.into_key_value().0
- }
-
- #[inline]
- pub fn get(&self) -> &V {
- self.get_key_value().1
- }
-
- #[inline]
- pub fn get_mut(&mut self) -> &mut V {
- self.get_key_value_mut().1
- }
-
- #[inline]
- pub fn into_mut(self) -> &'a mut V {
- self.into_key_value().1
- }
-
- #[inline]
- pub fn get_key_value(&self) -> (&K, &V) {
- unsafe {
- let node = *self.entry.key();
- let (key, value) = (*node.as_ptr()).entry_ref();
- (key, value)
- }
- }
-
- #[inline]
- pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) {
- unsafe {
- let node = *self.entry.key_mut();
- let (key, value) = (*node.as_ptr()).entry_mut();
- (key, value)
- }
- }
-
- #[inline]
- pub fn into_key_value(self) -> (&'a mut K, &'a mut V) {
- unsafe {
- let node = *self.entry.into_key();
- let (key, value) = (*node.as_ptr()).entry_mut();
- (key, value)
- }
- }
-
- #[inline]
- pub fn to_back(&mut self) {
- unsafe {
- let node = *self.entry.key_mut();
- detach_node(node);
- attach_before(node, NonNull::new_unchecked(self.values.as_ptr()));
- }
- }
-
- #[inline]
- pub fn to_front(&mut self) {
- unsafe {
- let node = *self.entry.key_mut();
- detach_node(node);
- attach_before(node, (*self.values.as_ptr()).links.value.next);
- }
- }
-
- #[inline]
- pub fn replace_value(&mut self, value: V) -> V {
- unsafe {
- let mut node = *self.entry.key_mut();
- mem::replace(&mut node.as_mut().entry_mut().1, value)
- }
- }
-
- #[inline]
- pub fn replace_key(&mut self, key: K) -> K {
- unsafe {
- let mut node = *self.entry.key_mut();
- mem::replace(&mut node.as_mut().entry_mut().0, key)
- }
- }
-
- #[inline]
- pub fn remove(self) -> V {
- self.remove_entry().1
- }
-
- #[inline]
- pub fn remove_entry(self) -> (K, V) {
- let node = self.entry.remove_entry().0;
- unsafe { remove_node(self.free, node) }
- }
-}
-
-pub struct RawVacantEntryMut<'a, K, V, S> {
- hash_builder: &'a S,
- values: &'a mut Option<NonNull<Node<K, V>>>,
- free: &'a mut Option<NonNull<Node<K, V>>>,
- entry: hash_map::RawVacantEntryMut<'a, NonNull<Node<K, V>>, (),
NullHasher>,
-}
-
-impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> {
- #[inline]
- pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V)
- where
- K: Hash,
- S: BuildHasher,
- {
- let hash = hash_key(self.hash_builder, &key);
- self.insert_hashed_nocheck(hash, key, value)
- }
-
- #[inline]
- pub fn insert_hashed_nocheck(
- self,
- hash: u64,
- key: K,
- value: V,
- ) -> (&'a mut K, &'a mut V)
- where
- K: Hash,
- S: BuildHasher,
- {
- let hash_builder = self.hash_builder;
- self.insert_with_hasher(hash, key, value, |k| hash_key(hash_builder,
k))
- }
-
- #[inline]
- pub fn insert_with_hasher(
- self,
- hash: u64,
- key: K,
- value: V,
- hasher: impl Fn(&K) -> u64,
- ) -> (&'a mut K, &'a mut V)
- where
- S: BuildHasher,
- {
- unsafe {
- ensure_guard_node(self.values);
- let mut new_node = allocate_node(self.free);
- new_node.as_mut().put_entry((key, value));
- attach_before(new_node,
NonNull::new_unchecked(self.values.as_ptr()));
-
- let node = *self
- .entry
- .insert_with_hasher(hash, new_node, (), move |k| {
- hasher((*k).as_ref().key_ref())
- })
- .0;
-
- let (key, value) = (*node.as_ptr()).entry_mut();
- (key, value)
- }
- }
-}
-
-impl<K, V, S> fmt::Debug for RawEntryBuilderMut<'_, K, V, S> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RawEntryBuilder").finish()
- }
-}
-
-impl<K: fmt::Debug, V: fmt::Debug, S> fmt::Debug for RawEntryMut<'_, K, V, S> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- RawEntryMut::Vacant(ref v) =>
f.debug_tuple("RawEntry").field(v).finish(),
- RawEntryMut::Occupied(ref o) =>
f.debug_tuple("RawEntry").field(o).finish(),
- }
- }
-}
-
-impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for RawOccupiedEntryMut<'_, K,
V> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RawOccupiedEntryMut")
- .field("key", self.key())
- .field("value", self.get())
- .finish()
- }
-}
-
-impl<K, V, S> fmt::Debug for RawVacantEntryMut<'_, K, V, S> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RawVacantEntryMut").finish()
- }
-}
-
-impl<K, V, S> fmt::Debug for RawEntryBuilder<'_, K, V, S> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("RawEntryBuilder").finish()
- }
-}
-
-unsafe impl<'a, K, V> Send for RawOccupiedEntryMut<'a, K, V>
-where
- K: Send,
- V: Send,
-{
-}
-
-unsafe impl<'a, K, V> Sync for RawOccupiedEntryMut<'a, K, V>
-where
- K: Sync,
- V: Sync,
-{
-}
-
-unsafe impl<'a, K, V, S> Send for RawVacantEntryMut<'a, K, V, S>
-where
- K: Send,
- V: Send,
- S: Send,
-{
-}
-
-unsafe impl<'a, K, V, S> Sync for RawVacantEntryMut<'a, K, V, S>
-where
- K: Sync,
- V: Sync,
- S: Sync,
-{
-}
-
-pub struct Iter<'a, K, V> {
- head: *const Node<K, V>,
- tail: *const Node<K, V>,
- remaining: usize,
- marker: PhantomData<(&'a K, &'a V)>,
-}
-
-pub struct IterMut<'a, K, V> {
- head: Option<NonNull<Node<K, V>>>,
- tail: Option<NonNull<Node<K, V>>>,
- remaining: usize,
- marker: PhantomData<(&'a K, &'a mut V)>,
-}
-
-pub struct IntoIter<K, V> {
- head: Option<NonNull<Node<K, V>>>,
- tail: Option<NonNull<Node<K, V>>>,
- remaining: usize,
- marker: PhantomData<(K, V)>,
-}
-
-pub struct Drain<'a, K, V> {
- free: NonNull<Option<NonNull<Node<K, V>>>>,
- head: Option<NonNull<Node<K, V>>>,
- tail: Option<NonNull<Node<K, V>>>,
- remaining: usize,
- // We want `Drain` to be covariant
- marker: PhantomData<(K, V, &'a LinkedHashMap<K, V>)>,
-}
-
-impl<K, V> IterMut<'_, K, V> {
- #[inline]
- pub(crate) fn iter(&self) -> Iter<'_, K, V> {
- Iter {
- head: self.head.as_ptr(),
- tail: self.tail.as_ptr(),
- remaining: self.remaining,
- marker: PhantomData,
- }
- }
-}
-
-impl<K, V> IntoIter<K, V> {
- #[inline]
- pub(crate) fn iter(&self) -> Iter<'_, K, V> {
- Iter {
- head: self.head.as_ptr(),
- tail: self.tail.as_ptr(),
- remaining: self.remaining,
- marker: PhantomData,
- }
- }
-}
-
-impl<K, V> Drain<'_, K, V> {
- #[inline]
- pub(crate) fn iter(&self) -> Iter<'_, K, V> {
- Iter {
- head: self.head.as_ptr(),
- tail: self.tail.as_ptr(),
- remaining: self.remaining,
- marker: PhantomData,
- }
- }
-}
-
-unsafe impl<'a, K, V> Send for Iter<'a, K, V>
-where
- K: Send,
- V: Send,
-{
-}
-
-unsafe impl<'a, K, V> Send for IterMut<'a, K, V>
-where
- K: Send,
- V: Send,
-{
-}
-
-unsafe impl<K, V> Send for IntoIter<K, V>
-where
- K: Send,
- V: Send,
-{
-}
-
-unsafe impl<'a, K, V> Send for Drain<'a, K, V>
-where
- K: Send,
- V: Send,
-{
-}
-
-unsafe impl<'a, K, V> Sync for Iter<'a, K, V>
-where
- K: Sync,
- V: Sync,
-{
-}
-
-unsafe impl<'a, K, V> Sync for IterMut<'a, K, V>
-where
- K: Sync,
- V: Sync,
-{
-}
-
-unsafe impl<K, V> Sync for IntoIter<K, V>
-where
- K: Sync,
- V: Sync,
-{
-}
-
-unsafe impl<'a, K, V> Sync for Drain<'a, K, V>
-where
- K: Sync,
- V: Sync,
-{
-}
-
-impl<'a, K, V> Clone for Iter<'a, K, V> {
- #[inline]
- fn clone(&self) -> Self {
- Iter { ..*self }
- }
-}
-
-impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for Iter<'_, K, V> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.clone()).finish()
- }
-}
-
-impl<K, V> fmt::Debug for IterMut<'_, K, V>
-where
- K: fmt::Debug,
- V: fmt::Debug,
-{
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.iter()).finish()
- }
-}
-
-impl<K, V> fmt::Debug for IntoIter<K, V>
-where
- K: fmt::Debug,
- V: fmt::Debug,
-{
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.iter()).finish()
- }
-}
-
-impl<K, V> fmt::Debug for Drain<'_, K, V>
-where
- K: fmt::Debug,
- V: fmt::Debug,
-{
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.iter()).finish()
- }
-}
-
-impl<'a, K, V> Iterator for Iter<'a, K, V> {
- type Item = (&'a K, &'a V);
-
- #[inline]
- fn next(&mut self) -> Option<(&'a K, &'a V)> {
- if self.remaining == 0 {
- None
- } else {
- self.remaining -= 1;
- unsafe {
- let (key, value) = (*self.head).entry_ref();
- self.head = (*self.head).links.value.next.as_ptr();
- Some((key, value))
- }
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- (self.remaining, Some(self.remaining))
- }
-}
-
-impl<'a, K, V> Iterator for IterMut<'a, K, V> {
- type Item = (&'a K, &'a mut V);
-
- #[inline]
- fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
- if self.remaining == 0 {
- None
- } else {
- self.remaining -= 1;
- unsafe {
- let head = self.head.as_ptr();
- let (key, value) = (*head).entry_mut();
- self.head = Some((*head).links.value.next);
- Some((key, value))
- }
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- (self.remaining, Some(self.remaining))
- }
-}
-
-impl<K, V> Iterator for IntoIter<K, V> {
- type Item = (K, V);
-
- #[inline]
- fn next(&mut self) -> Option<(K, V)> {
- if self.remaining == 0 {
- return None;
- }
- self.remaining -= 1;
- unsafe {
- let head = self.head.as_ptr();
- self.head = Some((*head).links.value.next);
- let mut e = Box::from_raw(head);
- Some(e.take_entry())
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- (self.remaining, Some(self.remaining))
- }
-}
-
-impl<'a, K, V> Iterator for Drain<'a, K, V> {
- type Item = (K, V);
-
- #[inline]
- fn next(&mut self) -> Option<(K, V)> {
- if self.remaining == 0 {
- return None;
- }
- self.remaining -= 1;
- unsafe {
- let mut head = NonNull::new_unchecked(self.head.as_ptr());
- self.head = Some(head.as_ref().links.value.next);
- let entry = head.as_mut().take_entry();
- push_free(self.free.as_mut(), head);
- Some(entry)
- }
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- (self.remaining, Some(self.remaining))
- }
-}
-
-impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> {
- #[inline]
- fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
- if self.remaining == 0 {
- None
- } else {
- self.remaining -= 1;
- unsafe {
- let tail = self.tail;
- self.tail = (*tail).links.value.prev.as_ptr();
- let (key, value) = (*tail).entry_ref();
- Some((key, value))
- }
- }
- }
-}
-
-impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> {
- #[inline]
- fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
- if self.remaining == 0 {
- None
- } else {
- self.remaining -= 1;
- unsafe {
- let tail = self.tail.as_ptr();
- self.tail = Some((*tail).links.value.prev);
- let (key, value) = (*tail).entry_mut();
- Some((key, value))
- }
- }
- }
-}
-
-impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
- #[inline]
- fn next_back(&mut self) -> Option<(K, V)> {
- if self.remaining == 0 {
- return None;
- }
- self.remaining -= 1;
- unsafe {
- let mut e = *Box::from_raw(self.tail.as_ptr());
- self.tail = Some(e.links.value.prev);
- Some(e.take_entry())
- }
- }
-}
-
-impl<'a, K, V> DoubleEndedIterator for Drain<'a, K, V> {
- #[inline]
- fn next_back(&mut self) -> Option<(K, V)> {
- if self.remaining == 0 {
- return None;
- }
- self.remaining -= 1;
- unsafe {
- let mut tail = NonNull::new_unchecked(self.tail.as_ptr());
- self.tail = Some(tail.as_ref().links.value.prev);
- let entry = tail.as_mut().take_entry();
- push_free(&mut *self.free.as_ptr(), tail);
- Some(entry)
- }
- }
-}
-
-impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {}
-
-impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {}
-
-impl<K, V> ExactSizeIterator for IntoIter<K, V> {}
-
-impl<K, V> Drop for IntoIter<K, V> {
- #[inline]
- fn drop(&mut self) {
- for _ in 0..self.remaining {
- unsafe {
- let tail = self.tail.as_ptr();
- self.tail = Some((*tail).links.value.prev);
- (*tail).take_entry();
- let _ = Box::from_raw(tail);
- }
- }
- }
-}
-
-impl<'a, K, V> Drop for Drain<'a, K, V> {
- #[inline]
- fn drop(&mut self) {
- for _ in 0..self.remaining {
- unsafe {
- let mut tail = NonNull::new_unchecked(self.tail.as_ptr());
- self.tail = Some(tail.as_ref().links.value.prev);
- tail.as_mut().take_entry();
- push_free(&mut *self.free.as_ptr(), tail);
- }
- }
- }
-}
-
-pub struct Keys<'a, K, V> {
- inner: Iter<'a, K, V>,
-}
-
-impl<K: fmt::Debug, V> fmt::Debug for Keys<'_, K, V> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.clone()).finish()
- }
-}
-
-impl<'a, K, V> Clone for Keys<'a, K, V> {
- #[inline]
- fn clone(&self) -> Keys<'a, K, V> {
- Keys {
- inner: self.inner.clone(),
- }
- }
-}
-
-impl<'a, K, V> Iterator for Keys<'a, K, V> {
- type Item = &'a K;
-
- #[inline]
- fn next(&mut self) -> Option<&'a K> {
- self.inner.next().map(|e| e.0)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
- }
-}
-
-impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a K> {
- self.inner.next_back().map(|e| e.0)
- }
-}
-
-impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
- #[inline]
- fn len(&self) -> usize {
- self.inner.len()
- }
-}
-
-pub struct Values<'a, K, V> {
- inner: Iter<'a, K, V>,
-}
-
-impl<K, V> Clone for Values<'_, K, V> {
- #[inline]
- fn clone(&self) -> Self {
- Values {
- inner: self.inner.clone(),
- }
- }
-}
-
-impl<K, V: fmt::Debug> fmt::Debug for Values<'_, K, V> {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.clone()).finish()
- }
-}
-
-impl<'a, K, V> Iterator for Values<'a, K, V> {
- type Item = &'a V;
-
- #[inline]
- fn next(&mut self) -> Option<&'a V> {
- self.inner.next().map(|e| e.1)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
- }
-}
-
-impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a V> {
- self.inner.next_back().map(|e| e.1)
- }
-}
-
-impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
- #[inline]
- fn len(&self) -> usize {
- self.inner.len()
- }
-}
-
-pub struct ValuesMut<'a, K, V> {
- inner: IterMut<'a, K, V>,
-}
-
-impl<K, V> fmt::Debug for ValuesMut<'_, K, V>
-where
- K: fmt::Debug,
- V: fmt::Debug,
-{
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_list().entries(self.inner.iter()).finish()
- }
-}
-
-impl<'a, K, V> Iterator for ValuesMut<'a, K, V> {
- type Item = &'a mut V;
-
- #[inline]
- fn next(&mut self) -> Option<&'a mut V> {
- self.inner.next().map(|e| e.1)
- }
-
- #[inline]
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.inner.size_hint()
- }
-}
-
-impl<'a, K, V> DoubleEndedIterator for ValuesMut<'a, K, V> {
- #[inline]
- fn next_back(&mut self) -> Option<&'a mut V> {
- self.inner.next_back().map(|e| e.1)
- }
-}
-
-impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
- #[inline]
- fn len(&self) -> usize {
- self.inner.len()
- }
-}
-
-impl<'a, K, V, S> IntoIterator for &'a LinkedHashMap<K, V, S> {
- type Item = (&'a K, &'a V);
- type IntoIter = Iter<'a, K, V>;
-
- #[inline]
- fn into_iter(self) -> Iter<'a, K, V> {
- self.iter()
- }
-}
-
-impl<'a, K, V, S> IntoIterator for &'a mut LinkedHashMap<K, V, S> {
- type Item = (&'a K, &'a mut V);
- type IntoIter = IterMut<'a, K, V>;
-
- #[inline]
- fn into_iter(self) -> IterMut<'a, K, V> {
- self.iter_mut()
- }
-}
-
-impl<K, V, S> IntoIterator for LinkedHashMap<K, V, S> {
- type Item = (K, V);
- type IntoIter = IntoIter<K, V>;
-
- #[inline]
- fn into_iter(mut self) -> IntoIter<K, V> {
- unsafe {
- let (head, tail) = if let Some(values) = self.values {
- let ValueLinks {
- next: head,
- prev: tail,
- } = values.as_ref().links.value;
-
- let _ = Box::from_raw(self.values.as_ptr());
- self.values = None;
-
- (Some(head), Some(tail))
- } else {
- (None, None)
- };
- let len = self.len();
-
- drop_free_nodes(self.free);
- self.free = None;
-
- self.map.clear();
-
- IntoIter {
- head,
- tail,
- remaining: len,
- marker: PhantomData,
- }
- }
- }
-}
-
-// A ZST that asserts that the inner HashMap will not do its own key hashing
-struct NullHasher;
-
-impl BuildHasher for NullHasher {
- type Hasher = Self;
-
- #[inline]
- fn build_hasher(&self) -> Self {
- Self
- }
-}
-
-impl Hasher for NullHasher {
- #[inline]
- fn write(&mut self, _bytes: &[u8]) {
- unreachable!("inner map should not be using its built-in hasher")
- }
-
- #[inline]
- fn finish(&self) -> u64 {
- unreachable!("inner map should not be using its built-in hasher")
- }
-}
-
-struct ValueLinks<K, V> {
- next: NonNull<Node<K, V>>,
- prev: NonNull<Node<K, V>>,
-}
-
-impl<K, V> Clone for ValueLinks<K, V> {
- #[inline]
- fn clone(&self) -> Self {
- *self
- }
-}
-
-impl<K, V> Copy for ValueLinks<K, V> {}
-
-struct FreeLink<K, V> {
- next: Option<NonNull<Node<K, V>>>,
-}
-
-impl<K, V> Clone for FreeLink<K, V> {
- #[inline]
- fn clone(&self) -> Self {
- *self
- }
-}
-
-impl<K, V> Copy for FreeLink<K, V> {}
-
-union Links<K, V> {
- value: ValueLinks<K, V>,
- free: FreeLink<K, V>,
-}
-
-struct Node<K, V> {
- entry: MaybeUninit<(K, V)>,
- links: Links<K, V>,
-}
-
-impl<K, V> Node<K, V> {
- #[inline]
- unsafe fn put_entry(&mut self, entry: (K, V)) {
- self.entry.as_mut_ptr().write(entry)
- }
-
- #[inline]
- unsafe fn entry_ref(&self) -> &(K, V) {
- &*self.entry.as_ptr()
- }
-
- #[inline]
- unsafe fn key_ref(&self) -> &K {
- &(*self.entry.as_ptr()).0
- }
-
- #[inline]
- unsafe fn entry_mut(&mut self) -> &mut (K, V) {
- &mut *self.entry.as_mut_ptr()
- }
-
- #[inline]
- unsafe fn take_entry(&mut self) -> (K, V) {
- self.entry.as_ptr().read()
- }
-}
-
-trait OptNonNullExt<T> {
- fn as_ptr(self) -> *mut T;
-}
-
-impl<T> OptNonNullExt<T> for Option<NonNull<T>> {
- #[inline]
- fn as_ptr(self) -> *mut T {
- match self {
- Some(ptr) => ptr.as_ptr(),
- None => ptr::null_mut(),
- }
- }
-}
-
-// Allocate a circular list guard node if not present.
-#[inline]
-unsafe fn ensure_guard_node<K, V>(head: &mut Option<NonNull<Node<K, V>>>) {
- if head.is_none() {
- let mut p = NonNull::new_unchecked(Box::into_raw(Box::new(Node {
- entry: MaybeUninit::uninit(),
- links: Links {
- value: ValueLinks {
- next: NonNull::dangling(),
- prev: NonNull::dangling(),
- },
- },
- })));
- p.as_mut().links.value = ValueLinks { next: p, prev: p };
- *head = Some(p);
- }
-}
-
-// Attach the `to_attach` node to the existing circular list *before* `node`.
-#[inline]
-unsafe fn attach_before<K, V>(
- mut to_attach: NonNull<Node<K, V>>,
- mut node: NonNull<Node<K, V>>,
-) {
- to_attach.as_mut().links.value = ValueLinks {
- prev: node.as_ref().links.value.prev,
- next: node,
- };
- node.as_mut().links.value.prev = to_attach;
- (*to_attach.as_mut().links.value.prev.as_ptr())
- .links
- .value
- .next = to_attach;
-}
-
-#[inline]
-unsafe fn detach_node<K, V>(mut node: NonNull<Node<K, V>>) {
- node.as_mut().links.value.prev.as_mut().links.value.next =
- node.as_ref().links.value.next;
- node.as_mut().links.value.next.as_mut().links.value.prev =
- node.as_ref().links.value.prev;
-}
-
-#[inline]
-unsafe fn push_free<K, V>(
- free_list: &mut Option<NonNull<Node<K, V>>>,
- mut node: NonNull<Node<K, V>>,
-) {
- node.as_mut().links.free.next = *free_list;
- *free_list = Some(node);
-}
-
-#[inline]
-unsafe fn pop_free<K, V>(
- free_list: &mut Option<NonNull<Node<K, V>>>,
-) -> Option<NonNull<Node<K, V>>> {
- if let Some(free) = *free_list {
- *free_list = free.as_ref().links.free.next;
- Some(free)
- } else {
- None
- }
-}
-
-#[inline]
-unsafe fn allocate_node<K, V>(
- free_list: &mut Option<NonNull<Node<K, V>>>,
-) -> NonNull<Node<K, V>> {
- if let Some(mut free) = pop_free(free_list) {
- free.as_mut().links.value = ValueLinks {
- next: NonNull::dangling(),
- prev: NonNull::dangling(),
- };
- free
- } else {
- NonNull::new_unchecked(Box::into_raw(Box::new(Node {
- entry: MaybeUninit::uninit(),
- links: Links {
- value: ValueLinks {
- next: NonNull::dangling(),
- prev: NonNull::dangling(),
- },
- },
- })))
- }
-}
-
-// Given node is assumed to be the guard node and is *not* dropped.
-#[inline]
-unsafe fn drop_value_nodes<K, V>(guard: NonNull<Node<K, V>>) {
- let mut cur = guard.as_ref().links.value.prev;
- while cur != guard {
- let prev = cur.as_ref().links.value.prev;
- cur.as_mut().take_entry();
- let _ = Box::from_raw(cur.as_ptr());
- cur = prev;
- }
-}
-
-// Drops all linked free nodes starting with the given node. Free nodes are
only non-circular
-// singly linked, and should have uninitialized keys / values.
-#[inline]
-unsafe fn drop_free_nodes<K, V>(mut free: Option<NonNull<Node<K, V>>>) {
- while let Some(some_free) = free {
- let next_free = some_free.as_ref().links.free.next;
- let _ = Box::from_raw(some_free.as_ptr());
- free = next_free;
- }
-}
-
-#[inline]
-unsafe fn remove_node<K, V>(
- free_list: &mut Option<NonNull<Node<K, V>>>,
- mut node: NonNull<Node<K, V>>,
-) -> (K, V) {
- detach_node(node);
- push_free(free_list, node);
- node.as_mut().take_entry()
-}
-
-#[inline]
-fn hash_key<S, Q>(s: &S, k: &Q) -> u64
-where
- S: BuildHasher,
- Q: Hash + ?Sized,
-{
- let mut hasher = s.build_hasher();
- k.hash(&mut hasher);
- hasher.finish()
-}
-
-// We do not drop the key and value when a value is filtered from the map
during the call to
-// `retain`. We need to be very careful not to have a live `HashMap` entry
pointing to
-// either a dangling `Node` or a `Node` with dropped keys / values. Since the
key and value
-// types may panic on drop, they may short-circuit the entry in the map
actually being
-// removed. Instead, we push the removed nodes onto the free list eagerly,
then try and
-// drop the keys and values for any newly freed nodes *after*
`HashMap::retain` has
-// completely finished.
-struct DropFilteredValues<'a, K, V> {
- free: &'a mut Option<NonNull<Node<K, V>>>,
- cur_free: Option<NonNull<Node<K, V>>>,
-}
-
-impl<'a, K, V> DropFilteredValues<'a, K, V> {
- #[inline]
- fn drop_later(&mut self, node: NonNull<Node<K, V>>) {
- unsafe {
- detach_node(node);
- push_free(&mut self.cur_free, node);
- }
- }
-}
-
-impl<'a, K, V> Drop for DropFilteredValues<'a, K, V> {
- fn drop(&mut self) {
- unsafe {
- let end_free = self.cur_free;
- while self.cur_free != *self.free {
- let cur_free = self.cur_free.as_ptr();
- (*cur_free).take_entry();
- self.cur_free = (*cur_free).links.free.next;
- }
- *self.free = end_free;
- }
- }
-}
diff --git a/ballista/cache/src/backend/policy/lru/hashlink/mod.rs
b/ballista/cache/src/backend/policy/lru/hashlink/mod.rs
deleted file mode 100644
index 938c24ca..00000000
--- a/ballista/cache/src/backend/policy/lru/hashlink/mod.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements. See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership. The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License. You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations
-// under the License.
-
-#[allow(clippy::wrong_self_convention)]
-mod linked_hash_map;
-pub mod lru_cache;
diff --git a/ballista/cache/src/backend/policy/lru/hashlink/lru_cache.rs
b/ballista/cache/src/backend/policy/lru/lru_cache.rs
similarity index 97%
rename from ballista/cache/src/backend/policy/lru/hashlink/lru_cache.rs
rename to ballista/cache/src/backend/policy/lru/lru_cache.rs
index 60231935..284a4a28 100644
--- a/ballista/cache/src/backend/policy/lru/hashlink/lru_cache.rs
+++ b/ballista/cache/src/backend/policy/lru/lru_cache.rs
@@ -16,14 +16,9 @@
// under the License.
use crate::backend::policy::lru::ResourceCounter;
-use crate::backend::policy::{
- lru::{
- hashlink::linked_hash_map::{self, IntoIter, Iter, IterMut,
LinkedHashMap},
- LruCachePolicy,
- },
- CachePolicy, CachePolicyPutResult,
-};
+use crate::backend::policy::{lru::LruCachePolicy, CachePolicy,
CachePolicyPutResult};
use hashbrown::hash_map::DefaultHashBuilder;
+use hashlink::linked_hash_map::{self, IntoIter, Iter, IterMut, LinkedHashMap};
use std::any::Any;
use std::fmt;
use std::fmt::Debug;
@@ -227,7 +222,7 @@ where
#[cfg(test)]
mod tests {
- use crate::backend::policy::lru::hashlink::lru_cache::LruCache;
+ use crate::backend::policy::lru::lru_cache::LruCache;
use crate::backend::policy::lru::{DefaultResourceCounter, ResourceCounter};
use crate::backend::policy::CachePolicy;
use hashbrown::HashMap;
diff --git a/ballista/cache/src/backend/policy/lru/mod.rs
b/ballista/cache/src/backend/policy/lru/mod.rs
index a63e5d04..a9b85569 100644
--- a/ballista/cache/src/backend/policy/lru/mod.rs
+++ b/ballista/cache/src/backend/policy/lru/mod.rs
@@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-pub mod hashlink;
+pub mod lru_cache;
use crate::backend::policy::CachePolicyPutResult;
use crate::backend::CachePolicy;
diff --git a/ballista/cache/src/loading_cache/driver.rs
b/ballista/cache/src/loading_cache/driver.rs
index 3723d9cf..614c6ead 100644
--- a/ballista/cache/src/loading_cache/driver.rs
+++ b/ballista/cache/src/loading_cache/driver.rs
@@ -452,7 +452,7 @@ where
#[cfg(test)]
mod tests {
- use crate::backend::policy::lru::hashlink::lru_cache::LruCache;
+ use crate::backend::policy::lru::lru_cache::LruCache;
use crate::listener::cache_policy::CachePolicyListener;
use crate::{CacheBackend, CacheDriver, CacheLoader,
CachePolicyWithListener};
diff --git a/ballista/cache/src/metrics/loading_cache.rs
b/ballista/cache/src/metrics/loading_cache.rs
index 58f72cb1..92a2e4fc 100644
--- a/ballista/cache/src/metrics/loading_cache.rs
+++ b/ballista/cache/src/metrics/loading_cache.rs
@@ -191,7 +191,7 @@ impl U64Counter {
#[cfg(test)]
mod tests {
- use crate::backend::policy::lru::hashlink::lru_cache::LruCache;
+ use crate::backend::policy::lru::lru_cache::LruCache;
use crate::backend::policy::lru::DefaultResourceCounter;
use crate::create_loading_cache_with_metrics;
use crate::loading_cache::loader::CacheLoader;
diff --git a/ballista/core/src/cache_layer/policy/file.rs
b/ballista/core/src/cache_layer/policy/file.rs
index 39a56603..98d76a11 100644
--- a/ballista/core/src/cache_layer/policy/file.rs
+++ b/ballista/core/src/cache_layer/policy/file.rs
@@ -19,7 +19,7 @@ use crate::cache_layer::medium::CacheMedium;
use crate::cache_layer::object_store::ObjectStoreWithKey;
use crate::error::{BallistaError, Result};
use async_trait::async_trait;
-use ballista_cache::backend::policy::lru::hashlink::lru_cache::LruCache;
+use ballista_cache::backend::policy::lru::lru_cache::LruCache;
use ballista_cache::backend::policy::lru::ResourceCounter;
use ballista_cache::listener::cache_policy::{
CachePolicyListener, CachePolicyWithListener,