├── .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 | [](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 | * worst-case |
17 | * amortized |
18 | * under persistent usage |
19 | *
20 | *
21 | *
22 | * peek |
23 | * O(1) |
24 | * O(1) |
25 | * O(1) |
26 | *
27 | *
28 | *
29 | * enqueue |
30 | * O(1) |
31 | * O(1) |
32 | * O(1) |
33 | *
34 | *
35 | *
36 | * dequeue |
37 | * O(n) |
38 | * O(1) |
39 | * O(n) |
40 | *
41 | *
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 | * worst-case |
17 | * amortized |
18 | * under persistent usage |
19 | *
20 | *
21 | *
22 | * peek |
23 | * O(1) |
24 | * O(1) |
25 | * O(1) |
26 | *
27 | *
28 | *
29 | * enqueue |
30 | * O(1) |
31 | * O(1) |
32 | * O(1) |
33 | *
34 | *
35 | *
36 | * dequeue |
37 | * O(1) |
38 | * O(1) |
39 | * O(1) |
40 | *
41 | *
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 |
--------------------------------------------------------------------------------