@@ -23,22 +23,54 @@ import cats.{Always, Eq, Eval, Foldable, Later, Now, Reducible, SemigroupK, Show
2323
2424import scala .collection .immutable ._
2525
26- final class NonEmptySet [A ] private (val set : SortedSet [A ]) {
26+ trait Newtype { self =>
27+ private [data] type Base
28+ private [data] trait Tag extends Any
29+ private [cats] type Type [A ] <: Base with Tag
30+ }
31+
32+ private [data] object NonEmptySetImpl extends NonEmptySetInstances with Newtype {
33+
34+ private [cats] def create [A ](s : SortedSet [A ]): Type [A ] =
35+ s.asInstanceOf [Type [A ]]
36+
37+ private [cats] def unwrap [A ](s : Type [A ]): SortedSet [A ] =
38+ s.asInstanceOf [SortedSet [A ]]
39+
40+
41+ def fromSet [A : Order ](as : SortedSet [A ]): Option [NonEmptySet [A ]] =
42+ if (as.nonEmpty) Option (create(as)) else None
43+
44+ def fromSetUnsafe [A : Order ](set : SortedSet [A ]): NonEmptySet [A ] =
45+ if (set.nonEmpty) create(set)
46+ else throw new IllegalArgumentException (" Cannot create NonEmptySet from empty set" )
47+
48+
49+ def of [A : Order ](a : A , as : A * ): NonEmptySet [A ] =
50+ create(SortedSet (a)(Order [A ].toOrdering) ++ SortedSet (as : _* )(Order [A ].toOrdering) + a)
51+ def apply [A : Order ](head : A , tail : SortedSet [A ]): NonEmptySet [A ] = create(SortedSet (head)(Order [A ].toOrdering) ++ tail)
52+ def one [A : Order ](a : A ): NonEmptySet [A ] = create(SortedSet (a)(Order [A ].toOrdering))
53+
54+ implicit def catsNonEmptySetOps [A ](value : NonEmptySet [A ]): NonEmptySetOps [A ] =
55+ new NonEmptySetOps (value)
56+ }
57+
58+
59+ private [data] sealed class NonEmptySetOps [A ](val value : NonEmptySetImpl .Type [A ]) {
60+
61+ private implicit val ordering : Ordering [A ] = toSortedSet.ordering
62+ private implicit val order : Order [A ] = Order .fromOrdering
63+
64+ /**
65+ * Converts this set to a `SortedSet`
66+ */
67+ def toSortedSet : SortedSet [A ] = NonEmptySetImpl .unwrap(value)
2768
28- private implicit def ordering : Ordering [A ] = set.ordering
29- private implicit def order : Order [A ] = Order .fromOrdering
3069
3170 /**
3271 * Adds an element to this set, returning a new `NonEmptySet`
33- * {{{
34- * scala> import cats.data.NonEmptySet
35- * scala> import cats.implicits._
36- * scala> val nes = NonEmptySet.of(1, 2, 4, 5)
37- * scala> nes + 3
38- * res0: cats.data.NonEmptySet[Int] = NonEmptyTreeSet(1, 2, 3, 4, 5)
39- * }}}
4072 */
41- def + (a : A ): NonEmptySet [A ] = new NonEmptySet (set + a)
73+ def add (a : A ): NonEmptySet [A ] = NonEmptySet .create(toSortedSet + a)
4274
4375 /**
4476 * Alias for [[union ]]
@@ -47,7 +79,7 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
4779 * scala> import cats.implicits._
4880 * scala> val nes = NonEmptySet.of(1, 2, 4, 5)
4981 * scala> nes ++ NonEmptySet.of(1, 2, 7)
50- * res0: cats.data.NonEmptySet[Int] = NonEmptyTreeSet (1, 2, 4, 5, 7)
82+ * res0: cats.data.NonEmptySet[Int] = TreeSet (1, 2, 4, 5, 7)
5183 * }}}
5284 */
5385 def ++ (as : NonEmptySet [A ]): NonEmptySet [A ] = union(as)
@@ -59,7 +91,7 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
5991 * scala> import cats.implicits._
6092 * scala> val nes = NonEmptySet.of(1, 2, 4, 5)
6193 * scala> nes | NonEmptySet.of(1, 2, 7)
62- * res0: cats.data.NonEmptySet[Int] = NonEmptyTreeSet (1, 2, 4, 5, 7)
94+ * res0: cats.data.NonEmptySet[Int] = TreeSet (1, 2, 4, 5, 7)
6395 * }}}
6496 */
6597 def | (as : NonEmptySet [A ]): NonEmptySet [A ] = union(as)
@@ -104,13 +136,13 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
104136 /**
105137 * Removes a key from this set, returning a new `SortedSet`.
106138 */
107- def - (a : A ): SortedSet [A ] = set - a
139+ def - (a : A ): SortedSet [A ] = toSortedSet - a
108140
109141 /**
110142 * Applies f to all the elements
111143 */
112144 def map [B : Order ](f : A ⇒ B ): NonEmptySet [B ] =
113- new NonEmptySet (SortedSet (set .map(f).to: _* )(Order [B ].toOrdering))
145+ NonEmptySetImpl .create (SortedSet (toSortedSet .map(f).to: _* )(Order [B ].toOrdering))
114146
115147 /**
116148 * Converts this set to a `NonEmptyList`.
@@ -122,22 +154,22 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
122154 * res0: cats.data.NonEmptyList[Int] = NonEmptyList(1, 2, 3, 4, 5)
123155 * }}}
124156 */
125- def toNonEmptyList : NonEmptyList [A ] = NonEmptyList .fromListUnsafe(set .toList)
157+ def toNonEmptyList : NonEmptyList [A ] = NonEmptyList .fromListUnsafe(toSortedSet .toList)
126158
127159 /**
128160 * Returns the first element of this set.
129161 */
130- def head : A = set .head
162+ def head : A = toSortedSet .head
131163
132164 /**
133165 * Returns all but the first element of this set.
134166 */
135- def tail : SortedSet [A ] = set .tail
167+ def tail : SortedSet [A ] = toSortedSet .tail
136168
137169 /**
138170 * Returns the last element of this set.
139171 */
140- def last : A = set .last
172+ def last : A = toSortedSet .last
141173
142174 /**
143175 * Alias for [[contains ]]
@@ -156,55 +188,50 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
156188 /**
157189 * Tests if some element is contained in this set.
158190 */
159- def contains (a : A ): Boolean = set (a)
191+ def contains (a : A ): Boolean = toSortedSet (a)
160192
161193 /**
162194 * Computes the difference of this set and another set.
163195 */
164- def diff (as : NonEmptySet [A ]): SortedSet [A ] = set -- as.set
196+ def diff (as : NonEmptySet [A ]): SortedSet [A ] = toSortedSet -- as.toSortedSet
165197
166198 /**
167199 * Computes the union between this NES and another NES.
168200 */
169- def union (as : NonEmptySet [A ]): NonEmptySet [A ] = new NonEmptySet (set ++ as.set )
201+ def union (as : NonEmptySet [A ]): NonEmptySet [A ] = NonEmptySetImpl .create(toSortedSet ++ as.toSortedSet )
170202
171203 /**
172204 * Computes the intersection between this set and another set.
173205 */
174- def intersect (as : NonEmptySet [A ]): SortedSet [A ] = set.filter(as.apply)
175-
176- /**
177- * Returns the number of elements in this set.
178- */
179- def size : Int = set.size
206+ def intersect (as : NonEmptySet [A ]): SortedSet [A ] = toSortedSet.filter(as.apply)
180207
181208 /**
182209 * Tests whether a predicate holds for all elements of this set.
183210 */
184- def forall (p : A ⇒ Boolean ): Boolean = set .forall(p)
211+ def forall (p : A ⇒ Boolean ): Boolean = toSortedSet .forall(p)
185212
186213 /**
187214 * Tests whether a predicate holds for at least one element of this set.
188215 */
189- def exists (f : A ⇒ Boolean ): Boolean = set .exists(f)
216+ def exists (f : A ⇒ Boolean ): Boolean = toSortedSet .exists(f)
190217
191218 /**
192219 * Returns the first value that matches the given predicate.
193220 */
194- def find (f : A ⇒ Boolean ): Option [A ] = set .find(f)
221+ def find (f : A ⇒ Boolean ): Option [A ] = toSortedSet .find(f)
195222
196223 /**
197224 * Returns a new `SortedSet` containing all elements where the result of `pf` is defined.
198225 */
199226 def collect [B : Order ](pf : PartialFunction [A , B ]): SortedSet [B ] = {
200227 implicit val ordering = Order [B ].toOrdering
201- set .collect(pf)
228+ toSortedSet .collect(pf)
202229 }
203230
204231 /**
205232 * Filters all elements of this set that do not satisfy the given predicate.
206233 */
207- def filter (p : A ⇒ Boolean ): SortedSet [A ] = set .filter(p)
234+ def filter (p : A ⇒ Boolean ): SortedSet [A ] = toSortedSet .filter(p)
208235
209236 /**
210237 * Filters all elements of this set that satisfy the given predicate.
@@ -216,19 +243,19 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
216243 * Left-associative fold using f.
217244 */
218245 def foldLeft [B ](b : B )(f : (B , A ) => B ): B =
219- set .foldLeft(b)(f)
246+ toSortedSet .foldLeft(b)(f)
220247
221248 /**
222249 * Right-associative fold using f.
223250 */
224251 def foldRight [B ](lb : Eval [B ])(f : (A , Eval [B ]) => Eval [B ]): Eval [B ] =
225- Foldable [SortedSet ].foldRight(set , lb)(f)
252+ Foldable [SortedSet ].foldRight(toSortedSet , lb)(f)
226253
227254 /**
228255 * Left-associative reduce using f.
229256 */
230257 def reduceLeft (f : (A , A ) => A ): A =
231- set .reduceLeft(f)
258+ toSortedSet .reduceLeft(f)
232259
233260 /**
234261 * Apply `f` to the "initial element" of this set and lazily combine it
@@ -260,7 +287,7 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
260287 * Reduce using the Semigroup of A
261288 */
262289 def reduce [AA >: A ](implicit S : Semigroup [AA ]): AA =
263- S .combineAllOption(set ).get
290+ S .combineAllOption(toSortedSet ).get
264291
265292 /**
266293 * Map a function over all the elements of this set and concatenate the resulting sets into one.
@@ -269,20 +296,15 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
269296 * scala> import cats.implicits._
270297 * scala> val nes = NonEmptySet.of(1, 2, 3)
271298 * scala> nes.concatMap(n => NonEmptySet.of(n, n * 4, n * 5))
272- * res0: cats.data.NonEmptySet[Int] = NonEmptyTreeSet (1, 2, 3, 4, 5, 8, 10, 12, 15)
299+ * res0: cats.data.NonEmptySet[Int] = TreeSet (1, 2, 3, 4, 5, 8, 10, 12, 15)
273300 * }}}
274301 */
275302 def concatMap [B : Order ](f : A => NonEmptySet [B ]): NonEmptySet [B ] = {
276303 implicit val ordering = Order [B ].toOrdering
277- new NonEmptySet (set .flatMap(f andThen (_.set )))
304+ NonEmptySetImpl .create(toSortedSet .flatMap(f andThen (_.toSortedSet )))
278305 }
279306
280307
281- /**
282- * Converts this set to a `SortedSet`
283- */
284- def toSortedSet : SortedSet [A ] = set
285-
286308 /**
287309 * Typesafe stringification method.
288310 *
@@ -291,7 +313,7 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
291313 * universal .toString method.
292314 */
293315 def show (implicit A : Show [A ]): String =
294- s " NonEmpty ${Show [SortedSet [A ]].show(set )}"
316+ s " NonEmpty ${Show [SortedSet [A ]].show(toSortedSet )}"
295317
296318 /**
297319 * Typesafe equality operator.
@@ -302,14 +324,12 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
302324 * universal equality provided by .equals.
303325 */
304326 def === (that : NonEmptySet [A ]): Boolean =
305- Eq [SortedSet [A ]].eqv(set , that.toSortedSet)
327+ Eq [SortedSet [A ]].eqv(toSortedSet , that.toSortedSet)
306328
307329 /**
308- * Alias for [[ size ]]
330+ * Returns the number of elements in this set.
309331 */
310- def length : Int = size
311-
312- override def toString : String = s " NonEmpty ${set.toString}"
332+ def length : Int = toSortedSet.size
313333
314334 /**
315335 * Zips this `NonEmptySet` with another `NonEmptySet` and applies a function for each pair of elements.
@@ -320,17 +340,17 @@ final class NonEmptySet[A] private (val set: SortedSet[A]) {
320340 * scala> val as = NonEmptySet.of(1, 2, 3)
321341 * scala> val bs = NonEmptySet.of("A", "B", "C")
322342 * scala> as.zipWith(bs)(_ + _)
323- * res0: cats.data.NonEmptySet[String] = NonEmptyTreeSet (1A, 2B, 3C)
343+ * res0: cats.data.NonEmptySet[String] = TreeSet (1A, 2B, 3C)
324344 * }}}
325345 */
326346 def zipWith [B , C : Order ](b : NonEmptySet [B ])(f : (A , B ) => C ): NonEmptySet [C ] =
327- new NonEmptySet (SortedSet ((set , b.toSortedSet).zipped.map(f).to: _* )(Order [C ].toOrdering))
347+ NonEmptySetImpl .create (SortedSet ((toSortedSet , b.toSortedSet).zipped.map(f).to: _* )(Order [C ].toOrdering))
328348
329349 /**
330350 * Zips this `NonEmptySet` with its index.
331351 */
332352 def zipWithIndex : NonEmptySet [(A , Int )] =
333- new NonEmptySet (set .zipWithIndex)
353+ NonEmptySetImpl .create(toSortedSet .zipWithIndex)
334354}
335355
336356private [data] sealed abstract class NonEmptySetInstances {
@@ -393,17 +413,3 @@ private[data] sealed abstract class NonEmptySetInstances {
393413 }
394414}
395415
396- object NonEmptySet extends NonEmptySetInstances {
397- def fromSet [A : Order ](as : SortedSet [A ]): Option [NonEmptySet [A ]] =
398- if (as.nonEmpty) Option (new NonEmptySet (as)) else None
399-
400- def fromSetUnsafe [A : Order ](set : SortedSet [A ]): NonEmptySet [A ] =
401- if (set.nonEmpty) new NonEmptySet (set)
402- else throw new IllegalArgumentException (" Cannot create NonEmptySet from empty set" )
403-
404-
405- def of [A : Order ](a : A , as : A * ): NonEmptySet [A ] =
406- new NonEmptySet (SortedSet (a)(Order [A ].toOrdering) ++ SortedSet (as : _* )(Order [A ].toOrdering) + a)
407- def apply [A : Order ](head : A , tail : SortedSet [A ]): NonEmptySet [A ] = new NonEmptySet (SortedSet (head)(Order [A ].toOrdering) ++ tail)
408- def one [A : Order ](a : A ): NonEmptySet [A ] = new NonEmptySet (SortedSet (a)(Order [A ].toOrdering))
409- }
0 commit comments