use std::cell::Cell;
use std::fmt::Debug;
use std::ptr::NonNull;
use solverforge_core::domain::PlanningSolution;
use solverforge_scoring::Director;
use super::entity::{EntityReference, EntitySelector};
#[derive(Debug, Default, Clone, Copy)]
struct MimicState {
has_next_recorded: bool,
has_next: bool,
next_recorded: bool,
recorded_entity: Option<EntityReference>,
}
struct SharedMimicState {
state: Cell<MimicState>,
refcount: Cell<usize>,
}
pub struct MimicRecorder {
ptr: NonNull<SharedMimicState>,
id: String,
}
impl MimicRecorder {
pub fn new(id: impl Into<String>) -> Self {
let shared = Box::new(SharedMimicState {
state: Cell::new(MimicState::default()),
refcount: Cell::new(1),
});
Self {
ptr: NonNull::from(Box::leak(shared)),
id: id.into(),
}
}
#[inline]
fn shared(&self) -> &SharedMimicState {
unsafe { self.ptr.as_ref() }
}
fn record_has_next(&self, has_next: bool) {
self.shared().state.set(MimicState {
has_next_recorded: true,
has_next,
next_recorded: false,
recorded_entity: None,
});
}
fn record_next(&self, entity: EntityReference) {
self.shared().state.set(MimicState {
has_next_recorded: true,
has_next: true,
next_recorded: true,
recorded_entity: Some(entity),
});
}
pub fn get_has_next(&self) -> Option<bool> {
let state = self.shared().state.get();
if state.has_next_recorded {
Some(state.has_next)
} else {
None
}
}
pub fn get_recorded_entity(&self) -> Option<EntityReference> {
let state = self.shared().state.get();
if state.next_recorded {
state.recorded_entity
} else {
None
}
}
pub fn id(&self) -> &str {
&self.id
}
pub fn reset(&self) {
self.shared().state.set(MimicState::default());
}
}
impl Clone for MimicRecorder {
fn clone(&self) -> Self {
let shared = self.shared();
shared.refcount.set(shared.refcount.get() + 1);
Self {
ptr: self.ptr,
id: self.id.clone(),
}
}
}
impl Drop for MimicRecorder {
fn drop(&mut self) {
let shared = self.shared();
let rc = shared.refcount.get() - 1;
if rc == 0 {
unsafe {
drop(Box::from_raw(self.ptr.as_ptr()));
}
} else {
shared.refcount.set(rc);
}
}
}
impl Debug for MimicRecorder {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MimicRecorder")
.field("id", &self.id)
.field("state", &self.shared().state.get())
.finish()
}
}
unsafe impl Send for MimicRecorder {}
unsafe impl Sync for MimicRecorder {}
pub struct MimicRecordingEntitySelector<S, ES> {
child: ES,
recorder: MimicRecorder,
_phantom: std::marker::PhantomData<fn() -> S>,
}
impl<S, ES> MimicRecordingEntitySelector<S, ES> {
pub fn new(child: ES, recorder: MimicRecorder) -> Self {
Self {
child,
recorder,
_phantom: std::marker::PhantomData,
}
}
pub fn recorder(&self) -> MimicRecorder {
self.recorder.clone()
}
}
impl<S: PlanningSolution, ES: Debug> Debug for MimicRecordingEntitySelector<S, ES> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MimicRecordingEntitySelector")
.field("child", &self.child)
.field("recorder_id", &self.recorder.id)
.finish()
}
}
impl<S, ES> EntitySelector<S> for MimicRecordingEntitySelector<S, ES>
where
S: PlanningSolution,
ES: EntitySelector<S>,
{
fn iter<'a, D: Director<S>>(
&'a self,
score_director: &'a D,
) -> impl Iterator<Item = EntityReference> + 'a {
self.recorder.reset();
let child_iter = self.child.iter(score_director);
RecordingIterator {
inner: child_iter,
recorder: &self.recorder,
}
}
fn size<D: Director<S>>(&self, score_director: &D) -> usize {
self.child.size(score_director)
}
fn is_never_ending(&self) -> bool {
self.child.is_never_ending()
}
}
struct RecordingIterator<'a, I> {
inner: I,
recorder: &'a MimicRecorder,
}
impl<'a, I: Iterator<Item = EntityReference>> Iterator for RecordingIterator<'a, I> {
type Item = EntityReference;
fn next(&mut self) -> Option<Self::Item> {
let next = self.inner.next();
match next {
Some(entity) => {
self.recorder.record_next(entity);
Some(entity)
}
None => {
self.recorder.record_has_next(false);
None
}
}
}
}
pub struct MimicReplayingEntitySelector {
recorder: MimicRecorder,
}
impl MimicReplayingEntitySelector {
pub fn new(recorder: MimicRecorder) -> Self {
Self { recorder }
}
}
impl Debug for MimicReplayingEntitySelector {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MimicReplayingEntitySelector")
.field("recorder_id", &self.recorder.id)
.finish()
}
}
impl<S: PlanningSolution> EntitySelector<S> for MimicReplayingEntitySelector {
fn iter<'a, D: Director<S>>(
&'a self,
_score_director: &'a D,
) -> impl Iterator<Item = EntityReference> + 'a {
ReplayingIterator {
recorder: &self.recorder,
returned: false,
}
}
fn size<D: Director<S>>(&self, _score_director: &D) -> usize {
if self.recorder.get_recorded_entity().is_some() {
1
} else {
0
}
}
fn is_never_ending(&self) -> bool {
false
}
}
struct ReplayingIterator<'a> {
recorder: &'a MimicRecorder,
returned: bool,
}
impl<'a> Iterator for ReplayingIterator<'a> {
type Item = EntityReference;
fn next(&mut self) -> Option<Self::Item> {
if self.returned {
return None;
}
match self.recorder.get_recorded_entity() {
Some(entity) => {
self.returned = true;
Some(entity)
}
None => {
match self.recorder.get_has_next() {
Some(false) => None, Some(true) => panic!(
"MimicReplayingEntitySelector: Recording selector's hasNext() was true \
but next() was never called. Ensure the recording selector's iterator \
is advanced before using the replaying selector."
),
None => panic!(
"MimicReplayingEntitySelector: No recording found. \
The recording selector must be iterated before the replaying selector."
),
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::heuristic::selector::entity::FromSolutionEntitySelector;
use crate::test_utils::create_simple_nqueens_director;
#[test]
fn test_mimic_recording_selector() {
let director = create_simple_nqueens_director(3);
let solution = director.working_solution();
for (i, queen) in solution.queens.iter().enumerate() {
assert_eq!(queen.column, i as i64);
}
let recorder = MimicRecorder::new("test");
let child = FromSolutionEntitySelector::new(0);
let recording = MimicRecordingEntitySelector::new(child, recorder);
let entities: Vec<_> = recording.iter(&director).collect();
assert_eq!(entities.len(), 3);
assert_eq!(entities[0], EntityReference::new(0, 0));
assert_eq!(entities[1], EntityReference::new(0, 1));
assert_eq!(entities[2], EntityReference::new(0, 2));
}
#[test]
fn test_mimic_replaying_selector() {
let director = create_simple_nqueens_director(3);
let recorder = MimicRecorder::new("test");
let child = FromSolutionEntitySelector::new(0);
let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
let replaying = MimicReplayingEntitySelector::new(recorder);
let mut recording_iter = recording.iter(&director);
let first = recording_iter.next().unwrap();
assert_eq!(first, EntityReference::new(0, 0));
let replayed: Vec<_> = replaying.iter(&director).collect();
assert_eq!(replayed.len(), 1);
assert_eq!(replayed[0], EntityReference::new(0, 0));
let second = recording_iter.next().unwrap();
assert_eq!(second, EntityReference::new(0, 1));
let replayed: Vec<_> = replaying.iter(&director).collect();
assert_eq!(replayed.len(), 1);
assert_eq!(replayed[0], EntityReference::new(0, 1));
}
#[test]
fn test_mimic_synchronized_iteration() {
let director = create_simple_nqueens_director(3);
let recorder = MimicRecorder::new("test");
let child = FromSolutionEntitySelector::new(0);
let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
let replaying = MimicReplayingEntitySelector::new(recorder);
for recorded in recording.iter(&director) {
let replayed: Vec<_> = replaying.iter(&director).collect();
assert_eq!(replayed.len(), 1);
assert_eq!(replayed[0], recorded);
}
}
#[test]
fn test_mimic_empty_selector() {
let director = create_simple_nqueens_director(0);
let recorder = MimicRecorder::new("test");
let child = FromSolutionEntitySelector::new(0);
let recording = MimicRecordingEntitySelector::new(child, recorder.clone());
let replaying = MimicReplayingEntitySelector::new(recorder);
let entities: Vec<_> = recording.iter(&director).collect();
assert_eq!(entities.len(), 0);
let replayed: Vec<_> = replaying.iter(&director).collect();
assert_eq!(replayed.len(), 0);
}
}