├── .travis.yml ├── README.md ├── build.sbt ├── project ├── build.properties └── plugins.sbt ├── scalacture-core └── src │ ├── main │ └── scala │ │ └── scalacture │ │ └── immutable │ │ └── queue │ │ ├── BatchedQueue.scala │ │ ├── HoodMelvilleQueue.scala │ │ ├── Queue.scala │ │ └── QueueLike.scala │ └── test │ └── scala │ └── scalacture │ ├── helper │ └── SeqSpec.scala │ └── immutable │ └── queue │ ├── BatchedQueueSpec.scala │ ├── HoodMelvilleQueueSpec.scala │ └── QueueSpec.scala ├── scalacture-experimental └── src │ ├── main │ └── scala │ │ └── scalacture │ │ └── experimental │ │ ├── immutable │ │ ├── deque │ │ │ └── BatchedDeque.scala │ │ └── priorityqueue │ │ │ ├── LeftistHeap.scala │ │ │ └── PairingHeap.scala │ │ ├── mutable │ │ ├── bloomfilter │ │ │ └── BloomFilter.scala │ │ └── trie │ │ │ └── Trie.scala │ │ └── util │ │ ├── Bytes.scala │ │ ├── Hashing.scala │ │ └── Math.scala │ └── test │ └── scala │ └── scalacture │ └── experimental │ └── mutable │ └── trie │ └── TrieSpec.scala └── scalacture-scalaz └── src ├── main └── scala │ └── scalacture │ └── scalaz │ └── immutable │ └── queue │ ├── BatchedQueue.scala │ ├── HoodMelvilleQueue.scala │ └── Queue.scala └── test └── scala └── scalacture └── scalaz └── immutable └── queue ├── BatchedQueueSpec.scala ├── HoodMelvilleQueueSpec.scala └── QueueSpec.scala /.travis.yml: -------------------------------------------------------------------------------- 1 | language: scala 2 | 3 | scala: 4 | - 2.10.7 5 | - 2.11.12 6 | - 2.12.8 7 | jdk: oraclejdk8 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Scalacture 2 | 3 | [![Build Status](https://travis-ci.org/okumin/scalacture.svg?branch=master)](https://travis-ci.org/okumin/scalacture) 4 | 5 | Scalacture is a project to implement all the data structures by Scala. 6 | 7 | ## Projects 8 | 9 | ### scalacture-core 10 | 11 | The main project. 12 | Stable APIs are here. 13 | 14 | * scalacture.immutable.queue 15 | * BatchedQueue 16 | * HoodMelvilleQueue 17 | 18 | ### scalacture-scalaz 19 | 20 | Provides Scalaz extensions. 21 | You can import type class instances for data structues implemented in Scalacture. 22 | 23 | For example, if you would like to import type class instances for `scalacture.immutable.queue.HoodMelvilleQueue`, 24 | 25 | ```scala 26 | import scalacture.scalaz.immutable.queue.hoodMelvilleQueue._ 27 | ``` 28 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | val projectName = "scalacture" 2 | 3 | val basicSettings = Seq( 4 | version := "0.1", 5 | scalaVersion := "2.11.12", 6 | crossScalaVersions := Seq("2.10.7", "2.11.12", "2.12.8") 7 | ) 8 | 9 | lazy val core = Project( 10 | id = s"$projectName-core", 11 | base = file(s"$projectName-core") 12 | ).settings( 13 | basicSettings, 14 | name := s"$projectName-core", 15 | libraryDependencies ++= Seq( 16 | "org.scalatest" %% "scalatest" % "3.0.8-RC2" % "test", 17 | "org.scalacheck" %% "scalacheck" % "1.14.0" % "test" 18 | ) 19 | ) 20 | 21 | lazy val scalaz = Project( 22 | id = s"$projectName-scalaz", 23 | base = file(s"$projectName-scalaz") 24 | ).settings( 25 | basicSettings, 26 | scalapropsWithScalaz, 27 | name := s"$projectName-scalaz", 28 | scalapropsVersion := "0.6.0", 29 | libraryDependencies ++= Seq( 30 | "org.scalaz" %% "scalaz-core" % "7.2.27" 31 | ) 32 | ).dependsOn( 33 | core 34 | ) 35 | 36 | lazy val experimental = Project( 37 | id = s"$projectName-experimental", 38 | base = file(s"$projectName-experimental") 39 | ).settings( 40 | basicSettings, 41 | name := s"$projectName-experimental" 42 | ).dependsOn( 43 | core, 44 | core % "test->test" 45 | ) 46 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version = 1.2.8 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | logLevel := Level.Warn 2 | 3 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.9") 4 | 5 | addSbtPlugin("com.github.scalaprops" % "sbt-scalaprops" % "0.3.1") 6 | -------------------------------------------------------------------------------- /scalacture-core/src/main/scala/scalacture/immutable/queue/BatchedQueue.scala: -------------------------------------------------------------------------------- 1 | package scalacture.immutable.queue 2 | 3 | import scala.collection.generic.{CanBuildFrom, GenericCompanion, GenericTraversableTemplate, SeqFactory} 4 | import scala.collection.mutable.ListBuffer 5 | import scala.collection.{GenTraversableOnce, mutable} 6 | 7 | /** 8 | * A queue made up of a pair of lists. 9 | * 10 | * This data structure achieves good amortized efficiency by batched rebuilding. 11 | * However persistently used, amortized bounds of `dequeue` degrade to the worst-case bounds of that. 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | *
worst-caseamortizedunder persistent usage
peekO(1)O(1)O(1)
enqueueO(1)O(1)O(1)
dequeueO(n)O(1)O(n)
42 | */ 43 | @SerialVersionUID(1382407360619706277L) 44 | final class BatchedQueue[+A] private (frontList: List[A], rearList: List[A]) 45 | extends Queue[A] 46 | with QueueLike[A, BatchedQueue[A]] 47 | with GenericTraversableTemplate[A, BatchedQueue] 48 | with Serializable { 49 | 50 | // Ensures that frontList is non-empty unless the queue is empty. 51 | private[this] def rebuild[B >: A](front: List[B], rear: List[B]): BatchedQueue[B] = { 52 | (front, rear) match { 53 | case (Nil, r) => new BatchedQueue[B](r.reverse, Nil) 54 | case (f, r) => new BatchedQueue[B](f, r) 55 | } 56 | } 57 | 58 | override def companion: GenericCompanion[BatchedQueue] = BatchedQueue 59 | 60 | override def length: Int = frontList.size + rearList.size 61 | 62 | override def isEmpty: Boolean = frontList.isEmpty && rearList.isEmpty 63 | 64 | override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[BatchedQueue[A], B, That]): That = { 65 | bf match { 66 | case _: BatchedQueue.GenericCanBuildFrom[_] => 67 | rebuild(frontList, that.toList.reverse ::: rearList).asInstanceOf[That] 68 | case _ => super.++(that) 69 | } 70 | } 71 | 72 | override def ++:[B >: A, That](that: Traversable[B])(implicit bf: CanBuildFrom[BatchedQueue[A], B, That]): That = { 73 | bf match { 74 | case _: BatchedQueue.GenericCanBuildFrom[_] => 75 | new BatchedQueue[B](that.toList ::: frontList, rearList).asInstanceOf[That] 76 | case _ => super.++:(that) 77 | } 78 | } 79 | 80 | override def +:[B >: A, That](elem: B)(implicit bf: CanBuildFrom[BatchedQueue[A], B, That]): That = { 81 | bf match { 82 | case _: BatchedQueue.GenericCanBuildFrom[_] => 83 | new BatchedQueue[B](elem :: frontList, rearList).asInstanceOf[That] 84 | case _ => super.+:(elem) 85 | } 86 | } 87 | 88 | override def reverse: BatchedQueue[A] = rebuild(rearList, frontList) 89 | 90 | /** 91 | * Returns the first element. 92 | * O(1) time. 93 | */ 94 | override def peek: A = frontList match { 95 | case Nil => throw new NoSuchElementException("This Queue is empty.") 96 | case x :: _ => x 97 | } 98 | 99 | /** 100 | * Creates a new queue with element added at the end of the old queue. 101 | * O(1) time. 102 | * @param elem the element to insert. 103 | * @return a new queue with the inserted element. 104 | */ 105 | override def enqueue[B >: A](elem: B): BatchedQueue[B] = { 106 | rebuild(frontList, elem :: rearList) 107 | } 108 | 109 | /** 110 | * Returns a tuple with the first element in the queue, and a new queue with this element removed. 111 | * O(n) worst-case time, O(1) amortized time. 112 | * @return the first element of the queue and a new queue. 113 | */ 114 | override def dequeue: (A, BatchedQueue[A]) = (frontList, rearList) match { 115 | case (Nil, _) => throw new NoSuchElementException("This Queue is empty.") 116 | case (x :: f, r) => (x, rebuild(f, r)) 117 | } 118 | } 119 | 120 | object BatchedQueue extends SeqFactory[BatchedQueue] { 121 | implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, BatchedQueue[A]] = { 122 | ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] 123 | } 124 | 125 | override def newBuilder[A]: mutable.Builder[A, BatchedQueue[A]] = { 126 | ListBuffer.empty[A].mapResult { xs => new BatchedQueue[A](xs, Nil) } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /scalacture-core/src/main/scala/scalacture/immutable/queue/HoodMelvilleQueue.scala: -------------------------------------------------------------------------------- 1 | package scalacture.immutable.queue 2 | 3 | import scala.collection.generic.{CanBuildFrom, GenericCompanion, GenericTraversableTemplate, SeqFactory} 4 | import scala.collection.mutable.ListBuffer 5 | import scala.collection.{GenTraversableOnce, mutable} 6 | import scalacture.immutable.queue.HoodMelvilleQueue.{Appending, Done, Idle, Reversing, RotationState} 7 | 8 | /** 9 | * A queue implemented by Hood and Melville. 10 | * 11 | * This is a immutable and real-time queue based on global rebuilding. 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 30 | * 31 | * 32 | * 33 | * 34 | * 35 | * 36 | * 37 | * 38 | * 39 | * 40 | * 41 | *
worst-caseamortizedunder persistent usage
peekO(1)O(1)O(1)
enqueueO(1)O(1)O(1)
dequeueO(1)O(1)O(1)
42 | */ 43 | @SerialVersionUID(1067800614785502062L) 44 | final class HoodMelvilleQueue[+A] private (diff: Int, 45 | working: List[A], 46 | state: RotationState[A], 47 | rearList: List[A]) 48 | extends Queue[A] 49 | with QueueLike[A, HoodMelvilleQueue[A]] 50 | with GenericTraversableTemplate[A, HoodMelvilleQueue] 51 | with Serializable { 52 | 53 | /** 54 | * A rotation starts when the length of the front list becomes one longer than that of the rear list. 55 | * A front list means a working copy on starting rotation. 56 | * And the rotation finishes when `exec` or `invalidate` are called 2m + 2 times, 57 | * where m is the initial length of the working copy. 58 | */ 59 | private[this] def exec[B >: A](state: RotationState[B]): RotationState[B] = state match { 60 | case Reversing(ok, x :: xs, fs, y :: ys, rs) => Reversing(ok + 1, xs, x :: fs, ys, y :: rs) 61 | case Reversing(ok, Nil, fs, y :: Nil, rs) => Appending(ok, fs, y :: rs) 62 | case Appending(0, _, rs) => Done(rs) 63 | case Appending(ok, f :: fs, rs) => Appending(ok - 1, fs, f :: rs) 64 | case s => s 65 | } 66 | 67 | private[this] def invalidate(state: RotationState[A]): RotationState[A] = state match { 68 | case Reversing(ok, xs, fs, ys, rs) => Reversing(ok - 1, xs, fs, ys, rs) 69 | case Appending(0, _, r :: rs) => Done(rs) 70 | case Appending(ok, fs, rs) => Appending(ok - 1, fs, rs) 71 | case s => s 72 | } 73 | 74 | /** 75 | * If the reverse of the front list is completed, 76 | * the true diff is achieved by the following calculation. 77 | * 78 | * Where `m` is the initial length of the working copy and the total number of times of `exec`, 79 | * `x` is the total number of times of that `enqueue` or `dequeue` are executed, 80 | * `d` is the true diff that represents the difference 81 | * between the length of the front list and that of the rear list. 82 | * 83 | * Since the initial `diff` is -1 and then `diff` decreases by 1 per `enqueue` or `dequeue`, 84 | * diff = -x - 1 85 | * x = -diff - 1 86 | * Since `exec` are called twice at the beginning of each rotation, 87 | * m = x + 2 88 | * = -diff - 1 + 2 89 | * = -diff + 1 90 | * Since `2m + 1` means the initial true diff 91 | * and then the true diff decreases by 1 per `enqueue` or `dequeue`, 92 | * d = 2m + 1 - x 93 | * = 2(1 - diff) + 1 - (-diff - 1) 94 | * = 4 - diff 95 | */ 96 | private[this] def execute[B >: A](diff: Int, 97 | working: List[B], 98 | state: RotationState[B], 99 | rear: List[B]): HoodMelvilleQueue[B] = { 100 | exec(state) match { 101 | case s @ Reversing(_, Nil, _, _ :: Nil, _) => new HoodMelvilleQueue[B](4 - diff, working, s, rear) 102 | case Done(xs) => new HoodMelvilleQueue[B](diff, xs, Idle, rear) 103 | case newState => new HoodMelvilleQueue[B](diff, working, newState, rear) 104 | } 105 | } 106 | 107 | /** 108 | * Where m is the initial length of the working copy on starting a rotation, 109 | * it is the following conditions to start the next rotation. 110 | * 111 | * - after 2m + 2 calls to `enqueue` or `dequeue` 112 | * because the length of the front list becomes longer than that of the rear list. 113 | * - after m calls to `dequeue` because the working copy becomes empty 114 | * 115 | * `exec` are called at the following occasion. 116 | * 117 | * - called twice at the beginning of each rotation 118 | * - called once for every `enqueue` or `dequeue` 119 | * 120 | * After `enqueue` or `dequeue` are called 2m + 2, `exec` has been called 2m + 4 times. 121 | * After `dequeue` is called m times, 122 | * `exec` has been called m + 2 times and `invalidate` has been called m times. 123 | * 124 | * Thus, a rotation always finishes before the next rotation starts. 125 | */ 126 | private[this] def check[B >: A](diff: Int, 127 | working: List[B], 128 | state: RotationState[B], 129 | rear: List[B]): HoodMelvilleQueue[B] = { 130 | (diff, working, state, rear) match { 131 | case (-1, ws, Idle, r :: Nil) => new HoodMelvilleQueue[B](1, r :: Nil, Idle, Nil) 132 | case (-1, w :: Nil, Idle, r1 :: r2 :: Nil) => new HoodMelvilleQueue[B](3, w :: r2 :: r1 :: Nil, Idle, Nil) 133 | case (-1, ws, Idle, rs) => execute(-1, ws, exec(Reversing(0, ws, Nil, rs, Nil)), Nil) 134 | case (d, ws, s, rs) => execute(d, ws, s, rs) 135 | } 136 | } 137 | 138 | override def companion: GenericCompanion[HoodMelvilleQueue] = HoodMelvilleQueue 139 | 140 | override def isEmpty: Boolean = working.isEmpty 141 | 142 | override def ++[B >: A, That](that: GenTraversableOnce[B])(implicit bf: CanBuildFrom[HoodMelvilleQueue[A], B, That]): That = { 143 | bf match { 144 | case _: HoodMelvilleQueue.GenericCanBuildFrom[_] => 145 | that.foldLeft[HoodMelvilleQueue[B]](this) { (q, x) => q.enqueue(x) }.asInstanceOf[That] 146 | case _ => super.++(that) 147 | } 148 | } 149 | 150 | /** 151 | * Returns the first element. 152 | * O(1) time. 153 | */ 154 | override def peek: A = working match { 155 | case Nil => throw new NoSuchElementException("This Queue is empty.") 156 | case x :: _ => x 157 | } 158 | 159 | /** 160 | * Creates a new queue with element added at the end of the old queue. 161 | * O(1) time. 162 | * @param elem the element to insert. 163 | * @return a new queue with the inserted element. 164 | */ 165 | override def enqueue[B >: A](elem: B): HoodMelvilleQueue[B] = { 166 | check(diff - 1, working, state, elem :: rearList) 167 | } 168 | 169 | /** 170 | * Returns a tuple with the first element in the queue, and a new queue with this element removed. 171 | * O(1) time. 172 | * @return the first element of the queue and a new queue. 173 | */ 174 | override def dequeue: (A, HoodMelvilleQueue[A]) = working match { 175 | case Nil => throw new NoSuchElementException("This Queue is empty.") 176 | case x :: xs => (x, check(diff - 1, xs, invalidate(state), rearList)) 177 | } 178 | } 179 | 180 | object HoodMelvilleQueue extends SeqFactory[HoodMelvilleQueue] { 181 | private sealed abstract class RotationState[+A] 182 | private case class Reversing[A](ok: Int, 183 | xs: List[A], 184 | fs: List[A], 185 | ys: List[A], 186 | rs: List[A]) extends RotationState[A] 187 | private case class Appending[A](ok: Int, fs: List[A], rs: List[A]) extends RotationState[A] 188 | private case class Done[A](xs: List[A]) extends RotationState[A] 189 | private case object Idle extends RotationState[Nothing] 190 | 191 | implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, HoodMelvilleQueue[A]] = { 192 | ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] 193 | } 194 | 195 | override def newBuilder[A]: mutable.Builder[A, HoodMelvilleQueue[A]] = { 196 | ListBuffer.empty[A].mapResult { xs => new HoodMelvilleQueue[A](xs.size, xs, Idle, Nil) } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /scalacture-core/src/main/scala/scalacture/immutable/queue/Queue.scala: -------------------------------------------------------------------------------- 1 | package scalacture.immutable.queue 2 | 3 | import scala.collection.generic.{CanBuildFrom, GenericCompanion, GenericTraversableTemplate, SeqFactory} 4 | import scala.collection.{immutable, mutable} 5 | 6 | /** 7 | * A FIFO queue. 8 | */ 9 | trait Queue[+A] 10 | extends QueueLike[A, Queue[A]] 11 | with immutable.LinearSeq[A] 12 | with GenericTraversableTemplate[A, Queue] { 13 | 14 | override def companion: GenericCompanion[Queue] = Queue 15 | 16 | override def toString(): String = mkString(stringPrefix + "(", ", ", ")") 17 | } 18 | 19 | object Queue extends SeqFactory[Queue] { 20 | implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Queue[A]] = { 21 | ReusableCBF.asInstanceOf[GenericCanBuildFrom[A]] 22 | } 23 | 24 | override def newBuilder[A]: mutable.Builder[A, Queue[A]] = BatchedQueue.newBuilder 25 | } 26 | -------------------------------------------------------------------------------- /scalacture-core/src/main/scala/scalacture/immutable/queue/QueueLike.scala: -------------------------------------------------------------------------------- 1 | package scalacture.immutable.queue 2 | 3 | import scala.collection.LinearSeqOptimized 4 | import scala.collection.generic.CanBuildFrom 5 | 6 | trait QueueLike[+A, +This <: Queue[A] with QueueLike[A, This]] 7 | extends LinearSeqOptimized[A, This] { self: This => 8 | 9 | final override def :+[B >: A, That](elem: B)(implicit bf: CanBuildFrom[This, B, That]): That = { 10 | bf match { 11 | case _: Queue.GenericCanBuildFrom[_] => enqueue(elem).asInstanceOf[That] 12 | case _ => super.:+(elem) 13 | } 14 | } 15 | 16 | final override def head: A = peek 17 | 18 | final override def tail: This = dequeueOption match { 19 | case Some((_, t)) => t 20 | case None => throw new UnsupportedOperationException("tail of empty queue") 21 | } 22 | 23 | override def isEmpty: Boolean 24 | 25 | /** 26 | * Returns the first element. 27 | */ 28 | def peek: A 29 | 30 | /** 31 | * Returns the first element or None if the queue is empty. 32 | */ 33 | final def peekOption: Option[A] = if (isEmpty) None else Some(peek) 34 | 35 | /** 36 | * Creates a new queue with element added at the end of the old queue. 37 | * @param elem the element to insert. 38 | * @return a new queue with the inserted element. 39 | */ 40 | def enqueue[B >: A](elem: B): Queue[B] 41 | 42 | /** 43 | * Returns a tuple with the first element in the queue, and a new queue with this element removed. 44 | * @return the first element of the queue and a new queue. 45 | */ 46 | def dequeue: (A, This) 47 | 48 | /** 49 | * Returns a tuple with the first element in the queue, and a new queue with this element removed. 50 | * @return the first element of the queue and a new queue or None if the queue is empty. 51 | */ 52 | final def dequeueOption: Option[(A, This)] = if (isEmpty) None else Some(dequeue) 53 | } 54 | -------------------------------------------------------------------------------- /scalacture-core/src/test/scala/scalacture/helper/SeqSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.helper 2 | 3 | import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream} 4 | import org.scalacheck.{Arbitrary, Gen} 5 | import org.scalatest.WordSpec 6 | import org.scalatest.prop.GeneratorDrivenPropertyChecks 7 | import scala.collection.generic.{CanBuildFrom, GenericTraversableTemplate, SeqFactory} 8 | import scala.collection.{SeqLike, breakOut} 9 | import scala.language.higherKinds 10 | 11 | abstract class SeqSpec[A: Arbitrary, CC[X] <: Seq[X] with SeqLike[X, CC[X]] with GenericTraversableTemplate[X, CC]](implicit private[this] val seqCBF: CanBuildFrom[CC[_], A, CC[A]]) 12 | extends WordSpec 13 | with GeneratorDrivenPropertyChecks { 14 | 15 | protected[this] def factory: SeqFactory[CC] 16 | 17 | protected[this] val elemsAndIndex: Gen[(List[A], Int)] = { 18 | for { 19 | elems <- Gen.listOf(Arbitrary.arbitrary[A]) 20 | n = elems.size 21 | index <- Gen.chooseNum(-1, n + 1, 0, 1, n - 1, n) 22 | } yield (elems, index) 23 | } 24 | 25 | "A Seq" should { 26 | "be able to serialize" in { 27 | forAll { elems: List[A] => 28 | val seq = factory(elems: _*) 29 | val outputStream = new ByteArrayOutputStream() 30 | new ObjectOutputStream(outputStream).writeObject(seq) 31 | val bytes = outputStream.toByteArray 32 | 33 | val inputStream = new ObjectInputStream(new ByteArrayInputStream(bytes)) 34 | val deserizized = inputStream.readObject().asInstanceOf[CC[A]] 35 | assert(deserizized === seq) 36 | } 37 | } 38 | 39 | "apply" when { 40 | "specifiying correct index" in { 41 | forAll(elemsAndIndex) { 42 | case (elems, index) => 43 | whenever(index >= 0 && index < elems.size) { 44 | assert(factory(elems: _*)(index) === elems(index)) 45 | } 46 | } 47 | } 48 | 49 | "index is out of range" in { 50 | val elemsAndIndex = for { 51 | elems <- Gen.listOf(Arbitrary.arbitrary[A]) 52 | n = elems.size 53 | index <- Gen.oneOf(Gen.negNum[Int], Gen.choose(n, Int.MaxValue)) 54 | } yield (elems, index) 55 | forAll(elemsAndIndex) { 56 | case (elems, index) => 57 | intercept[IndexOutOfBoundsException] { factory(elems: _*)(index) } 58 | intercept[IndexOutOfBoundsException] { elems(index) } 59 | } 60 | } 61 | } 62 | 63 | "iterator" in { 64 | forAll { elems: List[A] => 65 | assert(factory(elems: _*).iterator.toList === elems) 66 | } 67 | } 68 | 69 | "++" when { 70 | "same-result-type" in { 71 | forAll { (elems1: List[A], elems2: List[A]) => 72 | val actual: CC[A] = factory(elems1: _*) ++ factory(elems2: _*) 73 | assert(actual === elems1 ++ elems2) 74 | } 75 | } 76 | 77 | "converting into super type" in { 78 | forAll { (elems1: List[A], elems2: List[A]) => 79 | val actual: Seq[A] = factory(elems1: _*) ++ factory(elems2: _*) 80 | assert(actual === elems1 ++ elems2) 81 | } 82 | } 83 | 84 | "converting into another type" in { 85 | forAll { (elems1: List[A], elems2: List[A]) => 86 | val actual: List[A] = factory(elems1: _*).++(factory(elems2: _*))(breakOut) 87 | assert(actual === elems1 ++ elems2) 88 | } 89 | } 90 | } 91 | 92 | "++:" when { 93 | "same-result-type" in { 94 | forAll { (elems1: List[A], elems2: List[A]) => 95 | val actual: CC[A] = factory(elems1: _*) ++: factory(elems2: _*) 96 | assert(actual === elems1 ++: elems2) 97 | } 98 | } 99 | 100 | "converting into super type" in { 101 | forAll { (elems1: List[A], elems2: List[A]) => 102 | val actual: Seq[A] = factory(elems1: _*).++:(factory(elems2: _*)) 103 | assert(actual === elems1.++:(elems2)) 104 | } 105 | } 106 | 107 | "converting into another type" in { 108 | forAll { (elems1: List[A], elems2: List[A]) => 109 | val actual: List[A] = factory(elems1: _*).++:(factory(elems2: _*))(breakOut) 110 | assert(actual === elems1.++:(elems2)) 111 | } 112 | } 113 | } 114 | 115 | "+:" when { 116 | "same-result-type" in { 117 | forAll { (elems: List[A], elem: A) => 118 | val actual: CC[A] = elem +: factory(elems: _*) 119 | assert(actual === elem +: elems) 120 | } 121 | } 122 | 123 | "converting into super type" in { 124 | forAll { (elems: List[A], elem: A) => 125 | val actual: Seq[A] = elem +: factory(elems: _*) 126 | assert(actual === elem +: elems) 127 | } 128 | } 129 | 130 | "converting into another type" in { 131 | forAll { (elems: List[A], elem: A) => 132 | val actual: List[A] = factory(elems: _*).+:(elem)(breakOut) 133 | assert(actual === elem +: elems) 134 | } 135 | } 136 | } 137 | 138 | ":+" when { 139 | "same-result-type" in { 140 | forAll { (elems: List[A], elem: A) => 141 | val actual: CC[A] = factory(elems: _*) :+ elem 142 | assert(actual === elems :+ elem) 143 | } 144 | } 145 | 146 | "converting into super type" in { 147 | forAll { (elems: List[A], elem: A) => 148 | val actual: Seq[A] = factory(elems: _*) :+ elem 149 | assert(actual === elems :+ elem) 150 | } 151 | } 152 | 153 | "converting into another type" in { 154 | forAll { (elems: List[A], elem: A) => 155 | val actual: List[A] = factory(elems: _*).:+(elem)(breakOut) 156 | assert(actual === elems :+ elem) 157 | } 158 | } 159 | } 160 | 161 | "drop" in { 162 | forAll { (elems: List[A], n: Int) => 163 | assert(factory(elems: _*).drop(n) === elems.drop(n)) 164 | } 165 | } 166 | 167 | "dropRight" in { 168 | forAll { (elems: List[A], n: Int) => 169 | assert(factory(elems: _*).dropRight(n) === elems.dropRight(n)) 170 | } 171 | } 172 | 173 | "dropWhile" in { 174 | forAll { (elems: List[A], elem: A) => 175 | assert(factory(elems: _*).dropWhile(_ != elem) === elems.dropWhile(_ != elem)) 176 | } 177 | } 178 | 179 | "endsWith" in { 180 | forAll { (elems: List[A], end: List[A]) => 181 | assert(factory(elems: _*).endsWith(end) === elems.endsWith(end)) 182 | } 183 | } 184 | 185 | "filter" in { 186 | forAll { (elems: List[A], elem: A) => 187 | val actual: CC[A] = factory(elems: _*).filter(_ == elem) 188 | assert(actual === elems.filter(_ == elem)) 189 | } 190 | } 191 | 192 | "head" when { 193 | "Seq is non-empty" in { 194 | forAll(Gen.nonEmptyListOf(Arbitrary.arbitrary[A])) { elems: List[A] => 195 | assert(factory(elems: _*).head === elems.head) 196 | } 197 | } 198 | 199 | "Seq is empty" in { 200 | intercept[NoSuchElementException] { factory().head } 201 | intercept[NoSuchElementException] { Nil.head } 202 | } 203 | } 204 | 205 | "init" when { 206 | "Seq is non-empty" in { 207 | forAll(Gen.nonEmptyListOf(Arbitrary.arbitrary[A])) { elems: List[A] => 208 | assert(factory(elems: _*).init === elems.init) 209 | } 210 | } 211 | 212 | "Seq is empty" in { 213 | intercept[UnsupportedOperationException] { factory().init } 214 | intercept[UnsupportedOperationException] { Nil.init } 215 | } 216 | } 217 | 218 | "last" when { 219 | "Seq is non-empty" in { 220 | forAll(Gen.nonEmptyListOf(Arbitrary.arbitrary[A])) { elems: List[A] => 221 | assert(factory(elems: _*).last === elems.last) 222 | } 223 | } 224 | 225 | "Seq is empty" in { 226 | intercept[NoSuchElementException] { factory().last } 227 | intercept[NoSuchElementException] { Nil.last } 228 | } 229 | } 230 | 231 | "map" when { 232 | "same-result-type" in { 233 | forAll { elems: List[A] => 234 | val actual: CC[A] = factory(elems: _*).map(identity) 235 | assert(actual === elems.map(identity)) 236 | } 237 | } 238 | 239 | "converting into super type" in { 240 | forAll { elems: List[A] => 241 | val actual: Seq[A] = factory(elems: _*).map(identity) 242 | assert(actual === elems.map(identity)) 243 | } 244 | } 245 | 246 | "converting into another type" in { 247 | forAll { elems: List[A] => 248 | val actual: List[A] = factory(elems: _*).map(identity)(breakOut) 249 | assert(actual === elems.map(identity)) 250 | } 251 | } 252 | } 253 | 254 | "padTo" when { 255 | "same-result-type" in { 256 | forAll(elemsAndIndex, Arbitrary.arbitrary[A]) { 257 | case ((elems, len), elem) => 258 | val actual: CC[A] = factory(elems: _*).padTo(len, elem) 259 | assert(actual === elems.padTo(len, elem)) 260 | } 261 | } 262 | 263 | "converting into super type" in { 264 | forAll(elemsAndIndex, Arbitrary.arbitrary[A]) { 265 | case ((elems, len), elem) => 266 | val actual: Seq[A] = factory(elems: _*).padTo(len, elem) 267 | assert(actual === elems.padTo(len, elem)) 268 | } 269 | } 270 | 271 | "converting into another type" in { 272 | forAll(elemsAndIndex, Arbitrary.arbitrary[A]) { 273 | case ((elems, len), elem) => 274 | val actual: List[A] = factory(elems: _*).padTo(len, elem)(breakOut) 275 | assert(actual === elems.padTo(len, elem)) 276 | } 277 | } 278 | } 279 | 280 | "prefixLength" in { 281 | forAll { (elems: List[A], elem: A) => 282 | assert(factory(elems: _*).prefixLength(_ != elem) === elems.prefixLength(_ != elem)) 283 | } 284 | } 285 | 286 | "reverse" in { 287 | forAll { elems: List[A] => 288 | assert(factory(elems: _*).reverse === elems.reverse) 289 | } 290 | } 291 | 292 | "size" in { 293 | forAll { elems: List[A] => 294 | assert(factory(elems: _*).size === elems.size) 295 | } 296 | } 297 | 298 | "splitAt" in { 299 | forAll(elemsAndIndex) { 300 | case (elems, index) => 301 | assert(factory(elems: _*).splitAt(index) === elems.splitAt(index)) 302 | } 303 | } 304 | 305 | "tail" when { 306 | "Seq is non-empty" in { 307 | forAll(Gen.nonEmptyListOf(Arbitrary.arbitrary[A])) { elems: List[A] => 308 | assert(factory(elems: _*).tail === elems.tail) 309 | } 310 | } 311 | 312 | "Seq is empty" in { 313 | intercept[UnsupportedOperationException] { factory().tail } 314 | intercept[UnsupportedOperationException] { Nil.tail } 315 | } 316 | } 317 | 318 | "takeRight" in { 319 | forAll(elemsAndIndex) { 320 | case (elems, index) => 321 | assert(factory(elems: _*).takeRight(index) === elems.takeRight(index)) 322 | } 323 | } 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /scalacture-core/src/test/scala/scalacture/immutable/queue/BatchedQueueSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.immutable.queue 2 | 3 | import scala.collection.generic.SeqFactory 4 | 5 | class BatchedQueueSpec extends QueueSpec[BatchedQueue] { 6 | override protected[this] def factory: SeqFactory[BatchedQueue] = BatchedQueue 7 | 8 | "A BatchedQueue" should { 9 | "return BatchedQueue" when { 10 | "enqueueing" in { 11 | forAll { elem: Int => 12 | val actual: BatchedQueue[Int] = BatchedQueue.empty[Int].enqueue(elem) 13 | assert(actual === BatchedQueue(elem)) 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scalacture-core/src/test/scala/scalacture/immutable/queue/HoodMelvilleQueueSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.immutable.queue 2 | 3 | import scala.collection.generic.SeqFactory 4 | 5 | class HoodMelvilleQueueSpec extends QueueSpec[HoodMelvilleQueue] { 6 | override protected[this] def factory: SeqFactory[HoodMelvilleQueue] = HoodMelvilleQueue 7 | 8 | "A HoodMelvilleQueue" should { 9 | "return HoodMelvilleQueue" when { 10 | "enqueueing" in { 11 | forAll { elem: Int => 12 | val actual: HoodMelvilleQueue[Int] = HoodMelvilleQueue.empty[Int].enqueue(elem) 13 | assert(actual === HoodMelvilleQueue(elem)) 14 | } 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /scalacture-core/src/test/scala/scalacture/immutable/queue/QueueSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.immutable.queue 2 | 3 | import org.scalacheck.{Arbitrary, Gen} 4 | import scala.collection.generic.{CanBuildFrom, GenericTraversableTemplate, SeqFactory} 5 | import scala.language.higherKinds 6 | import scalacture.helper.SeqSpec 7 | 8 | abstract class QueueSpec[CC[X] <: Queue[X] with QueueLike[X, CC[X]] with GenericTraversableTemplate[X, CC]](implicit private[this] val seqCBF: CanBuildFrom[CC[_], Int, CC[Int]]) 9 | extends SeqSpec[Int, CC] { 10 | 11 | protected[this] sealed abstract class Command 12 | protected[this] case object Peek extends Command 13 | protected[this] case class Enqueue(x: Int) extends Command 14 | protected[this] case object Dequeue extends Command 15 | protected[this] object Command { 16 | implicit val arbitrary: Arbitrary[Command] = Arbitrary { 17 | Gen.oneOf[Command](Peek, Arbitrary.arbitrary[Int].map(Enqueue), Dequeue) 18 | } 19 | } 20 | 21 | "A Queue" should { 22 | "behave like a FIFO queue" in { 23 | forAll { (elems: List[Int], commands: List[Command]) => 24 | val zero = (factory(elems: _*): Queue[Int], scala.collection.immutable.Queue(elems: _*)) 25 | val (q, m) = commands.foldLeft(zero) { 26 | case ((queue, model), Peek) if queue.isEmpty && model.isEmpty => 27 | (queue, model) 28 | case ((queue, model), Peek) => 29 | assert(queue.peek === model.front) 30 | (queue, model) 31 | case ((queue, model), Enqueue(x)) => 32 | val newQueue = queue.enqueue(x) 33 | val newModel = model.enqueue(x) 34 | assert(newQueue.size === newModel.size) 35 | assert(newQueue.isEmpty === newModel.isEmpty) 36 | assert(newQueue === newModel) 37 | (newQueue, newModel) 38 | case ((queue, model), Dequeue) if queue.isEmpty && model.isEmpty => 39 | (queue, model) 40 | case ((queue, model), Dequeue) => 41 | val (qx, newQueue) = queue.dequeue 42 | val (mx, newModel) = model.dequeue 43 | assert(qx === mx) 44 | assert(newQueue.size === newModel.size) 45 | assert(newQueue.isEmpty === newModel.isEmpty) 46 | assert(newQueue === newModel) 47 | (newQueue, newModel) 48 | } 49 | assert(q === m) 50 | } 51 | } 52 | 53 | "have correct elements and maintain FIFO order" when { 54 | "enqueueing" in { 55 | forAll { elems: List[Int] => 56 | val actual = elems.foldLeft(factory.empty[Int]: Queue[Int]) { (queue, elem) => 57 | queue.enqueue(elem) 58 | } 59 | assert(actual === elems) 60 | assert(actual.length === elems.size) 61 | } 62 | } 63 | 64 | "dequeueing" in { 65 | forAll(elemsAndIndex) { 66 | case (elems, times) => 67 | val queue = factory(elems: _*) 68 | val (_dequeued, rest) = (1 to times).foldLeft((List.empty[Int], queue)) { 69 | case ((list, q), _) => 70 | q.dequeueOption match { 71 | case None => (list, q) 72 | case Some((x, qq)) => (x :: list, qq) 73 | } 74 | } 75 | val dequeued = _dequeued.reverse 76 | assert(dequeued === elems.take(times)) 77 | assert(rest === elems.drop(times)) 78 | assert(rest.length === elems.drop(times).size) 79 | assert(dequeued ::: rest.toList === elems) 80 | } 81 | } 82 | } 83 | 84 | "retrieve the first element" in { 85 | forAll(Gen.nonEmptyListOf(Arbitrary.arbitrary[Int])) { elems: List[Int] => 86 | val queue = factory(elems: _*) 87 | assert(queue.head === elems.head) 88 | assert(queue.tail === elems.tail) 89 | assert(queue.peek === elems.head) 90 | assert(queue.peekOption === Some(elems.head)) 91 | assert(queue.dequeue === (elems.head, elems.tail)) 92 | assert(queue.dequeueOption === Some((elems.head, elems.tail))) 93 | } 94 | } 95 | 96 | "not be able to dequeue" when { 97 | "the queue is empty" in { 98 | val empty = factory[Int]() 99 | intercept[NoSuchElementException] { empty.peek } 100 | assert(empty.peekOption === None) 101 | intercept[NoSuchElementException] { empty.dequeue } 102 | assert(empty.dequeueOption === None) 103 | } 104 | } 105 | } 106 | } 107 | 108 | class DefaultQueueSpec extends QueueSpec[Queue] { 109 | override protected[this] def factory: SeqFactory[Queue] = Queue 110 | } 111 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/immutable/deque/BatchedDeque.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.immutable.deque 2 | 3 | final class BatchedDeque[A] private (frontList: List[A], rearList: List[A]) { 4 | // Ensures that both front and rear are non-empty unless size <= 1. 5 | private[this] def balance(front: List[A], rear: List[A]): BatchedDeque[A] = (front, rear) match { 6 | case (Nil, r) => 7 | val (left, right) = r.splitAt(r.size / 2) 8 | new BatchedDeque[A](right.reverse, left) 9 | case (f, Nil) => 10 | val (left, right) = f.splitAt(f.size / 2) 11 | new BatchedDeque[A](left, right.reverse) 12 | case (f, r) => new BatchedDeque[A](f, r) 13 | } 14 | 15 | def front: A = (frontList, rearList) match { 16 | case (Nil, Nil) => sys.error("This Deque is empty.") 17 | case (Nil, x :: _) => x 18 | case (x :: f, _) => x 19 | } 20 | 21 | def back: A = (frontList, rearList) match { 22 | case (Nil, Nil) => sys.error("This Deque is empty.") 23 | case (x :: _, Nil) => x 24 | case (_, x :: _) => x 25 | } 26 | 27 | def pushFront(elem: A): BatchedDeque[A] = balance(elem :: frontList, rearList) 28 | 29 | def pushBack(elem: A): BatchedDeque[A] = balance(frontList, elem :: rearList) 30 | 31 | def popFront: (A, BatchedDeque[A]) = (frontList, rearList) match { 32 | case (Nil, Nil) => sys.error("This Deque is empty.") 33 | case (Nil, x :: _) => (x, BatchedDeque.empty) 34 | case (x :: fs, rs) => (x, balance(fs, rs)) 35 | } 36 | 37 | def popBack: (A, BatchedDeque[A]) = (frontList, rearList) match { 38 | case (Nil, Nil) => sys.error("This Deque is empty.") 39 | case (x :: _, Nil) => (x, BatchedDeque.empty) 40 | case (fs, x :: rs) => (x, balance(fs, rs)) 41 | } 42 | } 43 | 44 | object BatchedDeque { 45 | def empty[A]: BatchedDeque[A] = new BatchedDeque[A](Nil, Nil) 46 | } 47 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/immutable/priorityqueue/LeftistHeap.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.immutable.priorityqueue 2 | 3 | import scala.Ordering.Implicits._ 4 | import scalacture.experimental.immutable.priorityqueue.LeftistHeap.{Branch, Leaf} 5 | 6 | sealed abstract class LeftistHeap[A: Ordering] { 7 | protected def rank: Int 8 | 9 | final def findMin: A = this match { 10 | case Branch(v, _, _) => v 11 | case Leaf() => sys.error("This heap is empty.") 12 | } 13 | 14 | final def deleteMin(): LeftistHeap[A] = this match { 15 | case Branch(_, l, r) => l.meld(r) 16 | case Leaf() => sys.error("This heap is empty.") 17 | } 18 | 19 | final def meld(that: LeftistHeap[A]): LeftistHeap[A] = (this, that) match { 20 | case (Leaf(), h) => h 21 | case (h, Leaf()) => h 22 | case (Branch(v1, l1, r1), h2 @ Branch(v2, l2, r2)) if v1 <= v2 => 23 | Branch.balance(v1, l1, r1.meld(h2)) 24 | case (h1: Branch[A], Branch(v2, l2, r2)) => 25 | Branch.balance(v2, l2, r2.meld(h1)) 26 | } 27 | 28 | final def insert(x: A): LeftistHeap[A] = meld(Branch(x, Leaf(), Leaf())) 29 | } 30 | 31 | object LeftistHeap { 32 | def empty[A: Ordering]: LeftistHeap[A] = Leaf() 33 | 34 | private final case class Leaf[A: Ordering]() extends LeftistHeap[A] { 35 | override protected def rank: Int = 0 36 | } 37 | private final case class Branch[A: Ordering](value: A, 38 | left: LeftistHeap[A], 39 | right: LeftistHeap[A]) extends LeftistHeap[A] { 40 | override protected val rank: Int = right.rank + 1 41 | } 42 | private object Branch { 43 | // Ensures the leftist property. 44 | def balance[A: Ordering](value: A, a: LeftistHeap[A], b: LeftistHeap[A]): Branch[A] = { 45 | if (a.rank >= b.rank) Branch(value, a, b) else Branch(value, b, a) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/immutable/priorityqueue/PairingHeap.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.immutable.priorityqueue 2 | 3 | import scala.Ordering.Implicits._ 4 | import scala.annotation.tailrec 5 | import scalacture.experimental.immutable.priorityqueue.PairingHeap.{Branch, Leaf} 6 | 7 | sealed abstract class PairingHeap[A: Ordering] { 8 | final def findMin: A = this match { 9 | case Branch(v, _) => v 10 | case Leaf() => sys.error("This heap is empty.") 11 | } 12 | 13 | final def deleteMin(): PairingHeap[A] = { 14 | @tailrec 15 | def mergePairs(heaps: List[Branch[A]], paired: List[PairingHeap[A]]): List[PairingHeap[A]] = { 16 | heaps match { 17 | case Nil => paired 18 | case h :: Nil => h :: paired 19 | case h1 :: h2 :: hs => mergePairs(hs, h1.meld(h2) :: paired) 20 | } 21 | } 22 | 23 | this match { 24 | case Leaf() => sys.error("This heap is empty.") 25 | case Branch(_, Nil) => Leaf() 26 | case Branch(_, heaps) => 27 | mergePairs(heaps, Nil).foldLeft[PairingHeap[A]](Leaf()) { (acc, pair) => acc.meld(pair) } 28 | } 29 | } 30 | 31 | final def meld(that: PairingHeap[A]): PairingHeap[A] = (this, that) match { 32 | case (Leaf(), h) => h 33 | case (h, Leaf()) => h 34 | case (Branch(v1, hs1), h2 @ Branch(v2, _)) if v1 <= v2 => Branch(v1, h2 :: hs1) 35 | case (h1: Branch[A], Branch(v2, hs2)) => Branch(v2, h1 :: hs2) 36 | } 37 | 38 | final def insert(x: A): PairingHeap[A] = meld(Branch(x, Nil)) 39 | } 40 | 41 | object PairingHeap { 42 | def empty[A: Ordering]: PairingHeap[A] = Leaf() 43 | 44 | private final case class Leaf[A: Ordering]() extends PairingHeap[A] 45 | 46 | private final case class Branch[A: Ordering](value: A, 47 | heaps: List[Branch[A]]) extends PairingHeap[A] 48 | } 49 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/mutable/bloomfilter/BloomFilter.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.mutable.bloomfilter 2 | 3 | import scala.collection.mutable 4 | import scalacture.experimental.util.{Hashing, Math} 5 | 6 | /** 7 | * BloomFilter, a data structure that can test whether the specified element is a member or not. 8 | * Compared to ordinary sets, e.g. implemented by hash table, BloomFilter needs less space. 9 | * But it is possible that BloomFilter mistakes a non stored element for a member of this, 10 | * it is called false positive. On the other hands, BloomFilter never mistakes a member for a non member. 11 | * 12 | * If following n, m and k are given, 13 | * n = the number of members of this BloomFilter 14 | * m = the number of bits that this BloomFilter uses 15 | * k = the number of hash values 16 | * the false positive probability is 17 | * (1 - (1 - 1 / m) `^` kn) `^` k 18 | * 19 | * @param m the number of bits 20 | * @param k the number of hash values for each element 21 | * @param bitSet BitSet that stores elements 22 | */ 23 | class BloomFilter[A: Hashing] private (private val m: Int, 24 | private val k: Int, 25 | private var bitSet: mutable.BitSet) { 26 | 27 | def isAccepted(elem: A): Boolean = { 28 | BloomFilter.hash(elem, k).forall { h => bitSet.contains(math.abs(h % m)) } 29 | } 30 | 31 | def add(elem: A): Unit = { 32 | BloomFilter.hash(elem, k).foreach { h => 33 | bitSet += math.abs(h % m) 34 | } 35 | } 36 | 37 | def |(that: BloomFilter[A]): BloomFilter[A] = { 38 | require(that.m == m) 39 | require(that.k == k) 40 | new BloomFilter(m, k, bitSet | that.bitSet) 41 | } 42 | 43 | def |=(that: BloomFilter[A]): BloomFilter[A] = { 44 | require(that.m == m) 45 | require(that.k == k) 46 | bitSet |= that.bitSet 47 | this 48 | } 49 | } 50 | 51 | object BloomFilter { 52 | private def hash[A](x: A, num: Int)(implicit hashing: Hashing[A]): Seq[Int] = { 53 | (1 to num).map { i => Hashing.hash(x, i) } 54 | } 55 | 56 | /** 57 | * Creates a new instance of BloomFilter. 58 | */ 59 | def empty[A](bitSize: Int, numOfHashFunctions: Int)(implicit hashing: Hashing[A]): BloomFilter[A] = { 60 | require(bitSize > 0, "The number of bits must be greater than 0.") 61 | require(numOfHashFunctions > 0, "The number of hash functions must be greater than 0.") 62 | val length = ((bitSize - 1) >>> 6) + 1 63 | val bits = Array.fill(length)(0L) 64 | val bitSet = mutable.BitSet.fromBitMaskNoCopy(bits) 65 | new BloomFilter[A](bitSize, numOfHashFunctions, bitSet) 66 | } 67 | 68 | /** 69 | * Creates a new instance of BloomFilter with the false positive probability. 70 | * BloomFilter which this method creates satisfy the condition that 71 | * the expected probability does not exceed the specified allowableFalsePositiveProbability 72 | * as long as the num of stored element is smaller than or equal to n. 73 | * In addition to that, this method creates as small size BloomFilter as possible. 74 | * @param n the size to be stored in BloomFilter 75 | * @param allowableFalsePositiveProbability the upper bound of the false positive probability 76 | * @return BloomFilter 77 | */ 78 | def withFalsePositiveRate[A: Hashing](n: Int, 79 | allowableFalsePositiveProbability: Double): BloomFilter[A] = { 80 | // m = the size of bit array 81 | // k = the number of hash functions 82 | // p = the expected false positive probability. 83 | // After n messages have been stored, 84 | // the probability that the specific bit is still 0 is (1 - 1 / m) ^ kn. 85 | // So p is (1 - (1 - 1 / m) ^ kn) ^ k. 86 | // Since the smallest m is given when half the bits are 1 and half are 0, following k is given. 87 | val k = math.ceil(Math.log2(allowableFalsePositiveProbability)).toInt 88 | // If half the bits are 1 and half are 0, m = - n * log2(falseNegativeProbability) * log2(e). 89 | val m = math.ceil(- n * math.log(allowableFalsePositiveProbability) / math.pow(math.log(2), 2)).toInt 90 | empty(m, k) 91 | } 92 | 93 | /** 94 | * Creates a new instance of BloomFilter with the specified number of bits. 95 | * And this method minimizes the expected false positive probability given n elements. 96 | * @param n the size to be stored in BloomFilter 97 | * @param bitSize the number of bits 98 | * @return BloomFilter 99 | */ 100 | def withBitSize[A: Hashing](n: Int, bitSize: Int): BloomFilter[A] = { 101 | // the number of hash functions that minimizes the false positive probability 102 | val k = math.ceil(bitSize / n * Math.Ln2).toInt 103 | empty(bitSize, k) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/mutable/trie/Trie.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.mutable.trie 2 | 3 | import scala.annotation.tailrec 4 | 5 | class Trie[A] { 6 | private var value: Option[A] = None 7 | private[this] var children: Map[Char, Trie[A]] = Map.empty 8 | 9 | private def get(key: List[Char]): Option[A] = key match { 10 | case Nil => value 11 | case h :: t => children.get(h).flatMap(_.get(t)) 12 | } 13 | 14 | def get(key: String): Option[A] = get(key.toList) 15 | 16 | @tailrec 17 | private def put(key: List[Char], v: A): Unit = key match { 18 | case Nil => value = Some(v) 19 | case h :: t => children.get(h) match { 20 | case Some(trie) => trie.put(t, v) 21 | case None => 22 | val trie = Trie.empty[A] 23 | children += h -> trie 24 | trie.put(t, v) 25 | } 26 | } 27 | 28 | def put(key: String, v: A): Unit = put(key.toList, v) 29 | } 30 | 31 | object Trie { 32 | def empty[A]: Trie[A] = new Trie[A] 33 | } 34 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/util/Bytes.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.util 2 | 3 | import java.nio.ByteBuffer 4 | 5 | private[scalacture] object Bytes { 6 | private[this] val ShortByteSize = java.lang.Short.SIZE / java.lang.Byte.SIZE 7 | private[this] val IntByteSize = Integer.SIZE / java.lang.Byte.SIZE 8 | private[this] val LongByteSize = java.lang.Long.SIZE / java.lang.Byte.SIZE 9 | private[this] val FloatByteSize = java.lang.Float.SIZE / java.lang.Byte.SIZE 10 | private[this] val DoubleByteSize = java.lang.Double.SIZE / java.lang.Byte.SIZE 11 | private[this] val CharByteSize = Character.SIZE / java.lang.Byte.SIZE 12 | 13 | def fromByte(x: Byte): Array[Byte] = Array(x) 14 | 15 | def fromShort(x: Short): Array[Byte] = ByteBuffer.allocate(ShortByteSize).putShort(x).array() 16 | 17 | def fromInt(x: Int): Array[Byte] = ByteBuffer.allocate(IntByteSize).putInt(x).array() 18 | 19 | def fromLong(x: Long): Array[Byte] = ByteBuffer.allocate(LongByteSize).putLong(x).array() 20 | 21 | def fromFloat(x: Float): Array[Byte] = ByteBuffer.allocate(FloatByteSize).putFloat(x).array() 22 | 23 | def fromDouble(x: Double): Array[Byte] = ByteBuffer.allocate(DoubleByteSize).putDouble(x).array() 24 | 25 | def fromChar(x: Char): Array[Byte] = ByteBuffer.allocate(CharByteSize).putChar(x).array() 26 | } 27 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/util/Hashing.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.util 2 | 3 | import java.nio.charset.StandardCharsets 4 | import scala.util.hashing.MurmurHash3 5 | 6 | trait Hashing[A] { 7 | def hash(x: A): Int = hash(x, Hashing.DefaultSeed) 8 | 9 | def hash(x: A, seed: Int): Int 10 | } 11 | 12 | object Hashing { 13 | private val DefaultSeed = 0x3c074a61 14 | 15 | def hash[A](x: A)(implicit hashing: Hashing[A]): Int = hashing.hash(x) 16 | 17 | def hash[A](x: A, seed: Int)(implicit hashing: Hashing[A]): Int = hashing.hash(x, seed) 18 | 19 | def apply[A](f: A => Array[Byte]): Hashing[A] = new Hashing[A] { 20 | override def hash(x: A, seed: Int): Int = MurmurHash3.bytesHash(f(x), seed) 21 | } 22 | 23 | implicit val BytesHashing: Hashing[Array[Byte]] = apply(identity) 24 | 25 | implicit val ByteHashing: Hashing[Byte] = apply(Bytes.fromByte) 26 | 27 | implicit val ShortHashing: Hashing[Short] = apply(Bytes.fromShort) 28 | 29 | implicit val IntHashing: Hashing[Int] = apply(Bytes.fromInt) 30 | 31 | implicit val LongHashing: Hashing[Long] = apply(Bytes.fromLong) 32 | 33 | implicit val FloatHashing: Hashing[Float] = apply(Bytes.fromFloat) 34 | 35 | implicit val DoubleHashing: Hashing[Double] = apply(Bytes.fromDouble) 36 | 37 | implicit val CharHashing: Hashing[Char] = apply(Bytes.fromChar) 38 | 39 | implicit val StringHashing: Hashing[String] = apply(_.getBytes(StandardCharsets.UTF_8)) 40 | } 41 | -------------------------------------------------------------------------------- /scalacture-experimental/src/main/scala/scalacture/experimental/util/Math.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.util 2 | 3 | private[scalacture] object Math { 4 | val Ln2 = math.log(2.0) 5 | 6 | def log2(x: Double): Double = math.log(x) / Ln2 7 | } 8 | -------------------------------------------------------------------------------- /scalacture-experimental/src/test/scala/scalacture/experimental/mutable/trie/TrieSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.experimental.mutable.trie 2 | 3 | import org.scalatest.WordSpec 4 | import org.scalatest.prop.GeneratorDrivenPropertyChecks 5 | import scala.collection.mutable 6 | 7 | class TrieSpec extends WordSpec with GeneratorDrivenPropertyChecks { 8 | "TrieMap" should { 9 | "behave as Map" in { 10 | forAll { kvs: List[(String, Int)] => 11 | val map = mutable.Map.empty[String, Int] 12 | val trie = Trie.empty[Int] 13 | kvs.foreach { 14 | case (k, v) => 15 | map.put(k, v) 16 | trie.put(k, v) 17 | assert(map.get(k) === Some(v)) 18 | assert(trie.get(k) === Some(v)) 19 | } 20 | kvs.foreach { 21 | case (k, _) => assert(map.get(k) === trie.get(k)) 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scalacture-scalaz/src/main/scala/scalacture/scalaz/immutable/queue/BatchedQueue.scala: -------------------------------------------------------------------------------- 1 | package scalacture.scalaz.immutable.queue 2 | 3 | import scala.collection.generic.{CanBuildFrom, SeqFactory} 4 | import scalacture.immutable.queue.BatchedQueue 5 | 6 | trait BatchedQueueInstances extends QueueSubInstances { 7 | override type XQueue[A] = BatchedQueue[A] 8 | override implicit def canBuildFrom[A]: CanBuildFrom[XQueue[_], A, XQueue[A]] = BatchedQueue.canBuildFrom 9 | override protected[this] def factory: SeqFactory[XQueue] = BatchedQueue 10 | } 11 | 12 | object batchedQueue extends BatchedQueueInstances 13 | -------------------------------------------------------------------------------- /scalacture-scalaz/src/main/scala/scalacture/scalaz/immutable/queue/HoodMelvilleQueue.scala: -------------------------------------------------------------------------------- 1 | package scalacture.scalaz.immutable.queue 2 | 3 | import scala.collection.generic.{CanBuildFrom, SeqFactory} 4 | import scalacture.immutable.queue.HoodMelvilleQueue 5 | 6 | trait HoodMelvilleQueueInstances extends QueueSubInstances { 7 | override type XQueue[A] = HoodMelvilleQueue[A] 8 | override protected[this] def factory: SeqFactory[XQueue] = HoodMelvilleQueue 9 | override implicit def canBuildFrom[A]: CanBuildFrom[XQueue[_], A, XQueue[A]] = HoodMelvilleQueue.canBuildFrom 10 | } 11 | 12 | object hoodMelvilleQueue extends HoodMelvilleQueueInstances 13 | -------------------------------------------------------------------------------- /scalacture-scalaz/src/main/scala/scalacture/scalaz/immutable/queue/Queue.scala: -------------------------------------------------------------------------------- 1 | package scalacture.scalaz.immutable.queue 2 | 3 | import scala.annotation.tailrec 4 | import scala.collection.generic.{CanBuildFrom, GenericTraversableTemplate, SeqFactory} 5 | import scala.language.higherKinds 6 | import scalacture.immutable.queue.{Queue, QueueLike} 7 | import scalaz._ 8 | 9 | trait QueueSub { 10 | type XQueue[A] <: Queue[A] with QueueLike[A, XQueue[A]] with GenericTraversableTemplate[A, XQueue] 11 | implicit def canBuildFrom[A]: CanBuildFrom[XQueue[_], A, XQueue[A]] 12 | protected[this] def factory: SeqFactory[XQueue] 13 | } 14 | 15 | trait QueueSubInstances0 extends QueueSub { 16 | implicit def queueEqual[A: Equal]: Equal[XQueue[A]] = new Equal[XQueue[A]] { 17 | override def equalIsNatural: Boolean = Equal[A].equalIsNatural 18 | override def equal(a1: XQueue[A], a2: XQueue[A]): Boolean = a1.corresponds(a2)(Equal[A].equal) 19 | } 20 | } 21 | 22 | trait QueueSubInstances extends QueueSubInstances0 { 23 | implicit val queueInstance = { 24 | new Traverse[XQueue] 25 | with MonadPlus[XQueue] 26 | with Zip[XQueue] 27 | with Unzip[XQueue] 28 | with Align[XQueue] 29 | with IsEmpty[XQueue] { 30 | 31 | override def traverseImpl[G[_], A, B](fa: XQueue[A])(f: A => G[B])(implicit F: Applicative[G]): G[XQueue[B]] = { 32 | fa.foldLeft(F.point(empty[B])) { (fbs, a) => 33 | F.apply2(fbs, f(a))(_ :+ _) 34 | } 35 | } 36 | 37 | override def zip[A, B](a: => XQueue[A], b: => XQueue[B]): XQueue[(A, B)] = a match { 38 | case x if x.isEmpty => empty[(A, B)] 39 | case x => x.zip(b) 40 | } 41 | 42 | override def unzip[A, B](a: XQueue[(A, B)]): (XQueue[A], XQueue[B]) = a.unzip 43 | 44 | override def alignWith[A, B, C](f: A \&/ B => C): (XQueue[A], XQueue[B]) => XQueue[C] = { 45 | (as, bs) => 46 | val sizeA = as.size 47 | val sizeB = bs.size 48 | (as, bs).zipped.map((a, b) => f(\&/.Both(a, b))) ++ { 49 | if (sizeA > sizeB) as.drop(sizeB).map(a => f(\&/.This(a))) 50 | else bs.drop(sizeA).map(b => f(\&/.That(b))) 51 | } 52 | } 53 | 54 | override def isEmpty[A](fa: XQueue[A]): Boolean = fa.isEmpty 55 | 56 | override def empty[A]: XQueue[A] = factory.empty[A] 57 | 58 | override def bind[A, B](fa: XQueue[A])(f: (A) => XQueue[B]): XQueue[B] = fa.flatMap(f) 59 | 60 | override def point[A](a: => A): XQueue[A] = factory(a) 61 | 62 | override def plus[A](a: XQueue[A], b: => XQueue[A]): XQueue[A] = a ++ b 63 | } 64 | } 65 | 66 | implicit def queueMonoid[A]: Monoid[XQueue[A]] = new Monoid[XQueue[A]] { 67 | override def zero: XQueue[A] = factory.empty[A] 68 | override def append(f1: XQueue[A], f2: => XQueue[A]): XQueue[A] = f1 ++ f2 69 | } 70 | 71 | implicit def queueShow[A: Show]: Show[XQueue[A]] = new Show[XQueue[A]] { 72 | override def show(f: XQueue[A]): Cord = { 73 | Cord("[", Cord.mkCord(",", f.map(Show[A].show): _*), "]") 74 | } 75 | } 76 | 77 | implicit def queueOrder[A: Order]: Order[XQueue[A]] = new Order[XQueue[A]] { 78 | import Ordering._ 79 | @tailrec 80 | override def order(x: XQueue[A], y: XQueue[A]): Ordering = { 81 | (x.dequeueOption, y.dequeueOption) match { 82 | case (None, None) => EQ 83 | case (None, Some(_)) => LT 84 | case (Some(_), None) => GT 85 | case (Some((a, as)), Some((b, bs))) => Order[A].order(a, b) match { 86 | case EQ => order(as, bs) 87 | case o => o 88 | } 89 | } 90 | } 91 | } 92 | } 93 | 94 | trait QueueInstances extends QueueSubInstances { 95 | override type XQueue[A] = Queue[A] 96 | override protected[this] def factory: SeqFactory[XQueue] = Queue 97 | override implicit def canBuildFrom[A]: CanBuildFrom[XQueue[_], A, XQueue[A]] = Queue.canBuildFrom 98 | } 99 | 100 | object queue extends QueueInstances 101 | -------------------------------------------------------------------------------- /scalacture-scalaz/src/test/scala/scalacture/scalaz/immutable/queue/BatchedQueueSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.scalaz.immutable.queue 2 | 3 | import scalacture.immutable.queue.BatchedQueue 4 | import scalacture.scalaz.immutable.queue.batchedQueue._ 5 | import scalaprops._ 6 | import scalaprops.ScalapropsScalaz._ 7 | import scalaz.std.anyVal._ 8 | 9 | object BatchedQueueSpec extends Scalaprops { 10 | implicit def gen[A: Gen]: Gen[BatchedQueue[A]] = Gen.list[A].map(BatchedQueue(_: _*)) 11 | implicit val cogen: Cogen[BatchedQueue[Int]] = Cogen[List[Int]].contramap(_.toList) 12 | implicit val fgen: Gen[BatchedQueue[Int] => Int] = Gen.f1[BatchedQueue[Int], Int] 13 | 14 | val queueLaws = Properties.list( 15 | scalazlaws.equal.all[BatchedQueue[Int]], 16 | scalazlaws.monoid.all[BatchedQueue[Int]], 17 | scalazlaws.order.all[BatchedQueue[Int]], 18 | scalazlaws.traverse.all[BatchedQueue], 19 | scalazlaws.monadPlus.all[BatchedQueue], 20 | scalazlaws.zip.all[BatchedQueue], 21 | scalazlaws.align.all[BatchedQueue], 22 | scalazlaws.isEmpty.all[BatchedQueue] 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /scalacture-scalaz/src/test/scala/scalacture/scalaz/immutable/queue/HoodMelvilleQueueSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.scalaz.immutable.queue 2 | 3 | import scalacture.immutable.queue.HoodMelvilleQueue 4 | import scalacture.scalaz.immutable.queue.hoodMelvilleQueue._ 5 | import scalaprops._ 6 | import scalaprops.ScalapropsScalaz._ 7 | import scalaz.std.anyVal._ 8 | 9 | object HoodMelvilleQueueSpec extends Scalaprops { 10 | implicit def gen[A: Gen]: Gen[HoodMelvilleQueue[A]] = Gen.list[A].map(HoodMelvilleQueue(_: _*)) 11 | implicit val cogen: Cogen[HoodMelvilleQueue[Int]] = Cogen[List[Int]].contramap(_.toList) 12 | implicit val fgen: Gen[HoodMelvilleQueue[Int] => Int] = Gen.f1[HoodMelvilleQueue[Int], Int] 13 | 14 | val queueLaws = Properties.list( 15 | scalazlaws.equal.all[HoodMelvilleQueue[Int]], 16 | scalazlaws.monoid.all[HoodMelvilleQueue[Int]], 17 | scalazlaws.order.all[HoodMelvilleQueue[Int]], 18 | scalazlaws.traverse.all[HoodMelvilleQueue], 19 | scalazlaws.monadPlus.all[HoodMelvilleQueue], 20 | scalazlaws.zip.all[HoodMelvilleQueue], 21 | scalazlaws.align.all[HoodMelvilleQueue], 22 | scalazlaws.isEmpty.all[HoodMelvilleQueue] 23 | ) 24 | } 25 | -------------------------------------------------------------------------------- /scalacture-scalaz/src/test/scala/scalacture/scalaz/immutable/queue/QueueSpec.scala: -------------------------------------------------------------------------------- 1 | package scalacture.scalaz.immutable.queue 2 | 3 | import scalacture.immutable.queue.Queue 4 | import scalacture.scalaz.immutable.queue.queue._ 5 | import scalaprops._ 6 | import scalaprops.ScalapropsScalaz._ 7 | import scalaz.std.anyVal._ 8 | 9 | object QueueSpec extends Scalaprops { 10 | implicit def gen[A: Gen]: Gen[Queue[A]] = Gen.list[A].map(Queue(_: _*)) 11 | implicit val cogen: Cogen[Queue[Int]] = Cogen[List[Int]].contramap(_.toList) 12 | implicit val fgen: Gen[Queue[Int] => Int] = Gen.f1[Queue[Int], Int] 13 | 14 | val queueLaws = Properties.list( 15 | scalazlaws.equal.all[Queue[Int]], 16 | scalazlaws.monoid.all[Queue[Int]], 17 | scalazlaws.order.all[Queue[Int]], 18 | scalazlaws.traverse.all[Queue], 19 | scalazlaws.monadPlus.all[Queue], 20 | scalazlaws.zip.all[Queue], 21 | scalazlaws.align.all[Queue], 22 | scalazlaws.isEmpty.all[Queue] 23 | ) 24 | } 25 | --------------------------------------------------------------------------------