Added equals/hashCode contract to Vector2D/Vector3D #482

Closed
whiskeysierra wants to merge 1 commits from master into master
4 changed files with 149 additions and 2 deletions
Showing only changes of commit 2ddf9fcd4e - Show all commits

View File

@ -24,6 +24,19 @@ public interface Vector2D : Point<Double>, Vector {
}
override operator fun iterator(): Iterator<Double> = listOf(x, y).iterator()
/**
* Indicates whether some other vector is "equal to" this one.
* Any [Vector3D] is considered equal, if it contains the same components.
*/
override fun equals(other: Any?): Boolean
/**
* Returns a hash code value for this vector.
* The hash code is generated as if all the input values were placed into
* a list, and that list were hashed by calling `listOf(x, y).hashCode()`.
*/
override fun hashCode(): Int
}
public val Vector2D.r: Double
@ -35,7 +48,16 @@ public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y)
private data class Vector2DImpl(
override val x: Double,
override val y: Double,
) : Vector2D
) : Vector2D {
override fun equals(other: Any?) = when (other) {
this -> true
is Vector2D -> x == other.x && y == other.y
else -> false
}
override fun hashCode(): Int = listOf(x, y).hashCode()
}
/**
* 2D Euclidean space

View File

@ -26,6 +26,19 @@ public interface Vector3D : Point<Double>, Vector {
}
override operator fun iterator(): Iterator<Double> = listOf(x, y, z).iterator()
/**
* Indicates whether some other vector is "equal to" this one.
* Any [Vector3D] is considered equal, if it contains the same components.
*/
override fun equals(other: Any?): Boolean
/**
* Returns a hash code value for this vector.
* The hash code is generated as if all the input values were placed into
* a list, and that list were hashed by calling `listOf(x, y, z).hashCode()`.
*/
override fun hashCode(): Int
}
@Suppress("FunctionName")
@ -37,7 +50,16 @@ private data class Vector3DImpl(
override val x: Double,
override val y: Double,
override val z: Double,
) : Vector3D
) : Vector3D {
override fun equals(other: Any?) = when (other) {
this -> true
is Vector3D -> x == other.x && y == other.y && z == other.z
else -> false
}
override fun hashCode() = listOf(x, y, z).hashCode()
}
public object Euclidean3DSpace : GeometrySpace<Vector3D>, ScaleOperations<Vector3D> {
override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) }

View File

@ -37,4 +37,54 @@ internal class Vector2DTest {
fun y() {
assertEquals(-7.999, vector.y)
}
@Test
fun equality() {
val vector2 = AlternativeVector2D(1.0, -7.999)
// reflexive
assertEquals(vector, vector)
assertEquals(vector2, vector2)
// symmetric
assertEquals(vector, vector2)
assertEquals(vector2, vector)
// transitive
val vector3 = AlternativeVector2D(1.0, -7.999)
assertEquals(vector, vector2)
assertEquals(vector2, vector3)
assertEquals(vector3, vector)
}
@Test
fun hash() {
val vector2 = AlternativeVector2D(1.0, -7.999)
assertEquals(vector, vector2)
assertEquals(vector.hashCode(), vector2.hashCode())
}
private data class AlternativeVector2D(
override val x: Double,
override val y: Double,
) : Vector2D {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other !is Vector2D) return false
if (x != other.x) return false
if (y != other.y) return false
return true
}
override fun hashCode(): Int {
var result = 1
result = 31 * result + x.hashCode()
result = 31 * result + y.hashCode()
return result
}
}
}

View File

@ -43,4 +43,57 @@ internal class Vector3DTest {
fun z() {
assertEquals(0.001, vector.z)
}
@Test
fun equality() {
val vector2 = AlternativeVector3D(1.0, -7.999, 0.001)
// reflexive
assertEquals(vector, vector)
assertEquals(vector2, vector2)
// symmetric
assertEquals(vector, vector2)
assertEquals(vector2, vector)
// transitive
val vector3 = AlternativeVector3D(1.0, -7.999, 0.001)
assertEquals(vector, vector2)
assertEquals(vector2, vector3)
assertEquals(vector3, vector)
}
@Test
fun hash() {
val vector2 = AlternativeVector3D(1.0, -7.999, 0.001)
assertEquals(vector, vector2)
assertEquals(vector.hashCode(), vector2.hashCode())
}
private data class AlternativeVector3D(
override val x: Double,
override val y: Double,
override val z: Double,
) : Vector3D {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other == null || other !is Vector3D) return false
if (x != other.x) return false
if (y != other.y) return false
if (z != other.z) return false
return true
}
override fun hashCode(): Int {
var result = 1
result = 31 * result + x.hashCode()
result = 31 * result + y.hashCode()
result = 31 * result + z.hashCode()
return result
}
}
}