################################################################################ # TSL-LIBRARY: EMOS_DDT_ACCESS_Range_Lib ################################################################################ # Copyright (C) 2000 EMOS Computer Consulting GmbH # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # For further information please contact: # # Dean Rajovic # EMOS Computer Consulting GmbH # Oskar-Messter-Straße 25 # 85737 Ismaning # Germany # tel.: +49 89 608 765-0 # mailto:drajovic@emos.de # http://www.emos.de ################################################################################ # $Revision: 1.1.1.1 $ # $Author: drajovic $ # $Date: 2004/03/24 20:13:57 $ # $Archive: /MERCURY/Projects/EMOS_GPL/DDT/emos_ddt_access_range_lib/script $ # $NoKeywords: $ ################################################################################ #**# #* This library defines an "iterator" (as much as one can emulate a real #* iterator in a language such as TSL) for data tables (ddt-interface). #* The main benefits of this iterator are: #* 1.) you can loop through any table in an uniform way, #* 2.) you can choose one of four algorithms to iterate through the range: #* * sequntial (forward) #* * sequential (reverse) #* * random (values may get repeated) #* * random (values will not be repeated) #* 3.) you can simultaneously have iterators for multiple data tables #* (ane at a time per table!) #* 4.) you can use it to iterate any range of numbers (unrelated to data #* tables). #* <p>NOTE! #* <ul> #* <li> For more detailed instruction see comments for DDT_ACCESS_lib.</li> #* <li> This iterator does not (yet) support the syntax like DDT_ACCESS_lib. #* You can only specify a range with <code>from</code> and <code>to</code> parameters. It would #* be great if someone could find time to implement this.</li> #* </ul> #* PUBLIC CONSTANTS: #* <ul> #* <li>DDT_ACCESS_SEQUENTIAL</li> #* <li>DDT_ACCESS_REVERSE_ACCESS</li> #* <li>DDT_ACCESS_RANDOM</li> #* <li>DDT_ACCESS_RANDOM_NOREPEAT</li> #* <li>DDT_ACCESS_INVALID_MODE</li> #* <li>DDT_ACCESS_DEFAULT_MODE</li> #* </ul> #*/ #==================================================== # public variables #==================================================== public const DDT_ACCESS_SEQUENTIAL = 1; public const DDT_ACCESS_REVERSE = 2; public const DDT_ACCESS_RANDOM = 3; public const DDT_ACCESS_RANDOM_NOREPEAT = 4; public const DDT_ACCESS_INVALID_MODE = -666; public const DDT_ACCESS_DEFAULT_MODE = DDT_ACCESS_SEQUENTIAL; #==================================================== # private variables #==================================================== static accessMode[]; static minPos[], maxPos[], curPos[]; static posUnused[]; static indexArray[]; #==================================================== # public functions #==================================================== #** #* Initialises the range-access algorithm. #* @param table (in) the name od the iterator (data table) #* @param from (in) begining of range #* @param to (in) end of range #* @param mode (in) one of four possible access modes #* [default: DDT_ACCESS_SEQUENTIAL] #* @return #* E_OK: initialisation succeeded #* !E_OK: initialisation failed #*/ public function DDT_ACCESS_init_range( in table, in from, in to, in mode ) { auto rc; if ( from*1 <= 0 ) return E_ILLEGAL_PARAMETER; if ( to*1 < from*1 ) return E_ILLEGAL_PARAMETER; minPos[table] = from*1; maxPos[table] = to*1; init_index_array( table ); switch ( mode ) { case DDT_ACCESS_SEQUENTIAL: curPos[table] = minPos[table] - 1; break; case DDT_ACCESS_REVERSE: curPos[table] = maxPos[table] + 1; break; case DDT_ACCESS_RANDOM: curPos[table] = 0; break; case DDT_ACCESS_RANDOM_NOREPEAT: curPos[table] = 0; break; default: return DDT_ACCESS_INVALID_MODE; } accessMode[table] = mode; return E_OK; } #** #* Removes range-access for given table and frees the internal buffers. #* @param table (in) the name od the iterator (data table) #*/ public function DDT_ACCESS_clean_range ( in table ) { delete_dimension( accessMode, table ); delete_dimension( minPos, table ); delete_dimension( maxPos, table ); delete_dimension( curPos, table ); delete_dimension( posUnused, table ); delete_dimension( indexArray, table ); } #** #* Indicates whether there subsequent call to #* DDT_get_next_in_range() is about to succeed. #* @param table (in) the name od the iterator (data table) #* @return #* TRUE: there is still something left to be processed #* FALSE: all tests processed #*/ public function DDT_ACCESS_has_more_in_range ( in table ) { switch ( accessMode[table] ) { case DDT_ACCESS_SEQUENTIAL: case DDT_ACCESS_REVERSE: case DDT_ACCESS_RANDOM: case DDT_ACCESS_RANDOM_NOREPEAT: break; default: return 0; } return posUnused[table]; } #** #* Returns the index of the next test to be processed. #* @param table (in) the name od the iterator (data table) #* @return #* >0: test number #* <0: error ocurred #*/ public function DDT_ACCESS_get_next_in_range ( in table ) { switch ( accessMode[table] ) { case DDT_ACCESS_SEQUENTIAL: curPos[table]++; break; case DDT_ACCESS_REVERSE: curPos[table]--; break; case DDT_ACCESS_RANDOM: curPos[table] = get_random_pos( table ); break; case DDT_ACCESS_RANDOM_NOREPEAT: curPos[table] = get_norepeat_random_pos( table ); break; default: return DDT_ACCESS_INVALID_MODE; } return set_pos_used( table, curPos[table] ); } static function delete_index_array( in table ) { delete_dimension( indexArray, table ); delete minPos[table]; delete maxPos[table]; delete curPos[table]; delete posUnused[table]; } static function init_index_array( in table ) { auto i; delete_dimension( indexArray, table ); for ( i=minPos[table]; i <= maxPos[table]; i++ ) indexArray[table, i] = 0; posUnused[table] = maxPos[table]; } static function set_pos_used( in table, in pos ) { if ( indexArray[table, pos] == 0 ) { indexArray[table, pos] = 1; posUnused[table]--; } return pos; } static function get_random_pos( in table ) { return int( rand() * ( maxPos[table] - minPos[table] + 1) ) + minPos[table]; } static function get_norepeat_random_pos( in table ) { auto x; while (1) { x = get_random_pos( table ); if ( indexArray[table, x] == 0 ) break; } return set_pos_used( table, x ); } #** #* This function will delete a dimension from a multidimensional array. #*<p> WARNING! #* It will delete ALL dimensions with the same name. For example #* assume your three-dimensional array "arr" has the following content: #*<pre> arr["x",1,"x"] = "x1x"; #* arr["x",1,"y"] = "x1y"; #* arr["y",1,"x"] = "y1x"; #* arr["y",1,"y"] = "y1Y";</pre> #* then the following command #*<pre> delete_dimension( arr, "x" );</pre> #* will delete everything BUT #*<pre> arr["y",1,"y"] = "y1Y";</pre> #* @param arr (inout) array to be processed #* @param dim (in) dimension(s) to be removed #*/ static function delete_dimension( inout arr[], in dim ) { auto i; for ( i in arr ) if ( match (i, dim) ) delete arr[i]; } ########################################################################### # TSL-LIBRARY: EMOS_DDT_ACCESS_Range_Lib ###########################################################################