notable performance tuning for Library.separated_chunks variants;
authorwenzelm
Tue, 02 Jul 2024 21:54:12 +0200
changeset 80478 902e6da44a68
parent 80477 d32748570069
child 80479 762fcf8f9ced
notable performance tuning for Library.separated_chunks variants; more direct NoSuchElementException;
src/Pure/library.scala
--- a/src/Pure/library.scala	Tue Jul 02 21:35:40 2024 +0200
+++ b/src/Pure/library.scala	Tue Jul 02 21:54:12 2024 +0200
@@ -79,30 +79,60 @@
 
   def separated_chunks(sep: Char => Boolean, source: CharSequence): Iterator[CharSequence] =
     new Iterator[CharSequence] {
-      private val end = source.length
-      private def next_chunk(i: Int): Option[(CharSequence, Int)] = {
-        if (i < end) {
-          var j = i
-          while ({
-            j += 1
-            j < end && !sep(source.charAt(j))
-          }) ()
-          Some((source.subSequence(i + 1, j), j))
+      private val length = source.length
+      private var start = -1
+      private var stop = -1
+
+      private def end(i: Int): Int = {
+        var j = i
+        while (j < length && !sep(source.charAt(j))) { j += 1 }
+        j
+      }
+
+      // init
+      if (!source.isEmpty) { start = 0; stop = end(0) }
+
+      def hasNext: Boolean = 0 <= start && stop <= length
+
+      def next(): CharSequence =
+        if (hasNext) {
+          val chunk = source.subSequence(start, stop)
+          if (stop < length) { start = stop + 1; stop = end(start) }
+          else { start = -1; stop = -1 }
+          chunk
         }
-        else None
-      }
-      private var state: Option[(CharSequence, Int)] = if (end == 0) None else next_chunk(-1)
+        else throw new NoSuchElementException
+    }
+
+  def separated_chunks(sep: Char, source: String): Iterator[String] =
+    new Iterator[String] {
+      private var start = -1
+      private var stop = -1
+
+      private def end(i: Int): Int =
+        source.indexOf(sep, start) match {
+          case -1 => source.length
+          case j => j
+        }
 
-      def hasNext: Boolean = state.isDefined
-      def next(): CharSequence =
-        state match {
-          case Some((s, i)) => state = next_chunk(i); s
-          case None => Iterator.empty.next()
+      // init
+      if (source.nonEmpty) { start = 0; stop = end(0) }
+
+      def hasNext: Boolean =
+        0 <= start && start <= stop && stop <= source.length
+
+      def next(): String =
+        if (hasNext) {
+          val chunk = source.substring(start, stop)
+          if (stop < source.length) { start = stop + 1; stop = end(start) }
+          else { start = -1; stop = -1 }
+          chunk
         }
+        else throw new NoSuchElementException
     }
 
   def space_explode(sep: Char, str: String): List[String] =
-    separated_chunks(_ == sep, str).map(_.toString).toList
+    separated_chunks(sep, str).toList
 
 
   /* lines */