ropes.nim 4.1 KB

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