Skip to content

Commit 96991a7

Browse files
authored
fix: Fix shallow copy in getEntries and introduce new method (#104)
This pull request improves data integrity and security by addressing the shallow copy issue (#103) and providing a new method to read-only access the matrix elements. Signed-off-by: Ryuu Mitsuki <[email protected]>
2 parents 3d9d770 + 1b736e8 commit 96991a7

File tree

1 file changed

+78
-13
lines changed

1 file changed

+78
-13
lines changed

src/main/java/com/mitsuki/jmatrix/Matrix.java

+78-13
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
import com.mitsuki.jmatrix.core.MatrixUtils;
2929

3030
import java.util.Arrays;
31+
import java.util.ArrayList;
32+
import java.util.Collections;
33+
import java.util.List;
34+
import java.util.stream.Collectors;
3135

3236
/**
3337
* The <b>Matrix</b> class represents a two-dimensional (2D) array of {@code double}s.
@@ -2870,15 +2874,15 @@ public static boolean isSparse(Matrix m) {
28702874
"Matrix is null. Please ensure the matrix have been initialized.")
28712875
);
28722876
}
2873-
2877+
28742878
for (int r = 0; r < mSize[0]; r++) {
28752879
for (int c = 0; c < mSize[1]; c++) {
28762880
if (Math.abs(m.get(r, c)) > Matrix.THRESHOLD) {
28772881
numberNonZero++; // increment
28782882
}
28792883
}
28802884
}
2881-
2885+
28822886
return (numberNonZero <= Math.max(mSize[0], mSize[1]));
28832887
}
28842888

@@ -3651,24 +3655,85 @@ public static double getEntry(Matrix m, int row, int col) {
36513655

36523656

36533657
/**
3654-
* Returns the {@code double} two-dimensional array representation of this matrix elements.
3658+
* Retrieves a two-dimensional array representing the elements of this matrix,
3659+
* preserving data integrity.
36553660
*
3656-
* <p><b>Note:</b></p>
3657-
* If the matrix constructed by using {@link #Matrix()} constructor,
3658-
* this method would returns {@code null} instead (similar with the entries).
3661+
* <p>If the matrix was constructed using the default {@link #Matrix()} constructor
3662+
* without any explicit entries, this method returns {@code null}, indicating that
3663+
* the matrix has not been initialized with any data. To determine whether a matrix
3664+
* has uninitialized ({@code null}) entries, use the
3665+
* {@link MatrixUtils#isNullEntries(Matrix)} helper method.
36593666
*
3660-
* @return A two-dimensional array that represents entries of this matrix,
3661-
* returns {@code null} instead if the entries is uninitialized.
3667+
* <p><b>Implementation Note:</b></p>
3668+
* <p>As of version 1.5.0, this method would returns a deep copy of the internal
3669+
* matrix entries instead of returning the object reference of the entries itself
3670+
* (see <a href="https://github.com/mitsuki31/jmatrix/issues/103">#103</a>),
3671+
* this ensuring that modifications to the returned array do not affect
3672+
* the original matrix data. This is essential for preventing unintended side
3673+
* effects and maintaining data consistency.
3674+
*
3675+
* @return A two-dimensional array of {@code double} values representing the
3676+
* matrix entries, or {@code null} if the matrix is uninitialized.
36623677
*
36633678
* @since 1.0.0b.5
3664-
* @see #get(int, int)
3665-
* @see #getSize()
3679+
* @see #getReadOnlyEntries()
36663680
* @see MatrixUtils#isNullEntries(Matrix)
36673681
*/
36683682
public double[ ][ ] getEntries() {
3669-
// TODO: Fix the shallow copy of the returned array
3670-
// Here will lead to shallow copy of the entries array.
3671-
return this.ENTRIES;
3683+
return MatrixUtils.deepCopyOf(this.ENTRIES);
3684+
}
3685+
3686+
/**
3687+
* Obtains a read-only view of the matrix elements, safeguarding against
3688+
* unintended modifications.
3689+
*
3690+
* <p>This method offers a secure way to access the matrix elements without
3691+
* the risk of unintended modifications. This method returns a list of lists,
3692+
* where each inner list represents an immutable row of the matrix, ensuring
3693+
* data integrity and preventing accidental changes. Attempting to modify the
3694+
* elements will causing the method to throws an exception
3695+
* {@code UnsupportedOperationException}. If you want to get the matrix
3696+
* elements but can still access and modify each elements, consider to use the
3697+
* {@link #getEntries()} method instead.
3698+
*
3699+
* <p><b>Implementation Note:</b></p>
3700+
* <p>The method leverages the {@code Arrays.stream} API introduced in Java 8.
3701+
* This allows for concise and efficient conversion of primitive {@code double}
3702+
* arrays to {@code Double} objects and subsequent creation of unmodifiable
3703+
* lists. However, it's crucial to note that this approach might not be
3704+
* compatible with older Java versions that lack {@code Arrays.stream} functionality.
3705+
*
3706+
* @return An unmodifiable view list of lists containing the matrix entries.
3707+
* Each inner list represents a single row of the matrix, containing
3708+
* {@code Double} objects instead of primitive {@code double} values.
3709+
*
3710+
* @throws NullMatrixException If the entries of this matrix is {@code null}
3711+
* or this matrix has not been initialized.
3712+
*
3713+
* @since 1.5.0
3714+
* @see #getEntries()
3715+
*/
3716+
public List<List<Double>> getReadOnlyEntries() {
3717+
if (MatrixUtils.isNullEntries(this)) {
3718+
JMatrixUtils.raiseError(new NullMatrixException(
3719+
"Matrix is null. Please ensure the matrix are initialized."));
3720+
}
3721+
3722+
final int rows = this.getNumRows(); // Get the rows size
3723+
final List<List<Double>> readonlyEntries = new ArrayList<>(rows /* initial size */);
3724+
3725+
for (int i = 0; i < rows; i++) {
3726+
// Convert the double (primitive type) array to list of Double (class type)
3727+
List<Double> thisRow = Arrays.stream(this.ENTRIES[i])
3728+
.boxed()
3729+
.collect(Collectors.toList()); // Convert to List
3730+
// Lock each row and make it unmodifiable
3731+
readonlyEntries.add(Collections.unmodifiableList(thisRow));
3732+
}
3733+
3734+
// For the last touch, lock entirely the entries
3735+
// and return the read-only entries
3736+
return Collections.unmodifiableList(readonlyEntries);
36723737
}
36733738

36743739

0 commit comments

Comments
 (0)