User Tools

Site Tools


whole-array_20operations_20in_20structures

Whole-array operations in structures

by Richard Russell, August 2013

(for an alternative way of tackling this issue, see Variable-length array in a structure)

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:

        DIM struct{array(3,2)}
        FOR R% = 0 TO 3
          FOR C% = 0 TO 2
            struct.array(R%,C%) = -1
          NEXT
        NEXT R%

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:

        DIM struct{array(3,2)}
        PROC_arrayalias(struct{}, alias(), nil%, nil%, nil%)
        alias() = -1

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:

        DIM test{a%(0), b%, c#(3,2), d$, e$(1)}
        PROC_arrayalias(test{}, one%(), two#(), three$(), nil%)

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:

        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)

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.

        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
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
whole-array_20operations_20in_20structures.txt · Last modified: 2024/01/05 00:21 by 127.0.0.1