ropes.nim 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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*(cap = 80): string {.inline.} =
  20. result = newStringOfCap(cap)
  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 = default(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. raiseAssert "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. raiseAssert "invalid format string: " & frmt
  78. if j > high(args) + 1:
  79. raiseAssert "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. raiseAssert "invalid format string: " & frmt
  90. else:
  91. result.add(frmt[i])
  92. inc(i)
  93. proc `%`*(frmt: static[FormatStr], args: openArray[Rope]): Rope =
  94. runtimeFormat(frmt, args)
  95. template addf*(c: var Rope, frmt: FormatStr, args: openArray[Rope]) =
  96. ## shortcut for ``add(c, frmt % args)``.
  97. c.add(frmt % args)
  98. const
  99. bufSize = 1024 # 1 KB is reasonable
  100. proc equalsFile*(s: Rope, f: File): bool =
  101. ## returns true if the contents of the file `f` equal `r`.
  102. var
  103. buf: array[bufSize, char] = default(array[bufSize, char])
  104. bpos = buf.len
  105. blen = buf.len
  106. btotal = 0
  107. rtotal = 0
  108. when true:
  109. var spos = 0
  110. rtotal += s.len
  111. while spos < s.len:
  112. if bpos == blen:
  113. # Read more data
  114. bpos = 0
  115. blen = readBuffer(f, addr(buf[0]), buf.len)
  116. btotal += blen
  117. if blen == 0: # no more data in file
  118. result = false
  119. return
  120. let n = min(blen - bpos, s.len - spos)
  121. # TODO There's gotta be a better way of comparing here...
  122. if not equalMem(addr(buf[bpos]), cast[pointer](cast[int](cstring(s))+spos), n):
  123. result = false
  124. return
  125. spos += n
  126. bpos += n
  127. result = readBuffer(f, addr(buf[0]), 1) == 0 and
  128. btotal == rtotal # check that we've read all
  129. proc equalsFile*(r: Rope, filename: AbsoluteFile): bool =
  130. ## returns true if the contents of the file `f` equal `r`. If `f` does not
  131. ## exist, false is returned.
  132. var f: File = default(File)
  133. result = open(f, filename.string)
  134. if result:
  135. result = equalsFile(r, f)
  136. close(f)