mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
Allocator api feature for agb hashmap (#694)
This means hashmap can be used in stable.
This commit is contained in:
commit
a0a587ac05
|
@ -6,6 +6,9 @@ license = "MPL-2.0"
|
||||||
description = "A simple no_std hashmap implementation intended for use in the `agb` library"
|
description = "A simple no_std hashmap implementation intended for use in the `agb` library"
|
||||||
repository = "https://github.com/agbrs/agb"
|
repository = "https://github.com/agbrs/agb"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
allocator_api = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustc-hash = { version = "1", default-features = false }
|
rustc-hash = { version = "1", default-features = false }
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! A lot of the documentation for this module was copied straight out of the rust
|
//! A lot of the documentation for this module was copied straight out of the rust
|
||||||
//! standard library. The implementation however is not.
|
//! standard library. The implementation however is not.
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![feature(allocator_api)]
|
#![cfg_attr(feature = "allocator_api", feature(allocator_api))]
|
||||||
#![deny(clippy::all)]
|
#![deny(clippy::all)]
|
||||||
#![deny(clippy::must_use_candidate)]
|
#![deny(clippy::must_use_candidate)]
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
@ -26,9 +26,25 @@
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::{alloc::Global, vec::Vec};
|
pub(crate) use allocate::{Allocator, Global};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "allocator_api"))]
|
||||||
|
mod allocate {
|
||||||
|
pub trait Allocator {}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Global;
|
||||||
|
|
||||||
|
impl Allocator for Global {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "allocator_api")]
|
||||||
|
mod allocate {
|
||||||
|
pub(crate) use alloc::alloc::Global;
|
||||||
|
pub(crate) use core::alloc::Allocator;
|
||||||
|
}
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
alloc::Allocator,
|
|
||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
hash::{BuildHasher, BuildHasherDefault, Hash},
|
hash::{BuildHasher, BuildHasherDefault, Hash},
|
||||||
|
@ -174,12 +190,6 @@ impl<K, V> HashMap<K, V> {
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
Self::with_capacity_in(capacity, Global)
|
Self::with_capacity_in(capacity, Global)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[must_use]
|
|
||||||
pub fn distance_histogram(&self) -> (Vec<usize>, usize) {
|
|
||||||
self.nodes.distance_histogram()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K, V, ALLOCATOR: ClonableAllocator> HashMap<K, V, ALLOCATOR> {
|
impl<K, V, ALLOCATOR: ClonableAllocator> HashMap<K, V, ALLOCATOR> {
|
||||||
|
@ -583,7 +593,8 @@ impl<K, V, ALLOCATOR: ClonableAllocator> IntoIterator for HashMap<K, V, ALLOCATO
|
||||||
}
|
}
|
||||||
|
|
||||||
mod entries {
|
mod entries {
|
||||||
use core::{alloc::Allocator, hash::Hash};
|
use crate::allocate::Allocator;
|
||||||
|
use core::hash::Hash;
|
||||||
|
|
||||||
use super::{ClonableAllocator, HashMap, HashType};
|
use super::{ClonableAllocator, HashMap, HashType};
|
||||||
|
|
||||||
|
@ -948,6 +959,8 @@ impl core::ops::Add<i32> for HashType {
|
||||||
mod test {
|
mod test {
|
||||||
use core::{cell::RefCell, hash::Hasher};
|
use core::{cell::RefCell, hash::Hasher};
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use core::{alloc::Allocator, borrow::Borrow, mem};
|
use core::{borrow::Borrow, mem};
|
||||||
|
|
||||||
use alloc::{alloc::Global, vec::Vec};
|
|
||||||
|
|
||||||
|
use crate::allocate::{Allocator, Global};
|
||||||
use crate::{node::Node, number_before_resize, ClonableAllocator, HashType};
|
use crate::{node::Node, number_before_resize, ClonableAllocator, HashType};
|
||||||
|
|
||||||
|
mod vec;
|
||||||
|
use vec::MyVec;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct NodeStorage<K, V, ALLOCATOR: Allocator = Global> {
|
pub(crate) struct NodeStorage<K, V, ALLOCATOR: Allocator = Global> {
|
||||||
nodes: Vec<Node<K, V>, ALLOCATOR>,
|
nodes: MyVec<Node<K, V>, ALLOCATOR>,
|
||||||
max_distance_to_initial_bucket: i32,
|
max_distance_to_initial_bucket: i32,
|
||||||
|
|
||||||
number_of_items: usize,
|
number_of_items: usize,
|
||||||
|
@ -17,7 +19,7 @@ impl<K, V, ALLOCATOR: ClonableAllocator> NodeStorage<K, V, ALLOCATOR> {
|
||||||
pub(crate) fn with_size_in(capacity: usize, alloc: ALLOCATOR) -> Self {
|
pub(crate) fn with_size_in(capacity: usize, alloc: ALLOCATOR) -> Self {
|
||||||
assert!(capacity.is_power_of_two(), "Capacity must be a power of 2");
|
assert!(capacity.is_power_of_two(), "Capacity must be a power of 2");
|
||||||
|
|
||||||
let mut nodes = Vec::with_capacity_in(capacity, alloc);
|
let mut nodes = MyVec::with_capacity_in(capacity, alloc);
|
||||||
for _ in 0..capacity {
|
for _ in 0..capacity {
|
||||||
nodes.push(Node::new());
|
nodes.push(Node::new());
|
||||||
}
|
}
|
||||||
|
@ -202,22 +204,6 @@ impl<K, V, ALLOCATOR: ClonableAllocator> NodeStorage<K, V, ALLOCATOR> {
|
||||||
self.nodes.get_unchecked_mut(at)
|
self.nodes.get_unchecked_mut(at)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn distance_histogram(&self) -> (Vec<usize>, usize) {
|
|
||||||
let mut ret = Vec::new();
|
|
||||||
|
|
||||||
for node in self.nodes.iter() {
|
|
||||||
let distance = node.distance();
|
|
||||||
|
|
||||||
if distance >= 0 {
|
|
||||||
let distance = distance as usize;
|
|
||||||
ret.resize(ret.len().max(distance + 1), 0);
|
|
||||||
ret[distance] += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(ret, self.max_distance_to_initial_bucket as usize)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn clear(&mut self) {
|
pub(crate) fn clear(&mut self) {
|
||||||
self.max_distance_to_initial_bucket = 0;
|
self.max_distance_to_initial_bucket = 0;
|
||||||
self.number_of_items = 0;
|
self.number_of_items = 0;
|
||||||
|
|
66
agb-hashmap/src/node_storage/vec.rs
Normal file
66
agb-hashmap/src/node_storage/vec.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use crate::{Allocator, Global};
|
||||||
|
|
||||||
|
pub(crate) use inner::MyVec;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "allocator_api"))]
|
||||||
|
mod inner {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct MyVec<T, A: Allocator = Global>(Vec<T>, A);
|
||||||
|
|
||||||
|
impl<T, A: Allocator> MyVec<T, A> {
|
||||||
|
pub(crate) fn with_capacity_in(capacity: usize, allocator: A) -> Self {
|
||||||
|
Self(Vec::with_capacity(capacity), allocator)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn allocator(&self) -> &A {
|
||||||
|
&self.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T, A: Allocator> Deref for MyVec<T, A> {
|
||||||
|
type Target = Vec<T>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, A: Allocator> DerefMut for MyVec<T, A> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "allocator_api")]
|
||||||
|
mod inner {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct MyVec<T, A: Allocator = Global>(Vec<T, A>);
|
||||||
|
|
||||||
|
impl<T, A: Allocator> MyVec<T, A> {
|
||||||
|
pub(crate) fn with_capacity_in(capacity: usize, allocator: A) -> Self {
|
||||||
|
Self(Vec::with_capacity_in(capacity, allocator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, A: Allocator> Deref for MyVec<T, A> {
|
||||||
|
type Target = Vec<T, A>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, A: Allocator> DerefMut for MyVec<T, A> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ agb_image_converter = { version = "0.19.1", path = "../agb-image-converter" }
|
||||||
agb_sound_converter = { version = "0.19.1", path = "../agb-sound-converter" }
|
agb_sound_converter = { version = "0.19.1", path = "../agb-sound-converter" }
|
||||||
agb_macros = { version = "0.19.1", path = "../agb-macros" }
|
agb_macros = { version = "0.19.1", path = "../agb-macros" }
|
||||||
agb_fixnum = { version = "0.19.1", path = "../agb-fixnum" }
|
agb_fixnum = { version = "0.19.1", path = "../agb-fixnum" }
|
||||||
agb_hashmap = { version = "0.19.1", path = "../agb-hashmap" }
|
agb_hashmap = { version = "0.19.1", path = "../agb-hashmap", features = ["allocator_api"] }
|
||||||
bilge = "0.2"
|
bilge = "0.2"
|
||||||
qrcodegen-no-heap = { version = "1.8", optional = true }
|
qrcodegen-no-heap = { version = "1.8", optional = true }
|
||||||
portable-atomic = { version = "1.6.0", default-features = false, features = ["unsafe-assume-single-core"] }
|
portable-atomic = { version = "1.6.0", default-features = false, features = ["unsafe-assume-single-core"] }
|
||||||
|
|
Loading…
Reference in a new issue