1pub struct ChangeMoveSelector<S, V, ES, VS> {
3 entity_selector: ES,
4 value_selector: VS,
5 getter: fn(&S, usize, usize) -> Option<V>,
6 setter: fn(&mut S, usize, usize, Option<V>),
7 descriptor_index: usize,
8 variable_index: usize,
9 variable_name: &'static str,
10 allows_unassigned: bool,
11 _phantom: PhantomData<(fn() -> S, fn() -> V)>,
12}
13
14struct ChangeEntityValues<V> {
15 entity_ref: super::entity::EntityReference,
16 values: Vec<V>,
17 total_values: usize,
20 current_assigned: bool,
21}
22
23pub struct ChangeMoveCursor<S, V>
24where
25 S: PlanningSolution,
26 V: Clone + PartialEq + Send + Sync + Debug + 'static,
27{
28 store: CandidateStore<S, ChangeMove<S, V>>,
29 entity_values: Vec<ChangeEntityValues<V>>,
30 entity_offset: usize,
31 value_offset: usize,
32 getter: fn(&S, usize, usize) -> Option<V>,
33 setter: fn(&mut S, usize, usize, Option<V>),
34 descriptor_index: usize,
35 variable_index: usize,
36 variable_name: &'static str,
37 allows_unassigned: bool,
38}
39
40impl<S, V> ChangeMoveCursor<S, V>
41where
42 S: PlanningSolution,
43 V: Clone + PartialEq + Send + Sync + Debug + 'static,
44{
45 fn new(
46 entity_values: Vec<ChangeEntityValues<V>>,
47 getter: fn(&S, usize, usize) -> Option<V>,
48 setter: fn(&mut S, usize, usize, Option<V>),
49 descriptor_index: usize,
50 variable_index: usize,
51 variable_name: &'static str,
52 allows_unassigned: bool,
53 ) -> Self {
54 Self {
55 store: CandidateStore::new(),
56 entity_values,
57 entity_offset: 0,
58 value_offset: 0,
59 getter,
60 setter,
61 descriptor_index,
62 variable_index,
63 variable_name,
64 allows_unassigned,
65 }
66 }
67
68 #[inline(always)]
69 fn next_move(&mut self) -> Option<ChangeMove<S, V>> {
70 while self.entity_offset < self.entity_values.len() {
71 if self.value_offset < self.entity_values[self.entity_offset].total_values {
72 let entity_values = &mut self.entity_values[self.entity_offset];
73 let value = entity_values
74 .values
75 .drain(..1)
76 .next()
77 .expect("value slot below total_values must exist before its drain");
78 self.value_offset += 1;
79 return Some(ChangeMove::new(
80 entity_values.entity_ref.entity_index,
81 Some(value),
82 self.getter,
83 self.setter,
84 self.variable_index,
85 self.variable_name,
86 self.descriptor_index,
87 ));
88 }
89
90 let current = &self.entity_values[self.entity_offset];
91 let to_none_offset = current.total_values;
92 if self.allows_unassigned
93 && current.current_assigned
94 && self.value_offset == to_none_offset
95 {
96 self.value_offset += 1;
97 return Some(ChangeMove::new(
98 current.entity_ref.entity_index,
99 None,
100 self.getter,
101 self.setter,
102 self.variable_index,
103 self.variable_name,
104 self.descriptor_index,
105 ));
106 }
107
108 self.entity_offset += 1;
109 self.value_offset = 0;
110 }
111 None
112 }
113}
114
115impl<S, V> MoveCursor<S, ChangeMove<S, V>> for ChangeMoveCursor<S, V>
116where
117 S: PlanningSolution,
118 V: Clone + PartialEq + Send + Sync + Debug + 'static,
119{
120 fn next_candidate(&mut self, _solution: &S) -> Option<CandidateId> {
121 let mov = self.next_move()?;
122 Some(self.store.push(mov))
123 }
124
125 fn candidate(
126 &self,
127 id: CandidateId,
128 ) -> Option<MoveCandidateRef<'_, S, ChangeMove<S, V>>> {
129 self.store.candidate(id)
130 }
131
132 fn take_candidate(&mut self, id: CandidateId) -> ChangeMove<S, V> {
133 self.store.take_candidate(id)
134 }
135
136 #[inline(always)]
137 fn next_owned_candidate(&mut self, _solution: &S) -> Option<ChangeMove<S, V>> {
138 self.next_move()
139 }
140
141 #[inline(always)]
142 fn next_owned_candidate_inspected<T, F>(&mut self,
143 _solution: &S, mut inspect: F) -> Option<(ChangeMove<S, V>, T)>
144 where
145 F: for<'a> FnMut(MoveCandidateRef<'a, S, ChangeMove<S, V>>) -> Option<T>,
146 {
147 loop {
148 let mov = self.next_move()?;
149 if let Some(metadata) = inspect(MoveCandidateRef::Borrowed(&mov)) {
150 return Some((mov, metadata));
151 }
152 }
153 }
154
155 fn release_candidate(&mut self, id: CandidateId) -> bool {
156 self.store.release_candidate(id)
157 }
158}
159
160
161impl<S, V: Debug, ES: Debug, VS: Debug> Debug for ChangeMoveSelector<S, V, ES, VS> {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 f.debug_struct("ChangeMoveSelector")
164 .field("entity_selector", &self.entity_selector)
165 .field("value_selector", &self.value_selector)
166 .field("descriptor_index", &self.descriptor_index)
167 .field("variable_index", &self.variable_index)
168 .field("variable_name", &self.variable_name)
169 .field("allows_unassigned", &self.allows_unassigned)
170 .finish()
171 }
172}
173
174impl<S: PlanningSolution, V: Clone, ES, VS> ChangeMoveSelector<S, V, ES, VS> {
175 pub fn new(
176 entity_selector: ES,
177 value_selector: VS,
178 getter: fn(&S, usize, usize) -> Option<V>,
179 setter: fn(&mut S, usize, usize, Option<V>),
180 descriptor_index: usize,
181 variable_index: usize,
182 variable_name: &'static str,
183 ) -> Self {
184 Self {
185 entity_selector,
186 value_selector,
187 getter,
188 setter,
189 descriptor_index,
190 variable_index,
191 variable_name,
192 allows_unassigned: false,
193 _phantom: PhantomData,
194 }
195 }
196
197 pub fn with_allows_unassigned(mut self, allows_unassigned: bool) -> Self {
198 self.allows_unassigned = allows_unassigned;
199 self
200 }
201}
202
203impl<S: PlanningSolution, V: Clone + Send + Sync + Debug + 'static>
204 ChangeMoveSelector<S, V, FromSolutionEntitySelector, StaticValueSelector<S, V>>
205{
206 pub fn simple(
207 getter: fn(&S, usize, usize) -> Option<V>,
208 setter: fn(&mut S, usize, usize, Option<V>),
209 descriptor_index: usize,
210 variable_index: usize,
211 variable_name: &'static str,
212 values: Vec<V>,
213 ) -> Self {
214 Self {
215 entity_selector: FromSolutionEntitySelector::new(descriptor_index),
216 value_selector: StaticValueSelector::new(values),
217 getter,
218 setter,
219 descriptor_index,
220 variable_index,
221 variable_name,
222 allows_unassigned: false,
223 _phantom: PhantomData,
224 }
225 }
226}
227
228impl<S, V, ES, VS> MoveSelector<S, ChangeMove<S, V>> for ChangeMoveSelector<S, V, ES, VS>
229where
230 S: PlanningSolution,
231 V: Clone + PartialEq + Send + Sync + Debug + 'static,
232 ES: EntitySelector<S>,
233 VS: ValueSelector<S, V>,
234{
235 type Cursor<'a>
236 = ChangeMoveCursor<S, V>
237 where
238 Self: 'a;
239
240 fn open_cursor<'a, D: Director<S>>(&'a self, score_director: &D) -> Self::Cursor<'a> {
241 self.open_cursor_with_context(score_director, MoveStreamContext::default())
242 }
243
244 fn open_cursor_with_context<'a, D: Director<S>>(
245 &'a self,
246 score_director: &D,
247 context: MoveStreamContext,
248 ) -> Self::Cursor<'a> {
249 let solution = score_director.working_solution();
250 let canonical_entities = self.entity_selector.iter(score_director).collect::<Vec<_>>();
251 let entity_count = canonical_entities.len();
252 let entity_salt = 0xC4A4_6E00_0000_0001
253 ^ ((self.descriptor_index as u64) << 32)
254 ^ self.variable_index as u64;
255 let entity_values = (0..entity_count)
256 .map(|entity_offset| {
257 let entity_ref = canonical_entities
258 [context.selection_index(entity_offset, entity_count, entity_salt)];
259 let current_assigned = (self.getter)(
260 solution,
261 entity_ref.entity_index,
262 self.variable_index,
263 )
264 .is_some();
265 let canonical_values = self
266 .value_selector
267 .iter(
268 score_director,
269 entity_ref.descriptor_index,
270 entity_ref.entity_index,
271 )
272 .collect::<Vec<_>>();
273 let value_count = canonical_values.len();
274 let value_salt = 0xC4A4_6E00_0000_0000
275 ^ entity_ref.entity_index as u64
276 ^ ((self.descriptor_index as u64) << 32)
277 ^ self.variable_index as u64;
278 let values = if context.is_canonical() {
279 canonical_values
280 } else {
281 (0..value_count)
282 .map(|value_offset| {
283 canonical_values
284 [context.selection_index(value_offset, value_count, value_salt)]
285 .clone()
286 })
287 .collect()
288 };
289 ChangeEntityValues {
290 entity_ref,
291 total_values: value_count,
292 values,
293 current_assigned,
294 }
295 })
296 .collect();
297 ChangeMoveCursor::new(
298 entity_values,
299 self.getter,
300 self.setter,
301 self.descriptor_index,
302 self.variable_index,
303 self.variable_name,
304 self.allows_unassigned,
305 )
306 }
307
308 fn size<D: Director<S>>(&self, score_director: &D) -> usize {
309 self.entity_selector
310 .iter(score_director)
311 .map(|entity_ref| {
312 self.value_selector.size(
313 score_director,
314 entity_ref.descriptor_index,
315 entity_ref.entity_index,
316 ) + usize::from(
317 self.allows_unassigned
318 && (self.getter)(
319 score_director.working_solution(),
320 entity_ref.entity_index,
321 self.variable_index,
322 )
323 .is_some(),
324 )
325 })
326 .sum()
327 }
328}