tivec.clu 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. # extend
  2. # include "tidefs.clu"
  3. %
  4. % Vectors are fixed-length mutable collections of objects.
  5. % The elements are numbered starting from 0.
  6. %
  7. vector = cluster is create, equal, size, fetch, store,
  8. print
  9. rep = page
  10. % Oops! at the moment, all zero-length vectors are equal!
  11. % Does this matter??
  12. % If the size of the vector is zero, then the rep is NILPAGE.
  13. % If the size is less than BLOCKSIZE, then the rep is a page
  14. % whose first word contains the refcount and the size, and
  15. % the remaining words are the elements of the vector. If
  16. % the size is greater than or equal to BLOCKSIZE, then the
  17. % rep is a page whose first word contains the refcount and
  18. % the size, and the remaining words are subsidiary pages
  19. % of size BLOCKSIZE containing the data. Such pages may be
  20. % NILPAGEs, signifying that all elements of the pages are
  21. % UNDEFINED.
  22. MAXSIZE = (BLOCKSIZE-1)*BLOCKSIZE % size of largest vector
  23. BIGSIZE = BLOCKSIZE % size of smallest big vector
  24. create = proc (sz: word) returns (cvt) signals (negsize, toobig)
  25. if sz<0 then signal negsize end
  26. if sz>MAXSIZE then signal toobig end
  27. if sz=0 then return (page$NILPAGE ()) end
  28. p: page
  29. if sz < BIGSIZE then
  30. p := page$create (sz + 1, UNDEFINED)
  31. else
  32. p := page$create (countpages(sz)+1, page$NILPAGE ())
  33. end
  34. p[0] := pack (1, sz)
  35. return (p)
  36. end create
  37. equal = proc (v1, v2: cvt) returns (bool)
  38. return (v1 = v2)
  39. end equal
  40. size = proc (v: cvt) returns (word)
  41. if v = page$NILPAGE () then return (0) end
  42. return (getsize (force[word] (v[0])))
  43. end size
  44. fetch = proc (v: cvt, i: word) returns (any) signals (bounds)
  45. sz: word := vector$size (up (v))
  46. if i<0 | i>=sz then signal bounds end
  47. if sz < BIGSIZE then return (v[i+1]) end
  48. p: page := force[page] (v[i/BLOCKSIZE + 1])
  49. if p = page$NILPAGE () then return (UNDEFINED) end
  50. return (p[i//BLOCKSIZE])
  51. end fetch
  52. store = proc (v: cvt, i: word, e: any) signals (bounds)
  53. sz: word := vector$size (up (v))
  54. if i<0 | i>=sz then signal bounds end
  55. if sz < BIGSIZE then v[i+1] := e
  56. else
  57. p: page := force[page] (v[i/BLOCKSIZE + 1])
  58. if p = page$NILPAGE () then
  59. p := page$create (BLOCKSIZE, UNDEFINED)
  60. v[i/BLOCKSIZE + 1] := p
  61. end
  62. p[i//BLOCKSIZE] := e
  63. end
  64. end store
  65. %
  66. % Internal procedures for the VECTOR cluster.
  67. %
  68. pack = proc (refcount, sz: word) returns (word)
  69. % Pack the refcount and size into one header word.
  70. % Refcount not needed for simulation.
  71. return (sz)
  72. end pack
  73. getsize = proc (w: word) returns (word)
  74. return (w)
  75. end getsize
  76. getrefcount = proc (w: word) returns (word)
  77. return (1)
  78. end getrefcount
  79. countpages = proc (sz: word) returns (word)
  80. % Return the total number of pages needed.
  81. return ((sz + (BLOCKSIZE-1)) / BLOCKSIZE)
  82. end countpages
  83. %
  84. % Debugging Operations
  85. %
  86. print = proc (v: vector, s: stream)
  87. sz: word := vector$size (v)
  88. stream$puts (" Vector [rep=", s)
  89. page$print (down (v), s)
  90. stream$puts ("] size=", s)
  91. stream$puts (word$unparse (sz), s)
  92. if sz > 0 then
  93. stream$puts (" vals=", s)
  94. for i: word in word$from_to (0, 4) do
  95. if i < sz then
  96. value$print (s, v[i]) % True hack!!!
  97. stream$puts (" ", s)
  98. end
  99. end
  100. end
  101. stream$putl ("", s)
  102. end print
  103. end vector
  104. %
  105. % Segments are like vectors, except that elements can be added
  106. % and removed from the high end.
  107. %
  108. segment = cluster is create, equal, size, fetch, store, top, grow, shrink,
  109. trim, addh, remh
  110. % Our representation for segments is similar to that of
  111. % vectors. However, since a segment's size can be changed,
  112. % it is necessary to indirectly access the data page, as a
  113. % new, larger data page must be allocated when the old one is
  114. % full. Thus, there is no point in storing the refcount and
  115. % size in the first word of the data. Instead, we use
  116. % a dope vector:
  117. rep = record [rc: word, % the reference count
  118. big: bool, % true if 2-level structure
  119. size: word, % the visible size
  120. data: page]
  121. % This dope vector is not really a record. Actually, it is
  122. % a two-word page that is treated like a record.
  123. % In this implementation, we never release any physical
  124. % storage, regardless of how many elements are removed from
  125. % the segment.
  126. MAXSIZE = BLOCKSIZE*BLOCKSIZE % maximum size of segment
  127. BIGSIZE = BLOCKSIZE+1 % minimum size needing big segment
  128. LOWBOUND = 0 % low bound of segment
  129. create = proc (sz: word) returns (cvt) signals (negsize, toobig)
  130. if sz<0 then signal negsize end
  131. if sz>MAXSIZE then signal toobig end
  132. p: page
  133. if sz<BIGSIZE then
  134. p := page$create (sz, UNDEFINED)
  135. else
  136. p := page$create (countpages (sz), page$NILPAGE ())
  137. end
  138. return (rep${rc: 1, big: sz>=BIGSIZE, size: sz, data: p})
  139. end create
  140. equal = proc (v1, v2: cvt) returns (bool)
  141. return (v1 = v2)
  142. end equal
  143. size = proc (v: cvt) returns (word)
  144. return (v.size)
  145. end size
  146. fetch = proc (v: cvt, i: word) returns (any) signals (bounds)
  147. if i<LOWBOUND then signal bounds end
  148. i := i - LOWBOUND
  149. if i>=v.size then signal bounds end
  150. if v.big then
  151. p: page := force[page] (v.data[i/BLOCKSIZE])
  152. if p = page$NILPAGE () then return (UNDEFINED) end
  153. return (p[i//BLOCKSIZE])
  154. end
  155. return (v.data[i])
  156. end fetch
  157. store = proc (v: cvt, i: word, e: any) signals (bounds)
  158. if i<LOWBOUND then signal bounds end
  159. i := i - LOWBOUND
  160. if i>=v.size then signal bounds end
  161. if v.big then
  162. p: page := force[page] (v.data[i/BLOCKSIZE])
  163. if p = page$NILPAGE () then
  164. p := page$create (BLOCKSIZE, UNDEFINED)
  165. v.data[i/BLOCKSIZE] := p
  166. end
  167. p[i//BLOCKSIZE] := e
  168. else
  169. v.data[i] := e
  170. end
  171. end store
  172. top = proc (v: segment) returns (any) signals (bounds)
  173. sz: word := segment$size (v)
  174. if sz = 0 then signal bounds end
  175. return (v[sz+(LOWBOUND-1)])
  176. end top
  177. grow = proc (v: cvt, n: word) signals (negsize, toobig)
  178. if n<0 then signal negsize end
  179. if n=0 then return end
  180. if v.size > MAXSIZE-n % avoid overflow
  181. then signal toobig end
  182. nsize: word := v.size + n
  183. if nsize < BIGSIZE & ~v.big then % small -> small
  184. enlarge_small (v, nsize)
  185. elseif ~v.big then % small -> big
  186. small_to_big (v, nsize)
  187. else % big -> big
  188. enlarge_big (v, nsize)
  189. end
  190. v.size := nsize
  191. end grow
  192. shrink = proc (v: cvt, n: word) signals (negsize)
  193. if n<0 then signal negsize end
  194. if n>v.size then n := v.size end
  195. v.size := v.size - n
  196. end shrink
  197. trim = proc (v: segment, sz: word)
  198. if sz<0 then sz := 0 end % avoid overflow
  199. diff: word := segment$size(v) - sz % amount to be trimmed
  200. if diff<=0 then return end % no trimming needed
  201. segment$shrink (v, diff)
  202. end trim
  203. addh = proc (v: segment, e: any) signals (toobig)
  204. segment$grow (v, 1)
  205. except when toobig: signal toobig end
  206. segment$store (v, segment$size(v)+LOWBOUND-1, e)
  207. end addh
  208. remh = proc (v: segment) returns (any) signals (bounds)
  209. e: any := segment$top (v)
  210. except when bounds: signal bounds end
  211. segment$shrink (v, 1)
  212. end remh
  213. %
  214. % Internal procedures for the SEGMENT cluster.
  215. %
  216. enlarge_small = proc (v: rep, nsize: word)
  217. % Given a segment V with a 1-level representation, enlarge it
  218. % to size NSIZE by adding UNDEFINED elements.
  219. v.data := enlargepage (v.data, v.size, nsize, UNDEFINED)
  220. end enlarge_small
  221. small_to_big = proc (v: rep, nsize: word)
  222. % Given a segment V with a 1-level representation, change it
  223. % to a 2-level representation, adding UNDEFINED elements
  224. % to make a total size NSIZE.
  225. p: page := page$create (countpages (nsize), page$NILPAGE ())
  226. p[0] := enlargepage (v.data, v.size, BLOCKSIZE, UNDEFINED)
  227. v.data := p
  228. v.big := TRUE
  229. end small_to_big
  230. enlarge_big = proc (v: rep, nsize: word)
  231. % Given a segment V with a 2-level representation, enlarge it
  232. % to size NSIZE by adding UNDEFINED elements.
  233. old_npages: word := countpages (v.size)
  234. new_npages: word := countpages (nsize)
  235. if new_npages > old_npages then
  236. v.data := enlargepage (v.data, old_npages,
  237. new_npages, page$NILPAGE ())
  238. if old_npages > 0 then
  239. old_lsize: word := v.size - (old_npages-1)*BLOCKSIZE
  240. fill_page (force[page] (v.data[old_npages-1]),
  241. old_lsize, BLOCKSIZE)
  242. end
  243. elseif old_npages > 0 then
  244. old_lsize: word := v.size - (old_npages-1)*BLOCKSIZE
  245. fill_page (force[page] (v.data[old_npages-1]),
  246. old_lsize, old_lsize+(nsize-v.size))
  247. end
  248. end enlarge_big
  249. enlargepage = proc (p: page, oldsize, newsize: word, e: any)
  250. returns (page)
  251. % Return a page whose contents are the first OLDSIZE elements
  252. % of P, followed by at least NEWSIZE-OLDSIZE elements of value E.
  253. % The returned page may be the page P.
  254. % The NEWSIZE must not be larger than BLOCKSIZE.
  255. psize: word := p.size
  256. if newsize > psize then
  257. newp: page := page$create (newsize, e)
  258. for i: word in word$from_to (0, oldsize-1) do
  259. newp[i] := p[i]
  260. end
  261. return (newp)
  262. end
  263. for i: word in word$from_to (oldsize, newsize-1) do
  264. p[i] := e
  265. end
  266. return (p)
  267. end enlargepage
  268. countpages = proc (sz: word) returns (word)
  269. % return the total number of pages needed
  270. return ((sz + (BLOCKSIZE-1)) / BLOCKSIZE)
  271. end countpages
  272. fill_page = proc (p: page, oldsize, newsize: word)
  273. for i: word in word$from_to (oldsize, newsize-1) do
  274. p[i] := UNDEFINED
  275. end
  276. end fill_page
  277. end segment