mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-03-03 10:46:42 +01:00
Sorted and Ordered Vector Type Support (#3310)
* Implemented SortedVec class * Added support for ordered vectors * Made SortedVec an abstract class and introduced an OrderedNonces case class
This commit is contained in:
parent
c72c5f84e3
commit
5685371e11
3 changed files with 150 additions and 0 deletions
|
@ -0,0 +1,102 @@
|
|||
package org.bitcoins.core.util
|
||||
|
||||
import org.bitcoins.core.util.sorted.SortedVec
|
||||
import org.bitcoins.crypto.{ECPublicKey, NetworkElement, SchnorrNonce}
|
||||
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
|
||||
|
||||
class SortedVecTest extends BitcoinSUnitTest {
|
||||
behavior of "SortedVec"
|
||||
|
||||
implicit val networkElementOrd: Ordering[NetworkElement] = {
|
||||
case (x: NetworkElement, y: NetworkElement) =>
|
||||
x.bytes.compare(y.bytes)
|
||||
}
|
||||
|
||||
it should "sort correctly on construction with normal orderings" in {
|
||||
assert(SortedVec.sort(Vector(1, 2, 3)) == SortedVec(Vector(1, 2, 3)))
|
||||
assert(SortedVec.sort(Vector(3, 2, 1)) == SortedVec(Vector(1, 2, 3)))
|
||||
assert(
|
||||
SortedVec.sort(Vector(3.0, 2.0, 1.123)) == SortedVec(
|
||||
Vector(1.123, 2.0, 3.0)))
|
||||
assert(
|
||||
SortedVec.sort(Vector('c', 'b', 'a')) == SortedVec(Vector('a', 'b', 'c')))
|
||||
assert(
|
||||
SortedVec.sort(Vector("cab", "ceb", "abc")) == SortedVec(
|
||||
Vector("abc", "cab", "ceb")))
|
||||
assert(
|
||||
SortedVec.sort[SchnorrNonce, NetworkElement](Vector(
|
||||
SchnorrNonce(
|
||||
"c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"),
|
||||
SchnorrNonce(
|
||||
"92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc")
|
||||
)) == SortedVec[SchnorrNonce, NetworkElement](Vector(
|
||||
SchnorrNonce(
|
||||
"92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc"),
|
||||
SchnorrNonce(
|
||||
"c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea")
|
||||
)))
|
||||
}
|
||||
|
||||
it should "fail to construct with unsorted vector under normal orderings" in {
|
||||
assertThrows[IllegalArgumentException](SortedVec(Vector(3, 2, 1)))
|
||||
assertThrows[IllegalArgumentException](SortedVec(Vector(3.0, 2.0, 1.123)))
|
||||
assertThrows[IllegalArgumentException](SortedVec(Vector('c', 'b', 'a')))
|
||||
assertThrows[IllegalArgumentException](
|
||||
SortedVec(Vector("cab", "ceb", "abc")))
|
||||
assertThrows[IllegalArgumentException](
|
||||
SortedVec[SchnorrNonce, NetworkElement](Vector(
|
||||
SchnorrNonce(
|
||||
"c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"),
|
||||
SchnorrNonce(
|
||||
"92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc")
|
||||
)))
|
||||
}
|
||||
|
||||
it should "sort correctly on construction with custom orderings" in {
|
||||
implicit val parityOrd: Ordering[Int] = { case (x: Int, y: Int) =>
|
||||
(math.abs(x) % 2) - (math.abs(y) % 2)
|
||||
}
|
||||
|
||||
assert(SortedVec.sort(Vector(1, 2, 3, 4)) == SortedVec(Vector(2, 4, 1, 3)))
|
||||
assert(SortedVec.sort(Vector(2, 4, 1, 3)) == SortedVec(Vector(2, 4, 1, 3)))
|
||||
|
||||
implicit val remainderOrd: Ordering[Double] = {
|
||||
case (x: Double, y: Double) =>
|
||||
val diff = (x - x.floor) - (y - y.floor)
|
||||
if (diff > 0) 1 else if (diff == 0) 0 else -1
|
||||
}
|
||||
|
||||
assert(
|
||||
SortedVec.sort(Vector(0.95, 123.123, 5.55)) == SortedVec(
|
||||
Vector(123.123, 5.55, 0.95)))
|
||||
}
|
||||
|
||||
it should "fail to construct with unsorted vector under custom orderings" in {
|
||||
implicit val parityOrd: Ordering[Int] = { case (x: Int, y: Int) =>
|
||||
(math.abs(x) % 2) - (math.abs(y) % 2)
|
||||
}
|
||||
|
||||
assertThrows[IllegalArgumentException](SortedVec(Vector(1, 2, 3, 4)))
|
||||
|
||||
implicit val remainderOrd: Ordering[Double] = {
|
||||
case (x: Double, y: Double) =>
|
||||
val diff = (x - x.floor) - (y - y.floor)
|
||||
if (diff > 0) 1 else if (diff == 0) 0 else -1
|
||||
}
|
||||
|
||||
assertThrows[IllegalArgumentException](
|
||||
SortedVec(Vector(0.95, 5.55, 123.123)))
|
||||
}
|
||||
|
||||
it should "correctly handle ordered list" in {
|
||||
val nonce1 = ECPublicKey.freshPublicKey.schnorrNonce
|
||||
val nonce2 = ECPublicKey.freshPublicKey.schnorrNonce
|
||||
val nonce3 = ECPublicKey.freshPublicKey.schnorrNonce
|
||||
val nonces = Vector(nonce1, nonce2, nonce3)
|
||||
val wrongOrder = Vector(nonce2, nonce3, nonce1)
|
||||
|
||||
val _ = SortedVec(nonces)(SortedVec.forOrdered(nonces))
|
||||
assertThrows[IllegalArgumentException](
|
||||
SortedVec(wrongOrder)(SortedVec.forOrdered(nonces)))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package org.bitcoins.core.util.sorted
|
||||
|
||||
import org.bitcoins.crypto.SchnorrNonce
|
||||
|
||||
/** Represents an ordered set of SchnorrNonces */
|
||||
case class OrderedNonces(vec: Vector[SchnorrNonce])
|
||||
extends SortedVec[SchnorrNonce, SchnorrNonce](vec,
|
||||
SortedVec.forOrdered(vec))
|
|
@ -0,0 +1,40 @@
|
|||
package org.bitcoins.core.util.sorted
|
||||
|
||||
import org.bitcoins.core.util.SeqWrapper
|
||||
|
||||
/** Wraps a sorted Vector[T] and its Ordering (which may be for a supertype).
|
||||
*
|
||||
* For example SortedVec[SchnorrNonce, NetworkElement] would be a
|
||||
* Vector[SchnorrNonce] sorted as NetworkElements.
|
||||
*/
|
||||
abstract class SortedVec[T, B >: T](
|
||||
override val wrapped: Vector[T],
|
||||
ord: Ordering[B])
|
||||
extends SeqWrapper[T] {
|
||||
require(
|
||||
wrapped.init.zip(wrapped.tail).forall { case (x, y) => ord.lteq(x, y) },
|
||||
s"Vector must be sorted. $wrapped")
|
||||
}
|
||||
|
||||
object SortedVec {
|
||||
|
||||
/** For use with ordered lists so that changing order will not be allowed.
|
||||
*/
|
||||
def forOrdered[T](vec: Vector[T]): Ordering[T] = { case (x, y) =>
|
||||
vec.indexOf(x) - vec.indexOf(y)
|
||||
}
|
||||
|
||||
private case class SortedVecImpl[T, B >: T](vec: Vector[T])(implicit
|
||||
val ord: Ordering[B])
|
||||
extends SortedVec[T, B](vec, ord)
|
||||
|
||||
def sort[T, B >: T](vec: Vector[T])(implicit
|
||||
ord: Ordering[B]): SortedVec[T, B] = {
|
||||
SortedVecImpl(vec.sorted[B])
|
||||
}
|
||||
|
||||
def apply[T, B >: T](vec: Vector[T])(implicit
|
||||
ord: Ordering[B]): SortedVec[T, B] = {
|
||||
SortedVecImpl(vec)
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue