///|
/// A collection of `Weekday` values, stored as a 7-bit set.
///
/// Bit `i` corresponds to the weekday whose `Weekday::index()` is `i`
/// (`Mon = 0` .. `Sun = 6`); higher bits are always `0`.
///
/// Sets have no total order: the bit layout is a representation detail and
/// the meaningful relation is `is_subset`.
pub struct WeekdaySet {
priv bits : Int
} derive(Eq, Hash, @debug.Debug)
///|
pub extend WeekdaySet with Eq::{equal}
///|
pub extend WeekdaySet with Eq::{not_equal}
///|
/// Renders as a bracketed list of the members' short names in `Mon..Sun`
/// order, e.g. `[Mon, Fri]`; the empty set is `[]`.
pub impl Show for WeekdaySet with fn output(self, logger) {
let names = self.to_array().map(day => day.short_name())
logger.write_string("[" + names.join(", ") + "]")
}
///|
pub extend WeekdaySet with Show::{to_string, output}
///|
pub extend WeekdaySet with Hash::{hash, hash_combine}
///|
/// The empty set; see `empty`.
pub impl Default for WeekdaySet with fn default() {
WeekdaySet::empty()
}
///|
pub extend WeekdaySet with Default::{default}
///|
pub extend WeekdaySet with @debug.Debug::{to_repr}
///|
let all_weekdays : Array[Weekday] = [Mon, Tue, Wed, Thu, Fri, Sat, Sun]
///|
fn bit_for(day : Weekday) -> Int {
1 << day.index()
}
///|
/// The empty set, containing no weekdays; `Default::default()` returns it.
pub fn WeekdaySet::empty() -> WeekdaySet {
{ bits: 0, }
}
///|
/// The set containing all seven weekdays.
pub fn WeekdaySet::all() -> WeekdaySet {
{ bits: 0b111_1111, }
}
///|
/// A set containing exactly the given weekday; `single_day` reads it back.
pub fn WeekdaySet::single(day : Weekday) -> WeekdaySet {
{ bits: bit_for(day), }
}
///|
/// A set containing exactly the given weekdays.
pub fn WeekdaySet::from_array(days : Array[Weekday]) -> WeekdaySet {
let mut bits = 0
for day in days {
bits = bits | bit_for(day)
}
{ bits, }
}
///|
/// `Some(day)` if the set contains exactly one weekday, `None` otherwise; the
/// inverse of `WeekdaySet::single`.
pub fn WeekdaySet::single_day(self : WeekdaySet) -> Weekday? {
match self.bits {
0b000_0001 => Some(Mon)
0b000_0010 => Some(Tue)
0b000_0100 => Some(Wed)
0b000_1000 => Some(Thu)
0b001_0000 => Some(Fri)
0b010_0000 => Some(Sat)
0b100_0000 => Some(Sun)
_ => None
}
}
///|
/// The set with `day` added, unchanged if it was already a member.
pub fn WeekdaySet::insert(self : WeekdaySet, day : Weekday) -> WeekdaySet {
{ bits: self.bits | bit_for(day), }
}
///|
/// The set with `day` removed, unchanged if it was not a member.
pub fn WeekdaySet::remove(self : WeekdaySet, day : Weekday) -> WeekdaySet {
{ bits: self.bits & bit_for(day).lnot(), }
}
///|
/// Whether the set contains `day`.
pub fn WeekdaySet::contains(self : WeekdaySet, day : Weekday) -> Bool {
(self.bits & bit_for(day)) != 0
}
///|
/// Whether every weekday in `self` is also in `other`.
pub fn WeekdaySet::is_subset(self : WeekdaySet, other : WeekdaySet) -> Bool {
self.intersection(other) == self
}
///|
/// Weekdays that are in both `self` and `other`.
pub fn WeekdaySet::intersection(
self : WeekdaySet,
other : WeekdaySet,
) -> WeekdaySet {
{ bits: self.bits & other.bits, }
}
///|
/// Weekdays that are in either `self` or `other`.
pub fn WeekdaySet::union(self : WeekdaySet, other : WeekdaySet) -> WeekdaySet {
{ bits: self.bits | other.bits, }
}
///|
/// Weekdays that are in `self` or `other`, but not in both.
pub fn WeekdaySet::symmetric_difference(
self : WeekdaySet,
other : WeekdaySet,
) -> WeekdaySet {
{ bits: self.bits ^ other.bits, }
}
///|
/// Weekdays that are in `self` but not in `other`.
pub fn WeekdaySet::difference(
self : WeekdaySet,
other : WeekdaySet,
) -> WeekdaySet {
{ bits: self.bits & other.bits.lnot(), }
}
///|
/// The earliest weekday in the set, starting from Monday.
pub fn WeekdaySet::first(self : WeekdaySet) -> Weekday? {
for day in all_weekdays {
if self.contains(day) {
return Some(day)
}
}
None
}
///|
/// The latest weekday in the set, starting from Sunday.
pub fn WeekdaySet::last(self : WeekdaySet) -> Weekday? {
for i = all_weekdays.length() - 1; i >= 0; i = i - 1 {
let day = all_weekdays[i]
if self.contains(day) {
return Some(day)
}
}
None
}
///|
/// Whether the set contains no weekdays.
pub fn WeekdaySet::is_empty(self : WeekdaySet) -> Bool {
self.bits == 0
}
///|
/// The number of weekdays in the set.
pub fn WeekdaySet::length(self : WeekdaySet) -> Int {
let mut count = 0
for day in all_weekdays {
if self.contains(day) {
count = count + 1
}
}
count
}
///|
/// The weekdays in the set, in `Mon..Sun` order.
pub fn WeekdaySet::to_array(self : WeekdaySet) -> Array[Weekday] {
let result = []
for day in all_weekdays {
if self.contains(day) {
result.push(day)
}
}
result
}