reed_solomon_16/engine/
shards.rs

1use std::ops::{Bound, Index, IndexMut, RangeBounds};
2
3// ======================================================================
4// Shards - CRATE
5
6pub(crate) struct Shards {
7    shard_count: usize,
8    shard_bytes: usize,
9
10    // Flat array of `shard_count * shard_bytes` bytes.
11    data: Vec<u8>,
12}
13
14impl Shards {
15    pub(crate) fn as_ref_mut(&mut self) -> ShardsRefMut {
16        ShardsRefMut::new(self.shard_count, self.shard_bytes, self.data.as_mut())
17    }
18
19    pub(crate) fn new() -> Self {
20        Self {
21            shard_count: 0,
22            shard_bytes: 0,
23            data: Vec::new(),
24        }
25    }
26
27    pub(crate) fn resize(&mut self, shard_count: usize, shard_bytes: usize) {
28        assert!(shard_bytes > 0 && shard_bytes & 63 == 0);
29
30        self.shard_count = shard_count;
31        self.shard_bytes = shard_bytes;
32
33        self.data.resize(shard_count * shard_bytes, 0);
34    }
35}
36
37// ======================================================================
38// Shards - IMPL Index
39
40impl Index<usize> for Shards {
41    type Output = [u8];
42    fn index(&self, index: usize) -> &Self::Output {
43        &self.data[index * self.shard_bytes..(index + 1) * self.shard_bytes]
44    }
45}
46
47// ======================================================================
48// Shards - IMPL IndexMut
49
50impl IndexMut<usize> for Shards {
51    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
52        &mut self.data[index * self.shard_bytes..(index + 1) * self.shard_bytes]
53    }
54}
55
56// ======================================================================
57// ShardsRefMut - PUBLIC
58
59/// Mutable reference to shard array implemented as flat byte array.
60pub struct ShardsRefMut<'a> {
61    shard_count: usize,
62    shard_bytes: usize,
63
64    // Flat array of `shard_count * shard_bytes` bytes.
65    data: &'a mut [u8],
66}
67
68impl<'a> ShardsRefMut<'a> {
69    /// Returns mutable references to shards at `pos` and `pos + dist`.
70    ///
71    /// See source code of [`Naive::fft`] for an example.
72    ///
73    /// # Panics
74    ///
75    /// If `dist` is `0`.
76    ///
77    /// [`Naive::fft`]: crate::engine::Naive#method.fft
78    pub fn dist2_mut(&mut self, mut pos: usize, mut dist: usize) -> (&mut [u8], &mut [u8]) {
79        pos *= self.shard_bytes;
80        dist *= self.shard_bytes;
81
82        let (a, b) = self.data[pos..].split_at_mut(dist);
83        (&mut a[..self.shard_bytes], &mut b[..self.shard_bytes])
84    }
85
86    /// Returns mutable references to shards at
87    /// `pos`, `pos + dist`, `pos + dist * 2` and `pos + dist * 3`.
88    ///
89    /// See source code of [`NoSimd::fft`] for an example
90    /// (specifically the private method `fft_butterfly_two_layers`).
91    ///
92    /// # Panics
93    ///
94    /// If `dist` is `0`.
95    ///
96    /// [`NoSimd::fft`]: crate::engine::NoSimd#method.fft
97    pub fn dist4_mut(
98        &mut self,
99        mut pos: usize,
100        mut dist: usize,
101    ) -> (&mut [u8], &mut [u8], &mut [u8], &mut [u8]) {
102        pos *= self.shard_bytes;
103        dist *= self.shard_bytes;
104
105        let (ab, cd) = self.data[pos..].split_at_mut(dist * 2);
106        let (a, b) = ab.split_at_mut(dist);
107        let (c, d) = cd.split_at_mut(dist);
108
109        (
110            &mut a[..self.shard_bytes],
111            &mut b[..self.shard_bytes],
112            &mut c[..self.shard_bytes],
113            &mut d[..self.shard_bytes],
114        )
115    }
116
117    /// Returns `true` if this contains no shards.
118    pub fn is_empty(&self) -> bool {
119        self.shard_count == 0
120    }
121
122    /// Returns number of shards.
123    pub fn len(&self) -> usize {
124        self.shard_count
125    }
126
127    /// Creates new [`ShardsRefMut`] that references given `data`.
128    ///
129    /// # Panics
130    ///
131    /// If `data` is smaller than `shard_count * shard_bytes` bytes.
132    pub fn new(shard_count: usize, shard_bytes: usize, data: &'a mut [u8]) -> Self {
133        Self {
134            shard_count,
135            shard_bytes,
136            data: &mut data[..shard_count * shard_bytes],
137        }
138    }
139
140    /// Splits this [`ShardsRefMut`] into two so that
141    /// first includes shards `0..mid` and second includes shards `mid..`.
142    pub fn split_at_mut(&mut self, mid: usize) -> (ShardsRefMut, ShardsRefMut) {
143        let (a, b) = self.data.split_at_mut(mid * self.shard_bytes);
144        (
145            ShardsRefMut::new(mid, self.shard_bytes, a),
146            ShardsRefMut::new(self.shard_count - mid, self.shard_bytes, b),
147        )
148    }
149
150    /// Fills the given shard-range with `0u8`:s.
151    pub fn zero<R: RangeBounds<usize>>(&mut self, range: R) {
152        let start = match range.start_bound() {
153            Bound::Included(start) => start * self.shard_bytes,
154            Bound::Excluded(start) => (start + 1) * self.shard_bytes,
155            Bound::Unbounded => 0,
156        };
157
158        let end = match range.end_bound() {
159            Bound::Included(end) => (end + 1) * self.shard_bytes,
160            Bound::Excluded(end) => end * self.shard_bytes,
161            Bound::Unbounded => self.shard_count * self.shard_bytes,
162        };
163
164        self.data[start..end].fill(0);
165    }
166}
167
168// ======================================================================
169// ShardsRefMut - IMPL Index
170
171impl<'a> Index<usize> for ShardsRefMut<'a> {
172    type Output = [u8];
173    fn index(&self, index: usize) -> &Self::Output {
174        &self.data[index * self.shard_bytes..(index + 1) * self.shard_bytes]
175    }
176}
177
178// ======================================================================
179// ShardsRefMut - IMPL IndexMut
180
181impl<'a> IndexMut<usize> for ShardsRefMut<'a> {
182    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
183        &mut self.data[index * self.shard_bytes..(index + 1) * self.shard_bytes]
184    }
185}
186
187// ======================================================================
188// ShardsRefMut - CRATE
189
190impl<'a> ShardsRefMut<'a> {
191    pub(crate) fn copy_within(&mut self, mut src: usize, mut dest: usize, mut count: usize) {
192        src *= self.shard_bytes;
193        dest *= self.shard_bytes;
194        count *= self.shard_bytes;
195
196        self.data.copy_within(src..src + count, dest);
197    }
198
199    // Returns mutable references to flat-arrays of shard-ranges
200    // `x .. x + count` and `y .. y + count`.
201    //
202    // Ranges must not overlap.
203    pub(crate) fn flat2_mut(
204        &mut self,
205        mut x: usize,
206        mut y: usize,
207        mut count: usize,
208    ) -> (&mut [u8], &mut [u8]) {
209        x *= self.shard_bytes;
210        y *= self.shard_bytes;
211        count *= self.shard_bytes;
212
213        if x < y {
214            let (head, tail) = self.data.split_at_mut(y);
215            (&mut head[x..x + count], &mut tail[..count])
216        } else {
217            let (head, tail) = self.data.split_at_mut(x);
218            (&mut tail[..count], &mut head[y..y + count])
219        }
220    }
221}