Added equals/hashCode contract to Vector2D/Vector3D

This commit is contained in:
Willi Schönborn 2022-04-19 14:07:58 +02:00
parent 2144c6382c
commit 2ddf9fcd4e
No known key found for this signature in database
GPG Key ID: 1261358604AE1A0F
4 changed files with 149 additions and 2 deletions

View File

@ -24,6 +24,19 @@ public interface Vector2D : Point<Double>, Vector {
} }
override operator fun iterator(): Iterator<Double> = listOf(x, y).iterator() 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 public val Vector2D.r: Double
@ -35,7 +48,16 @@ public fun Vector2D(x: Double, y: Double): Vector2D = Vector2DImpl(x, y)
private data class Vector2DImpl( private data class Vector2DImpl(
override val x: Double, override val x: Double,
override val y: 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 * 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() 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") @Suppress("FunctionName")
@ -37,7 +50,16 @@ private data class Vector3DImpl(
override val x: Double, override val x: Double,
override val y: Double, override val y: Double,
override val z: 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> { public object Euclidean3DSpace : GeometrySpace<Vector3D>, ScaleOperations<Vector3D> {
override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) } override val zero: Vector3D by lazy { Vector3D(0.0, 0.0, 0.0) }

View File

@ -37,4 +37,54 @@ internal class Vector2DTest {
fun y() { fun y() {
assertEquals(-7.999, vector.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() { fun z() {
assertEquals(0.001, vector.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
}
}
} }