Skip to content

Commit

Permalink
Implement Set
Browse files Browse the repository at this point in the history
  • Loading branch information
alexkazik committed Dec 31, 2023
1 parent 7c0c1d2 commit 7e7565a
Show file tree
Hide file tree
Showing 11 changed files with 634 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ mod keys;
mod map;
#[cfg(feature = "serde")]
mod serialization;
mod set;
mod values;

pub use crate::set::{Set, SetIntoIter, SetIter};
use core::mem::{ManuallyDrop, MaybeUninit};

/// A faster alternative of [`std::collections::HashMap`].
Expand Down
29 changes: 29 additions & 0 deletions src/set/clone.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) 2023 Yegor Bugayenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::Set;

impl<T: Clone + PartialEq, const N: usize> Clone for Set<T, N> {
fn clone(&self) -> Self {
Self {
map: self.map.clone(),
}
}
}
45 changes: 45 additions & 0 deletions src/set/ctors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) 2023 Yegor Bugayenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::{Map, Set};

impl<T: PartialEq, const N: usize> Default for Set<T, N> {
/// Make a default empty [`Set`].
#[inline]
#[must_use]
fn default() -> Self {
Self::new()
}
}

impl<T: PartialEq, const N: usize> Set<T, N> {
/// Make it.
///
/// The size of the set is defined by the generic argument. For example,
/// this is how you make a set of four key-values pairs:
#[inline]
#[must_use]
#[allow(clippy::uninit_assumed_init)]
pub const fn new() -> Self {
Self {
map: Map::<T, (), N>::new(),
}
}
}
56 changes: 56 additions & 0 deletions src/set/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) 2023 Yegor Bugayenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::Set;
use core::fmt::{self, Debug, Formatter};

impl<T: PartialEq + Debug, const N: usize> Debug for Set<T, N> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}

#[cfg(test)]
mod test {

use super::*;

#[test]
fn debugs_set() {
let mut m: Set<String, 10> = Set::new();
m.insert("one".to_string());
m.insert("two".to_string());
assert_eq!(r#"{"one", "two"}"#, format!("{:?}", m));
}

#[test]
fn debug_alternate_set() {
let mut m: Set<String, 10> = Set::new();
m.insert("one".to_string());
m.insert("two".to_string());
assert_eq!(
r#"{
"one",
"two",
}"#,
format!("{:#?}", m)
);
}
}
53 changes: 53 additions & 0 deletions src/set/display.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) 2023 Yegor Bugayenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::Set;
use core::fmt::{self, Display, Formatter, Write};

impl<T: PartialEq + Display, const N: usize> Display for Set<T, N> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut first = true;
f.write_char('{')?;
for k in self {
if first {
first = false;
} else {
f.write_str(", ")?;
}
k.fmt(f)?;
}
f.write_char('}')?;
Ok(())
}
}

#[cfg(test)]
mod test {

use super::*;

#[test]
fn displays_set() {
let mut m: Set<String, 10> = Set::new();
m.insert("one".to_string());
m.insert("two".to_string());
assert_eq!(r#"{"one", "two"}"#, format!("{:?}", m));
}
}
49 changes: 49 additions & 0 deletions src/set/eq.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2023 Yegor Bugayenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::Set;

impl<T: PartialEq, const N: usize> PartialEq for Set<T, N> {
/// Two sets can be compared.
///
/// For example:
///
/// ```
/// let mut m1: micromap::Set<u8, 10> = micromap::Set::new();
/// let mut m2: micromap::Set<u8, 10> = micromap::Set::new();
/// m1.insert(1);
/// m2.insert(1);
/// # #[cfg(std)]
/// assert_eq!(m1, m2);
/// // two sets with different order of key-value pairs are still equal:
/// m1.insert(2);
/// m1.insert(3);
/// m2.insert(3);
/// m2.insert(2);
/// # #[cfg(std)]
/// assert_eq!(m1, m2);
/// ```
#[inline]
fn eq(&self, other: &Self) -> bool {
self.map.eq(&other.map)
}
}

impl<T: Eq, const N: usize> Eq for Set<T, N> {}
41 changes: 41 additions & 0 deletions src/set/from.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) 2023 Yegor Bugayenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::Set;

impl<T: PartialEq, const N: usize> FromIterator<T> for Set<T, N> {
#[inline]
#[must_use]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut s: Self = Self::new();
for k in iter {
s.insert(k);
}
s
}
}

impl<T: PartialEq, const N: usize> From<[T; N]> for Set<T, N> {
#[inline]
#[must_use]
fn from(arr: [T; N]) -> Self {
Self::from_iter(arr)
}
}
109 changes: 109 additions & 0 deletions src/set/functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) 2023 Yegor Bugayenko
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use crate::Set;
use core::borrow::Borrow;

impl<T: PartialEq, const N: usize> Set<T, N> {
/// Get its total capacity.
#[inline]
#[must_use]
pub const fn capacity(&self) -> usize {
self.map.capacity()
}

/// Is it empty?
#[inline]
#[must_use]
pub const fn is_empty(&self) -> bool {
self.map.is_empty()
}

/// Return the total number of pairs inside.
#[inline]
#[must_use]
pub const fn len(&self) -> usize {
self.map.len()
}

/// Does the set contain this key?
#[inline]
#[must_use]
pub fn contains_key<Q: PartialEq + ?Sized>(&self, k: &Q) -> bool
where
T: Borrow<Q>,
{
self.map.contains_key(k)
}

/// Remove by key.
#[inline]
pub fn remove<Q: PartialEq + ?Sized>(&mut self, k: &Q)
where
T: Borrow<Q>,
{
self.map.remove(k);
}

/// Insert a single pair into the set.
///
/// # Panics
///
/// It may panic if there are too many pairs in the set already. Pay attention,
/// it panics only in the "debug" mode. In the "release" mode, you are going to get
/// undefined behavior. This is done for the sake of performance, in order to
/// avoid a repetitive check for the boundary condition on every `insert()`.
#[inline]
pub fn insert(&mut self, k: T) {
self.map.insert(k, ());
}

/// Get a reference to a single value.
#[inline]
#[must_use]
pub fn get<Q: PartialEq + ?Sized>(&self, k: &Q) -> Option<&T>
where
T: Borrow<Q>,
{
self.map.get_key_value(k).map(|p| p.0)
}

/// Remove all pairs from it, but keep the space intact for future use.
#[inline]
pub fn clear(&mut self) {
self.map.clear();
}

/// Retains only the elements specified by the predicate.
#[inline]
pub fn retain<F: Fn(&T) -> bool>(&mut self, f: F) {
self.map.retain(|k, ()| f(k));
}

/// Removes a key from the set, returning the stored key and value if the
/// key was previously in the set.
#[inline]
pub fn take<Q: PartialEq + ?Sized>(&mut self, k: &Q) -> Option<T>
where
T: Borrow<Q>,
{
self.map.remove_entry(k).map(|p| p.0)
}
}
Loading

0 comments on commit 7e7565a

Please sign in to comment.