diff --git a/collections/src/main/scala/strawman/collection/immutable/WrappedString.scala b/collections/src/main/scala/strawman/collection/immutable/WrappedString.scala new file mode 100644 index 0000000000..0dccf07bad --- /dev/null +++ b/collections/src/main/scala/strawman/collection/immutable/WrappedString.scala @@ -0,0 +1,63 @@ +package strawman.collection +package immutable + +import scala.{Char, Int} +import scala.Predef.String +import mutable.{Builder, StringBuilder} + +/** + * This class serves as a wrapper augmenting `String`s with all the operations + * found in indexed sequences. + * + * The difference between this class and `StringOps` is that calling transformer + * methods such as `filter` and `map` will yield an object of type `WrappedString` + * rather than a `String`. + * + * @param self a string contained within this wrapped string + * + * @since 2.8 + * @define Coll `WrappedString` + * @define coll wrapped string + */ +final class WrappedString(val self: String) extends AbstractSeq[Char] with IndexedSeq[Char] { + + def apply(i: Int): Char = self.charAt(i) + + protected[this] def fromSpecificIterable(coll: strawman.collection.Iterable[Char]): IndexedSeq[Char] = + WrappedString.fromSpecific(coll) + protected[this] def newSpecificBuilder(): Builder[Char, IndexedSeq[Char]] = WrappedString.newBuilder() + def iterableFactory: SeqFactory[IndexedSeq] = ImmutableArray + + override def slice(from: Int, until: Int): WrappedString = { + val start = if (from < 0) 0 else from + if (until <= start || start >= self.length) + return new WrappedString("") + + val end = if (until > length) length else until + new WrappedString(self.substring(start, end)) + } + override def length = self.length + override def toString = self + override def view: StringView = new StringView(self) +} + +/** A companion object for wrapped strings. + * + * @since 2.8 + */ +object WrappedString extends SpecificIterableFactory[Char, WrappedString] { + def fromSpecific(it: IterableOnce[Char]): WrappedString = { + val b = newBuilder() + it match { + case it: Iterable[_] => + val s = it.knownSize + if(s >= 0) b.sizeHint(s) + case _ => + } + b ++= it + b.result() + } + val empty: WrappedString = new WrappedString("") + def newBuilder(): Builder[Char, WrappedString] = + new StringBuilder().mapResult(x => new WrappedString(x)) +} diff --git a/collections/src/main/scala/strawman/collection/package.scala b/collections/src/main/scala/strawman/collection/package.scala index d88de45ecf..8a70e0458a 100644 --- a/collections/src/main/scala/strawman/collection/package.scala +++ b/collections/src/main/scala/strawman/collection/package.scala @@ -136,6 +136,6 @@ class LowPriority { /** Convert array to WrappedArray. Lower priority than ArrayOps */ implicit def arrayToWrappedArray[T](xs: Array[T]): mutable.IndexedSeq[T] = mutable.WrappedArray.make[T](xs) - /** Convert string to iterable via view. Lower priority than StringOps */ - implicit def stringToView(s: String): immutable.StringView = new immutable.StringView(s) + /** Convert String to Seq. Lower priority than StringOps */ + implicit def stringToSeq(s: String): immutable.WrappedString = new immutable.WrappedString(s) }