1- //! A library for dynamically sized bitsets with small storage optimization.
1+ //! A library for dynamically sized bitsets with memory usage optimizations.
2+ //!
3+ //! The first <code>[usize::BITS] - 1</code> bits are stored without incurring any heap allocations.\
4+ //! Any larger values dynamically allocate an appropriately sized [`u32`] slice on the heap.\
5+ //! Furthermore [`SmolBitSet`] has a niche optimization so [`Option<SmolBitSet>`] has the same size of 1 [`usize`].
6+ //!
7+ //! # Example
8+ //!
9+ //! ```
10+ //! use smolbitset::SmolBitSet;
11+ //!
12+ //! let mut sbs = SmolBitSet::new();
13+ //!
14+ //! sbs |= 1u32 << 5;
15+ //! sbs >>= 5u8;
16+ //! assert_eq!(sbs, SmolBitSet::from(1u64));
17+ //!
18+ //! sbs |= !1u64;
19+ //! assert_eq!(sbs, SmolBitSet::from(u64::MAX));
20+ //!
21+ //! sbs <<= 64u16;
22+ //! assert_eq!(sbs, SmolBitSet::from_bits(&(64..128).collect::<Box<[_]>>()))
23+ //! ```
24+ //!
25+ //! # Minimum Supported Rust Version
26+ //!
27+ //! This is currently `1.89`, and is considered a breaking change to increase.
228//!
3- //! All values up to `usize::MAX >> 1` are stored without incurring any heap allocations.\
4- //! Any larger values dynamically allocate an appropriately sized `u32` slice on the heap.\
5- //! [`SmolBitSet`] also has a niche optimization so [`Option<SmolBitSet>`] and [`SmolBitSet`] have the same size of 1 [`usize`].
629
730#![ doc( html_root_url = "https://docs.rs/smolbitset/*" ) ]
831#![ allow( dead_code) ]
@@ -51,20 +74,21 @@ type BitSliceType = u32;
5174const BST_BITS : usize = BitSliceType :: BITS as usize ;
5275const INLINE_SLICE_PARTS : usize = usize:: BITS as usize / BST_BITS ;
5376
77+ /// A dynamically sized bitset with memory usage optimizations.
78+ ///
79+ /// The first <code>[usize::BITS] - 1</code> bits are stored without incurring any heap allocations.
5480#[ repr( transparent) ]
5581pub struct SmolBitSet {
5682 ptr : NonNull < BitSliceType > ,
5783}
5884
5985impl SmolBitSet {
60- /// Creates a new empty [`SmolBitSet`].
86+ /// Constructs a new, empty [`SmolBitSet`].
6187 ///
6288 /// # Examples
6389 ///
6490 /// ```
65- /// use smolbitset::SmolBitSet;
66- ///
67- /// # #[allow(unused_mut)]
91+ /// # use smolbitset::SmolBitSet;
6892 /// let mut sbs = SmolBitSet::new();
6993 /// ```
7094 #[ must_use]
@@ -75,23 +99,25 @@ impl SmolBitSet {
7599 Self { ptr }
76100 }
77101
78- /// Creates a new [`SmolBitSet`] from the provided `val` without any heap allocation .
102+ /// Constructs a new [`SmolBitSet`] from the provided `val` without any heap allocations .
79103 ///
80104 /// # Panics
81105 ///
82- /// Panics if the most significant bit in `val` is set to 1.
106+ /// Panics if the most significant bit in `val` is 1.
83107 ///
84108 /// # Examples
85109 ///
86110 /// ```
87- /// use smolbitset::SmolBitSet;
88- ///
111+ /// # use smolbitset::SmolBitSet;
89112 /// const sbs: SmolBitSet = SmolBitSet::new_small(1234);
90113 /// assert_eq!(sbs, SmolBitSet::from(1234u16));
91114 /// ```
92115 #[ must_use]
93116 pub const fn new_small ( val : usize ) -> Self {
94- assert ! ( val. leading_zeros( ) >= 1 , "the highest bit in val must be 0" ) ;
117+ assert ! (
118+ val. leading_zeros( ) >= 1 ,
119+ "the highest bit in val must be 0 for a non allocating SmolBitSet"
120+ ) ;
95121
96122 let mut res = Self :: new ( ) ;
97123 unsafe {
@@ -101,20 +127,33 @@ impl SmolBitSet {
101127 res
102128 }
103129
104- /// Creates a new [`SmolBitSet`] from the provided array of `bits` without any heap allocation .
130+ /// Constructs a new [`SmolBitSet`] from the provided array of bit indices without any heap allocations .
105131 ///
106132 /// # Panics
107133 ///
108- /// Panics if any bit index in `bits` is larger than or equal to `usize::BITS`.
134+ /// Panics if any bit index in `bits` is larger than or equal to [ `usize::BITS`] .
109135 ///
110136 /// # Examples
111137 ///
112138 /// ```
113- /// use smolbitset::SmolBitSet;
114- ///
139+ /// # use smolbitset::SmolBitSet;
115140 /// const sbs: SmolBitSet = SmolBitSet::from_bits_small([0, 4, 1, 6]);
116141 /// assert_eq!(sbs, SmolBitSet::from(0b0101_0011u8));
117142 /// ```
143+ ///
144+ /// ```should_panic
145+ /// # use smolbitset::SmolBitSet;
146+ /// // this panics since 63 is outside of the range
147+ /// // a SmolBitSet can hold without incurring a heap allocation
148+ /// let sbs = SmolBitSet::from_bits_small([63]);
149+ /// ```
150+ ///
151+ /// ```compile_fail
152+ /// # use smolbitset::SmolBitSet;
153+ /// // this fails to compile since the const evaluation
154+ /// // panics for the same reason as above
155+ /// const sbs: SmolBitSet = SmolBitSet::from_bits_small([63]);
156+ /// ```
118157 #[ must_use]
119158 pub const fn from_bits_small < const N : usize > ( bits : [ usize ; N ] ) -> Self {
120159 let mut res = 0 ;
@@ -123,8 +162,8 @@ impl SmolBitSet {
123162 while i < N {
124163 let b = bits[ i] ;
125164 assert ! (
126- b < usize :: BITS as usize ,
127- "bit index out of range for small bitset "
165+ b < usize :: BITS as usize - 1 ,
166+ "bit index out of range for a non allocating SmolBitSet "
128167 ) ;
129168
130169 res |= 1 << b;
@@ -134,17 +173,18 @@ impl SmolBitSet {
134173 Self :: new_small ( res)
135174 }
136175
137- /// Creates a new [`SmolBitSet`] from the provided slice of `bits` .
176+ /// Creates a new [`SmolBitSet`] from the provided slice of bit indices .
138177 ///
139178 /// # Examples
140179 ///
141180 /// ```
142- /// use smolbitset::SmolBitSet;
143- ///
144- /// let sbs = SmolBitSet::from_bits(&[0, 4, 3, 6 ]);
181+ /// # use smolbitset::SmolBitSet;
182+ /// // bit indices can be in any order
183+ /// let sbs = SmolBitSet::from_bits(&[0, 6, 4, 3 ]);
145184 /// assert_eq!(sbs, SmolBitSet::from(0b0101_1001u8));
146- /// # let sbs = SmolBitSet::from_bits(&[63]);
147- /// # assert_eq!(sbs, SmolBitSet::from(1u64 << 63));
185+ ///
186+ /// let sbs = SmolBitSet::from_bits(&[63]);
187+ /// assert_eq!(sbs, SmolBitSet::from(1u64 << 63));
148188 /// ```
149189 #[ must_use]
150190 pub fn from_bits ( bits : & [ usize ] ) -> Self {
@@ -336,6 +376,7 @@ impl SmolBitSet {
336376
337377 /// Returns the index of the most significant bit set to 1.
338378 ///
379+ /// # Warning
339380 /// The least significant bit is at index 1!
340381 #[ inline]
341382 fn highest_set_bit ( & self ) -> usize {
0 commit comments