summary refs log tree commit diff stats
path: root/compiler/ropes.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ropes.nim')
-rw-r--r--compiler/ropes.nim230
1 files changed, 25 insertions, 205 deletions
diff --git a/compiler/ropes.nim b/compiler/ropes.nim
index 1e7957337..e0d5aa0d3 100644
--- a/compiler/ropes.nim
+++ b/compiler/ropes.nim
@@ -7,213 +7,55 @@
 #    distribution, for details about the copyright.
 #
 
-# Ropes for the C code generator
-#
-#  Ropes are a data structure that represents a very long string
-#  efficiently; especially concatenation is done in O(1) instead of O(N).
-#  Ropes make use a lazy evaluation: They are essentially concatenation
-#  trees that are only flattened when converting to a native Nim
-#  string or when written to disk. The empty string is represented by a
-#  nil pointer.
-#  A little picture makes everything clear:
-#
-#  "this string" & " is internally " & "represented as"
-#
-#             con  -- inner nodes do not contain raw data
-#            /   \
-#           /     \
-#          /       \
-#        con       "represented as"
-#       /   \
-#      /     \
-#     /       \
-#    /         \
-#   /           \
-#"this string"  " is internally "
-#
-#  Note that this is the same as:
-#  "this string" & (" is internally " & "represented as")
-#
-#             con
-#            /   \
-#           /     \
-#          /       \
-# "this string"    con
-#                 /   \
-#                /     \
-#               /       \
-#              /         \
-#             /           \
-#" is internally "        "represented as"
-#
-#  The 'con' operator is associative! This does not matter however for
-#  the algorithms we use for ropes.
-#
-#  Note that the left and right pointers are not needed for leaves.
-#  Leaves have relatively high memory overhead (~30 bytes on a 32
-#  bit machines) and we produce many of them. This is why we cache and
-#  share leaves across different rope trees.
-#  To cache them they are inserted in a `cache` array.
-
-import
-  hashes
+# Ropes for the C code generator. Ropes are mapped to `string` directly nowadays.
 
 from pathutils import AbsoluteFile
 
+when defined(nimPreviewSlimSystem):
+  import std/[assertions, syncio, formatfloat]
+
 type
   FormatStr* = string  # later we may change it to CString for better
                        # performance of the code generator (assignments
                        # copy the format strings
                        # though it is not necessary)
-  Rope* = ref RopeObj
-  RopeObj*{.acyclic.} = object of RootObj # the empty rope is represented
-                                          # by nil to safe space
-    left, right: Rope
-    L: int                    # <= 0 if a leaf
-    data*: string
+  Rope* = string
 
-proc len*(a: Rope): int =
-  ## the rope's length
-  if a == nil: result = 0
-  else: result = abs a.L
+proc newRopeAppender*(cap = 80): string {.inline.} =
+  result = newStringOfCap(cap)
 
-proc newRope(data: string = ""): Rope =
-  new(result)
-  result.L = -data.len
-  result.data = data
+proc freeze*(r: Rope) {.inline.} = discard
 
-when not compileOption("threads"):
-  var
-    cache: array[0..2048*2 - 1, Rope]
-
-  proc resetRopeCache* =
-    for i in low(cache)..high(cache):
-      cache[i] = nil
-
-proc ropeInvariant(r: Rope): bool =
-  if r == nil:
-    result = true
-  else:
-    result = true #
-                  #    if r.data <> snil then
-                  #      result := true
-                  #    else begin
-                  #      result := (r.left <> nil) and (r.right <> nil);
-                  #      if result then result := ropeInvariant(r.left);
-                  #      if result then result := ropeInvariant(r.right);
-                  #    end
-
-var gCacheTries* = 0
-var gCacheMisses* = 0
-var gCacheIntTries* = 0
+proc resetRopeCache* = discard
 
-proc insertInCache(s: string): Rope =
-  when declared(cache):
-    inc gCacheTries
-    var h = hash(s) and high(cache)
-    result = cache[h]
-    if isNil(result) or result.data != s:
-      inc gCacheMisses
-      result = newRope(s)
-      cache[h] = result
-  else:
-    result = newRope(s)
-
-proc rope*(s: string): Rope =
-  ## Converts a string to a rope.
-  if s.len == 0:
-    result = nil
-  else:
-    result = insertInCache(s)
-  assert(ropeInvariant(result))
+template rope*(s: string): string = s
 
 proc rope*(i: BiggestInt): Rope =
   ## Converts an int to a rope.
-  inc gCacheIntTries
   result = rope($i)
 
 proc rope*(f: BiggestFloat): Rope =
   ## Converts a float to a rope.
   result = rope($f)
 
-proc `&`*(a, b: Rope): Rope =
-  if a == nil:
-    result = b
-  elif b == nil:
-    result = a
-  else:
-    result = newRope()
-    result.L = abs(a.L) + abs(b.L)
-    result.left = a
-    result.right = b
-
-proc `&`*(a: Rope, b: string): Rope =
-  ## the concatenation operator for ropes.
-  result = a & rope(b)
-
-proc `&`*(a: string, b: Rope): Rope =
-  ## the concatenation operator for ropes.
-  result = rope(a) & b
-
-proc `&`*(a: openArray[Rope]): Rope =
-  ## the concatenation operator for an openarray of ropes.
-  for i in 0..high(a): result = result & a[i]
-
-proc add*(a: var Rope, b: Rope) =
-  ## adds `b` to the rope `a`.
-  a = a & b
-
-proc add*(a: var Rope, b: string) =
-  ## adds `b` to the rope `a`.
-  a = a & b
-
-iterator leaves*(r: Rope): string =
-  ## iterates over any leaf string in the rope `r`.
-  if r != nil:
-    var stack = @[r]
-    while stack.len > 0:
-      var it = stack.pop
-      while it.left != nil:
-        assert it.right != nil
-        stack.add(it.right)
-        it = it.left
-        assert(it != nil)
-      yield it.data
-
-iterator items*(r: Rope): char =
-  ## iterates over any character in the rope `r`.
-  for s in leaves(r):
-    for c in items(s): yield c
-
 proc writeRope*(f: File, r: Rope) =
   ## writes a rope to a file.
-  for s in leaves(r): write(f, s)
+  write(f, r)
 
 proc writeRope*(head: Rope, filename: AbsoluteFile): bool =
-  var f: File
+  var f: File = default(File)
   if open(f, filename.string, fmWrite):
-    if head != nil: writeRope(f, head)
+    writeRope(f, head)
     close(f)
     result = true
   else:
     result = false
 
-proc `$`*(r: Rope): string =
-  ## converts a rope back to a string.
-  result = newString(r.len)
-  setLen(result, 0)
-  for s in leaves(r): result.add(s)
-
-proc ropeConcat*(a: varargs[Rope]): Rope =
-  # not overloaded version of concat to speed-up `rfmt` a little bit
-  for i in 0..high(a): result = result & a[i]
-
-proc prepend*(a: var Rope, b: Rope) = a = b & a
 proc prepend*(a: var Rope, b: string) = a = b & a
 
 proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
   var i = 0
-  result = nil
+  result = newRopeAppender()
   var num = 0
   while i < frmt.len:
     if frmt[i] == '$':
@@ -234,7 +76,7 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
           if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
         num = j
         if j > high(args) + 1:
-          doAssert false, "invalid format string: " & frmt
+          raiseAssert "invalid format string: " & frmt
         else:
           result.add(args[j-1])
       of '{':
@@ -246,10 +88,10 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
         num = j
         if frmt[i] == '}': inc(i)
         else:
-          doAssert false, "invalid format string: " & frmt
+          raiseAssert "invalid format string: " & frmt
 
         if j > high(args) + 1:
-          doAssert false, "invalid format string: " & frmt
+          raiseAssert "invalid format string: " & frmt
         else:
           result.add(args[j-1])
       of 'n':
@@ -259,14 +101,10 @@ proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
         result.add("\n")
         inc(i)
       else:
-        doAssert false, "invalid format string: " & frmt
-    var start = i
-    while i < frmt.len:
-      if frmt[i] != '$': inc(i)
-      else: break
-    if i - 1 >= start:
-      result.add(substr(frmt, start, i - 1))
-  assert(ropeInvariant(result))
+        raiseAssert "invalid format string: " & frmt
+    else:
+      result.add(frmt[i])
+      inc(i)
 
 proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
   runtimeFormat(frmt, args)
@@ -275,30 +113,19 @@ template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
   ## shortcut for ``add(c, frmt % args)``.
   c.add(frmt % args)
 
-when true:
-  template `~`*(r: string): Rope = r % []
-else:
-  {.push stack_trace: off, line_trace: off.}
-  proc `~`*(r: static[string]): Rope =
-    # this is the new optimized "to rope" operator
-    # the mnemonic is that `~` looks a bit like a rope :)
-    var r {.global.} = r % []
-    return r
-  {.pop.}
-
 const
   bufSize = 1024              # 1 KB is reasonable
 
-proc equalsFile*(r: Rope, f: File): bool =
+proc equalsFile*(s: Rope, f: File): bool =
   ## returns true if the contents of the file `f` equal `r`.
   var
-    buf: array[bufSize, char]
+    buf: array[bufSize, char] = default(array[bufSize, char])
     bpos = buf.len
     blen = buf.len
     btotal = 0
     rtotal = 0
 
-  for s in leaves(r):
+  when true:
     var spos = 0
     rtotal += s.len
     while spos < s.len:
@@ -324,15 +151,8 @@ proc equalsFile*(r: Rope, f: File): bool =
 proc equalsFile*(r: Rope, filename: AbsoluteFile): bool =
   ## returns true if the contents of the file `f` equal `r`. If `f` does not
   ## exist, false is returned.
-  var f: File
+  var f: File = default(File)
   result = open(f, filename.string)
   if result:
     result = equalsFile(r, f)
     close(f)
-
-proc writeRopeIfNotEqual*(r: Rope, filename: AbsoluteFile): bool =
-  # returns true if overwritten
-  if not equalsFile(r, filename):
-    result = writeRope(r, filename)
-  else:
-    result = false