Advertisement
Guest User

text

a guest
May 15th, 2019
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 7.05 KB | None | 0 0
  1.  
  2.  
  3. // Text.scala
  4. // Copyright (c) 2015 J. M. Spivey
  5.  
  6. /** A sequence of characters that allows (efficient) insertion and deletion
  7.  * in the middle. */
  8. class Text(init: Int) extends CharSequence {
  9.     /* A Text object represents the sequence of characters
  10.      * buffer[0..gap) ++ buffer[max-len+gap..max) */
  11.    
  12.     /** The gap buffer */
  13.     private var buffer = new Array[Char](init)
  14.    
  15.     /** Length of the represented text */
  16.     private var len = 0
  17.  
  18.     /** Position of the gap */
  19.     private var gap = 0
  20.  
  21.     /** Size of the buffer, defined for convenience */
  22.     private def max = buffer.length
  23.    
  24.     /** Construct a Text with a default initial capacity */
  25.     def this() { this(1000) }
  26.    
  27.     /** Construct a Text containing a single character */
  28.     def this(ch: Char) { this(4); insert(0, ch) }
  29.  
  30.     /** Construct a Text containing a specified string */
  31.     def this(s: String) { this(Math.max(s.length, 4)); insert(0, s) }
  32.  
  33.     /** Return the length of the text */
  34.     def length = len
  35.  
  36.     /** Return the character at a specified position */
  37.     def charAt(pos: Int) = {
  38.         assert(0 <= pos && pos < len)
  39.  
  40.         if (pos < gap)
  41.             buffer(pos)
  42.         else
  43.             buffer(max-len+pos)
  44.     }
  45.    
  46.     // Mutators: any changes or additions here require similar changes to
  47.     // the subclass PlaneText (the fragile base class problem).
  48.    
  49.     /** Make the text empty. */
  50.     def clear() {
  51.         gap = 0; len = 0
  52.     }
  53.  
  54.     /** Insert a single character. */
  55.     def insert(pos: Int, ch: Char) {
  56.         assert(0 <= pos && pos <= len)
  57.         makeRoom(1); moveGap(pos)
  58.         buffer(gap) = ch
  59.         gap += 1; len += 1
  60.     }
  61.    
  62.     /** Insert a string. */
  63.     def insert(pos: Int, s: String) {
  64.         assert(0 <= pos && pos <= len)
  65.         val n = s.length()
  66.         makeRoom(n); moveGap(pos)
  67.         s.getChars(0, n, buffer, pos)
  68.         gap += n; len += n
  69.     }
  70.    
  71.     /** Insert another text. */
  72.     def insert(pos: Int, t: Text) {
  73.         insertRange(pos, t, 0, t.length)
  74.     }
  75.    
  76.     /** Insert an immutable text */
  77.     def insert(pos: Int, t: Text.Immutable) {
  78.         t.getChars(this, pos)
  79.     }
  80.  
  81.     /** Insert range [start..start+nchars) from another text */
  82.     def insertRange(pos: Int, t: Text, start: Int, nchars: Int) {
  83.         assert(pos >= 0 && pos <= len && nchars >= 0 && t != this)
  84.        
  85.         makeRoom(nchars); moveGap(pos)
  86.         t.getChars(start, nchars, buffer, pos)
  87.         len += nchars; gap += nchars
  88.     }
  89.  
  90.     /** Insert the contents of a file. */
  91.     def insertFile(pos: Int, in: java.io.Reader) {
  92.         assert(0 <= pos && pos <= len)
  93.        
  94.         moveGap(pos)
  95.         while (true) {
  96.             makeRoom(4096)
  97.             val nread = in.read(buffer, gap, max-len)
  98.             if (nread < 0) return
  99.             gap += nread; len += nread
  100.         }
  101.     }
  102.  
  103.     /** Write the entire text on a file. */
  104.     def writeFile(out: java.io.Writer) {
  105.         if (gap > 0) out.write(buffer, 0, gap)
  106.         if (len > gap) out.write(buffer, max-len+gap, len-gap)
  107.     }
  108.  
  109.     /** Delete a single character. */
  110.     def deleteChar(pos: Int) {
  111.         assert(0 <= pos && pos < len)
  112.         moveGap(pos); len -= 1
  113.     }
  114.    
  115.     /** Delete the last character. */
  116.     def deleteLast() { deleteChar(len-1) }
  117.        
  118.     /** Delete a range of characters. */
  119.     def deleteRange(start: Int, nchars: Int) {
  120.         assert(start >= 0 && nchars >= 0 && start+nchars <= len)
  121.         moveGap(start); len -= nchars
  122.     }
  123.  
  124.     /** Copy range [start..start+nchars) into a char array arr[pos..) */
  125.     def getChars(start: Int, nchars: Int, arr: Array[Char], pos: Int) {
  126.         /* This is used for display update, so for speed we avoid
  127.            moving the gap. */
  128.  
  129.         assert(start >= 0 && nchars >= 0 && start+nchars <= len)
  130.  
  131.         if (start+nchars <= gap)
  132.             // Entirely in the low part
  133.             Array.copy(buffer, start, arr, pos, nchars)
  134.         else if (start >= gap)
  135.             // Entirely in the high part
  136.             Array.copy(buffer, max-len+start, arr, pos, nchars)
  137.         else {
  138.             val k = gap-start
  139.             Array.copy(buffer, start, arr, pos, k)
  140.             Array.copy(buffer, max-len+gap, arr, pos+k, nchars-k)
  141.         }
  142.     }
  143.  
  144.     /** Fetch the range [start..start+nchars) as an immutable text */
  145.     def getRange(start: Int, nchars: Int) =
  146.         new Text.Immutable(getString(start, nchars))
  147.    
  148.     /** Fetch a range into another text */
  149.     def getRange(start: Int, nchars: Int, buf: Text) {
  150.         buf.clear()
  151.         buf.insertRange(0, this, start, nchars)
  152.     }
  153.  
  154.     private def getString(start: Int, nchars: Int) = {
  155.         assert(start >= 0 && nchars >= 0 && start + nchars <= len)
  156.         if (gap < start+nchars) moveGap(start+nchars)
  157.         new String(buffer, start, nchars)
  158.     }
  159.    
  160.     /** Return the contents of the text as a String.  Be careful when using
  161.      * this for debugging: it has the (benign) side-effect of moving the gap
  162.      * to the end. */
  163.     override def toString() = getString(0, len)
  164.    
  165.     /** Select a range [start..end).  Required for CharSequence but unused. */
  166.     def subSequence(start: Int, end: Int): CharSequence = {
  167.         if (start < 0 || end < start || len < end)
  168.             throw new IndexOutOfBoundsException()
  169.         getString(start, end-start)
  170.     }
  171.    
  172.     /** Establish gap = pos by moving characters around */
  173.     private def moveGap(pos: Int) {
  174.         assert(0 <= pos && pos <= len)
  175.  
  176.         if (gap < pos)
  177.             // buffer[gap..pos) := buffer[max+gap-len..max+pos-len)
  178.             Array.copy(buffer, max-len+gap, buffer, gap, pos-gap)
  179.         else if (gap > pos)
  180.             // buffer[max+pos-len..max+gap-len) := buffer[pos..gap)
  181.             Array.copy(buffer, pos, buffer, max-len+pos, gap-pos)
  182.  
  183.         gap = pos
  184.     }
  185.    
  186.     /** Ensure that there is space for n more characters. */
  187.     private def makeRoom(n: Int) {
  188.         assert(n >= 0)
  189.        
  190.         if (max-len >= n) return
  191.  
  192.         val newmax = Math.max(2*max, len+n)
  193.         val newbuf = new Array[Char](newmax)
  194.         if (gap > 0)
  195.             Array.copy(buffer, 0, newbuf, 0, gap)
  196.         if (gap < len)
  197.             Array.copy(buffer, max-len+gap,
  198.                        newbuf, newmax-len+gap, len-gap)
  199.         buffer = newbuf
  200.     }
  201. }
  202.  
  203. object Text {
  204.     class Immutable private[Text] (private val contents: String)
  205.             extends CharSequence {
  206.         // The implementation here is trivial: just a Java string.
  207.        
  208.         def charAt(index: Int) = contents.charAt(index)
  209.  
  210.         def length = contents.length
  211.  
  212.         def getChars(text: Text, pos: Int) { text.insert(pos, contents) }
  213.  
  214.         def subSequence(start: Int, end: Int) =
  215.             contents.subSequence(start, end)
  216.  
  217.         override def equals(that: Any) = {
  218.             that match {
  219.                 case other: Immutable => contents.equals(other.contents)
  220.                 case _ => false
  221.             }
  222.         }
  223.  
  224.         override def hashCode = contents.hashCode
  225.     }
  226. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement