I386.ArrayXdBytes.Mod 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334
  1. (* CAPO - Computational Analysis Platform for Oberon - by Alan Freed and Felix Friedrich. *)
  2. (* Version 1, Update 2 *)
  3. MODULE ArrayXdBytes; (** AUTHOR "fof"; PURPOSE "Collection of all generic procedures on Xd arrays."; **)
  4. (* collection of all generic procedures on arbitrary dimenional arrays with arbitrary origin
  5. to increase speed, this module may be compiled with the \x option (index checks disabled) <- not yet *)
  6. (* any item containing the string "dbg" will be removed from this module, do NOT use *)
  7. IMPORT SYSTEM, Array1dBytes, dbgOut := KernelLog, DataIO;
  8. CONST
  9. strongIndexChecking = TRUE; debug = FALSE;
  10. TYPE
  11. Index* = LONGINT;
  12. IndexArray* = POINTER TO ARRAY OF Index;
  13. Address* = LONGINT;
  14. TYPE
  15. (** basic memory structure for arrays with arbitrary dimension *)
  16. ArrayMemoryStructure* = OBJECT
  17. VAR
  18. (* do not change the interface -> asm routines *)
  19. (** contiuous memory block *)
  20. baseadr: Index; (* lowest byte allocated for "MemoryDesc" = included *)
  21. bytes-: Index; (* size of memory used in BYTES (8bit) *)
  22. (** xd array description*)
  23. dim-: Index; (* dimension= LEN(len)=LEN(diminc) *)
  24. len-: IndexArray; (* length per dimension*)
  25. diminc-: IndexArray; (* dimincrease factor per dimension, do NOT expect diminc[0] < diminc[1] < ... ! *)
  26. elementsize: Index; (* length of basic element in bytes *)
  27. origin-: IndexArray;
  28. adrwoffset: Index; (* starting adress calculated with offset *)
  29. END ArrayMemoryStructure;
  30. TYPE
  31. (** element enumerator:
  32. if block = FALSE then traverses memory elementwise respecting dimension orders, e.g. a[0,0,0],a[0,0,1], ... , a[l3,l2,l1-1],a[l3,l2,l1] ,
  33. if block = TRUE then traverses memory blockwise with largest continuous blocks, e.g. (a[0,0,0]-a[0,l2,l1]), (a[1,0,0]-a[1,l2,l1]), ... , (a[l3,0,0]-a[l3,l2,1])*)
  34. Enumerator* = OBJECT
  35. VAR dim: LONGINT;
  36. mem: ArrayMemoryStructure;
  37. adr-, size-: LONGINT;
  38. lncdim: LONGINT; (* lowest not continuous dimension *)
  39. pos-, origin, len: IndexArray;
  40. PROCEDURE & Init*( mem: ArrayMemoryStructure; enumorigin, enumlen: IndexArray; block: BOOLEAN );
  41. VAR i: LONGINT;
  42. BEGIN
  43. SELF.mem := mem;
  44. IF enumorigin = NIL THEN enumorigin := mem.origin END;
  45. IF enumlen = NIL THEN enumlen := mem.len END;
  46. (* range checks must be done in higher level *)
  47. dim := LEN( enumorigin ); lncdim := 0; CheckIndexArray( dim, pos ); origin := enumorigin; len := enumlen;
  48. size := mem.elementsize; adr := mem.baseadr; i := 0;
  49. WHILE (i < dim) DO
  50. pos[i] := origin[i]; INC( adr, (origin[i] - mem.origin[i]) * mem.diminc[i] );
  51. IF block & (len[i] = mem.len[i]) & (size = mem.diminc[i]) THEN size := size * len[i]; INC( lncdim )
  52. ELSE block := FALSE; (* stop at lowest continuous block *)
  53. END;
  54. INC( i );
  55. END;
  56. IF debug THEN dbgOut.String( "Enumerator.init, lncdim:" ); dbgOut.Int( lncdim, 0 ); dbgOut.Ln; END;
  57. ASSERT ( size # 0 );
  58. END Init;
  59. PROCEDURE Next*( ): BOOLEAN;
  60. VAR i, j: LONGINT; org, length: LONGINT;
  61. BEGIN
  62. IF lncdim = dim THEN
  63. IF debug THEN dbgOut.String( "Enumerator.next: all continuous, dim=" ); dbgOut.Int( lncdim, 0 ); dbgOut.Ln; END;
  64. RETURN FALSE
  65. END; (* all continuous *)
  66. i := lncdim; INC( pos[i] ); INC( adr, mem.diminc[i] ); org := origin[i]; length := len[i];
  67. WHILE (i < dim - 1) & (pos[i] = org + length) DO (* find next dimension to increase *)
  68. pos[i] := org; DEC( adr, mem.diminc[i] * length ); INC( i ); INC( pos[i] ); INC( adr, mem.diminc[i] ); org := origin[i];
  69. length := len[i];
  70. END;
  71. IF debug THEN
  72. j := 0; dbgOut.String( "Enumerator.next:" );
  73. WHILE (j < dim) DO dbgOut.Int( pos[j], 0 ); dbgOut.String( "|" ); INC( j ); END;
  74. dbgOut.Ln;
  75. END;
  76. RETURN (pos[i] # org + length);
  77. END Next;
  78. END Enumerator;
  79. TYPE
  80. Array* = OBJECT (ArrayMemoryStructure)
  81. VAR (**)
  82. protector: ANY; (* temporary pointer to protect data from being garbage collected *)
  83. permutation-: IndexArray; (* permutation used for INTERNALLY accessing the data. *)
  84. bc-: SHORTINT; (* boundary condition, abstract *)
  85. (** public values *)
  86. (* boundaryCondition-: SHORTINT; *)
  87. (* used-: IndexArray; (* in preparation *)*)
  88. (** cache variables for faster access *)
  89. f0, f1, f2, f3: Index; (* cache data for dimensions 1-4 *)
  90. o0-, o1-, o2-, o3-, l0-, l1-, l2-, l3-: Index; (* cache data for dimensions 1-4 *)
  91. (* generally: range checks are done on 1d array only, not for each dimension *)
  92. PROCEDURE dbgWriteInfo*;
  93. BEGIN
  94. dbgWriteMemoryInfo( SELF );
  95. END dbgWriteInfo;
  96. (** get information about elementsize, must be provided by each implementation of Array *)
  97. PROCEDURE GetInfo*( VAR elementsize: LONGINT );
  98. BEGIN
  99. HALT( 1001 ); (* abstract *)
  100. END GetInfo;
  101. PROCEDURE SetBoundaryCondition*( c: SHORTINT ); (* to be overridden in higher level modules to determine access methods*)
  102. BEGIN
  103. bc := c;
  104. END SetBoundaryCondition;
  105. (** Allocate memory, should be provided by each implementation of Arrays but can also be done here *)
  106. PROCEDURE Allocate*( size: LONGINT; VAR baseadr: LONGINT; VAR protector: ANY );
  107. VAR alloc: POINTER TO ARRAY OF SYSTEM.BYTE;
  108. BEGIN
  109. NEW( alloc, size * elementsize ); baseadr := ADDRESSOF( alloc[0] ); protector := alloc;
  110. END Allocate;
  111. PROCEDURE ValidateCache*;
  112. VAR i: LONGINT;
  113. BEGIN
  114. IF dim > 3 THEN f3 := diminc[3]; o3 := origin[3]; l3 := len[3]; ELSE f3 := 0; l3 := 0; END;
  115. IF dim > 2 THEN f2 := diminc[2]; o2 := origin[2]; l2 := len[2]; ELSE f2 := 0; l2 := 0; END;
  116. IF dim > 1 THEN f1 := diminc[1]; o1 := origin[1]; l1 := len[1]; ELSE f1 := 0; l1 := 0; END;
  117. IF dim > 0 THEN f0 := diminc[0]; o0 := origin[0]; l0 := len[0]; ELSE f0 := 0; l0 := 0; END;
  118. i := 0; adrwoffset := baseadr;
  119. WHILE (i < dim) DO adrwoffset := adrwoffset - origin[i] * diminc[i]; INC( i ); END;
  120. END ValidateCache;
  121. PROCEDURE Init( newdim: LONGINT );
  122. BEGIN
  123. dim := newdim; CheckIndexArray( dim, len ); CheckIndexArray( dim, origin );
  124. CheckIndexArray( dim, permutation ); CheckIndexArray( dim, diminc );
  125. END Init;
  126. (** NewXdb, allocate memory for the array, should be called by any constructors of an implementation of array *)
  127. PROCEDURE & NewXdB*( neworigin, newlen: IndexArray);
  128. VAR i, size: LONGINT;
  129. BEGIN
  130. Init( LEN( newlen ) );
  131. IF newlen[0] = 0 THEN RETURN END; (* newlen[0]=0: create empty array for load procedure *)
  132. GetInfo( elementsize ); size := elementsize;
  133. FOR i := 0 TO dim - 1 DO size := size * newlen[i]; len[i] := newlen[i]; origin[i] := neworigin[i]; permutation[i] := i END;
  134. Allocate( size DIV elementsize, baseadr, protector ); ComputeIncrease( len, permutation, elementsize, diminc );
  135. bytes := diminc[dim - 1] * len[dim - 1]; ValidateCache; SetBoundaryCondition( bc );
  136. END NewXdB;
  137. (** AlikeX, return Array with same geometry, abstract, must be provided by any implementation of Array*)
  138. PROCEDURE AlikeX*( ): Array;
  139. BEGIN
  140. HALT( 2002 ); (* abstract *)
  141. END AlikeX;
  142. (** Copy: returns a deep copy of Array *)
  143. PROCEDURE CopyX*( ): Array;
  144. VAR copy: Array; i: Index;
  145. BEGIN
  146. copy := AlikeX();
  147. ASSERT ( bytes = copy.bytes ) (* should never happen, for dbgging only *) ;
  148. SYSTEM.MOVE( baseadr, copy.baseadr, bytes ); i := 0; RETURN copy;
  149. END CopyX;
  150. (** resize and / or shift origin, if copydata=TRUE then all data at same positions are kept *)
  151. PROCEDURE NewRangeX*( neworigin, newlen: IndexArray; preservedata: BOOLEAN );
  152. (* reduce or extend dimensions with copy *)
  153. VAR same: BOOLEAN; i: LONGINT; olddata: ArrayMemoryStructure;
  154. BEGIN
  155. IF LEN( newlen ) # LEN( neworigin ) THEN HALT( 1001 ) END;
  156. (* check if len equals old len*)
  157. IF LEN( newlen ) = dim THEN
  158. same := TRUE; i := 0;
  159. WHILE (i < dim) & same DO
  160. IF (newlen[i] # len[i]) OR (neworigin[i] # origin[i]) THEN same := FALSE END;
  161. INC( i );
  162. END;
  163. IF same THEN RETURN END;
  164. END;
  165. IF preservedata THEN NEW( olddata ); AMSCopyDescr( SELF, olddata );
  166. END;
  167. NewXdB( neworigin, newlen );
  168. IF preservedata THEN CopyDataPositionPreserving( olddata, SELF ) END;
  169. (* now setting new values *)
  170. END NewRangeX;
  171. (** optimize access for the dimensions ordered as given in "order". modifies the internal representation of the data *)
  172. PROCEDURE OptimizeForAccess*( order: ARRAY OF Index; preservedata: BOOLEAN );
  173. VAR old: ArrayMemoryStructure;
  174. BEGIN
  175. IF preservedata THEN NEW( old ); AMSCopyDescr( SELF, old ) END;
  176. IF CompletePermutation( order, permutation^ ) THEN
  177. ComputeIncrease( len, permutation, elementsize, diminc ); ValidateCache;
  178. IF preservedata THEN
  179. Allocate( bytes DIV elementsize, baseadr, protector ); ValidateCache;
  180. CopyDataByCoordinateTraversal( old, SELF );
  181. END;
  182. END;
  183. END OptimizeForAccess;
  184. (** optimize access for the dimensions ordered as given in "order". modifies the internal representation of the data but does NOT affect SELF.permutation! *)
  185. PROCEDURE PermuteDimensions*( permutation: IndexArray; rearrangeMemory: BOOLEAN );
  186. VAR old: ArrayMemoryStructure;
  187. BEGIN
  188. IF CheckPermutation( dim, permutation ^) THEN
  189. ApplyPermutation( permutation^, origin^ ); ApplyPermutation( permutation^, len^ );
  190. ApplyPermutation( permutation^, diminc^ ); ApplyPermutation( permutation^, SELF.permutation^ );
  191. ValidateCache;
  192. IF rearrangeMemory THEN
  193. NEW( old ); AMSCopyDescr( SELF, old ); NewXdB( origin, len ); CopyDataByCoordinateTraversal( old, SELF );
  194. END;
  195. END;
  196. END PermuteDimensions;
  197. (** delete <lenght> elements in dimension <dimension> at position <first> *)
  198. (** example:delete columns from matrix, remove data to vector etc. *)
  199. PROCEDURE DeleteElements*( dimension, first, length: Index );
  200. VAR old: ArrayMemoryStructure; srco, desto, destlen: IndexArray;
  201. BEGIN
  202. (** index checks: *)
  203. IF (dimension < 0) OR (dimension >= dim) THEN HALT( 1001 ) END;
  204. IF (first < origin[dimension]) OR (first + length > origin[dimension] + len[dimension]) THEN HALT( 1002 ) END;
  205. (** computation *)
  206. NEW( old ); AMSCopyDescr( SELF, old ); DEC( len[dimension], length ); NewXdB( origin, len );
  207. NEW( destlen, dim ); CopyIndexArray( old.len^, destlen ); NEW( srco, dim ); CopyIndexArray( old.origin^, srco );
  208. NEW( desto, dim ); CopyIndexArray( origin^, desto );
  209. IF first > srco[dimension] THEN
  210. destlen[dimension] := first - srco[dimension];
  211. CopyArrayPartToArrayPart( old, SELF, old.origin, destlen, origin, destlen );
  212. END;
  213. IF (first + length) < (old.origin[dimension] + old.len[dimension]) THEN
  214. desto[dimension] := first; srco[dimension] := first + length;
  215. destlen[dimension] := (old.origin[dimension] + old.len[dimension]) - (first + length);
  216. CopyArrayPartToArrayPart( old, SELF, srco, destlen, desto, destlen );
  217. END;
  218. END DeleteElements;
  219. (** insert <lenght> elements in dimension <dimension> at position <first> *)
  220. (** example: insert new columns in matrix, append data to vector etc. *)
  221. PROCEDURE InsertElements*( dimension, first, length: Index );
  222. VAR old: ArrayMemoryStructure; srco, desto, destlen: IndexArray;
  223. BEGIN
  224. (** index checks: *)
  225. IF (dimension < 0) OR (dimension >= dim) THEN HALT( 1001 ) END;
  226. IF (first < origin[dimension]) OR (first > origin[dimension] + len[dimension]) THEN HALT( 1002 ) END;
  227. NEW( old ); AMSCopyDescr( SELF, old ); INC( len[dimension], length ); NewXdB( origin, len );
  228. NEW( destlen, dim ); CopyIndexArray( old.len^, destlen ); NEW( srco, dim ); CopyIndexArray( old.origin^, srco );
  229. NEW( desto, dim ); CopyIndexArray( origin^, desto );
  230. IF first > srco[dimension] THEN
  231. destlen[dimension] := first - srco[dimension];
  232. CopyArrayPartToArrayPart( old, SELF, old.origin, destlen, origin, destlen );
  233. END;
  234. IF (first) < (old.origin[dimension] + old.len[dimension]) THEN
  235. desto[dimension] := first + length; srco[dimension] := first;
  236. destlen[dimension] := (old.origin[dimension] + old.len[dimension]) - (first);
  237. CopyArrayPartToArrayPart( old, SELF, srco, destlen, desto, destlen );
  238. END;
  239. END InsertElements;
  240. (** exchange elements at pos1 and pos2 in dimension <dimension>. *)
  241. PROCEDURE ToggleElements*( dimension: Index; pos1, pos2: Index );
  242. VAR offset1, offset2, swaplen, diminclen, srcadr, stop, dataadr: LONGINT; swapcache: IndexArray;
  243. BEGIN
  244. IF (dimension < 0) OR (dimension >= dim) THEN HALT( 1001 ); END;
  245. IF (pos1 < origin[dimension]) OR (pos1 >= origin[dimension] + len[dimension]) THEN HALT( 1002 ) END;
  246. IF (pos2 < origin[dimension]) OR (pos2 >= origin[dimension] + len[dimension]) THEN HALT( 1002 ) END;
  247. offset1 := diminc[dimension] * (pos1 - origin[dimension]);
  248. offset2 := diminc[dimension] * (pos2 - origin[dimension]); swaplen := diminc[dimension];
  249. diminclen := diminc[dimension] * len[dimension];
  250. NEW( swapcache, swaplen ); dataadr := ADDRESSOF( swapcache[0] ); stop := baseadr + bytes; srcadr := baseadr;
  251. WHILE (srcadr < stop) DO
  252. Array1dBytes.MoveB( srcadr + offset2, dataadr, swaplen );
  253. Array1dBytes.MoveB( srcadr + offset1, srcadr + offset2, swaplen );
  254. Array1dBytes.MoveB( dataadr, srcadr + offset1, swaplen ); INC( srcadr, diminclen );
  255. END;
  256. END ToggleElements;
  257. (** permute elements in dimension <dimension>, permutation must have length len[dimension] *)
  258. PROCEDURE PermuteElements*( dimension: Index; permutation: ARRAY OF Index );
  259. VAR i, swaplen, diminclen, stop, srcadr, dataadr: LONGINT; swapcache: IndexArray;
  260. BEGIN
  261. (** index checks: *)
  262. IF (dimension < 0) OR (dimension >= dim) THEN HALT( 1001 ); END;
  263. IF LEN( permutation ) # len[dimension] THEN HALT( 1002 ) END;
  264. IF LEN( permutation ) = 1 THEN RETURN END;
  265. WHILE (i < LEN( permutation )) DO
  266. permutation[i] := permutation[i] - origin[dimension];
  267. IF permutation[i] >= LEN( permutation ) THEN HALT( 1003 ) END;
  268. INC( i );
  269. END;
  270. (** computation *)
  271. swaplen := diminc[dimension]; diminclen := diminc[dimension] * len[dimension]; NEW( swapcache, diminclen );
  272. dataadr := ADDRESSOF( swapcache[0] ); stop := baseadr + bytes; srcadr := baseadr;
  273. WHILE (srcadr < stop) DO
  274. i := 0;
  275. WHILE (i < len[dimension]) DO
  276. Array1dBytes.MoveB( srcadr + swaplen * permutation[i], dataadr + swaplen * i, swaplen ); INC( i );
  277. END;
  278. Array1dBytes.MoveB( dataadr, srcadr, diminclen ); INC( srcadr, diminclen );
  279. END;
  280. END PermuteElements;
  281. (** reverse order of elements in dimension <dimension> *)
  282. PROCEDURE MirrorDimension*( dimension: Index );
  283. VAR swaplen, diminclen, srcadr, stop, i, stop2: LONGINT; dataadr: LONGINT; swapcache: IndexArray;
  284. BEGIN
  285. IF (dimension < 0) OR (dimension >= dim) THEN HALT( 1001 ); END;
  286. swaplen := diminc[dimension];
  287. IF dimension < dim - 1 THEN diminclen := diminc[dimension + 1] ELSE diminclen := bytes END;
  288. stop := baseadr + bytes; srcadr := baseadr; stop2 := len[dimension] DIV 2; NEW( swapcache, swaplen );
  289. dataadr := ADDRESSOF( swapcache[0] );
  290. WHILE (srcadr < stop) DO
  291. i := 0;
  292. WHILE (i < stop2) DO
  293. Array1dBytes.MoveB( srcadr + diminclen - (i + 1) * swaplen, dataadr, swaplen );
  294. Array1dBytes.MoveB( srcadr + i * swaplen, srcadr + diminclen - (i + 1) * swaplen, swaplen );
  295. Array1dBytes.MoveB( dataadr, srcadr + i * swaplen, swaplen ); INC( i );
  296. END;
  297. INC( srcadr, diminclen );
  298. END;
  299. END MirrorDimension;
  300. (** copy block of data within dimension <dimension> from <from> to <to> *)
  301. PROCEDURE BlockCopy*( dimension, from, to, length: Index );
  302. VAR swaplen, diminclen, stop: LONGINT;
  303. (*! todo: handle used *)
  304. BEGIN
  305. IF (dimension < 0) OR (dimension >= dim) THEN HALT( 1001 ); END;
  306. from := (from - origin[dimension]); to := (to - origin[dimension]);
  307. IF (from < origin[dimension]) OR (from + length > origin[dimension] + len[dimension]) THEN HALT( 1002 )
  308. END;
  309. IF (to < origin[dimension]) OR (to + length > origin[dimension] + len[dimension]) THEN HALT( 1002 ) END;
  310. IF from = to THEN RETURN
  311. END;
  312. from := from * diminc[dimension]; to := to * diminc[dimension]; swaplen := diminc[dimension] * length;
  313. diminclen := diminc[dimension] * len[dimension];
  314. stop := baseadr + bytes; INC( from, baseadr ); INC( to, baseadr );
  315. WHILE (from < stop) DO Array1dBytes.MoveB( from, to, swaplen ); INC( from, diminclen ); INC( to, diminclen ); END;
  316. END BlockCopy;
  317. (** move block of data within dimension <dimension> from <from> to <to> *)
  318. PROCEDURE BlockMove*( dimension, from, to, length: Index );
  319. VAR swaplen, diminclen, stop: LONGINT; movefrom, moveto, movelen, dataadr: LONGINT; swapcache: IndexArray;
  320. (*! todo: handle used *)
  321. BEGIN
  322. IF (dimension < 0) OR (dimension >= dim) THEN HALT( 1001 ); END;
  323. from := (from - origin[dimension]); to := (to - origin[dimension]);
  324. IF (from < 0) OR (from + length > len[dimension]) THEN HALT( 1002 )
  325. END;
  326. IF (to < 0) OR (to + length > len[dimension]) THEN HALT( 1002 ) END;
  327. IF from = to THEN RETURN
  328. END;
  329. from := from * diminc[dimension]; to := to * diminc[dimension]; swaplen := diminc[dimension] * length;
  330. diminclen := diminc[dimension] * len[dimension];
  331. NEW( swapcache, swaplen ); dataadr := ADDRESSOF( swapcache[0] );
  332. IF from < to THEN movefrom := (from + swaplen); movelen := (to - from); moveto := from;
  333. ELSE (* to < from *)
  334. movefrom := to; movelen := (from - to); moveto := to + swaplen;
  335. END;
  336. stop := baseadr + bytes; INC( from, baseadr ); INC( to, baseadr ); INC( movefrom, baseadr ); INC( moveto, baseadr );
  337. WHILE (from < stop) DO
  338. Array1dBytes.MoveB( from, dataadr, swaplen ); Array1dBytes.MoveB( movefrom, moveto, movelen );
  339. Array1dBytes.MoveB( dataadr, to, swaplen ); INC( from, diminclen ); INC( to, diminclen ); INC( movefrom, diminclen );
  340. INC( moveto, diminclen );
  341. END;
  342. END BlockMove;
  343. PROCEDURE LoadXd*( VAR R: DataIO.Reader );
  344. VAR version, i, size: LONGINT; readRawData: BOOLEAN; readbytes: LONGINT;
  345. BEGIN
  346. R.RawLInt( version ); R.RawLInt( dim ); NEW( len, dim ); NEW( diminc, dim ); NEW( origin, dim ); NEW( permutation, dim );
  347. GetInfo( elementsize ); size := 1;
  348. FOR i := 0 TO dim - 1 DO R.RawLInt( len[i] ); size := size * len[i]; END;
  349. Allocate( size, baseadr, protector ); bytes := size * elementsize;
  350. FOR i := 0 TO dim - 1 DO R.RawLInt( diminc[i] ); END;
  351. (* elementsize already set via GetInfo *)
  352. FOR i := 0 TO dim - 1 DO R.RawLInt( origin[i] ); END;
  353. (* protector set via Allocate *)
  354. FOR i := 0 TO dim - 1 DO R.RawLInt( permutation[i] ); END;
  355. ValidateCache; R.RawSInt( bc ); SetBoundaryCondition( bc );
  356. (* cache variables set via ValidateCache *)
  357. R.RawBool( readRawData );
  358. IF readRawData THEN R.RawLInt( readbytes );
  359. ASSERT ( readbytes = bytes );
  360. ASSERT ( bytes # 0 );
  361. ReadMemory( R, baseadr, bytes, readbytes );
  362. ASSERT ( readbytes = bytes )
  363. END;
  364. END LoadXd;
  365. PROCEDURE StoreXd*( VAR W: DataIO.Writer; storeRawData: BOOLEAN );
  366. CONST version = 0;
  367. VAR i: LONGINT;
  368. BEGIN
  369. W.RawLInt( version );
  370. (* baseadr+bytes set while Allocation *)
  371. W.RawLInt( dim );
  372. FOR i := 0 TO dim - 1 DO W.RawLInt( len[i] ); END;
  373. FOR i := 0 TO dim - 1 DO W.RawLInt( diminc[i] ); END;
  374. (* elementsize set via GetInfo *)
  375. FOR i := 0 TO dim - 1 DO W.RawLInt( origin[i] ); END;
  376. (* protector set via Allocate *)
  377. FOR i := 0 TO dim - 1 DO W.RawLInt( permutation[i] ); END;
  378. (* cache variables set via ValidateCache *)
  379. W.RawSInt( bc ); W.RawBool( storeRawData );
  380. IF storeRawData THEN
  381. ASSERT ( bytes # 0 );
  382. W.RawLInt( bytes ); StoreMemory( W, baseadr, bytes );
  383. END;
  384. END StoreXd;
  385. END Array;
  386. Rectangle = OBJECT
  387. VAR origin, len, destpos, destlen: IndexArray;
  388. next: Rectangle;
  389. END Rectangle;
  390. BoundaryEnum* = OBJECT (* object for enumeration of boundaries of a w.r.t (origin,len), additionally destination*)
  391. VAR root: Rectangle;
  392. PROCEDURE & Init*( a: Array; origin, len: IndexArray );
  393. VAR dim, this: LONGINT; rect: Rectangle; rectorigin, rectlen: IndexArray; i: LONGINT; done: BOOLEAN;
  394. PROCEDURE Min( x, y: Index ): Index;
  395. BEGIN
  396. IF x < y THEN RETURN x ELSE RETURN y END;
  397. END Min;
  398. PROCEDURE Max( x, y: Index ): Index;
  399. BEGIN
  400. IF x > y THEN RETURN x ELSE RETURN y END;
  401. END Max;
  402. PROCEDURE CutLower( VAR outero, outerlen: Index; innero, innerlen: Index ): BOOLEAN;
  403. BEGIN
  404. IF outero < innero THEN INC( outerlen, outero ); outerlen := Min( outerlen, innero ) - outero; RETURN TRUE
  405. ELSE RETURN FALSE
  406. END;
  407. END CutLower;
  408. PROCEDURE CutHigher( VAR outero, outerlen: Index; innero, innerlen: Index ): BOOLEAN;
  409. BEGIN
  410. IF outero + outerlen > innero + innerlen THEN
  411. INC( outerlen, outero ); outero := Max( innero + innerlen, outero ); outerlen := outerlen - outero; RETURN TRUE
  412. ELSE RETURN FALSE
  413. END;
  414. END CutHigher;
  415. BEGIN
  416. dim := LEN( origin );
  417. ASSERT ( dim = a.dim );
  418. ASSERT ( LEN( origin ) = LEN( len ) );
  419. done := FALSE; this := dim - 1;
  420. WHILE (this >= 0) & (~done) DO (* look for largest blocks in highest dimension *)
  421. IF rectlen = NIL THEN NEW( rectorigin, dim ); NEW( rectlen, dim ); END;
  422. FOR i := 0 TO dim - 1 DO rectorigin[i] := origin[i]; rectlen[i] := len[i]; END;
  423. IF CutLower( rectorigin[this], rectlen[this], a.origin[this], a.len[this] ) THEN
  424. INC( origin[this], rectlen[this] ); DEC( len[this], rectlen[this] );
  425. IF len[this] = 0 THEN done := TRUE END;
  426. NEW( rect ); rect.next := root; root := rect; rect.len := rectlen; rect.origin := rectorigin; rectorigin := NIL;
  427. rectlen := NIL;
  428. END;
  429. IF ~done THEN
  430. IF rectlen = NIL THEN NEW( rectorigin, dim ); NEW( rectlen, dim ); END;
  431. FOR i := 0 TO dim - 1 DO rectorigin[i] := origin[i]; rectlen[i] := len[i]; END;
  432. IF CutHigher( rectorigin[this], rectlen[this], a.origin[this], a.len[this] ) THEN
  433. DEC( len[this], rectlen[this] );
  434. IF len[this] = 0 THEN done := TRUE END;
  435. NEW( rect ); rect.next := root; root := rect; rect.len := rectlen; rect.origin := rectorigin; rectorigin := NIL;
  436. rectlen := NIL;
  437. END;
  438. END;
  439. DEC( this );
  440. END;
  441. END Init;
  442. PROCEDURE Get*( VAR origin, len: IndexArray ): BOOLEAN;
  443. BEGIN
  444. IF root # NIL THEN origin := root.origin; len := root.len; root := root.next; RETURN TRUE ELSE RETURN FALSE END;
  445. END Get;
  446. END BoundaryEnum;
  447. (* The in-line assember code works in WinAos, but not in Aos. Why? We don't know yet.
  448. (** store memory to Writer as if it was ARRAY OF CHAR *)
  449. PROCEDURE StoreMemory( W: DataIO.Writer; baseadr: LONGINT; len: LONGINT );
  450. VAR proc: PROCEDURE {DELEGATE} ( VAR x: ARRAY OF CHAR; ofs, len: LONGINT );
  451. PROCEDURE PushAndCall( writer: LONGINT; call: LONGINT; baseadr: LONGINT; len: LONGINT );
  452. CODE {SYSTEM.i386}
  453. PUSH len[EBP] ; array length
  454. PUSH baseadr[EBP] ; array position array[0]
  455. XOR EAX, EAX ;
  456. PUSH EAX ; offset
  457. PUSH len[EBP] ; len
  458. PUSH writer[EBP] ; writer
  459. CALL call[EBP] ; now call W.Bytes
  460. END PushAndCall;
  461. BEGIN
  462. proc := W.Bytes; PushAndCall( SYSTEM.VAL( LONGINT, W ), SYSTEM.VAL( LONGINT, proc ), baseadr, len );
  463. END StoreMemory;
  464. (** read memory from reader as if it was ARRAY OF CHAR *)
  465. PROCEDURE ReadMemory( R: DataIO.Reader; baseadr: LONGINT; size: LONGINT; VAR len: LONGINT );
  466. VAR proc: PROCEDURE {DELEGATE} ( VAR x: ARRAY OF CHAR; ofs, size: LONGINT; VAR len: LONGINT );
  467. PROCEDURE PushAndCall( reader: LONGINT; call: LONGINT; baseadr: LONGINT; size: LONGINT; lenadr: LONGINT );
  468. CODE {SYSTEM.i386}
  469. PUSH len[EBP] ;
  470. PUSH baseadr[EBP]
  471. XOR EAX, EAX
  472. PUSH EAX
  473. PUSH size[EBP]
  474. PUSH lenadr[EBP]
  475. PUSH reader[EBP]
  476. CALL call[EBP]
  477. END PushAndCall;
  478. BEGIN
  479. proc := R.Bytes; PushAndCall( SYSTEM.VAL( LONGINT, R ), SYSTEM.VAL( LONGINT, proc ), baseadr, size, ADDRESSOF( len ) );
  480. END ReadMemory;
  481. *)
  482. (** oberon versions of Store and Read Memory: *)
  483. PROCEDURE StoreMemory( W: DataIO.Writer; baseadr: LONGINT; len: LONGINT ); (* store memory to Writer *)
  484. VAR adr: LONGINT; char: CHAR;
  485. BEGIN
  486. adr := baseadr; INC( len, baseadr );
  487. WHILE (adr < len) DO SYSTEM.GET( adr, char ); W.Char( char ); INC( adr ); END;
  488. END StoreMemory;
  489. PROCEDURE ReadMemory( R: DataIO.Reader; baseadr: LONGINT; size: LONGINT; VAR len: LONGINT ); (* read memory from reader *)
  490. VAR adr: LONGINT; char: CHAR;
  491. BEGIN
  492. adr := baseadr; INC( size, baseadr ); len := 0;
  493. WHILE (adr < size) DO R.Char( char ); SYSTEM.PUT( adr, char ); INC( adr ); INC( len ); END;
  494. END ReadMemory;
  495. (** helper procedures , should be in-lined some time*)
  496. PROCEDURE CheckIndexArray( dim: Index; VAR a: IndexArray );
  497. BEGIN
  498. IF (a = NIL ) OR (LEN( a ) # dim) THEN NEW( a, dim ) END;
  499. END CheckIndexArray;
  500. PROCEDURE CopyIndexArray( src: ARRAY OF Index; dest: IndexArray );
  501. VAR i: LONGINT;
  502. BEGIN
  503. i := 0;
  504. WHILE (i < LEN( dest )) DO dest[i] := src[i]; INC( i ); END;
  505. END CopyIndexArray;
  506. PROCEDURE Intersect*( org1, len1, org2, len2: IndexArray; VAR org, len: IndexArray ): BOOLEAN;
  507. VAR i, dim: LONGINT; o1, o2, l1, l2: LONGINT;
  508. BEGIN
  509. IF (LEN( org1 ) # LEN( len1 )) OR (LEN( org2 ) # LEN( len2 )) THEN HALT( 1000 ) END;
  510. dim := MIN( LEN( org1 ), LEN( org2 ) ); NEW( org, dim ); NEW( len, dim ); i := 0;
  511. (*dbgSISISI("Intersection, from dims ",LEN(org1)," & ",LEN(org2)," to ",dim); *)
  512. WHILE (i < dim) DO
  513. o1 := org1[i]; o2 := org2[i]; l1 := len1[i] + o1; l2 := len2[i] + o2;
  514. IF o1 > o2 THEN org[i] := o1 ELSE org[i] := o2 END;
  515. IF l1 < l2 THEN len[i] := l1 - org[i] ELSE len[i] := l2 - org[i] END;
  516. IF len[i] <= 0 THEN RETURN FALSE END;
  517. (*
  518. dbgSISISI("o1=",o1," o2=",o2," o=",org[i]);
  519. dbgSISISI("l1= ",len1[i]," l2= ",len2[i]," l=",len[i]);
  520. *)
  521. INC( i );
  522. END;
  523. RETURN TRUE;
  524. END Intersect;
  525. PROCEDURE -CheckLEQ*( lesseq, than: LONGINT );
  526. (* invoke trap INDEX OUT OF RANGE if lesseq > than *)
  527. CODE {SYSTEM.i386}
  528. MOV ECX, [ESP] ; than
  529. MOV EBX, [ESP+4] ; less
  530. CMP EBX, ECX
  531. JLE ok
  532. PUSH 7
  533. INT 3
  534. ok:
  535. ADD ESP, 8
  536. END CheckLEQ;
  537. PROCEDURE -CheckLE*( lesseq, than: LONGINT );
  538. (* invoke trap INDEX OUT OF RANGE if lesseq > than *)
  539. CODE {SYSTEM.i386}
  540. MOV ECX, [ESP] ; than
  541. MOV EBX, [ESP+4] ; less
  542. CMP EBX, ECX
  543. JL ok
  544. PUSH 7
  545. INT 3
  546. ok:
  547. ADD ESP, 8
  548. END CheckLE;
  549. PROCEDURE -CheckEQ*( equals, this: LONGINT );
  550. (* invoke trap INDEX OUT OF RANGE if equals # this *)
  551. (*
  552. Oberon code for CheckEQ:
  553. PROCEDURE CheckEQ*(lesseq,than: LONGINT)
  554. BEGIN IF this=equals THEN HALT(100) (* in asm: invoke trap INDEX OUT OF RANGE *) END; END CheckEQ;
  555. *)
  556. CODE {SYSTEM.i386}
  557. MOV ECX, [ESP] ; this
  558. MOV EBX, [ESP+4] ; equals
  559. CMP EBX, ECX
  560. JE ok
  561. PUSH 7
  562. INT 3
  563. ok:
  564. ADD ESP, 8
  565. END CheckEQ;
  566. (** chck permutation for validity, precondition: permutation has less than 2^31 entries since bit 31 is used for marking *)
  567. PROCEDURE CheckPermutation( dim: LONGINT; VAR permutation: ARRAY OF LONGINT ): BOOLEAN;
  568. VAR i, j: LONGINT; valid: BOOLEAN; set: SET;
  569. BEGIN
  570. IF LEN( permutation ) # dim THEN RETURN FALSE END;
  571. i := 0;
  572. WHILE (i < dim) DO
  573. j := SYSTEM.VAL( LONGINT, SYSTEM.VAL( SET, permutation[i] ) - {31} ); INCL( SYSTEM.VAL( SET, permutation[j] ), 31 ); INC( i );
  574. END;
  575. i := 0; valid := TRUE;
  576. WHILE (i < dim) DO
  577. set := SYSTEM.VAL( SET, permutation[i] );
  578. IF 31 IN set THEN EXCL( set, 31 ) ELSE valid := FALSE END;
  579. permutation[i] := SYSTEM.VAL( LONGINT, set ); INC( i );
  580. END;
  581. RETURN valid;
  582. END CheckPermutation;
  583. (** make a valid permutation from firstpart of permutation, i.e. extend to len LEN(permutation) and check for validity
  584. example: beginning = (3,4), full = (1,2,3,4,5) -> full = (3,4,1,2,5)
  585. *)
  586. PROCEDURE CompletePermutation( beginning: ARRAY OF LONGINT; full: ARRAY OF LONGINT ): BOOLEAN;
  587. VAR srcdim, destdim, i, j, val, this, next: LONGINT;
  588. BEGIN
  589. srcdim := LEN( beginning ); destdim := LEN( full );
  590. IF srcdim > destdim THEN HALT( 100 ) END;
  591. i := 0;
  592. WHILE (i < destdim) DO full[i] := i; INC( i ); END;
  593. i := 0;
  594. WHILE (i < srcdim) DO (* check and insert, when possible *)
  595. val := beginning[i]; j := i; this := full[i]; full[i] := val;
  596. WHILE (j < destdim - 1) & (this # val) DO (* search *)
  597. INC( j ); next := full[j]; full[j] := this; this := next;
  598. END;
  599. IF (j = destdim - 1) & (this # val) THEN (* value not found in rest, i.e. no valid permutation ! *)
  600. RETURN FALSE;
  601. END;
  602. INC( i );
  603. END;
  604. RETURN TRUE;
  605. END CompletePermutation;
  606. PROCEDURE ApplyPermutation( permutation: ARRAY OF Index; VAR array: ARRAY OF Index );
  607. VAR i, dim: LONGINT;
  608. BEGIN
  609. dim := LEN( permutation ); i := 0;
  610. WHILE (i < dim) DO permutation[i] := array[permutation[i]]; INC( i ); END;
  611. i := 0;
  612. WHILE (i < dim) DO array[i] := permutation[i]; INC( i ); END;
  613. END ApplyPermutation;
  614. PROCEDURE IdentityPermutation( dim: LONGINT ): IndexArray;
  615. VAR a: IndexArray; i: LONGINT;
  616. BEGIN
  617. NEW( a, dim ); i := 0;
  618. WHILE (i < dim) DO a[i] := i; INC( i ); END;
  619. RETURN a;
  620. END IdentityPermutation;
  621. PROCEDURE ComputeIncrease( len: IndexArray; permutation: IndexArray; elementsize: LONGINT; diminc: IndexArray );
  622. VAR i: LONGINT;
  623. BEGIN
  624. IF permutation # NIL THEN
  625. i := 1; diminc[permutation[0]] := elementsize;
  626. WHILE (i < LEN( len )) DO diminc[permutation[i]] := diminc[permutation[i - 1]] * len[permutation[i - 1]]; INC( i ); END;
  627. ELSE
  628. i := 1; diminc[0] := elementsize;
  629. WHILE (i < LEN( len )) DO diminc[i] := diminc[i - 1] * len[i - 1]; INC( i ); END;
  630. END;
  631. END ComputeIncrease;
  632. (*
  633. (** shallow copy: any field of ArrayMemoryStructure is copied shallow *)
  634. PROCEDURE AMSCopyShallow( src: ArrayMemoryStructure; dest: ArrayMemoryStructure );
  635. BEGIN
  636. dest^ := src^;
  637. END AMSCopyShallow;
  638. *)
  639. (** description copy: fields of ArrayMemoryStructure are copied deep but not data *)
  640. PROCEDURE AMSCopyDescr( src: ArrayMemoryStructure; dest: ArrayMemoryStructure );
  641. BEGIN
  642. dest^ := src^; NEW( dest.len, src.dim ); CopyIndexArray( src.len^, dest.len ); NEW( dest.diminc, src.dim );
  643. CopyIndexArray( src.diminc^, dest.diminc ); NEW( dest.origin, src.dim ); CopyIndexArray( src.origin^, dest.origin );
  644. END AMSCopyDescr;
  645. PROCEDURE EnumArrayPart( mem: ArrayMemoryStructure; pos, len: IndexArray; chunks: BOOLEAN ): Enumerator;
  646. VAR enum: Enumerator; i: LONGINT; check: BOOLEAN;
  647. BEGIN
  648. check := FALSE;
  649. IF pos = NIL THEN pos := mem.origin ELSE check := TRUE; END;
  650. IF len = NIL THEN len := mem.len ELSE check := TRUE; END;
  651. (* consistency check *)
  652. IF check THEN
  653. IF (LEN( pos ) # mem.dim) OR (LEN( len ) # mem.dim) THEN HALT( 1000 ) END;
  654. i := 0;
  655. WHILE (i < mem.dim) DO
  656. IF (pos[i] < mem.origin[i]) OR (pos[i] + len[i] > mem.origin[i] + mem.len[i]) THEN HALT( 1001 ) END;
  657. INC( i );
  658. END;
  659. END;
  660. NEW( enum, mem, pos, len, chunks ); RETURN enum;
  661. END EnumArrayPart;
  662. (*
  663. (* included in EnumArrayPart with: pos=NIL,len=NIL but slightly faster: *)
  664. PROCEDURE EnumArray( mem: ArrayMemoryStructure; chunks: BOOLEAN ): Enumerator;
  665. VAR enum: Enumerator;
  666. BEGIN
  667. NEW( enum, mem, mem.origin, mem.len, chunks ); RETURN enum;
  668. END EnumArray;
  669. *)
  670. (** Traverse memory elementwise with a function proc, proc must be the adress of a PROCEDURE (VAR l: (elementtype) );
  671. example with basic type LONGREAL: TraverseMemory(ADDRESSOF(p),mem); with p := PROCEDURE (VAR l: LONGREAL); *)
  672. PROCEDURE TraverseMemory*( proc: Address; mem: ArrayMemoryStructure );
  673. VAR enum: Enumerator; len, diminclen, adr: LONGINT;
  674. PROCEDURE PushAdrAndCall( adr: LONGINT; calladr: LONGINT );
  675. CODE {SYSTEM.i386}
  676. PUSH [EBP+adr] ;
  677. CALL [EBP+calladr] ;
  678. ADD ESP, 4
  679. END PushAdrAndCall;
  680. BEGIN
  681. enum := EnumArrayPart( mem, NIL , NIL , FALSE ); diminclen := mem.elementsize;
  682. REPEAT
  683. len := enum.size; adr := enum.adr;
  684. WHILE (len > 0) DO PushAdrAndCall( adr, proc ); DEC( len, diminclen ); INC( adr, diminclen ); END;
  685. UNTIL ~enum.Next();
  686. END TraverseMemory;
  687. (** Traverse memory elementwise with a function proc, proc must be the adress of a PROCEDURE (VAR l,r: (elementtype) );
  688. example with basic type LONGREAL; TraverseMemory(ADDRESSOF(p),left,right); with p := PROCEDURE (VAR l,r: LONGREAL); *)
  689. PROCEDURE TraverseMemory2*( proc: Address; srcmem, destmem: ArrayMemoryStructure );
  690. VAR src, dest: Enumerator;
  691. PROCEDURE PushAdrAndCall2( src, dest: LONGINT; calladr: LONGINT );
  692. CODE {SYSTEM.i386}
  693. PUSH [EBP+src] ;
  694. PUSH [EBP+dest]
  695. CALL [EBP+calladr] ;
  696. ADD ESP, 8
  697. END PushAdrAndCall2;
  698. BEGIN
  699. ASSERT ( srcmem.elementsize = destmem.elementsize );
  700. src := EnumArrayPart( srcmem, NIL , NIL , FALSE ); dest := EnumArrayPart( destmem, NIL , NIL , FALSE );
  701. REPEAT PushAdrAndCall2( src.adr, dest.adr, proc ); UNTIL ~(src.Next() & dest.Next());
  702. END TraverseMemory2;
  703. (** Traverse memory elementwise with a function proc, proc must be the adress of a PROCEDURE (VAR l,r: (elementtype) );
  704. example with basic type LONGREAL; TraverseMemory(ADDRESSOF(p),left,right,dest); with p := PROCEDURE (VAR l,r,d: LONGREAL); *)
  705. PROCEDURE TraverseMemory3*( proc: Address; leftmem, rightmem, destmem: ArrayMemoryStructure );
  706. VAR left, right, dest: Enumerator;
  707. PROCEDURE PushAdrAndCall3( left, right, dest: LONGINT; calladr: LONGINT );
  708. CODE {SYSTEM.i386}
  709. PUSH [EBP+left] ;
  710. PUSH [EBP+right] ;
  711. PUSH [EBP+dest] ;
  712. CALL [EBP+calladr] ;
  713. ADD ESP, 12
  714. END PushAdrAndCall3;
  715. BEGIN
  716. ASSERT ( leftmem.elementsize = rightmem.elementsize );
  717. ASSERT ( rightmem.elementsize = destmem.elementsize );
  718. left := EnumArrayPart( leftmem, NIL , NIL , FALSE ); right := EnumArrayPart( rightmem, NIL , NIL , FALSE );
  719. dest := EnumArrayPart( destmem, NIL , NIL , FALSE );
  720. REPEAT PushAdrAndCall3( left.adr, right.adr, dest.adr, proc ); UNTIL ~(left.Next() & right.Next() & dest.Next());
  721. END TraverseMemory3;
  722. PROCEDURE TraverseAndCopy( src, dest: Enumerator );
  723. VAR srcdiminclen, destdiminclen, diminclen, srcadr, destadr: LONGINT;
  724. BEGIN
  725. srcadr := src.adr; destadr := dest.adr; srcdiminclen := src.size; destdiminclen := dest.size;
  726. IF (srcdiminclen < destdiminclen) THEN diminclen := srcdiminclen ELSE diminclen := destdiminclen END;
  727. REPEAT
  728. IF debug THEN dbgSISISI( "Traverse and copy: ", srcadr, ",", destadr, ",", diminclen ); END;
  729. SYSTEM.MOVE( srcadr, destadr, diminclen ); DEC( srcdiminclen, diminclen ); DEC( destdiminclen, diminclen );
  730. INC( srcadr, diminclen ); INC( destadr, diminclen );
  731. IF srcdiminclen = 0 THEN
  732. IF src.Next() THEN srcdiminclen := src.size; srcadr := src.adr END;
  733. END;
  734. IF destdiminclen = 0 THEN
  735. IF dest.Next() THEN destdiminclen := dest.size; destadr := dest.adr END;
  736. END;
  737. UNTIL (srcdiminclen = 0) OR (destdiminclen = 0);
  738. IF (srcdiminclen # 0) OR (destdiminclen # 0) THEN
  739. dbgS( "WARNING: Traverse and Copy: DIFFERENT SIZES " );
  740. IF debug THEN HALT( 1003 ) END;
  741. END;
  742. END TraverseAndCopy;
  743. (** copy procedure, copies data from srcmem to destmem going through src and dest elementwise.
  744. This procedure does NOT check for same dimensions and does NOT observe limits in each dimension but it respects global limits
  745. example: copying two dimensional 3x2-Matrix to one dimensional vector with length 5 yields:
  746. a[0,0] -> v[0], a[0,1] -> v[1], a[1,0] -> v[2], a[1,1] -> v[3], a[2,0] -> v[4]
  747. *)
  748. PROCEDURE CopyDataByCoordinateTraversal*( srcmem, destmem: ArrayMemoryStructure );
  749. VAR src, dest: Enumerator;
  750. BEGIN
  751. IF srcmem.elementsize # destmem.elementsize THEN HALT( 100 ) END;
  752. src := EnumArrayPart( srcmem, NIL , NIL , TRUE ); dest := EnumArrayPart( destmem, NIL , NIL , TRUE );
  753. TraverseAndCopy( src, dest );
  754. END CopyDataByCoordinateTraversal;
  755. PROCEDURE CopyDataRaw*( srcmem, destmem: ArrayMemoryStructure );
  756. VAR len: LONGINT;
  757. BEGIN
  758. len := MIN( srcmem.bytes, destmem.bytes ); SYSTEM.MOVE( srcmem.baseadr, destmem.baseadr, len );
  759. END CopyDataRaw;
  760. PROCEDURE CopyDataPositionPreserving*( srcmem, destmem: ArrayMemoryStructure );
  761. VAR pos, len: IndexArray; src, dest: Enumerator;
  762. BEGIN
  763. IF Intersect( srcmem.origin, srcmem.len, destmem.origin, destmem.len, pos, len ) THEN
  764. src := EnumArrayPart( srcmem, pos, len, TRUE ); dest := EnumArrayPart( destmem, pos, len, TRUE );
  765. TraverseAndCopy( src, dest );
  766. END;
  767. END CopyDataPositionPreserving;
  768. PROCEDURE MakeMemoryStructure*( dim: LONGINT; origin, len: IndexArray; elementsize: Index;
  769. baseadr: Address ): ArrayMemoryStructure;
  770. VAR memory: ArrayMemoryStructure;
  771. BEGIN
  772. NEW( memory ); memory.dim := dim; NEW( memory.len, dim ); NEW( memory.diminc, dim ); NEW( memory.origin, dim );
  773. memory.elementsize := elementsize; memory.baseadr := baseadr; memory.adrwoffset := baseadr;
  774. Array1dBytes.MoveB( ADDRESSOF( len[0] ), ADDRESSOF( memory.len[0] ), SIZEOF( LONGINT ) * dim );
  775. Array1dBytes.MoveB( ADDRESSOF( origin[0] ), ADDRESSOF( memory.origin[0] ), SIZEOF( LONGINT ) * dim );
  776. ComputeIncrease( memory.len, NIL , elementsize, memory.diminc );
  777. (* (* bug fixed in Vs 1.1 *) (** check: *)
  778. i := 0; uadr := 0;
  779. WHILE (i < dim) DO INC( uadr, (memory.len[i] - 1) * memory.diminc[i] ); INC( i ); END;
  780. memory.bytes := uadr; *)
  781. memory.bytes := memory.diminc[dim - 1] * memory.len[dim - 1]; RETURN memory;
  782. END MakeMemoryStructure;
  783. PROCEDURE MakeContinuousMemStruct*( adr, elements, elementsize: LONGINT; VAR memory: ArrayMemoryStructure );
  784. BEGIN
  785. IF memory = NIL THEN NEW( memory ) END;
  786. IF memory.dim # 1 THEN memory.dim := 1; NEW( memory.len, 1 ); NEW( memory.diminc, 1 ); NEW( memory.origin, 1 ); END;
  787. memory.len[0] := elements; memory.diminc[0] := elementsize; memory.origin[0] := 0;
  788. memory.elementsize := elementsize; memory.bytes := elements * elementsize; memory.baseadr := adr;
  789. END MakeContinuousMemStruct;
  790. PROCEDURE CheckEqDimensions*( l, r: Array );
  791. (*! optimzie -> inline: *)
  792. VAR i: LONGINT;
  793. BEGIN
  794. CheckEQ( l.dim, r.dim ); CheckEQ( l.elementsize, r.elementsize );
  795. FOR i := 0 TO l.dim - 1 DO CheckEQ( l.len[i], r.len[i] ); CheckEQ( l.origin[i], r.origin[i] ); END;
  796. END CheckEqDimensions;
  797. PROCEDURE ToggleDimensions*( a: Array; d1, d2: LONGINT; rearrangeMemory: BOOLEAN );
  798. VAR permutation: IndexArray;
  799. BEGIN
  800. permutation := IdentityPermutation( a.dim ); permutation[d1] := d2; permutation[d2] := d1;
  801. a.PermuteDimensions( permutation, rearrangeMemory );
  802. END ToggleDimensions;
  803. PROCEDURE dbgS( s: ARRAY OF CHAR );
  804. BEGIN
  805. dbgOut.String( s ); dbgOut.Ln;
  806. END dbgS;
  807. PROCEDURE dbgSI( s: ARRAY OF CHAR; i: LONGINT );
  808. BEGIN
  809. dbgOut.String( s ); dbgOut.Int( i, 10 ); dbgOut.Ln;
  810. END dbgSI;
  811. PROCEDURE dbgSISI( s: ARRAY OF CHAR; i: LONGINT; s2: ARRAY OF CHAR; i2: LONGINT );
  812. BEGIN
  813. dbgOut.String( s ); dbgOut.Int( i, 1 ); dbgOut.String( s2 ); dbgOut.Int( i2, 1 ); dbgOut.Ln;
  814. END dbgSISI;
  815. PROCEDURE dbgSISISI( s: ARRAY OF CHAR; i: LONGINT; s2: ARRAY OF CHAR; i2: LONGINT; s3: ARRAY OF CHAR; i3: LONGINT );
  816. BEGIN
  817. dbgOut.String( s ); dbgOut.Int( i, 1 ); dbgOut.String( s2 ); dbgOut.Int( i2, 1 ); dbgOut.String( s3 );
  818. dbgOut.Int( i3, 1 ); dbgOut.Ln;
  819. END dbgSISISI;
  820. PROCEDURE dbgWriteMemoryInfo*( a: ArrayMemoryStructure );
  821. VAR i: LONGINT;
  822. BEGIN
  823. dbgS( "---------------------------------" ); dbgS( "DebugInfo for ArrayXdBytes.Array: " ); dbgSISI( "Array with dimension", a.dim, " and elementsize: ", a.elementsize ); dbgSISI( "Adress:", a.baseadr, "; bytes used:", a.bytes ); dbgSI( "Adr with offset:", a.adrwoffset );
  824. FOR i := 0 TO a.dim - 1 DO dbgS( "----------" ); dbgSI( "Index: ", i ); dbgSISISI( "origin= ", a.origin[i], ",len=", a.len[i], "diminc= ", a.diminc[i] ); END;
  825. IF a IS Array THEN
  826. WITH a: Array DO dbgS( "----------" ); dbgSISI( "f0=", a.f0, "; f1=", a.f1 ); dbgSISI( "f2=", a.f2, "; f3=", a.f3 );
  827. END;
  828. END;
  829. dbgS( "---------------------------------" );
  830. END dbgWriteMemoryInfo;
  831. PROCEDURE Adr1*( a: Array; x: Index ): Index;
  832. (*! optimzie -> inline: *)
  833. VAR adr: Index;
  834. BEGIN
  835. adr := a.adrwoffset + x * a.f0; Array1dBytes.AdrCheck( adr, a.baseadr, a.bytes ); RETURN adr;
  836. END Adr1;
  837. PROCEDURE Adr2*( a: Array; x, y: Index ): Index;
  838. (*! optimzie -> inline: *)
  839. VAR adr: Index;
  840. BEGIN
  841. adr := a.adrwoffset + x * a.f0 + y * a.f1; Array1dBytes.AdrCheck( adr, a.baseadr, a.bytes ); RETURN adr;
  842. END Adr2;
  843. PROCEDURE Adr3*( a: Array; x, y, z: Index ): Index;
  844. (*! optimzie -> inline: *)
  845. VAR adr: Index;
  846. BEGIN
  847. adr := a.adrwoffset + x * a.f0 + y * a.f1 + z * a.f2; Array1dBytes.AdrCheck( adr, a.baseadr, a.bytes ); RETURN adr;
  848. END Adr3;
  849. PROCEDURE Adr4*( a: Array; x, y, z, t: Index ): Index;
  850. (*! optimzie -> inline: *)
  851. VAR adr: Index;
  852. BEGIN
  853. adr := a.adrwoffset + x * a.f0 + y * a.f1 + z * a.f2 + t * a.f3; Array1dBytes.AdrCheck( adr, a.baseadr, a.bytes );
  854. RETURN adr;
  855. END Adr4;
  856. PROCEDURE AdrX*( a: ArrayMemoryStructure; VAR b: ARRAY OF Index; dim: Index ): Index;
  857. (*! optimzie -> inline: *)
  858. VAR adr, i: Index;
  859. BEGIN
  860. CheckLEQ( dim, a.dim ); adr := a.adrwoffset; i := 0;
  861. WHILE (i < dim) DO adr := adr + a.diminc[i] * b[i]; (* a.IncUsage( i, b[i] + 1 ); *) INC( i ); END;
  862. Array1dBytes.AdrCheck( adr, a.baseadr, a.bytes ); RETURN adr;
  863. END AdrX;
  864. (*
  865. fof 080728: open array return value not allowed any more
  866. PROCEDURE Array1*( x: LONGINT ): ARRAY OF LONGINT;
  867. (*! optimzie -> inline: *)
  868. VAR index: IndexArray;
  869. BEGIN
  870. NEW( index, 1 ); index[0] := x; RETURN index^;
  871. END Array1;
  872. *)
  873. PROCEDURE Index1*( x: LONGINT ): IndexArray;
  874. (*! optimzie -> inline: *)
  875. VAR index: IndexArray;
  876. BEGIN
  877. NEW( index, 1 ); index[0] := x; RETURN index;
  878. END Index1;
  879. PROCEDURE Array1*( x: LONGINT ): IndexArray;
  880. (*! optimzie -> inline: *)
  881. VAR index: IndexArray;
  882. BEGIN
  883. NEW( index, 1 ); index[0] := x; RETURN index;
  884. END Array1;
  885. (*
  886. fof 080728: open array return value not allowed any more PROCEDURE Array2*( x, y: LONGINT ): ARRAY OF LONGINT;
  887. (*! optimzie -> inline: *)
  888. VAR index: IndexArray;
  889. BEGIN
  890. NEW( index, 2 ); index[0] := x; index[1] := y; RETURN index^
  891. END Array2;
  892. *)
  893. PROCEDURE Index2*( x, y: LONGINT ): IndexArray;
  894. (*! optimzie -> inline: *)
  895. VAR index: IndexArray;
  896. BEGIN
  897. NEW( index, 2 ); index[0] := x; index[1] := y; RETURN index
  898. END Index2;
  899. PROCEDURE Array2*( x, y: LONGINT ): IndexArray;
  900. (*! optimzie -> inline: *)
  901. VAR index: IndexArray;
  902. BEGIN
  903. NEW( index, 2 ); index[0] := x; index[1] := y; RETURN index
  904. END Array2;
  905. (*
  906. fof 080728: open array return value not allowed any more PROCEDURE Array3*( x, y, z: LONGINT ): ARRAY OF LONGINT;
  907. (*! optimzie -> inline: *)
  908. VAR index: IndexArray;
  909. BEGIN
  910. NEW( index, 3 ); index[0] := x; index[1] := y; index[2] := z; RETURN index^;
  911. END Array3;
  912. *)
  913. PROCEDURE Array3*( x, y, z: LONGINT ): IndexArray;
  914. (*! optimzie -> inline: *)
  915. VAR index: IndexArray;
  916. BEGIN
  917. NEW( index, 3 ); index[0] := x; index[1] := y; index[2] := z; RETURN index;
  918. END Array3;
  919. PROCEDURE Index3*( x, y, z: LONGINT ): IndexArray;
  920. (*! optimzie -> inline: *)
  921. VAR index: IndexArray;
  922. BEGIN
  923. NEW( index, 3 ); index[0] := x; index[1] := y; index[2] := z; RETURN index;
  924. END Index3;
  925. (*
  926. fof 080728: open array return value not allowed any more
  927. PROCEDURE Array4*( x, y, z, t: LONGINT ): ARRAY OF LONGINT;
  928. (*! optimzie -> inline: *)
  929. VAR index: IndexArray;
  930. BEGIN
  931. NEW( index, 4 ); index[0] := x; index[1] := y; index[2] := z; index[3] := t; RETURN index^;
  932. END Array4;
  933. *)
  934. PROCEDURE Index4*( x, y, z, t: LONGINT ): IndexArray;
  935. (*! optimzie -> inline: *)
  936. VAR index: IndexArray;
  937. BEGIN
  938. NEW( index, 4 ); index[0] := x; index[1] := y; index[2] := z; index[3] := t; RETURN index;
  939. END Index4;
  940. PROCEDURE Array4*( x, y, z, t: LONGINT ): IndexArray;
  941. (*! optimzie -> inline: *)
  942. VAR index: IndexArray;
  943. BEGIN
  944. NEW( index, 4 ); index[0] := x; index[1] := y; index[2] := z; index[3] := t; RETURN index;
  945. END Array4;
  946. PROCEDURE IndexX*( VAR a: ARRAY OF LONGINT ): IndexArray;
  947. VAR index: IndexArray;
  948. BEGIN
  949. NEW( index, LEN( a ) ); SYSTEM.MOVE( ADDRESSOF( a[0] ), ADDRESSOF( index[0] ), LEN( a ) * SIZEOF( LONGINT ) ); RETURN index;
  950. END IndexX;
  951. PROCEDURE IndexCpy*( src: IndexArray ): IndexArray;
  952. VAR dest: IndexArray; i: LONGINT;
  953. BEGIN
  954. NEW( dest, LEN( src ) ); i := 0;
  955. WHILE (i < LEN( dest )) DO dest[i] := src[i]; INC( i ); END;
  956. RETURN dest;
  957. END IndexCpy;
  958. PROCEDURE Get1*( a: Array; x: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  959. (*! optimzie -> inline: *)
  960. BEGIN
  961. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  962. SYSTEM.MOVE( Adr1( a, x ), ADDRESSOF( v ), a.elementsize );
  963. END Get1;
  964. PROCEDURE Get2*( a: Array; x, y: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  965. (*! optimzie -> inline: *)
  966. BEGIN
  967. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  968. SYSTEM.MOVE( Adr2( a, x, y ), ADDRESSOF( v ), a.elementsize );
  969. END Get2;
  970. PROCEDURE Get3*( a: Array; x, y, z: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  971. (*! optimzie -> inline: *)
  972. BEGIN
  973. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  974. SYSTEM.MOVE( Adr3( a, x, y, z ), ADDRESSOF( v ), a.elementsize );
  975. END Get3;
  976. PROCEDURE Get4*( a: Array; x, y, z, t: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  977. (*! optimzie -> inline: *)
  978. BEGIN
  979. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  980. SYSTEM.MOVE( Adr4( a, x, y, z, t ), ADDRESSOF( v ), a.elementsize );
  981. END Get4;
  982. PROCEDURE GetX*( a: Array; VAR b: ARRAY OF Index; dim: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  983. (*! optimzie -> inline: *)
  984. BEGIN
  985. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  986. (* dimension is checked in AdrX *)
  987. SYSTEM.MOVE( AdrX( a, b, dim ), ADDRESSOF( v ), a.elementsize );
  988. END GetX;
  989. PROCEDURE Set1*( a: Array; x: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  990. (*! optimzie -> inline: *)
  991. BEGIN
  992. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  993. SYSTEM.MOVE( ADDRESSOF( v ), Adr1( a, x ), a.elementsize );
  994. END Set1;
  995. PROCEDURE Set2*( a: Array; x, y: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  996. (*! optimzie -> inline: *)
  997. BEGIN
  998. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  999. SYSTEM.MOVE( ADDRESSOF( v ), Adr2( a, x, y ), a.elementsize );
  1000. END Set2;
  1001. PROCEDURE Set3*( a: Array; x, y, z: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  1002. (*! optimzie -> inline: *)
  1003. BEGIN
  1004. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  1005. SYSTEM.MOVE( ADDRESSOF( v ), Adr3( a, x, y, z ), a.elementsize );
  1006. END Set3;
  1007. PROCEDURE Set4*( a: Array; x, y, z, t: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  1008. (*! optimzie -> inline: *)
  1009. BEGIN
  1010. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  1011. SYSTEM.MOVE( ADDRESSOF( v ), Adr4( a, x, y, z, t ), a.elementsize );
  1012. END Set4;
  1013. PROCEDURE SetX*( a: Array; VAR b: ARRAY OF Index; dim: Index; VAR v: ARRAY OF SYSTEM.BYTE );
  1014. (*! optimzie -> inline: *)
  1015. BEGIN
  1016. IF LEN( v ) # a.elementsize THEN HALT( 100 ) END;
  1017. SYSTEM.MOVE( ADDRESSOF( v ), AdrX( a, b, dim ), a.elementsize );
  1018. END SetX;
  1019. (*
  1020. PROCEDURE SubArrayMemoryStructure*( a: Array; pos: ARRAY OF Index; dims, len: ARRAY OF Index; VAR memory: ArrayMemoryStructure );
  1021. (* dimension of Memory LEN(origin)=LEN(len) *)
  1022. VAR dim, i, thisdim: LONGINT;
  1023. BEGIN
  1024. dim := LEN( dims );
  1025. IF (dim # LEN( len )) THEN HALT( 100 ) END;
  1026. IF (LEN( pos ) # a.dim) THEN HALT( 101 ) END;
  1027. CheckLEQ( dim, a.dim );
  1028. WHILE (i < dim) DO thisdim := dims[i]; dims[i] := a.diminc[thisdim]; INC( i ); END;
  1029. MakeMemoryStructure( dim, len, dims, AdrX( a, pos, a.dim ), a.baseadr + a.bytes, a.elementsize, memory );
  1030. END SubArrayMemoryStructure;
  1031. *)
  1032. (** copy part of one array to another, may also be used to extract dimensions from array a to b,
  1033. example: a= 3x4 matrix , v= vector with len 10
  1034. CopyArrayParts(a,v,(1,1),(1,4),(2),(4)) copies elements 1-4 of column 1 to vector beginning at position 2 *)
  1035. PROCEDURE CopyArrayPartToArrayPart*( srcmem, destmem: ArrayMemoryStructure;
  1036. srcpos, srclen, destpos, destlen: IndexArray );
  1037. VAR src, dest: Enumerator;
  1038. BEGIN
  1039. src := EnumArrayPart( srcmem, srcpos, srclen, TRUE ); dest := EnumArrayPart( destmem, destpos, destlen, TRUE );
  1040. TraverseAndCopy( src, dest );
  1041. END CopyArrayPartToArrayPart;
  1042. PROCEDURE FillArrayPart*( mem: ArrayMemoryStructure; pos, len: IndexArray; val: ARRAY OF SYSTEM.BYTE );
  1043. VAR src: Enumerator; nrElems: LONGINT;
  1044. BEGIN
  1045. IF LEN( val ) # mem.elementsize THEN HALT( 1001 ) END;
  1046. src := EnumArrayPart( mem, pos, len, TRUE ); nrElems := src.size DIV mem.elementsize;
  1047. REPEAT Array1dBytes.Fill( src.adr, val, nrElems ); UNTIL ~src.Next();
  1048. END FillArrayPart;
  1049. PROCEDURE CopyArrayToMemory*( srcmem: ArrayMemoryStructure; destadr: Index; nrelems: Index );
  1050. VAR destmem: ArrayMemoryStructure;
  1051. BEGIN
  1052. IF nrelems * srcmem.elementsize > srcmem.bytes THEN HALT( 1001 ) END;
  1053. MakeContinuousMemStruct( destadr, nrelems, srcmem.elementsize, destmem );
  1054. CopyDataByCoordinateTraversal( srcmem, destmem );
  1055. END CopyArrayToMemory;
  1056. (** copy memory fromadr -> adr, bytes *)
  1057. PROCEDURE CopyMemoryToArray*( srcadr: Index; destmem: ArrayMemoryStructure; nrelems: Index );
  1058. VAR srcmem: ArrayMemoryStructure;
  1059. BEGIN
  1060. IF nrelems * destmem.elementsize > destmem.bytes THEN HALT( 1001 ) END;
  1061. MakeContinuousMemStruct( srcadr, nrelems, destmem.elementsize, srcmem );
  1062. CopyDataByCoordinateTraversal( srcmem, destmem );
  1063. END CopyMemoryToArray;
  1064. PROCEDURE CopyArrayPartToMemory*( srcmem: ArrayMemoryStructure; destadr: Index; srcpos, srclen: IndexArray;
  1065. destlen: Index );
  1066. VAR src, dest: Enumerator; destmem: ArrayMemoryStructure;
  1067. BEGIN
  1068. MakeContinuousMemStruct( destadr, destlen, srcmem.elementsize, destmem );
  1069. src := EnumArrayPart( srcmem, srcpos, srclen, TRUE ); dest := EnumArrayPart( destmem, NIL , NIL , TRUE );
  1070. TraverseAndCopy( src, dest );
  1071. END CopyArrayPartToMemory;
  1072. PROCEDURE CopyMemoryToArrayPart*( srcadr: Index; destmem: ArrayMemoryStructure; srclen: Index;
  1073. destpos, destlen: IndexArray );
  1074. VAR src, dest: Enumerator; srcmem: ArrayMemoryStructure;
  1075. BEGIN
  1076. MakeContinuousMemStruct( srcadr, srclen, destmem.elementsize, srcmem );
  1077. src := EnumArrayPart( srcmem, NIL , NIL , TRUE ); dest := EnumArrayPart( destmem, destpos, destlen, TRUE );
  1078. TraverseAndCopy( src, dest );
  1079. END CopyMemoryToArrayPart;
  1080. PROCEDURE -InBounds*( origin, len: Index; idx: Index ): BOOLEAN;
  1081. CODE {SYSTEM.i386}
  1082. ; if (idx < origin) or (idx-origin >= len) then return false end;
  1083. ; return true;
  1084. ; AL=1 : TRUE; AL=0: FALSE
  1085. MOV EAX, [ESP] ; EAX := idx
  1086. MOV EBX, [ESP+4] ; EBX := len
  1087. MOV ECX, [ESP+8] ; ECX := origin
  1088. CMP EAX, ECX ;
  1089. JL outbound ; idx < origin: outbound
  1090. SUB EAX, ECX
  1091. CMP EAX, EBX
  1092. JGE outbound ; (idx-origin) >= len
  1093. MOV AL, 1
  1094. JMP done ;
  1095. outbound:
  1096. MOV AL, 0
  1097. done:
  1098. ADD ESP, 12
  1099. END InBounds;
  1100. PROCEDURE -PeriodicBounds*( origin, len: Index; idx: Index ): Index;
  1101. CODE {SYSTEM.i386}
  1102. ; DEC( idx, origin ); idx := idx MOD len; INC( idx, origin );
  1103. ; modulus:
  1104. ; a := b MOD c; c -> EBX ; b -> EAX
  1105. ; CDQ
  1106. ; IDIV EBX
  1107. ; CMP EDX,0
  1108. ; JNL 2
  1109. ; ADD EDX,EBX
  1110. ; EDX -> a
  1111. MOV EAX, [ESP] ; EAX := idx
  1112. SUB EAX, [ESP+8] ; EAX := EAX-origin
  1113. MOV EBX, [ESP+4] ; EBX := len
  1114. CDQ
  1115. IDIV EBX
  1116. CMP EDX, 0
  1117. JNL 2
  1118. ADD EDX, EBX
  1119. MOV EAX, EDX
  1120. ADD EAX, [ESP+8]
  1121. ADD ESP, 12
  1122. END PeriodicBounds;
  1123. PROCEDURE MirrorOnB*( origin, len: Index; idx: Index ): Index; (* mirror on origin / origin + len, infinite domain*)
  1124. (*! optimize -> inline *)
  1125. BEGIN
  1126. IF len = 1 THEN RETURN idx END;
  1127. DEC( idx, origin ); DEC( len );
  1128. IF ODD( idx DIV (len) ) THEN RETURN origin + len - idx MOD (len); ELSE RETURN origin + idx MOD (len) END;
  1129. END MirrorOnB;
  1130. PROCEDURE MirrorOffB*( origin, len: Index; idx: Index ): Index; (* mirror between origin and origin -1 / origin + len and origin +len+1, infinite domain*)
  1131. (*! optimize -> inline *)
  1132. BEGIN
  1133. DEC( idx, origin );
  1134. IF ODD( idx DIV len ) THEN RETURN origin + (-idx - 1) MOD (len) ELSE RETURN origin + idx MOD len; END;
  1135. END MirrorOffB;
  1136. PROCEDURE TestB*;
  1137. VAR i: Index;
  1138. BEGIN
  1139. FOR i := -30 TO 30 DO dbgOut.Int( i, 1 ); dbgOut.String( ":" ); dbgOut.Int( MirrorOffB( 2, 7, i ), 1 ); dbgOut.Ln; END;
  1140. FOR i := -30 TO 30 DO dbgOut.Int( i, 1 ); dbgOut.String( ":" ); dbgOut.Int( MirrorOnB( 2, 7, i ), 1 ); dbgOut.Ln; END;
  1141. END TestB;
  1142. END ArrayXdBytes.
  1143. ArrayXdBytes.TestB ~