rbuffer.ml 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. (**************************************************************************)
  2. (* *)
  3. (* Copyright (C) Jean-Christophe Filliatre *)
  4. (* *)
  5. (* This software is free software; you can redistribute it and/or *)
  6. (* modify it under the terms of the GNU Library General Public *)
  7. (* License version 2.1, with the special exception on linking *)
  8. (* described in file LICENSE. *)
  9. (* *)
  10. (* This software is distributed in the hope that it will be useful, *)
  11. (* but WITHOUT ANY WARRANTY; without even the implied warranty of *)
  12. (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *)
  13. (* *)
  14. (**************************************************************************)
  15. (* Ropes-based implementation of Buffer *)
  16. type rope =
  17. | Str of string
  18. | App of rope * rope * int (* total length *)
  19. let rope_empty = Str ""
  20. let rope_length = function
  21. | Str s -> String.length s
  22. | App (_, _, n) -> n
  23. let rec rope_nth i = function
  24. | Str s ->
  25. String.unsafe_get s i
  26. | App (l, r, _) ->
  27. let ll = rope_length l in
  28. if i < ll then rope_nth i l else rope_nth (i - ll) r
  29. type t = {
  30. mutable rope : rope; (* the left part is a rope *)
  31. mutable buffer : bytes; (* the right part is a buffer... *)
  32. mutable position : int; (* ...with [position] bytes used *)
  33. }
  34. let create n =
  35. let n = if n < 1 then 1 else n in
  36. let n = if n > Sys.max_string_length then Sys.max_string_length else n in
  37. let s = Bytes.create n in
  38. { rope = rope_empty; buffer = s; position = 0; }
  39. let reset b =
  40. b.rope <- rope_empty;
  41. b.position <- 0
  42. let clear = reset
  43. let length b =
  44. rope_length b.rope + b.position
  45. (* [blit s i r] blits the contents of rope [r] in string [s] at index [i] *)
  46. let rec blit_rope s i = function
  47. | Str str ->
  48. String.blit str 0 s i (String.length str)
  49. | App (l, r, _) ->
  50. let ll = rope_length l in
  51. blit_rope s i l;
  52. blit_rope s (i + ll) r
  53. (* rename contents to unsafe_contents to avoid accidental usage *)
  54. let unsafe_contents b =
  55. let r = rope_length b.rope in
  56. let n = b.position in
  57. let len = r + n in
  58. if len > Sys.max_string_length then invalid_arg "Rbuffer.contents";
  59. let s = Bytes.create len in
  60. blit_rope s 0 b.rope;
  61. Bytes.blit b.buffer 0 s r n;
  62. Bytes.unsafe_to_string s
  63. (* [blit_subrope s i ofs len] blits the subrope [r[ofs..ofs+len-1]] in string
  64. [s] at index [i] *)
  65. let rec blit_subrope s i ofs len = function
  66. | Str str ->
  67. assert (ofs >= 0 && ofs + len <= String.length str);
  68. String.blit str ofs s i len
  69. | App (l, r, _) ->
  70. let ll = rope_length l in
  71. if ofs + len <= ll then
  72. blit_subrope s i ofs len l
  73. else if ofs >= ll then
  74. blit_subrope s i (ofs - ll) len r
  75. else begin
  76. let lenl = ll - ofs in
  77. blit_subrope s i ofs lenl l;
  78. blit_subrope s (i + lenl) 0 (len - lenl) r
  79. end
  80. let sub b ofs len =
  81. let r = rope_length b.rope in
  82. if len > Sys.max_string_length ||
  83. ofs < 0 || len < 0 || ofs > r + b.position - len
  84. then invalid_arg "Buffer.sub";
  85. let s = Bytes.create len in
  86. if ofs + len <= r then
  87. blit_subrope s 0 ofs len b.rope
  88. else if ofs >= r then
  89. Bytes.blit b.buffer (ofs - r) s 0 len
  90. else begin
  91. blit_subrope s 0 ofs (r - ofs) b.rope;
  92. Bytes.blit b.buffer 0 s (r - ofs) (ofs + len - r)
  93. end;
  94. Bytes.unsafe_to_string s
  95. let nth b i =
  96. let r = rope_length b.rope in
  97. if i < 0 || i >= r + b.position then invalid_arg "Buffer.nth";
  98. if i < r then rope_nth i b.rope else Bytes.unsafe_get b.buffer (i - r)
  99. (* moves the data in [b.buffer], if any, to the rope; ensures [b.position=0] *)
  100. let move_buffer_to_rope b =
  101. let pos = b.position in
  102. if pos > 0 then begin
  103. let n = Bytes.length b.buffer in
  104. if pos = n then begin
  105. (* whole buffer goes to the rope; faster to allocate a new buffer *)
  106. b.rope <- App (b.rope, Str (Bytes.unsafe_to_string b.buffer), rope_length b.rope + pos);
  107. b.buffer <- Bytes.create n
  108. end else begin
  109. (* part of the buffer goes to the rope; easier to copy it *)
  110. b.rope <- App (b.rope, Str (Bytes.sub_string b.buffer 0 pos),
  111. rope_length b.rope + pos)
  112. end;
  113. b.position <- 0
  114. end
  115. let add_char b c =
  116. if b.position = Bytes.length b.buffer then move_buffer_to_rope b;
  117. let pos = b.position in
  118. Bytes.set b.buffer pos c;
  119. b.position <- pos + 1
  120. (* allocates space for [len] bytes and returns the corresponding place
  121. (as a string and an offset within that string) *)
  122. let alloc b len =
  123. let n = Bytes.length b.buffer in
  124. let pos = b.position in
  125. let len' = pos + len in
  126. if len' <= n then begin
  127. (* fits in the buffer *)
  128. b.position <- len';
  129. b.buffer, pos
  130. end else if len' <= Sys.max_string_length then begin
  131. (* buffer and len fit in a new string, allocated in the rope *)
  132. let str = Bytes.create len' in
  133. Bytes.blit b.buffer 0 str 0 pos;
  134. b.rope <- App (b.rope, Str (Bytes.unsafe_to_string str), rope_length b.rope + len');
  135. b.position <- 0;
  136. str, pos
  137. end else begin
  138. (* buffer and len require two strings, allocated in the rope *)
  139. let str = Bytes.create len in
  140. b.rope <- App (b.rope,
  141. App (Str (Bytes.sub_string b.buffer 0 pos), Str (Bytes.unsafe_to_string str), len'),
  142. rope_length b.rope + len');
  143. b.position <- 0;
  144. str, 0
  145. end
  146. let safe_add_substring b s offset len =
  147. let str, pos = alloc b len in
  148. String.blit s offset str pos len
  149. let add_substring b s offset len =
  150. if offset < 0 || len < 0 || offset > String.length s - len
  151. then invalid_arg "Buffer.add_substring";
  152. safe_add_substring b s offset len
  153. let add_string b s =
  154. safe_add_substring b s 0 (String.length s)
  155. let add_buffer b b2 =
  156. if b.position > 0 then move_buffer_to_rope b;
  157. (* now we have b.position = 0 *)
  158. b.rope <- App (b.rope, b2.rope, rope_length b.rope + rope_length b2.rope);
  159. add_substring b (Bytes.unsafe_to_string b2.buffer) 0 b2.position
  160. let rec add_channel b ic len =
  161. if len <= Sys.max_string_length then begin
  162. let str, pos = alloc b len in
  163. really_input ic str pos len
  164. end else begin
  165. let str, pos = alloc b Sys.max_string_length in
  166. really_input ic str pos Sys.max_string_length;
  167. add_channel b ic (len - Sys.max_string_length)
  168. end
  169. let output_buffer oc b =
  170. let rec loop wl = match wl with
  171. | Str s :: wl ->
  172. output oc (Bytes.of_string s) 0 (String.length s);
  173. loop wl
  174. | App( l, r, _) :: wl ->
  175. loop (l :: r :: wl)
  176. | [] ->
  177. ()
  178. in
  179. loop [b.rope];
  180. output oc b.buffer 0 b.position
  181. open Format
  182. let print fmt b =
  183. let rec loop wl = match wl with
  184. | Str s :: wl ->
  185. pp_print_string fmt s;
  186. loop wl
  187. | App( l, r, _) :: wl ->
  188. loop (l :: r :: wl)
  189. | [] ->
  190. ()
  191. in
  192. loop [b.rope];
  193. pp_print_string fmt (Bytes.sub_string b.buffer 0 b.position)