card_est_array/impls/
slice_estimator_array.rs

1/*
2 * SPDX-FileCopyrightText: 2024 Matteo Dell'Acqua
3 * SPDX-FileCopyrightText: 2025 Sebastiano Vigna
4 *
5 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6 */
7
8use super::DefaultEstimator;
9use crate::traits::*;
10use sux::traits::Word;
11use sync_cell_slice::{SyncCell, SyncSlice};
12
13/// An array for estimators implementing a shared [`EstimationLogic`], and whose
14/// backend is a slice.
15///
16/// Note that we need a specific type for arrays of slice backends as one cannot
17/// create a slice of slices.
18pub struct SliceEstimatorArray<L, W, S> {
19    pub(super) logic: L,
20    pub(super) backend: S,
21    _marker: std::marker::PhantomData<W>,
22}
23
24/// A view of a [`SliceEstimatorArray`] as a [`SyncEstimatorArray`].
25pub struct SyncSliceEstimatorArray<L, W, S> {
26    pub(super) logic: L,
27    pub(super) backend: S,
28    _marker: std::marker::PhantomData<W>,
29}
30
31unsafe impl<L, W, S> Sync for SyncSliceEstimatorArray<L, W, S>
32where
33    L: Sync,
34    W: Sync,
35    S: Sync,
36{
37}
38
39impl<L: SliceEstimationLogic<W> + Sync, W: Word, S: AsRef<[SyncCell<W>]> + Sync>
40    SyncEstimatorArray<L> for SyncSliceEstimatorArray<L, W, S>
41{
42    unsafe fn set(&self, index: usize, content: &L::Backend) {
43        debug_assert!(content.as_ref().len() == self.logic.backend_len());
44        let offset = index * self.logic.backend_len();
45        for (c, &b) in self.backend.as_ref()[offset..].iter().zip(content.as_ref()) {
46            c.set(b)
47        }
48    }
49
50    fn logic(&self) -> &L {
51        &self.logic
52    }
53
54    unsafe fn get(&self, index: usize, backend: &mut L::Backend) {
55        debug_assert!(backend.as_ref().len() == self.logic.backend_len());
56        let offset = index * self.logic.backend_len();
57        for (b, c) in backend
58            .iter_mut()
59            .zip(self.backend.as_ref()[offset..].iter())
60        {
61            *b = c.get();
62        }
63    }
64
65    unsafe fn clear(&self) {
66        self.backend.as_ref().iter().for_each(|c| c.set(W::ZERO))
67    }
68
69    fn len(&self) -> usize {
70        self.backend.as_ref().len() / self.logic.backend_len()
71    }
72}
73
74impl<L: SliceEstimationLogic<W>, W, S: AsRef<[W]>> SliceEstimatorArray<L, W, S> {
75    /// Returns the number of estimators in the array.
76    #[inline(always)]
77    pub fn len(&self) -> usize {
78        let backend = self.backend.as_ref();
79        debug_assert!(backend.len() % self.logic.backend_len() == 0);
80        backend.len() / self.logic.backend_len()
81    }
82
83    /// Returns `true` if the array contains no estimators.
84    #[inline(always)]
85    pub fn is_empty(&self) -> bool {
86        self.backend.as_ref().is_empty()
87    }
88}
89
90impl<L: SliceEstimationLogic<W> + Clone + Sync, W: Word, S: AsMut<[W]>> AsSyncArray<L>
91    for SliceEstimatorArray<L, W, S>
92{
93    type SyncEstimatorArray<'a>
94        = SyncSliceEstimatorArray<L, W, &'a [SyncCell<W>]>
95    where
96        Self: 'a;
97
98    fn as_sync_array(&mut self) -> SyncSliceEstimatorArray<L, W, &[SyncCell<W>]> {
99        SyncSliceEstimatorArray {
100            logic: self.logic.clone(),
101            backend: self.backend.as_mut().as_sync_slice(),
102            _marker: std::marker::PhantomData,
103        }
104    }
105}
106
107impl<L, W, S: AsRef<[W]>> AsRef<[W]> for SliceEstimatorArray<L, W, S> {
108    fn as_ref(&self) -> &[W] {
109        self.backend.as_ref()
110    }
111}
112
113impl<L, W, S: AsMut<[W]>> AsMut<[W]> for SliceEstimatorArray<L, W, S> {
114    fn as_mut(&mut self) -> &mut [W] {
115        self.backend.as_mut()
116    }
117}
118
119impl<L: SliceEstimationLogic<W>, W: Word> SliceEstimatorArray<L, W, Box<[W]>> {
120    /// Creates a new estimator slice with the provided logic.
121    ///
122    /// # Arguments
123    /// * `logic`: the estimator logic to use.
124    /// * `len`: the number of the estimators in the array.
125    pub fn new(logic: L, len: usize) -> Self {
126        let num_backend_len = logic.backend_len();
127        let backend = vec![W::ZERO; len * num_backend_len].into();
128        Self {
129            logic,
130            backend,
131            _marker: std::marker::PhantomData,
132        }
133    }
134}
135
136impl<L: SliceEstimationLogic<W> + Clone, W: Word, S: AsRef<[W]>> EstimatorArray<L>
137    for SliceEstimatorArray<L, W, S>
138{
139    type Estimator<'a>
140        = DefaultEstimator<L, &'a L, &'a [W]>
141    where
142        Self: 'a;
143
144    #[inline(always)]
145    fn get_backend(&self, index: usize) -> &L::Backend {
146        let offset = index * self.logic.backend_len();
147        &self.backend.as_ref()[offset..][..self.logic.backend_len()]
148    }
149
150    #[inline(always)]
151    fn logic(&self) -> &L {
152        &self.logic
153    }
154
155    #[inline(always)]
156    fn get_estimator(&self, index: usize) -> Self::Estimator<'_> {
157        DefaultEstimator::new(&self.logic, self.get_backend(index))
158    }
159
160    #[inline(always)]
161    fn len(&self) -> usize {
162        self.len()
163    }
164}
165
166impl<L: SliceEstimationLogic<W> + Clone, W: Word, S: AsRef<[W]> + AsMut<[W]>> EstimatorArrayMut<L>
167    for SliceEstimatorArray<L, W, S>
168{
169    type EstimatorMut<'a>
170        = DefaultEstimator<L, &'a L, &'a mut [W]>
171    where
172        Self: 'a;
173
174    #[inline(always)]
175    fn get_backend_mut(&mut self, index: usize) -> &mut L::Backend {
176        let offset = index * self.logic.backend_len();
177        &mut self.backend.as_mut()[offset..][..self.logic.backend_len()]
178    }
179
180    #[inline(always)]
181    fn get_estimator_mut(&mut self, index: usize) -> Self::EstimatorMut<'_> {
182        let logic = &self.logic;
183        // We have to extract manually the backend because get_backend_mut
184        // borrows self mutably, but we need to borrow just self.backend.
185        let offset = index * self.logic.backend_len();
186        let backend = &mut self.backend.as_mut()[offset..][..self.logic.backend_len()];
187
188        DefaultEstimator::new(logic, backend)
189    }
190
191    #[inline(always)]
192    fn clear(&mut self) {
193        self.backend.as_mut().iter_mut().for_each(|v| *v = W::ZERO)
194    }
195}