|
Hello Lloyd, This isn't really all that difficult. The simple solution (and the one most familiar to RPG programmers) is to create an array with sufficient space for the most likely number of entries. If the range is 40 to 60 entries then create an array with room for 70 (and code some sort of limits test to warn when the array gets ful). However, you wanted to know how to do this dynamically. There are two possiblities that spring to mind: 1/ Create a multiple occurrence data structure (MODS) describing the record (easy here since it is externally described). The numer of occurrences can be the largest amount supported by the language -- RPG IV == 32,767 2/ Create an array with each element being the length of a record and 32,767 elements. The trick is that both the array and the data structure are based on a pointer. The compiler will define a view of storage but will not allocate storage. That is your responsibility. Use the ALLOC function to create enough space for the expected amount of storage. The value used is the length of each record multiplied by the number of expected records. Your program needs to track how much room has been allocated and how much has been used. Assume you allocate storage for 40 entries. When you fetch the 41st record you use REALLOC to increase the storage space by some amount (maybe record length times 10). When you fetch the 51st record you call REALLOC again. When you finsh processing the array or MODS you use DEALLOC to release the storage. Note that there are APIs which will allow dynamic storage manipulation so this technique is available to other languages also. CEEGTST == ALLOC; CEECZST == REALLOC; CEEFRST == DEALLOC Examples of this technique can be found in any decent book on C programming and every book shop has tens of these. Translation table follows: ALLOC == malloc() or calloc() REALLOC == realloc() DEALLOC == free() but they behave in a similar fashion. The big problem from an RPG perspective is that you cannot define an open-ended array or MODS. You have to tell the compiler the number of elements required and you can't change it at run time. One solution is to use the languages maximum supported value since based structures don't occupy storage. Another is to only use a pointer with a single record defined and bump it up through the allocated storage effectively managing your own array. So for a very quick, off the tips of my fingers, spot the deliberate mistake, RPG IV example: FWORKFILE IFE DISK * Declare some magic values D $DftNbrRcd C CONST(40) D $IncNbrRcd C CONST(10) D $MaxNbrRcd C CONST(32767) * Declare some work fields D @DynPtr S * D CurOccur S 5 0 D UsdOccur S LIKE(CurOccur) D AvlOccur S LIKE(CurOccur) D INZ($DftNbrRcd) D Record S EXTNAME(WORKFILE) * Now we define two views of storage both based on the same pointer. We can treat the * the storage as a multiple occurence data structure or as an array. We cannot yet * reference the storage because it has not been allocated. D Struct DS BASED(@DynPtr) D EXTNAME(WORKFILE) D PREFIX(W_) D OCCUR($MaxNbrRcd) D Array S BASED(@DynPtr) D LIKE(Struct) D DIM($MaxNbrRcd) D StgAmt S 5 0 * Now we allocate the expected amount of storage C EVAL StgAmt = $DftNbrRcd * %SIZE(Struct) C ALLOC StgAmt @DynPtr * Starting at the first occurrence of the MODS, fill it with data from WORKFILE C READ WORKFMT 99 C DOW *IN99 = *OFF C EVAL CurOccur = CurOccur + 1 C OCCUR Struct C MOVE Record Struct C READ WORKFMT 99 * If we have more data and we have filled the available space ... C IF ((*IN99 = *OFF) AND (CurOccur = AvlOccur)) * ... get some more space. C EVAL StgAmt = StgAmt + ($IncNbrRcd * %SIZE(Struct)) C REALLOC StgAmt @DynPtr C EVAL AvlOccur = AvlOccur + $IncNbrRcd C ENDIF * ... and around we go again to fill the next occurrence C ENDDO * Save the num r of actual elements filled with data C EVAL UsdOccur = CurOccur * The MODS is filled with data and we can start using it (the above code could all go in * the *INZSR routine. : * Code which does stuff using the MODS and array goes here : * Now we release the allocated storage, clean up, and go home C DEALLOC @DynPtr C SETON LR C RETURN You would need to add error handling to cope with the situation where you had filled all 32,767 elements in the array/MODS. I leave that as an exercise for the reader. Remember that any LOOKUP operation on the array is linear and a binary search should be considered for more than 100 elements. See the archive for a discussion on this topic. You may find in practice that a linear search on a large number of elements is slower than a CHAIN to a record (and index) already in main store. Also data in the array does not necessarily reflect the current data values in the DB file. Another alternative, particularly if the data in the WORKFILE is going to be shared by multiple jobs is to populate a user space with the data and share that user space amongst the jobs. In this case the basing pointer is set to address the user space. The QUSPTRUS API can be used to set the address. A common job would be used to load the user space (or simply use the space instead of a file). The advantage to these techniques over simply using the database file is reduced I/O (even when the file is completely in main store (through paging or SETOBJACC). Dynamically allocated storage comes from the HEAP (and there are flavours of HEAP storage too) which is part of the job and therefore always in main store, the user space does need to be demand-paged but there is less overhead than with DB files and it does give access to 16MB of space. It will always be faster to access program storage than DB storage primarily due to avoding all the DB code. Of course benchmarks may need to be performed to determine which technique works best in your situation. (Hah! the ever useful escape clause strikes again!) Regards, Simon Coulter. «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«» «» FlyByNight Software AS/400 Technical Specialists «» «» Eclipse the competition - run your business on an IBM AS/400. «» «» «» «» Phone: +61 3 9419 0175 Mobile: +61 0411 091 400 «» «» Fax: +61 3 9419 0175 mailto: shc@flybynight.com.au «» «» «» «» Windoze should not be open at Warp speed. «» «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«» //--- forwarded letter ------------------------------------------------------- > X-Mailer: Forte Agent 1.5/32.451 > Date: Thu, 29 Apr 99 23:50:31 +0000 > From: lgoodbar@watervalley.net > To: midrange-l@midrange.com > Reply-To: MIDRANGE-L@midrange.com > Subject: Dynamic arrays > > I have a work file (about 50 records) that is accessed very often by a RPG4 > program. I was thinking about reading the file into an array to make lookups > faster. The problem is the file changes in size; sometimes it's 50 records, > sometimes 60, or 40, etc. I'd like to create a dynamically-sized array at > runtime. I briefly looked at the ALLOC/DEALLOC/REALLOC opcodes, but they > really didn't make much sense. > > Is there a relatively easy way of creating dynamic arrays in RPG, or am I > forced to create an arbitrary upper limit? > > Thanks, > Loyd +--- | This is the Midrange System Mailing List! | To submit a new message, send your mail to MIDRANGE-L@midrange.com. | To subscribe to this list send email to MIDRANGE-L-SUB@midrange.com. | To unsubscribe from this list send email to MIDRANGE-L-UNSUB@midrange.com. | Questions should be directed to the list owner/operator: david@midrange.com +---
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2025 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.