Added equals/hashCode contract to Vector2D/Vector3D #482
@ -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
|
||||
|
@ -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) }
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user