bellframe/row/
same_stage_vec.rs

1use std::{
2    fmt::{Debug, Display, Formatter},
3    ops::{Index, Range, RangeBounds},
4};
5
6use itertools::Itertools;
7
8use crate::{utils, Bell, Block, InvalidRowError, Row, RowBuf, Stage};
9
10use super::DbgRow;
11
12/// A heap-allocated buffer of [`Row`]s which are required to have the same [`Stage`].  Collecting
13/// [`Row`]s of the same [`Stage`] is nearly always what we want, and having a type to enforce this
14/// is convenient.
15///
16/// Requiring matching [`Stage`]s has useful performance benefits too.  These stem from the fact
17/// that the [`Row`]s can simply be stored sequentially in one [`Vec`] without any indirection or
18/// extra allocations.  This is both more cache-friendly and uses less memory.
19///
20/// Additionally, having a linear memory layout makes `SameStageVec`s extremely amenable to SIMD
21/// optimisations (which haven't yet been implemented).  This would allow us to do common
22/// operations (like permuting all the [`Row`]s or finding the path of a [`Bell`]) extremely
23/// quickly.  For example, SIMD can perform permutation at 16 bells per CPU cycle (or 32 on very
24/// new CPUs).
25///
26/// # Example
27///
28/// ```
29/// use bellframe::{RowBuf, SameStageVec, Stage};
30///
31/// // Create a new `SameStageVec` for 6-bell rows
32/// let mut new_buffer = SameStageVec::new(Stage::MINOR);
33/// // Add some nice rows
34/// new_buffer.push(&RowBuf::rounds(Stage::MINOR));
35/// new_buffer.push(&RowBuf::queens(Stage::MINOR));
36/// new_buffer.push(&RowBuf::backrounds(Stage::MINOR));
37/// // `new_buffer` now contains 3 rows
38/// assert_eq!(new_buffer.len(), 3);
39/// // The 3rd row is backrounds
40/// assert!(new_buffer[2].is_backrounds());
41/// ```
42#[derive(Clone, PartialEq, Eq, Hash)]
43pub struct SameStageVec {
44    /// A contiguous chunk of [`Bell`]s, containing all the [`Row`]s concatenated together.  For
45    /// example, the start of a plain course of Cambridge Surprise Minor would be stored as
46    /// `123456214365124635216453261435624153621435...`
47    /// or, with spaces inserted between rows for ease of display:
48    /// `123456 214365 124635 216453 261435 624153 621435 ...`
49    ///
50    /// **Invariant**: Each [`Stage`]-aligned segment of `bells` must form a valid [`Row`]
51    /// according to the Framework (see [`Row`]'s docs).  A sub-slice is [`Stage`]-aligned if its
52    /// length is `self.stage` and its start index is an integer multiple of `self.stage`.
53    ///
54    /// **Invariant**: `self.bells.len()` is an integer multiple of `self.stage`.
55    bells: Vec<Bell>,
56    /// The [`Stage`] of all the [`Row`]s in this buffer.
57    stage: Stage,
58}
59
60impl SameStageVec {
61    //////////////////
62    // CONSTRUCTORS //
63    //////////////////
64
65    /// Creates a new `SameStageVec` containing no [`Row`]s, expecting to be given [`Row`]s of a
66    /// given [`Stage`].  Identical to [`SameStageVec::empty`].
67    #[inline]
68    pub fn new(stage: Stage) -> Self {
69        Self::empty(stage)
70    }
71
72    /// Creates a new `SameStageVec` containing no [`Row`]s, expecting to be given [`Row`]s of a
73    /// given [`Stage`].  Identical to [`SameStageVec::new`].
74    #[inline]
75    pub fn empty(stage: Stage) -> Self {
76        Self {
77            bells: Vec::new(),
78            stage,
79        }
80    }
81
82    /// Creates a new `SameStageVec` that can hold `capacity` [`Row`]s without re-allocating, and
83    /// all the [`Row`]s are expected to have a given [`Stage`].
84    ///
85    /// # Panics
86    ///
87    /// Panics if `Stage::ZERO` is passed.
88    #[inline]
89    pub fn with_capacity(stage: Stage, capacity: usize) -> Self {
90        Self {
91            bells: Vec::with_capacity(capacity * stage.num_bells()),
92            stage,
93        }
94    }
95
96    /// Creates a `SameStageVec` containing exactly one row, reusing the allocation from an
97    /// existing [`RowBuf`].
98    #[inline]
99    pub fn from_row_buf(row: RowBuf) -> Self {
100        let stage = row.stage();
101        // SAFETY: `row.to_bell_vec()` generates a Vec containing the `Bell`s of exactly one valid `Row`
102        unsafe { Self::from_bell_vec_unchecked(row.into_bell_vec(), stage) }
103    }
104
105    /// Parse a `SameStageVec` from a [`str`]ing, where each line is parsed into a [`Row`].
106    pub fn parse(s: &str) -> Result<Self, ParseError> {
107        // Create an iterator of (line_num, line) pairs, where `line_number` is indexed from 1
108        let mut line_iter = s.lines().enumerate().map(|(idx, v)| (idx + 1, v));
109
110        // Parse the first line before creating the `SameStageVec` (since we need to know upfront
111        // what the stage is going to be).
112        let (_one, first_line) = line_iter.next().unwrap(); // strings always contain at least one line
113        let first_row =
114            RowBuf::parse(first_line).map_err(|err| ParseError::InvalidRow { line_num: 1, err })?;
115        // Create a `SameStageVec`, which starts out containing the first row
116        let mut new_vec = SameStageVec::from_row_buf(first_row.clone());
117
118        // Now parse the rest of the lines into the new `SameStageVec`
119        for (line_num, line) in line_iter {
120            // Parse the line into a Row, and fail if its either invalid or doesn't match the stage
121            let parsed_row =
122                RowBuf::parse(line).map_err(|err| ParseError::InvalidRow { line_num, err })?;
123            if parsed_row.stage() != first_row.stage() {
124                return Err(ParseError::IncompatibleStages {
125                    line_num,
126                    first_stage: first_row.stage(),
127                    different_stage: parsed_row.stage(),
128                });
129            }
130            new_vec.push(&parsed_row);
131        }
132
133        Ok(new_vec)
134    }
135
136    /// Creates a `SameStageVec` from a [`Vec`] of [`Bell`]s (containing the [`Row`]s concatenated
137    /// together), without checking that they correspond to valid [`Row`]s.
138    ///
139    /// # Safety
140    ///
141    /// This function is safe if `bells` is formed of a sequence of valid [`Row`]s (each of the
142    /// provided [`Stage`]) concatenated together.
143    #[inline]
144    pub unsafe fn from_bell_vec_unchecked(bells: Vec<Bell>, stage: Stage) -> Self {
145        Self { bells, stage }
146    }
147
148    //////////////////
149    // SIZE GETTERS //
150    //////////////////
151
152    /// The [`Stage`] of every [`Row`] in this `SameStageVec`.
153    #[inline]
154    pub fn stage(&self) -> Stage {
155        self.stage
156    }
157
158    /// Gets the number of [`Row`]s contained in this `SameStageVec`
159    #[inline]
160    pub fn len(&self) -> usize {
161        // In debug builds, check that `bells` contains a whole number of rows
162        debug_assert!(self.bells.len() % self.stage.num_bells() == 0);
163        // Calculate the length
164        self.bells.len() / self.stage.num_bells()
165    }
166
167    /// Returns `true` if this `SameStageVec` contains no [`Row`]s.
168    #[inline]
169    pub fn is_empty(&self) -> bool {
170        self.bells.is_empty()
171    }
172
173    /////////////////
174    // ROW GETTERS //
175    /////////////////
176
177    /// Gets a reference to the [`Row`] at a given `index`, or `None` if `index >= self.len()`.
178    pub fn get(&self, index: usize) -> Option<&Row> {
179        let bell_slice = self.bells.get(self.get_range_of_row(index))?;
180        // SAFETY: by invariant, each stage-aligned segment of `self.bells` is a valid `Row`
181        Some(unsafe { Row::from_slice_unchecked(bell_slice) })
182    }
183
184    /// Gets a mutable reference to the [`Row`] at a given `index`, or `None` if
185    /// `index >= self.len()`.
186    pub fn get_mut(&mut self, index: usize) -> Option<&mut Row> {
187        let range = self.get_range_of_row(index);
188        let bell_slice = self.bells.get_mut(range)?;
189        // SAFETY: by invariant, each stage-aligned segment of `self.bells` is a valid `Row`
190        Some(unsafe { Row::from_mut_slice_unchecked(bell_slice) })
191    }
192
193    /// Returns a [`RowSlice`] containing all the rows [`Row`] in this [`SameStageVec`].
194    pub fn as_slice(&self) -> RowSlice {
195        RowSlice {
196            bells: &self.bells,
197            stage: self.stage,
198        }
199    }
200
201    /// Returns a [`RowSlice`] containing all the rows [`Row`] in this [`SameStageVec`].
202    pub fn as_slice_range(&self, range: impl RangeBounds<usize>) -> RowSlice {
203        let inclusive_start = match range.start_bound() {
204            std::ops::Bound::Included(&s) => s,
205            std::ops::Bound::Excluded(&s) => s + 1,
206            std::ops::Bound::Unbounded => 0,
207        };
208        let exclusive_end = match range.end_bound() {
209            std::ops::Bound::Included(&s) => s + 1,
210            std::ops::Bound::Excluded(&s) => s,
211            std::ops::Bound::Unbounded => self.len(),
212        };
213        let bell_range =
214            (inclusive_start * self.stage.num_bells())..(exclusive_end * self.stage.num_bells());
215        RowSlice {
216            bells: &self.bells[bell_range],
217            stage: self.stage,
218        }
219    }
220
221    /// Gets a reference to the first [`Row`], if it exists.
222    pub fn first(&self) -> Option<&Row> {
223        self.get(0)
224    }
225
226    /// Gets a mutable reference to the first [`Row`], if it exists.
227    pub fn first_mut(&mut self) -> Option<&mut Row> {
228        self.get_mut(0)
229    }
230
231    /// Gets a reference to the last [`Row`], if it exists.
232    pub fn last(&self) -> Option<&Row> {
233        self.get(self.len().checked_sub(1)?)
234    }
235
236    /// Gets a mutable reference to the last [`Row`], if it exists.
237    pub fn last_mut(&mut self) -> Option<&mut Row> {
238        self.get_mut(self.len().checked_sub(1)?)
239    }
240
241    /// Returns an [`Iterator`] over the [`Row`]s in this buffer.
242    #[inline]
243    pub fn iter(&self) -> Iter {
244        Iter {
245            // The invariant on `bells_left` follows because there is an identical invariant on
246            // `SameStageVec.bells`
247            bells_left: &self.bells,
248            stage: self.stage,
249        }
250    }
251
252    /// Returns a [`Vec`] containing the place of a [`Bell`] in each [`Row`] in this
253    /// `SameStageVec`.  Returns `None` if the [`Bell`] exceeds the [`Stage`] of `self`.
254    pub fn path_of(&self, bell: Bell) -> Vec<usize> {
255        self.iter().map(|r| r.place_of(bell).unwrap()).collect_vec()
256    }
257
258    ////////////////
259    // OPERATIONS //
260    ////////////////
261
262    /// Mutates `self` to become empty
263    #[inline]
264    pub fn clear(&mut self) {
265        self.bells.clear();
266    }
267
268    /// Adds a new [`Row`] to the end of the buffer, checking that its [`Stage`] is as expected.
269    #[inline]
270    #[track_caller]
271    pub fn push(&mut self, row: &Row) {
272        self.check_stage("row", row.stage());
273        self.bells.extend(row.bell_iter());
274    }
275
276    /// Removes the last [`Row`] from `self` and returning if it.  Returns `None` if `self`
277    /// contains no elements.
278    #[inline]
279    pub fn pop(&mut self) -> Option<RowBuf> {
280        // Compute the index of the first `Bell` in the last `Row`, and return `None` if that index
281        // would be negative
282        let start_index = self.bells.len().checked_sub(self.stage.num_bells())?;
283        debug_assert_eq!(self.bells.len() % self.stage.num_bells(), 0);
284        debug_assert_eq!(start_index % self.stage.num_bells(), 0);
285        // SAFETY: `start_index` and `self.bells.len()` are multiples of `self.stage.num_bells()`,
286        // so `self.bells[start_index..]` is 'stage-aligned'.  By invariant, every stage-aligned
287        // segment of `self.bells` is a valid `Row`.
288        Some(unsafe { RowBuf::from_bell_iter_unchecked(self.bells.drain(start_index..)) })
289    }
290
291    /// Extends this buffer with the [`Row`]s yielded by an [`Iterator`].  If any of the [`Row`]s
292    /// cause a [`Stage`] mismatch, an error is returned and the buffer is left unchanged.
293    pub fn extend<T: AsRef<Row>>(&mut self, row_iter: impl IntoIterator<Item = T>) {
294        for r in row_iter.into_iter() {
295            self.bells.extend(r.as_ref().bell_iter());
296        }
297    }
298
299    /// Extend `self` with the [`Row`]s from `other`, returning an error if the [`Stage`]s don't
300    /// match.  `x.extend_from_buf(y)` has the same effect as `x.extend(y)` (because
301    /// `&SameStageVec` implements [`IntoIterator`]) but `extend_from_buf` is faster since the
302    /// [`Stage`] comparison is only performed once.
303    #[inline]
304    #[track_caller]
305    pub fn extend_from_buf(&mut self, other: &Self) {
306        self.check_stage("other block", other.stage());
307        self.bells.extend(other.bells.iter().copied()); // Copy bells across in one go
308    }
309
310    /// Extend `self` with the [`Row`]s from another [`SameStageVec`], pre-multiplying them all by
311    /// a given [`Row`].
312    #[inline]
313    #[track_caller]
314    pub fn extend_transposed(&mut self, transposition: &Row, other: &Self) {
315        self.extend_range_transposed(transposition, other, ..)
316    }
317
318    /// Extend `self` with the [`Row`]s from a region of another [`SameStageVec`], pre-multiplying
319    /// them all by a given [`Row`].
320    #[inline]
321    #[track_caller]
322    pub fn extend_range_transposed(
323        &mut self,
324        transposition: &Row,
325        other: &Self,
326        range: impl RangeBounds<usize>,
327    ) {
328        self.check_stage("transposition", transposition.stage());
329        // TODO: Write a vectorised routine for this
330        self.bells.extend(
331            other.bells[other.to_bell_range(range)]
332                .iter()
333                .map(|b| transposition[b.index()]),
334        );
335    }
336
337    /// Take a range of `self`, pre-multiply all the `Row`s and extend `self` with them.
338    #[inline]
339    #[track_caller]
340    pub fn extend_transposed_from_within(
341        &mut self,
342        range: impl RangeBounds<usize>,
343        transposition: &Row,
344    ) {
345        self.check_stage("transposition", transposition.stage());
346        // Copy the bells one-by-one, because otherwise we'd have to borrow `self.bells` twice and
347        // the borrow checker doesn't like that.
348        for i in self.to_bell_range(range) {
349            let transposed_bell = transposition[self.bells[i].index()];
350            self.bells.push(transposed_bell);
351        }
352    }
353
354    /// Pre-multiplies every [`Row`] in this `Block` in-place by another [`Row`].
355    #[track_caller]
356    pub fn pre_multiply(&mut self, lhs_row: &Row) {
357        self.check_stage("LHS row", lhs_row.stage());
358        // TODO: Write vectorised routine for this
359        for b in &mut self.bells {
360            // SAFETY:
361            // - We know that `self.stage() == lhs_row.stage()`
362            // - Because of the `Row` invariants, `b.index() < self.stage()` for all `b` in
363            //   `self.bells`
364            // => `b.index() < lhs_row.stage()` for every `b`
365            *b = unsafe { lhs_row.get_bell_unchecked(b.index()) };
366        }
367    }
368
369    /// Creates a copy of `self`, where every [`Row`] has been pre-multiplied by another [`Row`].
370    pub fn pre_multiplied(&self, lhs_row: &Row) -> Self {
371        let mut new_vec = Self::new(self.stage);
372        new_vec.extend_transposed(lhs_row, self);
373        new_vec
374    }
375
376    /// Splits `self` into two `SameStageVec`s (`a` and `b`) where:
377    /// - `a.len() == index`, and
378    /// - `self == a.extend_from_buf(&b)` (i.e. no rows are created or destroyed)
379    ///
380    /// Returns `None` if `index > self.len()`
381    pub fn split(self, index: usize) -> Option<(Self, Self)> {
382        let (left_bells, right_bells) =
383            utils::split_vec(self.bells, index * self.stage.num_bells())?;
384        Some((
385            // SAFETY: `self.bells` is split at an integer multiple of `self.stage`, which must be
386            // a row boundary, so each side is a valid sequence of `Row`s
387            unsafe { Self::from_bell_vec_unchecked(left_bells, self.stage) },
388            unsafe { Self::from_bell_vec_unchecked(right_bells, self.stage) },
389        ))
390    }
391
392    //////////////////////
393    // HELPER FUNCTIONS //
394    //////////////////////
395
396    /// Converts a generic [`RangeBounds`] **over [`Row`]s** into a [`Range`] **over [`Bell`]s**
397    /// which explicitly refers to the same region of `self`.
398    #[allow(clippy::let_and_return)]
399    fn to_bell_range(&self, range: impl RangeBounds<usize>) -> Range<usize> {
400        let row_range = utils::clamp_range(range, self.len());
401        let bell_range =
402            row_range.start * self.stage.num_bells()..row_range.end * self.stage.num_bells();
403        bell_range
404    }
405
406    /// Gets the [`Range`] of `self.bells` which would contain the [`Row`] at a given `index`.
407    fn get_range_of_row(&self, index: usize) -> Range<usize> {
408        let s = self.stage.num_bells();
409        index * s..(index + 1) * s
410    }
411
412    #[track_caller]
413    fn check_stage(&self, name: &str, rhs_stage: Stage) {
414        assert_eq!(
415            self.stage, rhs_stage,
416            "Stage mismatch: `Block` has stage {:?} but {:?} has stage {:?}",
417            self.stage, name, rhs_stage,
418        );
419    }
420}
421
422/// A slice of [`Row`]s of the same [`Stage`], stored consecutively in memory.
423#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
424pub struct RowSlice<'a> {
425    pub bells: &'a [Bell],
426    pub stage: Stage,
427}
428
429impl<'r> RowSlice<'r> {
430    pub fn from_row(row: &'r Row) -> RowSlice<'r> {
431        Self {
432            bells: row.bells(),
433            stage: row.stage(),
434        }
435    }
436}
437
438impl<'r> From<&'r Row> for RowSlice<'r> {
439    fn from(row: &'r Row) -> Self {
440        Self::from_row(row)
441    }
442}
443
444impl<'r> From<&'r RowBuf> for RowSlice<'r> {
445    fn from(row: &'r RowBuf) -> Self {
446        Self::from_row(row.as_row())
447    }
448}
449
450impl<'r> From<&'r SameStageVec> for RowSlice<'r> {
451    fn from(vec: &'r SameStageVec) -> Self {
452        vec.as_slice()
453    }
454}
455
456impl<'r, T> From<&'r Block<T>> for RowSlice<'r> {
457    fn from(block: &'r Block<T>) -> Self {
458        block.row_vec().as_slice_range(..block.len())
459    }
460}
461
462impl Index<usize> for SameStageVec {
463    type Output = Row;
464
465    #[track_caller]
466    fn index(&self, index: usize) -> &Self::Output {
467        self.get(index).unwrap_or_else(|| {
468            panic!(
469                "Index of `SameStageVec` is out of range (index was {} but there are only {} rows)",
470                index,
471                self.len()
472            )
473        })
474    }
475}
476
477impl Debug for SameStageVec {
478    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
479        let mut formatter = f.debug_tuple("SameStageVec");
480        for row in self {
481            formatter.field(&DbgRow(row)); // Only display the bells
482        }
483        formatter.finish()
484    }
485}
486
487impl<'v> IntoIterator for &'v SameStageVec {
488    type Item = &'v Row;
489
490    type IntoIter = Iter<'v>;
491
492    fn into_iter(self) -> Self::IntoIter {
493        self.iter()
494    }
495}
496
497/// An [`Iterator`] which yields [`Row`]s from a [`SameStageVec`]
498#[derive(Debug, Clone)]
499pub struct Iter<'v> {
500    /// Invariant: Just like [`SameStageVec`], every [`Stage`]-aligned segment of `bells_left` must
501    /// form a valid row according to the Framework.
502    bells_left: &'v [Bell],
503    stage: Stage,
504}
505
506impl<'v> Iterator for Iter<'v> {
507    type Item = &'v Row;
508
509    fn next(&mut self) -> Option<Self::Item> {
510        if self.bells_left.is_empty() {
511            return None;
512        }
513        // Remove the first `self.stage` elements from `self.bells_left`.  Since we've removed
514        // `self.stage` items, this means that the stage-aligned segments haven't changed, so the
515        // invariant on `self.bells_left` is still satisfied.
516        let (next_row, future_rows) = self.bells_left.split_at(self.stage.num_bells());
517        self.bells_left = future_rows;
518        // SAFETY: the invariant on `self.bells_left` requires that `next_row` (a stage-aligned
519        // segment of `self.bells_left`) forms a valid `Row`.
520        Some(unsafe { Row::from_slice_unchecked(next_row) })
521    }
522
523    // PERF: Implement better routines for methods such as `nth`, etc. for which repeatedly calling
524    // `next()` is unnecessarily slow.
525}
526
527impl<'v> DoubleEndedIterator for Iter<'v> {
528    fn next_back(&mut self) -> Option<Self::Item> {
529        if self.bells_left.is_empty() {
530            return None;
531        }
532        // Remove the last `self.stage` elements from `self.bells_left`.  Since we've removed
533        // `self.stage` items, this means that the stage-aligned segments haven't changed, so the
534        // invariant on `self.bells_left` is still satisfied.
535        let (future_rows, next_row) = self
536            .bells_left
537            .split_at(self.bells_left.len() - self.stage.num_bells());
538        self.bells_left = future_rows;
539        // SAFETY: the invariant on `self.bells_left` requires that `next_row` (a stage-aligned
540        // segment of `self.bells_left`) forms a valid `Row`.
541        Some(unsafe { Row::from_slice_unchecked(next_row) })
542    }
543}
544
545impl<'v> ExactSizeIterator for Iter<'v> {
546    #[inline]
547    fn len(&self) -> usize {
548        self.bells_left.len() / self.stage.num_bells()
549    }
550}
551
552/// The possible ways that [`SameStageVec::parse`] could fail
553#[derive(Debug, Clone)]
554pub enum ParseError {
555    ZeroStage,
556    InvalidRow {
557        line_num: usize,
558        err: InvalidRowError,
559    },
560    IncompatibleStages {
561        line_num: usize,
562        first_stage: Stage,
563        different_stage: Stage,
564    },
565}
566
567impl Display for ParseError {
568    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
569        match self {
570            ParseError::ZeroStage => write!(f, "Can't make a `SameStageVec` with stage 0"),
571            ParseError::InvalidRow {
572                line_num: line,
573                err,
574            } => {
575                write!(f, "Error parsing row on line {}: {}", line, err)
576            }
577            ParseError::IncompatibleStages {
578                line_num: line,
579                first_stage,
580                different_stage,
581            } => {
582                write!(
583                    f,
584                    "Row on line {} has different stage ({}) to the first stage ({})",
585                    line, different_stage, first_stage
586                )
587            }
588        }
589    }
590}
591
592impl std::error::Error for ParseError {}