use super::Modulus;
use flint_sys::fmpz_mod::fmpz_mod_ctx_clear;
use std::rc::Rc;
impl Clone for Modulus {
fn clone(&self) -> Self {
Modulus {
modulus: Rc::clone(&self.modulus),
}
}
}
impl Drop for Modulus {
fn drop(&mut self) {
if Rc::strong_count(&self.modulus) <= 1 {
let mut a = *self.modulus;
unsafe {
fmpz_mod_ctx_clear(&mut a);
}
}
}
}
#[cfg(test)]
mod test_clone {
use super::Modulus;
use std::{rc::Rc, str::FromStr};
#[test]
fn references_increased() {
let a = Modulus::from(3);
assert_eq!(Rc::strong_count(&a.modulus), 1);
let b = a.clone();
assert_eq!(Rc::strong_count(&a.modulus), 2);
assert_eq!(Rc::strong_count(&b.modulus), 2);
let c = b.clone();
assert_eq!(Rc::strong_count(&a.modulus), 3);
assert_eq!(Rc::strong_count(&b.modulus), 3);
assert_eq!(Rc::strong_count(&c.modulus), 3);
}
#[test]
fn same_reference() {
let a = Modulus::from_str(&"1".repeat(65)).unwrap();
let b = a.clone();
assert_eq!(
&a.get_fmpz_mod_ctx_struct().to_owned().n[0].0,
&b.get_fmpz_mod_ctx_struct().to_owned().n[0].0
);
}
}
#[cfg(test)]
mod test_drop {
use super::Modulus;
use std::{collections::HashSet, rc::Rc, str::FromStr};
#[test]
fn references_decreased() {
let a = Modulus::from(3);
assert_eq!(Rc::strong_count(&a.modulus), 1);
{
let b = a.clone();
assert_eq!(Rc::strong_count(&a.modulus), 2);
assert_eq!(Rc::strong_count(&b.modulus), 2);
}
assert_eq!(Rc::strong_count(&a.modulus), 1);
let b = a.clone();
assert_eq!(Rc::strong_count(&a.modulus), 2);
assert_eq!(Rc::strong_count(&b.modulus), 2);
let c = b.clone();
assert_eq!(Rc::strong_count(&a.modulus), 3);
assert_eq!(Rc::strong_count(&b.modulus), 3);
assert_eq!(Rc::strong_count(&c.modulus), 3);
drop(a);
assert_eq!(Rc::strong_count(&b.modulus), 2);
}
fn create_and_drop_modulus() -> i64 {
let a = Modulus::from_str(&"1".repeat(65)).unwrap();
a.get_fmpz_mod_ctx_struct().n[0].0
}
#[test]
fn free_memory() {
let mut storage_addresses = HashSet::new();
for _i in 0..5 {
storage_addresses.insert(create_and_drop_modulus());
}
assert!(storage_addresses.len() < 5);
}
}