use coco_sys::coco_suite_t;
use std::{ffi::CString, ptr};
use crate::{observer::Observer, problem::Problem};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ProblemIdx(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FunctionIdx(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct InstanceIdx(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DimensionIdx(pub usize);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Name {
Bbob,
BbobBiobj,
BbobBiobjExt,
BbobLargescale,
BbobConstrained,
BbobMixint,
BbobBiobjMixint,
Toy,
}
impl Name {
fn as_str(&self) -> &'static str {
match self {
Name::Bbob => "bbob",
Name::BbobBiobj => "bbob-biobj",
Name::BbobBiobjExt => "bbob-biobj-ext",
Name::BbobLargescale => "bbob-largescale",
Name::BbobConstrained => "bbob-constrained",
Name::BbobMixint => "bbob-mixint",
Name::BbobBiobjMixint => "bbob-biobj-mixint",
Name::Toy => "toy",
}
}
}
pub struct Suite {
pub(crate) inner: *mut coco_suite_t,
name: CString,
instance: CString,
options: CString,
}
impl Clone for Suite {
fn clone(&self) -> Self {
Suite::new_raw(
self.name.clone(),
self.instance.clone(),
self.options.clone(),
)
.unwrap()
}
}
unsafe impl Send for Suite {}
impl Suite {
pub fn new(name: Name, instance: &str, options: &str) -> Option<Suite> {
let name = CString::new(name.as_str()).unwrap();
let instance = CString::new(instance).unwrap();
let options = CString::new(options).unwrap();
Self::new_raw(name, instance, options)
}
fn new_raw(name: CString, instance: CString, options: CString) -> Option<Suite> {
let inner =
unsafe { coco_sys::coco_suite(name.as_ptr(), instance.as_ptr(), options.as_ptr()) };
if inner.is_null() {
None
} else {
Some(Suite {
inner,
name,
instance,
options,
})
}
}
pub fn function_from_function_index(&self, function_idx: FunctionIdx) -> usize {
unsafe { coco_sys::coco_suite_get_function_from_function_index(self.inner, function_idx.0) }
}
pub fn dimension_from_dimension_index(&self, dimension_idx: DimensionIdx) -> usize {
unsafe {
coco_sys::coco_suite_get_dimension_from_dimension_index(self.inner, dimension_idx.0)
}
}
pub fn instance_from_instance_index(&self, instance_idx: InstanceIdx) -> usize {
unsafe { coco_sys::coco_suite_get_instance_from_instance_index(self.inner, instance_idx.0) }
}
pub fn next_problem<'s>(&'s mut self, observer: Option<&mut Observer>) -> Option<Problem<'s>> {
let observer = observer.map(|o| o.inner).unwrap_or(ptr::null_mut());
let inner = unsafe { coco_sys::coco_suite_get_next_problem(self.inner, observer) };
if inner.is_null() {
return None;
}
unsafe {
coco_sys::coco_suite_forget_current_problem(self.inner);
}
Some(Problem::new(inner, self))
}
pub fn problem(&mut self, problem_idx: ProblemIdx) -> Option<Problem> {
let inner = unsafe { coco_sys::coco_suite_get_problem(self.inner, problem_idx.0) };
if inner.is_null() {
return None;
}
Some(Problem::new(inner, self))
}
pub fn problem_by_function_dimension_instance(
&mut self,
function: usize,
dimension: usize,
instance: usize,
) -> Option<Problem> {
let inner = unsafe {
coco_sys::coco_suite_get_problem_by_function_dimension_instance(
self.inner,
function as usize,
dimension as usize,
instance as usize,
)
};
if inner.is_null() {
return None;
}
Some(Problem::new(inner, self))
}
pub fn number_of_problems(&self) -> usize {
unsafe {
coco_sys::coco_suite_get_number_of_problems(self.inner)
.try_into()
.unwrap()
}
}
}
impl Drop for Suite {
fn drop(&mut self) {
unsafe {
coco_sys::coco_suite_free(self.inner);
}
}
}