From: <bi...@us...> - 2014-07-19 22:44:03
|
Revision: 10317 http://sourceforge.net/p/oorexx/code-0/10317 Author: bigrixx Date: 2014-07-19 22:43:59 +0000 (Sat, 19 Jul 2014) Log Message: ----------- Another full day of code changes Modified Paths: -------------- sandbox/rick/newsource/interpreter/api/ThreadContextStubs.cpp sandbox/rick/newsource/interpreter/classes/ArrayClass.cpp sandbox/rick/newsource/interpreter/classes/ArrayClass.hpp sandbox/rick/newsource/interpreter/classes/ClassClass.cpp sandbox/rick/newsource/interpreter/classes/ClassClass.hpp sandbox/rick/newsource/interpreter/classes/IntegerClass.cpp sandbox/rick/newsource/interpreter/classes/IntegerClass.hpp sandbox/rick/newsource/interpreter/classes/ListClass.cpp sandbox/rick/newsource/interpreter/classes/NumberStringClass.cpp sandbox/rick/newsource/interpreter/classes/NumberStringClass.hpp sandbox/rick/newsource/interpreter/classes/ObjectClass.cpp sandbox/rick/newsource/interpreter/classes/ObjectClass.hpp sandbox/rick/newsource/interpreter/classes/QueueClass.cpp sandbox/rick/newsource/interpreter/classes/QueueClass.hpp sandbox/rick/newsource/interpreter/concurrency/ActivationFrame.hpp sandbox/rick/newsource/interpreter/concurrency/RexxActivity.cpp sandbox/rick/newsource/interpreter/instructions/ParseInstruction.cpp sandbox/rick/newsource/interpreter/runtime/MethodArguments.hpp Modified: sandbox/rick/newsource/interpreter/api/ThreadContextStubs.cpp =================================================================== --- sandbox/rick/newsource/interpreter/api/ThreadContextStubs.cpp 2014-07-18 23:56:29 UTC (rev 10316) +++ sandbox/rick/newsource/interpreter/api/ThreadContextStubs.cpp 2014-07-19 22:43:59 UTC (rev 10317) @@ -287,7 +287,7 @@ RexxString *name = new_upper_string(n); ProtectedObject p(name); // convert the name to a string instance, and check the environments. - return ((RexxObject *)o)->hasMethod(name) == TheTrueObject; + return ((RexxObject *)o)->hasMethod(name); } catch (RexxNativeActivation *) Modified: sandbox/rick/newsource/interpreter/classes/ArrayClass.cpp =================================================================== --- sandbox/rick/newsource/interpreter/classes/ArrayClass.cpp 2014-07-18 23:56:29 UTC (rev 10316) +++ sandbox/rick/newsource/interpreter/classes/ArrayClass.cpp 2014-07-19 22:43:59 UTC (rev 10317) @@ -179,9 +179,9 @@ for (size_t i = 0; i < count; i++) { // each dimension must be there and must be a non-negative integer value - // ...a dimension of 0 really does not make sense, right? - // TODO: Figure out the impact of specifying 0 in a multi-dimension array...does this - // make sense at all? + // ...a dimension of 0 really does not make sense, right, but does work. + // this creates a multi-dimensional array of zero size which will get resized + // on the first assignment. Doesn't really make sense, but it's perfectly legal. RexxObject *currentDim = dims[i]; size_t currentSize = currentDim->requiredNonNegative(i + 1); // going to do an overflow? By dividing, we can detect a @@ -199,14 +199,13 @@ } // a final sanity check for out of bounds - if (totalSize >= MaxFixxedArraySize) + if (totalSize >= MaxFixedArraySize) { reportException(Error_Incorrect_method_array_too_big); } // create a new array item - // TODO: make sure the constructor sets the itemCount to 0. Protected<ArrayClass> temp = new (totalSize) ArrayClass; // set the dimension array @@ -295,6 +294,9 @@ */ ArrayClass::ArrayClass(RexxObject **objs, size_t count) { + itemCount = 0; + lastItem = 0; + // if we have array items, do a quick copy of the object references if (count != 0) { @@ -317,10 +319,6 @@ */ RexxObject *ArrayClass::copy() { - // TODO: if we have an expansion array, then allocate - // just a single item of the correct size and copy that. - // could be a significant performance improvement. - // if we've expanded in the past, then just copy the // expansion array and update it with the appropriate // values from this array. @@ -329,13 +327,14 @@ // make a copy of ourself ArrayClass *newArray = (ArrayClass *)expansionArray->copy(); newArray->dimensions = dimensions; - // TODO: Double check how arraySize is handled with the expansion array. - // I don't think that needs to be copied, but not sure. maximumSize might also - // be suspect. - newArray->maximumSize = maximumSize; + // NOTE: the array size and maximum size are already correct + // in the extension array. We need to copy the other fields. + // In fact, the arraySize in the main array is the chopped + // size of the stub array, not the full size, so we definitely + // must not copy that. newArray->lastItem = lastItem; newArray->itemCount = itemCount; - // the copy is non-expanded now. + // the copy of the extension array is now the only one. newArray->expansionArray = newArray; } else @@ -365,6 +364,9 @@ // if we expand, we adjust the expansion size down so we don't overrun. // but we need to mark our space too, since we could be the expansion array. + // NOTE that we could be the original array or the extension. The extension + // array doesn't track last item, so it needs to mark the entire active + // section of the array because it won't know everything. memory_mark_array(arraySize, objects); } @@ -434,6 +436,19 @@ /** + * Simple inline method for setting a value in the array. NOTE: + * this is used only during sorting! + * + * @param value The value to set. + * @param position The index position. + */ +inline void ArrayClass::setSortItem(RexxInternalObject *value, size_t position) +{ + expansionArray->objects[position - 1] = value; +} + + +/** * Simple inline method for clearing an array position * * @param value The value to set. @@ -482,6 +497,26 @@ /** + * Inline method for copying an array item from one array to + * another. This only updates if we are getting a non-null + * value. This also updates the itemCount and lastItem values + * on the set. + * + * @param value The value to set. + * @param position The index position. + */ +inline void ArrayClass::copyArrayItem(RexxInternalObject *value, size_t position) +{ + // only perform the set if this is non-null to avoid changing the count and last + // positions for a null copy. + if (value != OREF_NULL) + { + setArrayItem(value, position); + } +} + + +/** * Inline method for setting an object into the array and * updating the item count and last item positions, if * necessary. @@ -569,8 +604,6 @@ */ RexxObject *ArrayClass::putRexx(RexxObject **arguments, size_t argCount) { - // TODO: consider some helper routines for sorting out the - // variable arguments here. if (argcount < 2) { reportException(Error_Incorrect_method_minarg, IntegerTwo); @@ -579,9 +612,9 @@ RexxObject *value = arguments[0]; requiredArgument(value, ARG_ONE); - // all the rest of the arguments are the index...go valicate it, and expand if necessary + // all the rest of the arguments are the index...go validate it, and expand if necessary size_t position; - validateIndex(arguments + 1, argCount - 1, 2, RaiseBoundsInvalid | ExtendUpper | RaiseBoundsTooMany, position); + validateIndex(arguments + 1, argCount - 1, ARG_TWO, IndexUpdate, position); // set the new value and return nothing put(value, position); @@ -730,7 +763,7 @@ else { // validate the index and expand if necessary. - validateIndex(&index, 1, 2, RaiseBoundsInvalid | RaiseBoundsTooMany, position); + validateIndex(index, ARG_TWO, IndexAccess, position); position = position + 1; // we insert AFTER the given index, so bump this } @@ -783,7 +816,7 @@ size_t position; // array position // validate the index and expand if necessary. - validateIndex(&index, 1, 1, RaiseBoundsInvalid | RaiseBoundsTooMany, position); + validateIndex(index, ARG_ONE, IndexAccess, position); // do the actual insertion return deleteItem(position); @@ -885,7 +918,7 @@ { size_t position; // validate the index - if (validateIndex(arguments, argCount, 1, RaiseBoundsTooMany | RaiseBoundsInvalid, position)) + if (validateIndex(arguments, argCount, ARG_ONE, IndexAccess, position)) { // return .nil for anything out of bounds return TheNilObject; @@ -956,7 +989,7 @@ { size_t position; // if this position doesn't validate, just return .nil - if (!validateIndex(arguments, argCount, 1, RaiseBoundsTooMany | RaiseBoundsInvalid, position)) + if (!validateIndex(arguments, argCount, ARG_ONE, IndexAccess, position)) { return TheNilObject; } @@ -1049,7 +1082,7 @@ // asking for dimension of single? if (isSingleDimensional()) { - only return something if the requested position was 0 + // only return something if the requested position was 0 if (position == 1) { @@ -1108,227 +1141,261 @@ } -void ArrayClass::setExpansion(RexxObject * expansion) -/******************************************************************************/ -/* Function: Set a new expansion array item */ -/******************************************************************************/ +/** + * Process and validate a potentially multi-dimensional array + * index. If the index is out of bounds in any dimension it will + * either return false or raise an error, depending on the bounds + * checking parameter. + * + * @param index The array of objects representing the index. + * @param indexCount The count of index items. + * @param argPosition The argument position (used for error + * reporting) + * @param boundsError Flags indicating how bounds errors should + * be handled. + * @param position The returned flattened index pointing to the actual + * item in the array. + * + * @return true if this was a valid index (within bounds) based + * on the bounds checking flags. + */ +bool ArrayClass::validateIndex(RexxObject **index, size_t indexCount, + size_t argPosition, size_t boundsError, stringsize_t &position) { - OrefSet(this, this->expansionArray, (ArrayClass *)expansion); -} + // one possibility is a single array used as a single argument specifying the + // index position. If this is the case, dummy up the argument list to point + // to the array's information. - -bool ArrayClass::validateIndex( /* validate an array index */ - RexxObject **_index, /* array index (possibly multi-dim) */ - size_t indexCount, /* size of the index array */ - size_t _start, /* starting point on the array */ - size_t bounds_error, /* raise errors on out-of-bounds */ - stringsize_t &position) // returned position -/******************************************************************************/ -/* Function: Process and validate a potentially multi-dimensional array */ -/* index. If the index is out of bounds in any dimension it will */ -/* either return false or raise an error, depending on the bounds */ -/* checking parameter. */ -/******************************************************************************/ -{ - RexxObject *value; /* individual index value */ - size_t numsubs; /* number of subscripts */ - size_t i; /* loop counter */ - size_t multiplier; /* accumlation factor */ - size_t offset; /* accumulated offset */ - size_t _dimension; /* current working dimension */ - size_t numSize; /* temporary long variable */ - - // do we really have a single index item given as an array? - if (indexCount == 1 && _index[0] != OREF_NULL && isOfClass(Array, _index[0])) + if (indexCount == 1 && index[0] != OREF_NULL && isOfClass(Array, index[0])) { // we process this exactly the same way, but swap the count and // pointers around to be the array data. - ArrayClass *indirect = (ArrayClass *)_index[0]; + ArrayClass *indirect = (ArrayClass *)index[0]; indexCount = indirect->items(); - _index = indirect->data(); + index = (RexxObject **)indirect->data(); } /* Is this array one-dimensional? */ if (isSingleDimensional()) { - /* Too many subscripts? Say so. */ - if (indexCount > 1) + return validateSingleDimensionIndex(index, indexCount, argPosition, boundsError, position); + } + else + { + return validateMultiDimensionIndex(index, indexCount, argPosition, boundsError, position); + } +} + + +/** + * Process and validate an index for a single dimension array + * (The most common index). This might end up reconfiguring + * this array to a multi-dimension array if it is still zero + * sized. + * + * @param index The array of objects representing the index. + * @param indexCount The count of index items. + * @param argPosition The argument position (used for error + * reporting) + * @param boundsError + * Flags indicating how bounds errors should be handled. + * @param position The returned flattened index pointing to the actual + * item in the array. + * + * @return true if this was a valid index (within bounds) based + * on the bounds checking flags. + */ +bool ArrayClass::validateSingleDimensionIndex(RexxObject **index, size_t indexCount, + size_t argPosition, size_t boundsError, stringsize_t &position) +{ + // we have a single dimension array and one argument...we are very happy! + if (indexCount == 1) + { + position = index[0]->requiredPositive((start); + // ok, this is out of bounds. Figure out how to handle this + if (!isInbounds(position)) { - /* should the array be extended? */ - if ((bounds_error & ExtendUpper) && this->dimensions == OREF_NULL) + // could be WAAAAAAY out of bounds. + if (position >= MaxFixedArraySize) { - /* anytyhing in the array? */ - /* or explicitly created array with 0*/ - /* elements (.array~new(0)) */ - if (this->size() != 0) - { - /* Yes, number of dims can't change */ - /* report apropriate bounds */ - reportException(Error_Incorrect_method_maxsub, IntegerOne); - } - else - { - /* its empty, entendarray for new siz*/ - /* extend the array. */ - this->extendMulti(_index, indexCount, _start); - /* Call us again to get position, now*/ - /* That the array is extended. */ - return this->validateIndex(_index, indexCount, _start, bounds_error, position); - } + reportException(Error_Incorrect_method_array_too_big); } - - else if (bounds_error & RaiseBoundsTooMany) + // if we're doing a put operation, we need to extend the upper bounds + // to include + if (boundsError & ExtendUpper) { - /* anytyhing in the array? */ - /* or explicitly created array with 0*/ - /* elements (.array~new(0)) */ - if (this->dimensions != OREF_NULL || this->size() != 0) - { - /* report apropriate bounds */ - reportException(Error_Incorrect_method_maxsub, IntegerOne); - } - else - { - return false; /* just report not here */ - } + // yes, expand to at least that size. + extend(position); + return true; } + // not asked to extend or raise an error, but indicate this is no good. else { - return false; /* not fixed yet, but don't complain */ + return false; } } - /* Too few? subscripts? Say so. */ - else if (indexCount == 0) + // good index...we're done. + return true; + } + // a multi-dimension array for a single dimension item. We might need to + // reconfigure this into a multidimension array + if (indexCount > 1) + { + // should the array be extended? This can only extended if + // the size is still 0 and this was not set explicitly (indicated by + // having an dimensions array resulting from calling .array~new(0) + + // TODO: pretty sure there are no unit tests for this extension behaviour + if (boundsError & ExtendUpper) { - /* report apropriate bounds */ - reportException(Error_Incorrect_method_minarg, _start); - } - /* validate integer index */ - position = _index[0]->requiredPositive((int)_start); - /* out of bounds? */ - if (position > this->size() ) - { - if (position >= MAX_FIXEDARRAY_SIZE) + // both of these are error conditions + if (isFixedDimension()) { - reportException(Error_Incorrect_method_array_too_big); + reportException(Error_Incorrect_method_maxsub, IntegerOne); } - /* are we to expand the array? */ - if (bounds_error & ExtendUpper) + else { - /* yes, compute amount to expand */ - this->extend(position - this->size()); - + // ok, we can extend this into a multi-dimension item + extendMulti(index, indexCount, start); + // we have successfully turned into a multi-dimension array, so + // loop back around and try to validate the index. + return validateMultiDimensionIndex(index, indexCount, argPosition , boundsError, position); } - /* need to raise an error? */ - else if (bounds_error & RaiseBoundsUpper) + } + // asked to raise an error if we have too many? Need to sort out + // which error to issue. + else if (boundsError & RaiseBoundsTooMany) + { + // already have a fixed dimension? + if (isFixedDimension()) { - reportException(Error_Incorrect_method_array, position); + // too many subscripts + reportException(Error_Incorrect_method_maxsub, IntegerOne); } + // We are not yet fixed in dimension, so we could be expanded later. else { - return false; /* just return indicator */ + return false; } } - } - else - { /* multidimensional array */ - /* get the number of subscripts */ - numsubs = indexCount; - numSize = this->dimensions->size();/* Get the size of dimension */ - /* right number of subscripts? */ - if (numsubs == numSize) - { - multiplier = 1; /* multiply by 1 for first dimension */ - offset = 0; /* no accumulated offset */ - - for (i = numsubs; i > 0; i--) - { /* loop through the dimensions */ - - value = _index[i - 1]; - - if (value == OREF_NULL) /* not given? */ - { - /* this is an error too */ - reportException(Error_Incorrect_method_noarg, i + _start); - } - /* validate integer index */ - position = value->requiredPositive((int)i); - /* get the current dimension */ - _dimension = ((RexxInteger *)this->dimensions->get(i))->getValue(); - if (position > _dimension) - { /* too large? */ - /* should the array be extended? */ - if (bounds_error & ExtendUpper) - { - /* go extend it. */ - this->extendMulti(_index, indexCount, _start); - /* Call us again to get position, now*/ - /* That the array is extended. */ - return this->validateIndex(_index, indexCount, _start, bounds_error, position); - } - /* need to raise an error? */ - else if (bounds_error & RaiseBoundsUpper) - { - reportException(Error_Incorrect_method_array, position); - } - else - { - return false; /* just return indicator */ - } - } - /* calculate next offset */ - offset += multiplier * (position - 1); - multiplier *= _dimension; /* step the multiplier */ - } - position = offset + 1; /* get accumulated position */ - } - /* Not enough subscripts? */ - else if (numsubs < numSize) - { - reportException(Error_Incorrect_method_minsub, numSize); - } - // must be too many subscripts + // asked to fail this silently else { - reportException(Error_Incorrect_method_maxsub, numSize); + return false; } } - return true; /* return the position */ + // zero subscripts is always an error + else + { + reportException(Error_Incorrect_method_minarg, argPosition); + } } /** - * Make sure that the array has been expanded to sufficient - * size for a primitive put operation. + * Process and validate an index for a multi dimension array. * - * @param newSize The new required size. + * @param index The array of objects representing the index. + * @param indexCount The count of index items. + * @param argPosition The argument position (used for error + * reporting) + * @param boundsError + * Flags indicating how bounds errors should be handled. + * @param position The returned flattened index pointing to the actual + * item in the array. + * + * @return true if this was a valid index (within bounds) based + * on the bounds checking flags. */ -void ArrayClass::ensureSpace(size_t newSize) +bool ArrayClass::validateMultiDimensionIndex(RexxObject **index, size_t indexCount, + size_t argPosition, size_t boundsError, stringsize_t &position) { - /* out of bounds? */ - if (newSize > this->size()) + size_t numSubscripts = indexCount; + size_t numDimensions = dimensions->size(); + + // do we have the right number of subscripts for this array? + // this is worth processing. + if (numSubscripts == numDimensions) { - if (newSize >= MAX_FIXEDARRAY_SIZE) + // a multiplier for translating into an absolute index position + size_t multiplier = 1; + size_t offset = 0; + + // now loop through all of the index values + for (size_t i = numSubscripts; i > 0; i--) { - reportException(Error_Incorrect_method_array_too_big); + // each subscript is required. + RexxObject *value = index[i - 1]; + // this must be a positive whole number and is required. + position = positionArgument(value, argPosition + i); + + // get the current dimension + size_t dimension = ((RexxInteger *)dimensions->get(i))->getValue(); + // is this position larger than the current dimension? Check how + // the out of bounds situation should be handled. + if (position > dimension) + { + // allowed to extend...we resize this array to at least match the + // upper bounds on all dimensions here. + if (boundsError & ExtendUpper) + { + // go extend this + extendMulti(index, indexCount, argPosition); + // Ok, now try validating again now that the array has expanded. + // Note that because all subscripts are handled here, we should not + // need to extend a second time. + return validateMultiDimensionIndex(index, indexCount, argPosition, boundsError, position); + } + // asked to raise an error? + else if (boundsError & RaiseBoundsUpper) + { + reportException(Error_Incorrect_method_array, position); + } + // probably a get() request, we just need to know if this is out of bounds, + // so fail silently. + + // TODO: Technically, we should probably validate that the rest of the arguments are at + // least valid. + else + { + return false; + } + } + + // calculate the next offset position + offset += multiplier * (position - 1); + // and get the total dimension base size. + multiplier *= dimension; } - /* yes, compute amount to expand */ - this->extend(newSize - this->size()); - + // get the accumulated position value...we now have a good value within the bounds + position = offset + 1; + return true; } + // we have a mismatch between the index and the number of dimensions...issue the appropriate error + else if (numSubscripts < numDimensions) + { + reportException(Error_Incorrect_method_minsub, numDimensions); + } + // must be too many subscripts + else + { + reportException(Error_Incorrect_method_maxsub, numDimensions); + } } - +/** + * Return the array size as an integer object + * + * @return An integer object containing the array size. + */ RexxInteger *ArrayClass::sizeRexx() -/******************************************************************************/ -/* Function: Return the array size as an integer object */ -/******************************************************************************/ { return new_integer(size()); } + /** * Section an array to the given size. * @@ -1337,40 +1404,44 @@ * * @return A new array representing the given section. */ -ArrayClass *ArrayClass::section(size_t _start, size_t _end) +ArrayClass *ArrayClass::section(size_t start, size_t _end) { - size_t newSize; /* Size for new array. */ - ArrayClass *newArray; /* The new array. */ + // 0 means the starting position was omitted, so start + // from the beginning + if (start == 0) + { + start = 1; + } - if (_start == 0) /* starting position specified? */ + // ending position omitted or, End pos past end of array? + // either way, this goes to the end of the array + if (end == 0 || end > size()) { - _start = 1; /* nope, start at begining */ + end = size(); } - /* ending position omitted */ - /* or, End pos past end of array? */ - if (_end == 0 || _end > this->size()) + // if the start is before the end, then we have something to section + if (start <= end) { - _end = this->size(); /* yes, use end of array */ + // get a new array of the required size + size_t newSize = _end + 1 - _start; + ArrayClass *newArray = (ArrayClass *)new_array(newSize); + // while we could just copy the elements in one shot, + // we need to process each element so that the item count and + // last item fields are properly set up. + for (size_t i = 1; i <= newSize; i++, start++) + { + newArray->put(get(start), i); + } + return newArray; } - if (_start <= _end) - { /* is start before end? */ - newSize = _end + 1 - _start; /* yes, compute new size */ - /* Get new array, of needed size */ - newArray = (ArrayClass *)new_array(newSize); - // a new array cannot be oldspace, by definition. It's safe to use - // memcpy to copy the data. - /* yes, we can do a memcpy */ - memcpy(newArray->data(), slotAddress(_start), sizeof(RexxObject *) * newSize); - } else { - /* return 0 element array */ - newArray = (ArrayClass *)new_array((size_t)0); + return new_array((size_t)0); } - return newArray; /* return the newly created array */ } + /** * Extract a section of the array as another array * @@ -1379,340 +1450,277 @@ * * @return A new array containing the section elements. */ -RexxObject *ArrayClass::sectionRexx(RexxObject * _start, RexxObject * _end) +ArrayClass *ArrayClass::sectionRexx(RexxObject *start, RexxObject *end) { - /* multidimensional array? */ - if (isMultiDimensional()) - { - /* this is an error */ - reportException(Error_Incorrect_method_section); - } + // not allowed for a multi dimensional array + checkMultiDimensinoal("SECTION"); // the index is required requiredArgument(_start, ARG_ONE); - size_t nstart; // array position - // validate the index and expand if necessary. - this->validateIndex(&_start, 1, 1, RaiseBoundsInvalid | RaiseBoundsTooMany, nstart); - size_t nend = 0; ; - if (_end == OREF_NULL) /* If no end position specified, */ + size_t nstart; + // validate the index + validateIndex(start, ARG_ONE, IndexAccess, nstart); + + // the ending position is a length value and defaults to the size of the array + size_t nend = optionalLengthArgument(end, size(), ARG_TWO); + + if (nstart > size()) { - nend = this->size(); /* Defaults to last element */ + nend = 0; } else - { /* End specified - check it out */ - nend = _end->requiredNonNegative(ARG_TWO); + { + // now cap the length at the remaining size of the array + nend = Numerics::minVal(nend, size() - nstart + 1); } - if (!isOfClass(Array, this)) /* actually an array subclass? */ + // get an array of the appropriate subclass + ArrayClass *newArray = allocateArrayOfClass(nend); + // copy all of the elements + for (size_t i = 1; i <= nend; i++, nstart++) { - /* need to do this the slow way */ - return this->sectionSubclass(nstart, nend); + newArray->put(get(nstart), i); } - if (nstart > this->size()) /* too big? */ + return newArray; +} + + +/** + * Allocate an array of the same class as the target. Used + * for the section operation. + * + * @param size The size of the array. + * + * @return An array object allocated from the same class as the + * receiver. + */ +RexxArray *ArrayClass::allocateArrayOfClass(size_t size) +{ + // typical is a just a primitive array. + if (isOfClass(Array, this)) { - // return a zero-size array - return (ArrayClass *)(((ArrayClass *)TheNullArray)->copy()); + return new_array(size); } - else - { - /* go past the bounds? */ - if (nend > this->size() - nstart + 1) - { - nend = this->size() - nstart + 1;/* truncate to the end */ - } - if (nend == 0) /* requesting zero? */ - { - /* return zero elements */ - return (ArrayClass *)(((ArrayClass *)TheNullArray)->copy()); - } - else - { /* real sectioning to do */ - /* create a new array */ - ArrayClass *rref = (ArrayClass *)new_array(nend); - for (size_t i = 1; i <= nend; i++) - { /* loop through the elements */ - /* copy an element */ - rref->put(this->get(nstart + i - 1), i); - } - return rref; /* return the new array */ - } - } + + // need to do this by sending a message to the class object. + ProtectedObject result; + classObject()->sendMessageOREF_NEW, new_integer(size), result); + return (ArrayClass *)(RexxObject *)result; } -RexxObject *ArrayClass::sectionSubclass( - size_t _start, /* starting element */ - size_t _end ) /* ending element */ -/******************************************************************************/ -/* Function: Rexx level section method */ -/******************************************************************************/ + +/** + * Retrieve the first element index from the array as an integer + * object + * + * @return The index of the first item. + */ +RexxObject *ArrayClass::firstRexx() { - size_t i; /* loop counter */ - ArrayClass *newArray; /* returned array */ - ProtectedObject result; + // locate the first item + size_t index = firstIndex(); - if (_start > this->size()) /* too big? */ - { - this->behaviour->getOwningClass()->sendMessage(OREF_NEW, IntegerZero, result); - newArray = (ArrayClass *)(RexxObject *)result; - } - /* return a zero element one */ - else - { - if (_end > this->size() - _start + 1) - { - /* go past the bounds? */ - _end = this->size() - _start + 1;/* truncate to the end */ - } - if (_end == 0) /* requesting zero? */ - { - this->behaviour->getOwningClass()->sendMessage(OREF_NEW, IntegerZero, result); - newArray = (ArrayClass *)(RexxObject *)result; - } - /* return a zero element one */ - else - { /* real sectioning to do */ - /* create a new array */ - this->behaviour->getOwningClass()->sendMessage(OREF_NEW, new_integer(_end), result); - newArray = (ArrayClass *)(RexxObject *)result; - for (i = 1; i <= _end; i++) /* loop through the elements */ - { - /* copy an element */ - newArray->sendMessage(OREF_PUT, this->get(_start + i - 1), new_integer(i)); - } - } - } - return newArray; /* return the new array */ + // if no element found, this is the nil object. Otherwise, convert + // the index into external form (we could be multidimensional) + // this is all handled by convertIndex() + return convertIndex(index); } -RexxObject *ArrayClass::firstRexx() -/******************************************************************************/ -/* Function: Retrieve the first element index from the array as an integer */ -/* object */ -/******************************************************************************/ + +/** + * Retrieve the index of the first real element + * + * @return The index of the first item. + */ +size_t *ArrayClass::firstIndex() { - /* get the address of the first */ - /*element in the array */ - RexxObject **thisObject = this->expansionArray->objects; - size_t _arraySize = this->size(); /* get the size of the array */ - /* find first position in the */ - /*array with data */ + // locate the next index starting from the 0th position (this will + // start the search at index 1). + return nextIndex(0); +} - size_t i; - for (i = 0; i < _arraySize && thisObject[i] == OREF_NULL; i++); - if (i == _arraySize) /* is array empty */ - { - return TheNilObject; /* return nil object */ - } - else - { - /* return index of the first entry */ - return convertIndex(i + 1); - } +/** + * Return the index of the last array item as an integer object + * + * @return The index position, as an object. + */ +RexxObject *ArrayClass::lastRexx() +{ + return convertIndex(lastItem); } -RexxObject *ArrayClass::lastRexx() -/******************************************************************************/ -/* Function: Return the index of the last array item as an integer object */ -/******************************************************************************/ + +/** + * Return the index of the last item in the array. Returns + * 0 if the array is empty. + * + * @return The index of the last item. + */ +size_t ArrayClass::lastIndex() { - // for an empy array, the index is .nil - if (lastElement == 0) - { - return TheNilObject; - } - - // return as an object - return (RexxObject *)convertIndex(lastElement); + return lastItem; } + /** * Return the first item in the array, or .nil if the * array is empty. * * @return The first item in the array */ -RexxObject *ArrayClass::firstItem() +RexxInternalObject *ArrayClass::firstItem() { - /* get the address of the first */ - /*element in the array */ - RexxObject **thisObject = this->expansionArray->objects; - size_t _arraySize = this->size(); /* get the size of the array */ - /* find first position in the */ - /*array with data */ - - for (size_t i = 0; i < _arraySize; i++) - { - // if we have a non-nil object, return it - if (thisObject[i] != OREF_NULL) - { - return thisObject[i]; - } - } - // not found, return .nil - return TheNilObject; + // find the index of the first item + size_t index = firstIndex(); + return index == 0 ? TheNilObject : get(index); } + /** * Return the last item in the array. * * @return The last item, or .nil if the array is empty. */ -RexxObject *ArrayClass::lastItem() +RexxInternalObject *ArrayClass::lastItem() { - // for an empy array, the item is .nil - if (lastElement == 0) + return lastItem == 0 ? TheNilObject : get(lastItem); +} + +/** + * Find the next index position with an item. + * + * @param index The index position to search from. + * + * @return The index position of the next item, or 0 if there is no + * next item. + */ +size_t ArrayClass::nextIndex(size_t index) +{ + // scan from the next slot up to the last item position. Note that + // we allow a starting value of 0...useful for locating the first index! + for (size_t nextIndex = index +1; nextIndex <= lastItem; nextIndex++) { - return TheNilObject; + if (isOccupied(nextIndex)) + { + return nextIndex; + } } - // return the last item - return (RexxObject *)get(lastElement); + // nothing found + return 0; } -size_t ArrayClass::lastIndex() -/******************************************************************************/ -/* Function: Return the index of the last array item as an integer object */ -/******************************************************************************/ -{ - return lastElement; // we've kept track of this -} -RexxObject *ArrayClass::nextRexx(RexxObject **arguments, size_t argCount) -/******************************************************************************/ -/* Function: Return the next entry after a given array index */ -/******************************************************************************/ +/** + * Return the next entry after a given array index + * + * @param arguments The pointer to the index arguments. + * @param argCount The count of index arguments. + * + * @return The index position of the next item, as an object. + */ +RexxObject *ArrayClass::nextRexx(RexxObject **arguments, size_t argCount) { size_t position; - /* go validate the index */ - if (!this->validateIndex(arguments, argCount, 1, RaiseBoundsTooMany | RaiseBoundsInvalid, position)) + // go validate the index + if (!validateIndex(arguments, argCount, ARG_ONE, IndexAccess, position)) { // out of bounds results in the .nil object return TheNilObject; } - /* get the address of the first */ - /*element in the array */ - RexxObject **thisObject = this->data(); - size_t _arraySize = this->size(); /* get the size of the array */ - /* find next entry in the array with */ - /*data */ - size_t i; - for (i = position; i < _arraySize && thisObject[i] == OREF_NULL; i++); + // go locate the next item + return convertIndex(nextIndex(position)); +} - if (i >= this->size()) + +/** + * Return the index preceeding a given index + * + * @param index The starting index position + * + * @return The previous index position with an item. Returns 0 if + * none was found. + */ +size_t ArrayClass::previousRexx(size_t index) +{ + // no need to scan if past the end position...we know the answer. + if (index >= lastItem) { - return TheNilObject; /* return nil object */ + return lastItem; } - else + // scan backwards from the starting index until we found an occupied slot. + for (size_t previous = index; previous > 0; previous--) { - /* return index of the next entry */ - return convertIndex(i + 1); + if (isOccupied(previous)) + { + return previous; + } } + // nothing found + return 0; } -RexxObject *ArrayClass::previousRexx(RexxObject **arguments, size_t argCount) -/******************************************************************************/ -/* Function: Return the index preceeding a given index */ -/******************************************************************************/ + +/** + * Return the index preceeding a given index + * + * @param arguments The index arguments (might be multi dimensional) + * @param argCount The count of index elements. + * + * @return The index position, as an object. + */ +RexxObject *ArrayClass::previousRexx(RexxObject **arguments, size_t argCount) { size_t position; - - this->validateIndex(arguments, argCount, 1, RaiseBoundsTooMany | RaiseBoundsInvalid, position); - /* get the index object into an */ - /*integer object */ - size_t i = position; - - size_t _arraySize = this->size(); /* get the size of the array */ - - if (i > _arraySize) /* beyond the size of the array? */ + // go validate the index + if (!validateIndex(arguments, argCount, ARG_ONE, IndexAccess, position)) { - /* set i to one more than the last */ - /*entry */ - i = _arraySize; + // out of bounds results in the .nil object + return TheNilObject; } - else - { - i = i-1; /* Account for 0 based 'C' arrays */ - } - /* get the address of the first */ - /*element in the array */ - RexxObject **thisObject = this->expansionArray->objects; - /* find previous entry in the */ - /*array with data */ - for (; i > 0 && thisObject[i-1] == OREF_NULL; i--); - - if (i == 0) - { - return TheNilObject; /* return nil object */ - } - else - { - /* return the index to the */ - /*previous entry */ - return convertIndex(i); - } + // go locate the next item + return convertIndex(previousIndex(position)); } -RexxObject *ArrayClass::hasIndexRexx(RexxObject ** _index, size_t _indexCount) -/******************************************************************************/ -/* Function: True if array has an entry for the index, false otherwise */ -/* Note: This routine should not raise an error, regardless of the indices */ -/* being used. The only error produced is if no parms were passed. */ -/******************************************************************************/ + +/** + * True if array has an entry for the index, false otherwise + * + * Note: This routine should not raise an error, regardless of the indices + * being used. The only error produced is if no parms were passed. + * + * @param index Arguments for a potential multi-dimensional array index. + * @param indexCount The count of indexes. + * + * @return .true if there is an item at that position, .false otherwise. + */ +RexxObject *ArrayClass::hasIndexRexx(RexxObject **index, size_t indexCount) { - stringsize_t position; /* array position */ - - /* go validate the index */ - if (!this->validateIndex(_index, _indexCount, 1, RaiseBoundsTooMany | RaiseBoundsInvalid, position)) + // validate the index position. Out of bounds is always false. + if (!validateIndex(index, indexCount, ARG_ONE, IndexAccess, position)) { - /* this is false */ return TheFalseObject; - } - else /* check the position */ - { - /* have a real entry? */ - if (*(this->data() + position - 1) != OREF_NULL) - { - /* got a true */ - return TheTrueObject; - } - else - { - /* no index here */ - return TheFalseObject; - } - } + // now check the slot position + return booleanObject(hasIndex(position)); } -bool ArrayClass::hasIndexNative(size_t _index) -/******************************************************************************/ -/* Function: Determine if an element exist for a position */ -/******************************************************************************/ -{ - /* in bounds and here? */ - if (_index > 0 && _index <= this->size() && *(this->data() + _index - 1) != OREF_NULL) - { - return true; /* this is true */ - } - else - { - return false; /* nope, don't have it */ - } -} -ArrayClass *ArrayClass::makeArray(void) -/******************************************************************************/ -/* Function: Return a single dimension array of self, with only items that */ -/* has values, so it will be of size items. */ -/******************************************************************************/ +/** + * Return a single dimension array of self, with only items that + * has values, so it will be of size items. + * + * @return A single-dimension array containing all of the items in the array (non-sparse). + */ +ArrayClass *ArrayClass::makeArray() { // for an array, this is the all items value. - return this->allItems(); + return allItems(); } @@ -1724,20 +1732,18 @@ ArrayClass *ArrayClass::allItems() { // get a result array of the appropriate size - ArrayClass *newArray = (ArrayClass *)new_array(this->items()); + ArrayClass *newArray = (ArrayClass *)new_array(items()); - // we need to fill in based on actual items, not the index. - size_t count = 0; - RexxObject **item = this->data(); - // loop through the array, copying all of the items. - for (size_t iterator = 0; iterator < this->size(); iterator++ ) + // now fill in that array + size_t count = 1; + for (size_t index = 1; index <= lastItem; index++) { - // if this is a real array item, copy over to the result - if (item[iterator] != OREF_NULL) + if (isOccupied(index)) { - newArray->put(item[iterator], ++count); + newArray->put(get(index), count++); } } + return newArray; } @@ -1770,28 +1776,41 @@ return newArray; } -// Temporary bypass for BUG #1700606 -#if 0 + +/** + * Handle a REQUEST('STRING') request for a REXX string object + * + * @return A string value for the array. + */ RexxString *ArrayClass::primitiveMakeString() -/******************************************************************************/ -/* Function: Handle a REQUEST('STRING') request for a REXX string object */ -/******************************************************************************/ { - return this->makeString((RexxString *)OREF_NULL); /* forward to the real makestring method */ + // forward to the real makestring method + return toString(OREF_NULL, OREF_NULL); } -#endif +/** + * Convert an array into a string item + * + * @param format The optional format ('C' or 'L') + * @param separator The separator between elements for the 'L' format. + * + * @return A single string value for the array. + */ RexxString *ArrayClass::makeString(RexxString *format, RexxString *separator) { return toString(format, separator); } -RexxString *ArrayClass::toString( /* concatenate array elements to create string object */ - RexxString *format, /* format of concatenation (one of: "C", "L") */ - RexxString *separator) /* separator to use if "L" is specified for format */ -/******************************************************************************/ -/* Function: Make a string out of an array */ -/******************************************************************************/ + +/** + * Convert an array into a string item + * + * @param format The optional format ('C' or 'L') + * @param separator The separator between elements for the 'L' format. + * + * @return A single string value for the array. + */ +RexxString *ArrayClass::toString(RexxString *format, RexxString *separator) { size_t _items; size_t i; @@ -1802,38 +1821,25 @@ RexxObject *item; /* inserted value item */ int i_form = 0; /* 1 == line, 2 == char */ - mutbuffer = new RexxMutableBuffer(); - ProtectedObject p1(mutbuffer); + // we build up in a mutable buffer + Protected<RexxMutableBuffer> mutbuffer = new RexxMutableBuffer(); + // convert into a non-sparse single dimension array item. + Protected<ArrayClass> newArray = makeArray(); - newArray = this->makeArray(); /* maybe multidimensional, make onedimensional */ - ProtectedObject p2(newArray); + // get the count of items + size_t itemCount = newArray->items(); - _items = newArray->items(); /* and the actual count in the array */ + // get the option argument and apply the default + char form = optionalOptionArgument(format, 'L', ARG_ONE); - if (format != OREF_NULL) + // must be one of L or C. + if (form != 'L' && form != 'C') { - // a string value is required here - format = stringArgument(format, ARG_ONE); - } - - if (format == OREF_NULL) - { - i_form = 2; /* treat item as LINE by default */ - } - else if (toupper((format->getStringData()[0])) == 'C') - { - i_form = 1; - } - else if (toupper((format->getStringData()[0])) == 'L') - { - i_form = 2; - } - else - { reportException(Error_Incorrect_method_option, "CL", format); } - if (i_form == 1) /* character oriented processing */ + // character oriented process. The separator string is not allowed with that form + if (form == 'C') { if (separator != OREF_NULL) { @@ -1841,76 +1847,85 @@ } - for (i = 1; i <=_items ; i++) /* loop through the array */ + // loop through the array + for (size_t i = 1; i <=_items ; i++) { - item = newArray->get(i); /* get the next item */ + item = newArray->get(i); + // if we have a real item (which we should since we used makearray() at the + // beginning if (item != OREF_NULL) { - RexxObject * _stringValue = item->requiredString(); - if (_stringValue != TheNilObject) - { - mutbuffer->append(_stringValue); - } + // NOTE: We use stringValue here rather than requestString(). You can + // get into some nasty recursion problems with with trying to do a full + // string resolution here. Items like arrays stored in arrays will display + // as "An Array". + RexxString *value = item->stringValue(); + mutbuffer->append(value); } } } - else if (i_form == 2) /* line oriented processing */ + // LINE oriented processing + else { + Protected<RexxString> lineEndString; if (separator != OREF_NULL) { - line_end_string = stringArgument(separator, ARG_TWO); + lineEndString = stringArgument(separator, ARG_TWO); } else { - line_end_string = new_string(line_end); + lineEndString = new_string(line_end); } - ProtectedObject p3(line_end_string); bool first = true; - for (i = 1; i <= _items; i++) /* loop through the array */ + for (size_t i = 1; i <= _items; i++) { - item = newArray->get(i); /* get the next item */ + item = newArray->get(i); if (item != OREF_NULL) { // append a linend between the previous item and this one. if (!first) { - mutbuffer->append((RexxObject *) line_end_string); + mutbuffer->append(line_end_string); } - RexxObject *_stringValue = item->requiredString(); - if (_stringValue != TheNilObject) - { - mutbuffer->append(_stringValue); - } + RexxString *value = item->stringValue(); + mutbuffer->append(value); first = false; } } } - newString = mutbuffer->makeString(); - return newString; + return mutbuffer->makeString(); } -RexxObject *ArrayClass::join( /* join two arrays into one */ - ArrayClass *other) /* array to be appended to self */ -/******************************************************************************/ -/* Function: Join two arrays into one array */ -/******************************************************************************/ + +/** + * Join two arrays into one array. + * + * @param other The other array of the join operation. + * + * @return A new array will all elements of the first. + */ +RexxObject *ArrayClass::join(ArrayClass *other) { /* get new array, total size is size */ /* of both arrays. */ - ArrayClass *newArray = (ArrayClass*)new_array(this->size() + other->size()); + // get a new array with the combined size of the two arrays. + ArrayClass *newArray = (ArrayClass*)new_array(size() + other->size()); // it's safe to just copy the references because the newArray will be new space - /* copy first array into new one */ - memcpy(newArray->data(), this->data(), this->dataSize()); - /* copy 2nd array into the new one */ - /* after the first one. */ + // copy first array into new one + memcpy(newArray->data(), data(), dataSize()); + // copy 2nd array into the new one after the first one memcpy((void *)newArray->slotAddress(this->size() + 1), other->data(), other->dataSize()); - return newArray; /* All done, return joined array */ + // we need to update the items and the last item pointer + newArray->itemCount = items() + other->items(); + newArray->lastItem = size() + other->lastItem; + return newArray; } + /** * An Array is being expanded so chop off the data (array) * portion of this array. @@ -1929,8 +1944,16 @@ { for (size_t i = 0; i < arraySize; i++) { + // Note, we do this directly rather than use + // the other setting methods because we don't + // want touch the item count or last item, and + // we certainly don't want to hit the expansion array + // by mistake. setField(objects[i], OREF_NULL); } + // we don't get marked as an oldspace object, but adjust the + // array size down anyway. + arraySize = 0; } else { @@ -1942,77 +1965,76 @@ } } -void ArrayClass::shrink( - size_t amount) /* amount to shrink an array */ -/******************************************************************************/ -/* Function: Shrink an array without reallocating any elements */ -/* Single Dimension ONLY */ -/******************************************************************************/ -{ - size_t _size = this->size(); /* get the size */ - size_t newSize = _size - amount; /* get the new size */ - this->expansionArray->arraySize = newSize; -} - - -size_t ArrayClass::indexOf( - RexxObject *target) /* target object to locate */ -/*****************************************************************************/ -/* Function: To search a list in the form of an array for... [truncated message content] |