qfall_math/integer_mod_q/poly_over_zq/ownership.rs
1// Copyright 2023 Jan Niklas Siemer
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! This module contains implementations of functions
10//! important for ownership such as the [`Clone`] and [`Drop`] trait.
11//!
12//! The explicit functions contain the documentation.
13
14use super::PolyOverZq;
15use flint3_sys::{fmpz_mod_poly_clear, fmpz_mod_poly_set};
16
17impl Clone for PolyOverZq {
18 /// Clones the given [`PolyOverZq`] element by returning a deep clone,
19 /// storing the actual value separately and including
20 /// a reference to the [`Modulus`](crate::integer_mod_q::Modulus) element.
21 ///
22 /// # Examples
23 /// ```
24 /// use qfall_math::integer_mod_q::PolyOverZq;
25 /// use std::str::FromStr;
26 ///
27 /// let a = PolyOverZq::from_str("4 0 1 -2 3 mod 13").unwrap();
28 /// let b = a.clone();
29 /// ```
30 fn clone(&self) -> Self {
31 let mut out = PolyOverZq::from(&self.modulus);
32
33 unsafe {
34 fmpz_mod_poly_set(
35 &mut out.poly,
36 &self.poly,
37 self.modulus.get_fmpz_mod_ctx_struct(),
38 )
39 };
40
41 out
42 }
43}
44
45impl Drop for PolyOverZq {
46 /// Drops the given memory allocated for the underlying value
47 /// and frees the allocated memory of the corresponding
48 /// [`Modulus`](crate::integer_mod_q::Modulus) if no other references are left.
49 ///
50 /// # Examples
51 /// ```
52 /// use qfall_math::integer_mod_q::PolyOverZq;
53 /// use std::str::FromStr;
54 /// {
55 /// let a = PolyOverZq::from_str("4 0 1 -2 3 mod 13").unwrap();
56 /// } // as a's scope ends here, it get's dropped
57 /// ```
58 ///
59 /// ```
60 /// use qfall_math::integer_mod_q::PolyOverZq;
61 /// use std::str::FromStr;
62 ///
63 /// let a = PolyOverZq::from_str("4 0 1 -2 3 mod 13").unwrap();
64 /// drop(a); // explicitly drops a's value
65 /// ```
66 fn drop(&mut self) {
67 unsafe {
68 fmpz_mod_poly_clear(&mut self.poly, self.modulus.get_fmpz_mod_ctx_struct());
69 }
70 }
71}
72
73/// Test that the [`Clone`] trait is correctly implemented.
74#[cfg(test)]
75mod test_clone {
76 use super::PolyOverZq;
77 use std::str::FromStr;
78
79 /// Check if clone points to same point in memory
80 #[test]
81 fn same_reference() {
82 let a = PolyOverZq::from_str(&format!("4 {} 1 -2 3 mod {}", i64::MAX, u64::MAX)).unwrap();
83
84 let b = a.clone();
85
86 // check that Modulus isn't stored twice
87 assert_eq!(
88 a.modulus.get_fmpz_mod_ctx_struct().n[0],
89 b.modulus.get_fmpz_mod_ctx_struct().n[0]
90 );
91
92 // check that values on heap are stored separately
93 assert_ne!(unsafe { *a.poly.coeffs.offset(0) }, unsafe {
94 *b.poly.coeffs.offset(0)
95 }); // heap
96 assert_eq!(unsafe { *a.poly.coeffs.offset(1) }, unsafe {
97 *b.poly.coeffs.offset(1)
98 }); // stack
99 assert_ne!(unsafe { *a.poly.coeffs.offset(2) }, unsafe {
100 *b.poly.coeffs.offset(2)
101 }); // heap
102 assert_eq!(unsafe { *a.poly.coeffs.offset(3) }, unsafe {
103 *b.poly.coeffs.offset(3)
104 }); // stack
105
106 // check if length of polynomials is equal
107 assert_eq!(a.poly.length, b.poly.length);
108 }
109
110 /// Ensure that the zero polynomial can be cloned.
111 #[test]
112 fn zero_polynomial() {
113 let a = PolyOverZq::from_str("0 mod 17").unwrap();
114 let b = PolyOverZq::from_str("1 17 mod 17").unwrap();
115
116 assert_eq!(a, a.clone());
117 assert_eq!(b, b.clone());
118 assert_eq!(a.get_mod(), a.clone().get_mod());
119 }
120
121 /// Ensure that cloning preserves the value and modulus.
122 #[test]
123 fn correct_value() {
124 let a = PolyOverZq::from_str(&format!("4 {} 1 -2 3 mod {}", i64::MAX, u64::MAX)).unwrap();
125
126 let b = a.clone();
127
128 assert_eq!(a, b);
129 assert_eq!(a.get_mod(), b.get_mod());
130 }
131}
132
133#[cfg(test)]
134mod test_drop {
135 use super::PolyOverZq;
136 use std::{collections::HashSet, str::FromStr};
137
138 /// Creates and drops a [`PolyOverZq`] object, and outputs
139 /// the storage point in memory of that [`fmpz_mod_poly`](flint3_sys::fmpz_mod_poly::fmpz_mod_poly_t) struct
140 fn create_and_drop_modulus() -> (i64, i64) {
141 let a = PolyOverZq::from_str(&format!("2 {} -2 mod {}", i64::MAX, u64::MAX)).unwrap();
142
143 (unsafe { *a.poly.coeffs.offset(0) }, unsafe {
144 *a.poly.coeffs.offset(1)
145 })
146 }
147
148 /// Check whether freed memory is reused afterwards
149 #[test]
150 fn free_memory() {
151 let mut storage_addresses = HashSet::new();
152
153 for _i in 0..5 {
154 let (a, b) = create_and_drop_modulus();
155 storage_addresses.insert(a);
156 storage_addresses.insert(b);
157 }
158
159 assert!(storage_addresses.len() < 10);
160 }
161}