1use crate::board::{Cell, Col, Digit, House, Line, Position, Row};
9use crate::helper::Unsolvable;
10use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
14pub struct Set<T: SetElement>(pub(crate) T::Storage);
15
16#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub struct Iter<T: SetElement>(T::Storage);
19
20impl<T: SetElement> IntoIterator for Set<T>
21where
22 Iter<T>: Iterator,
23{
24 type Item = <Iter<T> as Iterator>::Item;
25 type IntoIter = Iter<T>;
26
27 fn into_iter(self) -> Self::IntoIter {
28 Iter(self.0)
29 }
30}
31
32macro_rules! impl_binary_bitops {
37 ( $( $trait:ident, $fn_name:ident);* $(;)* ) => {
38 $(
39 impl<T: SetElement> $trait for Set<T> {
40 type Output = Self;
41
42 #[inline(always)]
43 fn $fn_name(self, other: Self) -> Self {
44 Set(
45 $trait::$fn_name(self.0, other.0)
46 )
47 }
48 }
49
50 impl<T: SetElement> $trait<T> for Set<T> {
51 type Output = Self;
52
53 #[inline(always)]
54 fn $fn_name(self, other: T) -> Self {
55 $trait::$fn_name(self, other.as_set())
56 }
57 }
58 )*
59 };
60}
61
62macro_rules! impl_bitops_assign {
63 ( $( $trait:ident, $fn_name:ident);* $(;)* ) => {
64 $(
65 impl<T: SetElement> $trait for Set<T> {
66 #[inline(always)]
67 fn $fn_name(&mut self, other: Self) {
68 $trait::$fn_name(&mut self.0, other.0)
69 }
70 }
71
72 impl<T: SetElement> $trait<T> for Set<T> {
73 #[inline(always)]
74 fn $fn_name(&mut self, other: T) {
75 $trait::$fn_name(self, other.as_set())
76 }
77 }
78 )*
79 };
80}
81
82impl_binary_bitops!(
83 BitAnd, bitand;
84 BitOr, bitor;
85 BitXor, bitxor;
86);
87
88impl_bitops_assign!(
89 BitAndAssign, bitand_assign;
90 BitOrAssign, bitor_assign;
91 BitXorAssign, bitxor_assign;
92);
93
94impl<T: SetElement> Not for Set<T>
95where
96 Self: PartialEq + Copy,
97{
98 type Output = Self;
99 fn not(self) -> Self {
100 Self::ALL.without(self)
101 }
102}
103
104#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
106pub struct Empty;
107
108impl From<Empty> for Unsolvable {
109 fn from(_: Empty) -> Unsolvable {
110 Unsolvable
111 }
112}
113
114impl<T: SetElement> Set<T>
115where
116 Self: PartialEq + Copy,
119{
120 pub const ALL: Set<T> = Set(<T as SetElement>::ALL);
122
123 pub const NONE: Set<T> = Set(<T as SetElement>::NONE);
125
126 pub fn from_bits(mask: T::Storage) -> Self {
131 assert!(mask <= <T as SetElement>::ALL);
132 Set(mask)
133 }
134
135 pub fn bits(self) -> T::Storage {
137 self.0
138 }
139
140 pub fn without(self, other: Self) -> Self {
142 Set(self.0 & !other.0)
143 }
144
145 pub fn remove(&mut self, other: Self) {
147 self.0 &= !other.0;
148 }
149
150 pub fn overlaps(&self, other: Self) -> bool {
152 *self & other != Set::NONE
153 }
154
155 pub fn contains(&self, other: impl Into<Self>) -> bool {
157 let other = other.into();
158 *self & other == other
159 }
160
161 pub fn len(&self) -> u8 {
163 T::count_possibilities(self.0) as u8
164 }
165
166 pub fn is_empty(&self) -> bool {
168 self.len() == 0
169 }
170
171 pub fn is_full(&self) -> bool {
173 *self == Self::ALL
174 }
175
176 pub fn unique(self) -> Result<Option<T>, Empty>
180 where
181 Iter<T>: Iterator<Item = T>,
182 {
183 match self.len() {
184 1 => {
185 let element = self.into_iter().next();
186 debug_assert!(element.is_some());
187 Ok(element)
188 }
189 0 => Err(Empty),
190 _ => Ok(None),
191 }
192 }
193
194 #[allow(unused)]
200 pub(crate) fn one_possibility(self) -> T
201 where
202 Iter<T>: Iterator<Item = T>,
203 {
204 self.into_iter().next().expect("mask is empty")
205 }
206}
207
208#[allow(missing_docs)]
212pub trait SetElement: Sized + set_element::Sealed {
213 const ALL: Self::Storage;
214 const NONE: Self::Storage;
215
216 type Storage: BitAnd<Output = Self::Storage>
217 + BitAndAssign
218 + BitOr<Output = Self::Storage>
219 + BitOrAssign
220 + BitXor<Output = Self::Storage>
221 + BitXorAssign
222 + Not<Output = Self::Storage>
223 + PartialOrd
224 + std::fmt::Binary
225 + Copy;
226
227 fn count_possibilities(set: Self::Storage) -> u32;
228 fn as_set(self) -> Set<Self>;
229}
230mod set_element {
231 use super::*;
232 pub trait Sealed {}
233
234 macro_rules! impl_sealed {
235 ($($type:ty),*) => {
236 $(
237 impl Sealed for $type {}
238 )*
239 };
240 }
241
242 impl_sealed! {
243 Cell, Digit, Row, Col, House, Line, Position<Line>, Position<House>
244 }
245}
246
247const fn n_bits_set(bitset_size: u8) -> u128 {
249 (1 << bitset_size) - 1
250}
251
252macro_rules! impl_setelement {
253 ( $( $type:ty => $storage_ty:ty, $bitset_size:expr),* $(,)* ) => {
254 $(
255 impl SetElement for $type {
256 const ALL: $storage_ty = n_bits_set($bitset_size) as $storage_ty;
259 const NONE: $storage_ty = 0;
260
261 type Storage = $storage_ty;
262
263 fn count_possibilities(set: Self::Storage) -> u32 {
264 set.count_ones()
265 }
266
267 fn as_set(self) -> Set<Self> {
268 Set(1 << self.as_index() as u8)
269 }
270 }
271
272 impl $type {
273 pub fn as_set(self) -> Set<Self> {
275 SetElement::as_set(self)
276 }
277 }
278 )*
279 };
280}
281
282impl_setelement!(
283 Cell => u128, 81,
285 Digit => u16, 9,
287
288 Line => u32, 18, House => u32, 27, Position<Line> => u16, 9,
299 Position<House> => u16, 9,
300 );
305
306macro_rules! impl_iter_for_setiter {
307 ( $( $type:ty => $constructor:expr ),* $(,)* ) => {
308 $(
309 impl Iterator for Iter<$type> {
310 type Item = $type;
311
312 fn next(&mut self) -> Option<Self::Item> {
313 debug_assert!(self.0 <= <Set<$type>>::ALL.0, "{:o}", self.0);
314 if self.0 == 0 {
315 return None;
316 }
317 let lowest_bit = self.0 & (!self.0 + 1);
318 let bit_pos = lowest_bit.trailing_zeros() as u8;
319 self.0 ^= lowest_bit;
320 Some($constructor(bit_pos))
321 }
322 }
323 )*
324 };
325}
326
327impl_iter_for_setiter!(
329 Cell => Cell::new,
330 Digit => Digit::from_index,
331 Line => Line::new,
332 House => House::new,
333 Position<Line> => Position::new,
336 Position<House> => Position::new,
337 );
341
342use std::fmt;
343impl<T: SetElement> fmt::Binary for Set<T> {
344 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
345 write!(f, "{:b}", self.0)
346 }
347}