Whole-array+operations+in+structures

//by Richard Russell, August 2013//

As it states in the main [|help documentation] the 'whole array' operations (e.g. assignment, arithmetic and the SUM and MOD functions) cannot be used with arrays which are structure members. Similarly, you cannot pass a structure-member array as the parameter of an FN or PROC. These limitations arise because of the need to maintain compatibility with versions of BBC BASIC prior to the introduction of structures.

Usually these limitations are not serious, for example to initialise the contents of an array one can simply use a loop: code format="bb4w" DIM struct{array(3,2)} FOR R% = 0 TO 3 FOR C% = 0 TO 2 struct.array(R%,C%) = -1 NEXT NEXT R% code However there may be occasions when it would be convenient to be able to use the whole-array operations. Fortunately there is a way, although it has a few restrictions. By calling the procedure **PROC_arrayalias** (listed below) it is possible to create a conventional array which is an //alias// of an array in a structure. If a whole-array operation is performed on this alias array, the array in the structure is also affected, and if the structure array is modified the alias array also changes.

So for example an equivalent functionality to the code above may be achieved as follows: code format="bb4w" DIM struct{array(3,2)} PROC_arrayalias(struct{}, alias, nil%, nil%, nil%) alias = -1 code Note the use of dummy variables **nil%** to 'pad out' the procedure call to the correct number of parameters. It is possible to create up to four - expandable to nine, see below - alias arrays in this way, each one corresponding to a different array within the structure (non-array members are ignored in this process). So for example: code format="bb4w" DIM test{a%(0), b%, c#(3,2), d$, e$(1)} PROC_arrayalias(test{}, one%, two#, three$, nil%) code Here the three arrays **one%**, **two#** and **three$** become aliases of the structure members **test.a%**, **test.c#** and **test.e$** respectively. It is important that the type suffix (%, #, $ etc.) of the alias array is the same as the structure member. If there is an array for which you have no need of an alias, pass a dummy variable for that parameter.

As stated previously, any of the whole-array operations (except SWAP) may be performed on the alias arrays, even something as simple as determining the dimensions: code format="bb4w" DIM test{a%(0), b%, c#(3,2), d$, e$(1)} PROC_arrayalias(test{}, nil%, two#, nil%, nil%) maxrow% = DIM(two#, 1) maxcol% = DIM(two#, 2) code Sadly there are a few limitations to this technique:
 * The structure cannot be declared using a prototype (although sub-structures can).
 * The structure cannot be an element of an array of structures.
 * Arrays contained within sub-structures cannot be aliased.
 * The last structure member must not be a sub-structure.
 * Sub-sub-structures are allowed only **before** the first array member.
 * The memory layout of the structure changes, so (e.g.) it cannot be passed to an API function.

As a warning that the layout of the structure is changed the **DIM(struct{})** function, which gives the structure's size in bytes, returns an increased value.

Here is the **PROC_arrayalias** procedure. Up to five more parameters (which must have the formal variables **E%**, **F%**, **G%**, **H%** and **I%**) may be added if there are more arrays in the structure. No other code changes are required. code format="bb4w" DEF PROC_arrayalias(RETURN s{}, RETURN A%, RETURN B%, RETURN C%, RETURN D%) LOCAL J%,K%,L%,M%,N%,O%,P%,Q%,R%,S%,T% DIM T% LOCAL 100 : N% = ^A% P% = !^s{}+4 : WHILE !P% P% = !P% : ENDWHILE P% += 4 : REPEAT P% += 1 : UNTIL ?P%=0 IF P%?TRUE = &28 P% += 4*P%?5 + 1 P% = (P% + 8) AND -4 IF P%<>s{} ERROR 100, "Structure incompatible with array alias" L% = ^s{} P% = !L% + 4 J% = TRUE REPEAT Q% = P% + 4 Q% += LEN$$Q% R% = Q% + 1 IF Q%?TRUE = &28 THEN IF J% P% -= 4 Q% += 4*Q%?5 + 6 S% = Q% - P%         O% += S%          K% = !^s{} + 4 IF !^s{} >= Q% !^s{} -= S%         REPEAT M% = !K% IF M% >= Q% !K% -= S%           K% = M%          UNTIL K% = 0 FOR K% = ^A% TO N% STEP 4 IF !K% >= Q% !K% -= S%         NEXT M% = s{} + !R% - S%         !R% += O%          !L% = M%          FOR K% = 0 TO S% - 1 : K%?T% = K%?P% : NEXT FOR K% = 0 TO M% - P% - 1 : K%?P% = K%?Q% : NEXT FOR K% = 0 TO S% - 1 : K%?M% = K%?T% : NEXT !N% = M% + R% - P% + 4 N% += 4 P% = M%         IF J% P% += 4 ELSE IF Q%?TRUE = &7B THEN R%!4 += O%           IF !R% > P% !R% -= O%            R% = !R% + 4 WHILE !R% IF !R% > P% !R% -= O%             R% = !R% ENDWHILE ELSE !R% += O%         ENDIF ENDIF L% = P%       P% = !P% J% = FALSE UNTIL P%=0 !(^s{}+4) -= O%     !!^s{} += O%      ENDPROC code