input-stream.sl 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2. %
  3. % Input-Stream.SL (TOPS-20 Version) - File Input Stream Objects
  4. %
  5. % Author: Alan Snyder
  6. % Hewlett-Packard/CRC
  7. % Date: 29 July 1982
  8. %
  9. % This package is 6.6 times faster than the standard unbuffered I/O.
  10. % (Using message passing, it is only 1.7 times faster.)
  11. %
  12. % Note: this code will only run COMPILED.
  13. %
  14. % See TESTING code at the end of this file for examples of use.
  15. % Be sure to include "(CompileTime (load objects))" at the beginning
  16. % of any file that uses this package.
  17. %
  18. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  19. (BothTimes (load objects jsys))
  20. (defun open-input (file-name)
  21. (let ((s (make-instance 'input-stream)))
  22. (=> s open file-name)
  23. s))
  24. %(CompileTime (setq *pgwd t))
  25. (CompileTime (setq FILE-BUFFER-SIZE (* 5 512)))
  26. (defflavor input-stream ((jfn NIL) % TOPS-20 file number
  27. ptr % "pointer" to next char in buffer
  28. count % number of valid chars in buffer
  29. eof-flag % T => this bufferfull is the last
  30. file-name % full name of actual file
  31. buffer % input buffer
  32. )
  33. ()
  34. (gettable-instance-variables file-name)
  35. )
  36. % Note: The JSYS function can't be used for the 'SIN' JSYS because the function
  37. % handles errors. The 'SIN' JSYS will report an error on end-of-file if errors
  38. % are being handled.
  39. (CompileTime (put 'sin 'OpenCode '((jsys 42) (move (reg 1) (reg 3)))))
  40. (CompileTime (put 'closf 'OpenCode '((jsys 18) (move (reg 1) (reg 1)))))
  41. (defmethod (input-stream getc) ()
  42. % Return the next character from the file. Line termination
  43. % is represented by a single NEWLINE (LF) character.
  44. % Note: returns NIL on end of file.
  45. (if (WLessP ptr count)
  46. (let ((ch (prog1
  47. (igets buffer ptr)
  48. (setf ptr (wplus2 ptr 1))
  49. )))
  50. % Ignore CR's
  51. (if (WNEq ch (char CR)) ch (input-stream$getc self))
  52. )
  53. (input-stream$fill-buffer-and-getc self)
  54. ))
  55. % The above function was coded to produce good compiled code
  56. % using the current PSL compiler. Here's the output. Note
  57. % that no stack variables are used. The main path uses 16
  58. % instructions. There is room for improvement.
  59. % (*ENTRY INPUT-STREAM$GETC EXPR 1)
  60. % G0002 (MOVE (REG 4) (REG 1))
  61. % (MOVE (REG T1) (INDEXED (REG 1) 6))
  62. % (CAMG (REG T1) (INDEXED (REG 1) 5))
  63. % (JRST G0004)
  64. % (MOVE (REG 2) (INDEXED (REG 1) 5))
  65. % (MOVE (REG 1) (INDEXED (REG 1) 4))
  66. % (AOS (REG 1))
  67. % (ADJBP (REG 2) "L0010")
  68. % (LDB (REG 1) (REG 2))
  69. % (MOVE (REG 3) (REG 1))
  70. % (MOVE (REG 1) (INDEXED (REG 4) 5))
  71. % (AOS (REG 1))
  72. % (MOVEM (REG 1) (INDEXED (REG 4) 5))
  73. % (MOVE (REG 1) (REG 3))
  74. % (CAIE (REG 1) 13)
  75. % (JRST G0001)
  76. % (MOVE (REG 1) (REG 4))
  77. % (JRST G0002)
  78. % G0004 (JRST (ENTRY INPUT-STREAM$FILL-BUFFER-AND-GETC))
  79. % G0001 (POPJ (REG ST) 0)
  80. % L0010 (FULLWORD (FIELDPOINTER (INDEXED (REG 1) 0) 0 7))
  81. (defmethod (input-stream fill-buffer-and-getc) ()
  82. % Implementation note: Removing all of this code from GETC improves the
  83. % quality of the compiled code for GETC. In particular, the compiler is able
  84. % to keep SELF in a register, instead of saving it in a stack variable and
  85. % (excessively) reloading it every time it is needed. Making this change
  86. % increased the performance of buffered input from 4X to 6.6X the standard
  87. % unbuffered input.
  88. (if eof-flag
  89. NIL
  90. (let ((n (sin jfn (jconv buffer) (WDifference 0 #.FILE-BUFFER-SIZE))))
  91. (if (not (WEQ n 0)) (setf eof-flag T))
  92. (setf count (WPlus2 #.FILE-BUFFER-SIZE n))
  93. (setf ptr 0)
  94. (input-stream$getc self))))
  95. (defmethod (input-stream getc-image) ()
  96. % Return the next character from the file. Do not perform
  97. % any translation. In particular, return all <CR>s.
  98. % Returns NIL on end of file.
  99. (if (WLessP ptr count)
  100. (prog1
  101. (igets buffer ptr)
  102. (setf ptr (wplus2 ptr 1))
  103. )
  104. (input-stream$fill-buffer-and-getc-image self)
  105. ))
  106. (defmethod (input-stream fill-buffer-and-getc-image) ()
  107. (if eof-flag
  108. NIL
  109. (let ((n (sin jfn (jconv buffer) (WDifference 0 #.FILE-BUFFER-SIZE))))
  110. (if (not (WEQ n 0)) (setf eof-flag T))
  111. (setf count (WPlus2 #.FILE-BUFFER-SIZE n))
  112. (setf ptr 0)
  113. (input-stream$getc-image self))))
  114. (defmethod (input-stream empty?) ()
  115. (null (input-stream$peekc self)))
  116. (defmethod (input-stream peekc) ()
  117. % Return the next character from the file, but don't advance
  118. % to the next character. Returns NIL on end of file.
  119. (if (WLessP ptr count)
  120. (let ((ch (igets buffer ptr)))
  121. % Ignore CR's
  122. (if (WNEq ch (char CR))
  123. ch
  124. (setf ptr (wplus2 ptr 1))
  125. (input-stream$peekc self))
  126. )
  127. (input-stream$fill-buffer-and-peekc self)
  128. ))
  129. (defmethod (input-stream fill-buffer-and-peekc) ()
  130. (if eof-flag
  131. NIL
  132. (let ((n (sin jfn (jconv buffer) (WDifference 0 #.FILE-BUFFER-SIZE))))
  133. (if (not (WEQ n 0)) (setf eof-flag T))
  134. (setf count (WPlus2 #.FILE-BUFFER-SIZE n))
  135. (setf ptr 0)
  136. (input-stream$peekc self))))
  137. (defmethod (input-stream open) (name-of-file)
  138. % Open the specified file for input via SELF. If the file cannot
  139. % be opened, a Continuable Error is generated.
  140. (if jfn (input-stream$close self))
  141. (setf buffer (MkString #.FILE-BUFFER-SIZE (char space)))
  142. (setf ptr 0)
  143. (setf count 0)
  144. (setf eof-flag NIL)
  145. (setf jfn (Dec20Open name-of-file
  146. (int2sys 2#001000000000000001000000000000000000)
  147. (int2sys 2#000111000000000000010000000000000000)
  148. ))
  149. (if (= jfn 0) (setf jfn NIL))
  150. (if (null jfn)
  151. (=> self open
  152. (ContinuableError 0
  153. (BldMsg "Unable to Open '%w' for Input." name-of-file)
  154. name-of-file))
  155. (setf file-name (MkString 200 (char space)))
  156. (jsys1 file-name jfn #.(bits 2 5 8 11 14 35) 0 #.(get 'jsJFNS 'NewNam))
  157. (setf file-name (recopystringtonull file-name))
  158. ))
  159. (defmethod (input-stream close) ()
  160. (if jfn (progn
  161. (closf jfn)
  162. (setf jfn NIL)
  163. (setf buffer NIL)
  164. (setf count 0)
  165. (setf ptr 0)
  166. (setf eof-flag T)
  167. )))
  168. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  169. % TESTING CODE
  170. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  171. (CommentOutCode (progn
  172. (de test-buffered-input (name-of-file)
  173. (setq s (open-input name-of-file))
  174. (while (setq ch (input-stream$getc s))
  175. (WriteChar ch)
  176. )
  177. (=> s close)
  178. (Prin2 "---EOF---")
  179. NIL
  180. )
  181. (de time-buffered-input (name-of-file)
  182. (setq start-time (time))
  183. (setq s (open-input name-of-file))
  184. (while (setq ch (input-stream$getc s))
  185. )
  186. (=> s close)
  187. (- (time) start-time)
  188. )
  189. (de time-buffered-input-1 (name-of-file)
  190. (setq start-time (time))
  191. (setq s (open-input name-of-file))
  192. (while (setq ch (=> s getc))
  193. )
  194. (=> s close)
  195. (- (time) start-time)
  196. )
  197. (de time-standard-input (name-of-file)
  198. (setq start-time (time))
  199. (setq chan (open name-of-file 'INPUT))
  200. (while (not (= (setq ch (ChannelReadChar chan)) (char EOF)))
  201. )
  202. (close chan)
  203. (- (time) start-time)
  204. )
  205. (de time-input (name-of-file)
  206. (list
  207. (time-buffered-input name-of-file)
  208. (time-buffered-input-1 name-of-file)
  209. (time-standard-input name-of-file)
  210. ))
  211. )) % End CommentOutCode