-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
4,479 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
mod table; | ||
pub(crate) use self::fork::raw::RawIter; | ||
pub(crate) use self::table::{IterRef, Table}; | ||
pub(crate) use ::hashbrown::raw::RawIter; | ||
|
||
mod fork; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
#![allow(unused)] | ||
|
||
// Copied and modified under the MIT license. | ||
// Copyright (c) 2016 Amanieu d'Antras | ||
// | ||
// Imported using import_hashbrown.ps1, the below section is the only part | ||
// copied by hand. | ||
// | ||
// After an import of the crate some sections might need to be modified. | ||
// | ||
// See: https://github.com/rust-lang/hashbrown | ||
// The relevant fork: https://github.com/udoprog/hashbrown/tree/raw-infallible-context | ||
// Relevant issue: https://github.com/rust-lang/hashbrown/issues/456 | ||
|
||
#![allow(clippy::manual_map)] | ||
|
||
#[macro_use] | ||
mod macros; | ||
pub(crate) mod raw; | ||
mod scopeguard; | ||
|
||
/// The error type for `try_reserve` methods. | ||
#[derive(Clone, PartialEq, Eq, Debug)] | ||
pub enum TryReserveError { | ||
/// Error due to the computed capacity exceeding the collection's maximum | ||
/// (usually `isize::MAX` bytes). | ||
CapacityOverflow, | ||
|
||
/// The memory allocator returned an error | ||
AllocError { | ||
/// The layout of the allocation request that failed. | ||
layout: alloc::alloc::Layout, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// See the cfg-if crate. | ||
#[allow(unused_macro_rules)] | ||
macro_rules! cfg_if { | ||
// match if/else chains with a final `else` | ||
($( | ||
if #[cfg($($meta:meta),*)] { $($it:item)* } | ||
) else * else { | ||
$($it2:item)* | ||
}) => { | ||
cfg_if! { | ||
@__items | ||
() ; | ||
$( ( ($($meta),*) ($($it)*) ), )* | ||
( () ($($it2)*) ), | ||
} | ||
}; | ||
|
||
// match if/else chains lacking a final `else` | ||
( | ||
if #[cfg($($i_met:meta),*)] { $($i_it:item)* } | ||
$( | ||
else if #[cfg($($e_met:meta),*)] { $($e_it:item)* } | ||
)* | ||
) => { | ||
cfg_if! { | ||
@__items | ||
() ; | ||
( ($($i_met),*) ($($i_it)*) ), | ||
$( ( ($($e_met),*) ($($e_it)*) ), )* | ||
( () () ), | ||
} | ||
}; | ||
|
||
// Internal and recursive macro to emit all the items | ||
// | ||
// Collects all the negated cfgs in a list at the beginning and after the | ||
// semicolon is all the remaining items | ||
(@__items ($($not:meta,)*) ; ) => {}; | ||
(@__items ($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { | ||
// Emit all items within one block, applying an appropriate #[cfg]. The | ||
// #[cfg] will require all `$m` matchers specified and must also negate | ||
// all previous matchers. | ||
cfg_if! { @__apply cfg(all($($m,)* not(any($($not),*)))), $($it)* } | ||
|
||
// Recurse to emit all other items in `$rest`, and when we do so add all | ||
// our `$m` matchers to the list of `$not` matchers as future emissions | ||
// will have to negate everything we just matched as well. | ||
cfg_if! { @__items ($($not,)* $($m,)*) ; $($rest)* } | ||
}; | ||
|
||
// Internal macro to Apply a cfg attribute to a list of items | ||
(@__apply $m:meta, $($it:item)*) => { | ||
$(#[$m] $it)* | ||
}; | ||
} | ||
|
||
// Helper macro for specialization. This also helps avoid parse errors if the | ||
// default fn syntax for specialization changes in the future. | ||
#[cfg(feature = "nightly")] | ||
macro_rules! default_fn { | ||
(#[$($a:tt)*] $($tt:tt)*) => { | ||
#[$($a)*] default $($tt)* | ||
} | ||
} | ||
#[cfg(not(feature = "nightly"))] | ||
macro_rules! default_fn { | ||
($($tt:tt)*) => { | ||
$($tt)* | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
pub(crate) use self::inner::{do_alloc, Allocator, Global}; | ||
|
||
// Nightly-case. | ||
// Use unstable `allocator_api` feature. | ||
// This is compatible with `allocator-api2` which can be enabled or not. | ||
// This is used when building for `std`. | ||
#[cfg(feature = "nightly")] | ||
mod inner { | ||
use crate::alloc::alloc::Layout; | ||
pub use crate::alloc::alloc::{Allocator, Global}; | ||
use core::ptr::NonNull; | ||
|
||
#[allow(clippy::map_err_ignore)] | ||
pub(crate) fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> { | ||
match alloc.allocate(layout) { | ||
Ok(ptr) => Ok(ptr.as_non_null_ptr()), | ||
Err(_) => Err(()), | ||
} | ||
} | ||
} | ||
|
||
// Basic non-nightly case. | ||
// This uses `allocator-api2` enabled by default. | ||
// If any crate enables "nightly" in `allocator-api2`, | ||
// this will be equivalent to the nightly case, | ||
// since `allocator_api2::alloc::Allocator` would be re-export of | ||
// `core::alloc::Allocator`. | ||
#[cfg(all(not(feature = "nightly"), feature = "allocator-api2"))] | ||
mod inner { | ||
use crate::alloc::alloc::Layout; | ||
pub use allocator_api2::alloc::{Allocator, Global}; | ||
use core::ptr::NonNull; | ||
|
||
#[allow(clippy::map_err_ignore)] | ||
pub(crate) fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> { | ||
match alloc.allocate(layout) { | ||
Ok(ptr) => Ok(ptr.cast()), | ||
Err(_) => Err(()), | ||
} | ||
} | ||
} | ||
|
||
// No-defaults case. | ||
// When building with default-features turned off and | ||
// neither `nightly` nor `allocator-api2` is enabled, | ||
// this will be used. | ||
// Making it impossible to use any custom allocator with collections defined | ||
// in this crate. | ||
// Any crate in build-tree can enable `allocator-api2`, | ||
// or `nightly` without disturbing users that don't want to use it. | ||
#[cfg(not(any(feature = "nightly", feature = "allocator-api2")))] | ||
mod inner { | ||
use crate::alloc::alloc::{alloc, dealloc, Layout}; | ||
use core::ptr::NonNull; | ||
|
||
#[allow(clippy::missing_safety_doc)] // not exposed outside of this crate | ||
pub unsafe trait Allocator { | ||
fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()>; | ||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout); | ||
} | ||
|
||
#[derive(Copy, Clone)] | ||
pub struct Global; | ||
|
||
unsafe impl Allocator for Global { | ||
#[inline] | ||
fn allocate(&self, layout: Layout) -> Result<NonNull<u8>, ()> { | ||
unsafe { NonNull::new(alloc(layout)).ok_or(()) } | ||
} | ||
#[inline] | ||
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) { | ||
dealloc(ptr.as_ptr(), layout); | ||
} | ||
} | ||
|
||
impl Default for Global { | ||
#[inline] | ||
fn default() -> Self { | ||
Global | ||
} | ||
} | ||
|
||
pub(crate) fn do_alloc<A: Allocator>(alloc: &A, layout: Layout) -> Result<NonNull<u8>, ()> { | ||
alloc.allocate(layout) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
use super::imp::{ | ||
BitMaskWord, NonZeroBitMaskWord, BITMASK_ITER_MASK, BITMASK_MASK, BITMASK_STRIDE, | ||
}; | ||
|
||
/// A bit mask which contains the result of a `Match` operation on a `Group` and | ||
/// allows iterating through them. | ||
/// | ||
/// The bit mask is arranged so that low-order bits represent lower memory | ||
/// addresses for group match results. | ||
/// | ||
/// For implementation reasons, the bits in the set may be sparsely packed with | ||
/// groups of 8 bits representing one element. If any of these bits are non-zero | ||
/// then this element is considered to true in the mask. If this is the | ||
/// case, `BITMASK_STRIDE` will be 8 to indicate a divide-by-8 should be | ||
/// performed on counts/indices to normalize this difference. `BITMASK_MASK` is | ||
/// similarly a mask of all the actually-used bits. | ||
/// | ||
/// To iterate over a bit mask, it must be converted to a form where only 1 bit | ||
/// is set per element. This is done by applying `BITMASK_ITER_MASK` on the | ||
/// mask bits. | ||
#[derive(Copy, Clone)] | ||
pub(crate) struct BitMask(pub(crate) BitMaskWord); | ||
|
||
#[allow(clippy::use_self)] | ||
impl BitMask { | ||
/// Returns a new `BitMask` with all bits inverted. | ||
#[inline] | ||
#[must_use] | ||
#[allow(dead_code)] | ||
pub(crate) fn invert(self) -> Self { | ||
BitMask(self.0 ^ BITMASK_MASK) | ||
} | ||
|
||
/// Returns a new `BitMask` with the lowest bit removed. | ||
#[inline] | ||
#[must_use] | ||
fn remove_lowest_bit(self) -> Self { | ||
BitMask(self.0 & (self.0 - 1)) | ||
} | ||
|
||
/// Returns whether the `BitMask` has at least one set bit. | ||
#[inline] | ||
pub(crate) fn any_bit_set(self) -> bool { | ||
self.0 != 0 | ||
} | ||
|
||
/// Returns the first set bit in the `BitMask`, if there is one. | ||
#[inline] | ||
pub(crate) fn lowest_set_bit(self) -> Option<usize> { | ||
if let Some(nonzero) = NonZeroBitMaskWord::new(self.0) { | ||
Some(Self::nonzero_trailing_zeros(nonzero)) | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
/// Returns the number of trailing zeroes in the `BitMask`. | ||
#[inline] | ||
pub(crate) fn trailing_zeros(self) -> usize { | ||
// ARM doesn't have a trailing_zeroes instruction, and instead uses | ||
// reverse_bits (RBIT) + leading_zeroes (CLZ). However older ARM | ||
// versions (pre-ARMv7) don't have RBIT and need to emulate it | ||
// instead. Since we only have 1 bit set in each byte on ARM, we can | ||
// use swap_bytes (REV) + leading_zeroes instead. | ||
if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { | ||
self.0.swap_bytes().leading_zeros() as usize / BITMASK_STRIDE | ||
} else { | ||
self.0.trailing_zeros() as usize / BITMASK_STRIDE | ||
} | ||
} | ||
|
||
/// Same as above but takes a `NonZeroBitMaskWord`. | ||
#[inline] | ||
fn nonzero_trailing_zeros(nonzero: NonZeroBitMaskWord) -> usize { | ||
if cfg!(target_arch = "arm") && BITMASK_STRIDE % 8 == 0 { | ||
// SAFETY: A byte-swapped non-zero value is still non-zero. | ||
let swapped = unsafe { NonZeroBitMaskWord::new_unchecked(nonzero.get().swap_bytes()) }; | ||
swapped.leading_zeros() as usize / BITMASK_STRIDE | ||
} else { | ||
nonzero.trailing_zeros() as usize / BITMASK_STRIDE | ||
} | ||
} | ||
|
||
/// Returns the number of leading zeroes in the `BitMask`. | ||
#[inline] | ||
pub(crate) fn leading_zeros(self) -> usize { | ||
self.0.leading_zeros() as usize / BITMASK_STRIDE | ||
} | ||
} | ||
|
||
impl IntoIterator for BitMask { | ||
type Item = usize; | ||
type IntoIter = BitMaskIter; | ||
|
||
#[inline] | ||
fn into_iter(self) -> BitMaskIter { | ||
// A BitMask only requires each element (group of bits) to be non-zero. | ||
// However for iteration we need each element to only contain 1 bit. | ||
BitMaskIter(BitMask(self.0 & BITMASK_ITER_MASK)) | ||
} | ||
} | ||
|
||
/// Iterator over the contents of a `BitMask`, returning the indices of set | ||
/// bits. | ||
#[derive(Copy, Clone)] | ||
pub(crate) struct BitMaskIter(pub(crate) BitMask); | ||
|
||
impl BitMaskIter { | ||
/// Flip the bit in the mask for the entry at the given index. | ||
/// | ||
/// Returns the bit's previous state. | ||
#[inline] | ||
#[allow(clippy::cast_ptr_alignment)] | ||
#[cfg(feature = "raw")] | ||
pub(crate) unsafe fn flip(&mut self, index: usize) -> bool { | ||
// NOTE: The + BITMASK_STRIDE - 1 is to set the high bit. | ||
let mask = 1 << (index * BITMASK_STRIDE + BITMASK_STRIDE - 1); | ||
self.0 .0 ^= mask; | ||
// The bit was set if the bit is now 0. | ||
self.0 .0 & mask == 0 | ||
} | ||
} | ||
|
||
impl Iterator for BitMaskIter { | ||
type Item = usize; | ||
|
||
#[inline] | ||
fn next(&mut self) -> Option<usize> { | ||
let bit = self.0.lowest_set_bit()?; | ||
self.0 = self.0.remove_lowest_bit(); | ||
Some(bit) | ||
} | ||
} |
Oops, something went wrong.