ropes.nim 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #
  2. #
  3. # The Nim Compiler
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Ropes for the C code generator. Ropes are mapped to `string` directly nowadays.
  10. import hashes
  11. from pathutils import AbsoluteFile
  12. when defined(nimPreviewSlimSystem):
  13. import std/[assertions, syncio, formatfloat]
  14. type
  15. FormatStr* = string # later we may change it to CString for better
  16. # performance of the code generator (assignments
  17. # copy the format strings
  18. # though it is not necessary)
  19. Rope* = string
  20. proc newRopeAppender*(): string {.inline.} =
  21. result = newString(0)
  22. proc freeze*(r: Rope) {.inline.} = discard
  23. proc resetRopeCache* = discard
  24. template rope*(s: string): string = s
  25. proc rope*(i: BiggestInt): Rope =
  26. ## Converts an int to a rope.
  27. result = rope($i)
  28. proc rope*(f: BiggestFloat): Rope =
  29. ## Converts a float to a rope.
  30. result = rope($f)
  31. proc writeRope*(f: File, r: Rope) =
  32. ## writes a rope to a file.
  33. write(f, r)
  34. proc writeRope*(head: Rope, filename: AbsoluteFile): bool =
  35. var f: File
  36. if open(f, filename.string, fmWrite):
  37. writeRope(f, head)
  38. close(f)
  39. result = true
  40. else:
  41. result = false
  42. proc prepend*(a: var Rope, b: string) = a = b & a
  43. proc runtimeFormat*(frmt: FormatStr, args: openArray[Rope]): Rope =
  44. var i = 0
  45. result = newRopeAppender()
  46. var num = 0
  47. while i < frmt.len:
  48. if frmt[i] == '$':
  49. inc(i) # skip '$'
  50. case frmt[i]
  51. of '$':
  52. result.add("$")
  53. inc(i)
  54. of '#':
  55. inc(i)
  56. result.add(args[num])
  57. inc(num)
  58. of '0'..'9':
  59. var j = 0
  60. while true:
  61. j = j * 10 + ord(frmt[i]) - ord('0')
  62. inc(i)
  63. if i >= frmt.len or frmt[i] notin {'0'..'9'}: break
  64. num = j
  65. if j > high(args) + 1:
  66. doAssert false, "invalid format string: " & frmt
  67. else:
  68. result.add(args[j-1])
  69. of '{':
  70. inc(i)
  71. var j = 0
  72. while frmt[i] in {'0'..'9'}:
  73. j = j * 10 + ord(frmt[i]) - ord('0')
  74. inc(i)
  75. num = j
  76. if frmt[i] == '}': inc(i)
  77. else:
  78. doAssert false, "invalid format string: " & frmt
  79. if j > high(args) + 1:
  80. doAssert false, "invalid format string: " & frmt
  81. else:
  82. result.add(args[j-1])
  83. of 'n':
  84. result.add("\n")
  85. inc(i)
  86. of 'N':
  87. result.add("\n")
  88. inc(i)
  89. else:
  90. doAssert false, "invalid format string: " & frmt
  91. var start = i
  92. while i < frmt.len:
  93. if frmt[i] != '$': inc(i)
  94. else: break
  95. if i - 1 >= start:
  96. result.add(substr(frmt, start, i - 1))
  97. proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
  98. runtimeFormat(frmt, args)
  99. template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
  100. ## shortcut for ``add(c, frmt % args)``.
  101. c.add(frmt % args)
  102. const
  103. bufSize = 1024 # 1 KB is reasonable
  104. proc equalsFile*(s: Rope, f: File): bool =
  105. ## returns true if the contents of the file `f` equal `r`.
  106. var
  107. buf: array[bufSize, char]
  108. bpos = buf.len
  109. blen = buf.len
  110. btotal = 0
  111. rtotal = 0
  112. when true:
  113. var spos = 0
  114. rtotal += s.len
  115. while spos < s.len:
  116. if bpos == blen:
  117. # Read more data
  118. bpos = 0
  119. blen = readBuffer(f, addr(buf[0]), buf.len)
  120. btotal += blen
  121. if blen == 0: # no more data in file
  122. result = false
  123. return
  124. let n = min(blen - bpos, s.len - spos)
  125. # TODO There's gotta be a better way of comparing here...
  126. if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
  127. result = false
  128. return
  129. spos += n
  130. bpos += n
  131. result = readBuffer(f, addr(buf[0]), 1) == 0 and
  132. btotal == rtotal # check that we've read all
  133. proc equalsFile*(r: Rope, filename: AbsoluteFile): bool =
  134. ## returns true if the contents of the file `f` equal `r`. If `f` does not
  135. ## exist, false is returned.
  136. var f: File
  137. result = open(f, filename.string)
  138. if result:
  139. result = equalsFile(r, f)
  140. close(f)