Professional Documents
Culture Documents
One of the core changes is the way I use memory in programs. Historically, I would minimize the use of memory, but now I go to the opposite extreme and use memory as much as possible. For example, if I was writing an order entry program, instead of maintaining order details on the database as they are entered, I would store the complete order in memory and write it to the database when the order is complete.
RPG allows us to maximize the use of memory by defining very large field sizes and, more importantly, by using arrays.
In this article, I want to examine some of the many weird and wonderful features of defining and using arrays.
Array Sizes
Regardless of how an array is defined, the amount of memory occupied by an array may not exceed 16 M (16,773,104). Up to V5R4, an array may have 32,767 elements, and the maximum size of an element is 64K (65,535). In V6R1, these two limits are increased to 16M (e.g., you can define an array of 16M one-byte elements or an array of two each of 8M one-byte elements).
D CompileData D D D D D MonthNames
DS 27a 27a 27a 27a 9a Inz('January Inz('April Inz('July Inz('October February March May August June ) ')
September')
Overlay(CompileData) Dim(12)
S S
10a 10i 0
Dim(100) Ascend
Figure 3 shows a strange feature of overlaying an array in a data structure. The Address array is defined as having 100 elements, each element being 87 characters in length. The rest of the data structure appears to define subfields that overlay the first element of the array (i.e., the combined length of the subfields is 87 characters). But such is not the case; since the subfields overlay an array, they are themselves arrays.
This means that any operation (such as SortA) executed on a subfield actually affects the overlaid (or base) array. In the example shown in Figure 3, the SortA of City results in the
Address array being sorted based on the 61st to 80th character of each element. Or the SortA of State results in the Address array being sorted based on the 81st and 82nd character of each element.
DS 87a 30a 30a 20a 2a 5a S 10i 0 Dim(100) Ascend Overlay(Address) Overlay(Address:*Next) Overlay(Address:*Next) Overlay(Address:*Next) Overlay(Address:*Next)
D noLoaded /Free
SortA %SubArr(City:1:NoLoaded);
Sorting Lists
You can use the feature of overlaying an array in a data structure to allow users to sort lists of non-volatile data by selected columns.
Figure 4 shows a snippet of the DDS for a display file containing a load-all subfile. The Return Cursor Location (RTNCSRLOC) keyword is used to determine which record (CSRREC) and field (CSRFLD) the cursor is positioned on when the screen is returned (i.e., the names of the screen format and the field are returned in CSRREC and CSRFLD).
R SUBREC
SFL
A A A A A A A A A A A A A A A A A A
SFLNXTCHG
DSPATR(RI PC)
SFLCTL(SUBREC) OVERLAY
51 52 53 51
SFLDSP SFLDSPCTL SFLCLR SFLEND(*MORE) SFLSIZ(0050) SFLPAG(0014) RTNCSRLOC(*RECNAME &CSRREC &CSRFLD) CSRREC CSRFLD 10 10 H H
Figure 5 shows the relevant portions of the subfile program. The main points to note are below (numbers correspond to the numbers in the figure):
1. An externally defined data structure (SubRecData) is used to store an image of a subfile record. The field names used in the subfile correspond to those input from the database files (CCODE, ANAME, REFNUM, STATUS). 2. AllSubRec is a 9999-element (the maximum number of records in a subfile) array where each element is an image of the SubRecData data structure.
3. Subfields that correspond to the fields in the subfile record overlay the AllSubRec array, so each of these is, in turn, an array. Note that there are no hard-coded lengths or data types in this data structure; all of the components of the data structure are defined using the Like keyword, and the use of *Next in the Overlay keyword means you need only be concerned with the sequence of the fields in the subfile record. 4. All required records are read from the customer file and added to the AllSubRec array. When records are input, the data is placed in the CCODE, ANAME, REFNUM, and STATUS fields in the SubRecData data structure; the data structure is then copied to the next array element. At the end of the routine, the field RecordsInSubfile indicates the number of elements loaded in the array. 5. The subfile is loaded directly from the AllSubRec array, an element is moved to the SubRecData data structure, and the subfile record corresponding to the array element is written. The important point to note is that each element of the array is loaded to the corresponding subfile record. 6. Based on the value of the CSRFLD field set on the RTNCSRLOC keyword, the corresponding subfield is used to sort the AllSubRec array. The %SubArr BIF and the RecordsInSubfile field are used to ensure that only the loaded elements are sorted. Processing continues with the subfile being reloaded.
// Info for storing subfile data and sorting it (1) D SubRecData D (2) D AllSubRec D D (3) D D D D D D ArrStatus ArrOption ArrCode ArrName ArrRefNum E Ds Ds Like(SubRecData) Dim(9999) Ascend Like(Option) OverLay(AllSubRec) Like(CCode) OverLay(AllSubRec:*Next) Like(AName) OverLay(AllSubRec:*Next) Like(RefNum) Overlay(AllSubRec:*Next) Like(Status) Overlay(AllSubRec:*Next) ExtName(SUBSORTD:SUBREC)
//----------------------------------------------------------------
RRN = 0; Option = *Blanks; SetLL *Start Cust; Read Cust; Dow Not %EOF(Cust); RRN += 1; (4) AllSubRec(RRN) = SubRecData; Read Cust; EndDo; RecordsInSubfile = RRN; //================================================================ (5) For RRN = 1 To RecordsInSubfile; SubRecData = AllSubRec(RRN); Write SubRec; EndFor; //================================================================ (6) Select; When CsrFld = 'CCODE'; SortA %SubArr(ArrCode:1:RecordsInSubfile);
EndSR; /END-FREE
Although this technique is not suitable for volatile data, it does provide a very easy means to quickly re-sequence data for presentation purposes (a subfile in this case, but it could just as easily be for a Web page).
Ds 30a 20a 2a 5a
Figure 7 shows the definition of a data structure array (Customers) that contains two data structure arrays (Home and Business). The LIKEDS keyword is used to define a data structure within a data structure, each of these data structures being an array as well. You now have a three-dimensional array!
Ds
Customers(3).Home(2).Street(1) = Customer(4).Business(2).Street(1);
Yes, you can go to a fourth dimension if you wish. You are restricted only in that the outer data structure array may not exceed a total size of 16M (up to V5R4), and an individual data structure definition may not exceed 64K.
The unnamed data structure contains an array (Address); each element is the length of an element of ArrDs, and it has the same number of elements as the ArrDs array. Because of the basing pointer, each element of the Address array overlays an element of the ArrDs array. The Address array is overlaid with subfields (which are in turn arrays themselves), and, as you saw earlier, these subfield arrays may be used to sort the Address array, which, in turn, means you are actually sorting the ArrDs array.
Ds 30a 20a 2a
Zip S Ds
Like(ArrDs.Street) Overlay(Address) Like(ArrDs.Street) Overlay(Address:*Next) Like(ArrDs.City) Overlay(Address:*Next) Like(ArrDs.State) Overlay(Address:*Next) Like(ArrDs.Zip) Overlay(Address:*Next)
D MyArr
10
Dim(32767) Based(pMyArr)
j = i - OffSet; If (j > %Elem(MyArr)); OffSet += %Elem(MyArr); j = i - OffSet; pMyArr = pMyArr + %Size(MyArr:*All); EndIf; MyArr = Value; EndFor;
Use the C functions qsort and bsearch if you need to sort or perform a lookup on one of these extremely large arrays; examples are available in the Redbook Who Knew You Could Do That with RPG IV?
And Finally...
We have a historical tendency to refrain from loading a lot of information into memory. When we break the habit, we discover there are a lot of neat things we can get our programs to do with little or no performance overhead. Arrays play a key role in maximizing how our programs utilize memory. And some of it is just plain fun!