/** * Exported Rexx method for adding an item to a collection. * The put operation is delegated to the implementing * class virtual function. * * @param _value The value to add. * @param _index The index for the added item. * * @return Always returns OREF_NULL. */ RexxObject *RexxHashTableCollection::putRexx(RexxObject *_value, RexxObject *_index) { requiredArgument(_value, OREF_positional, ARG_ONE); /* make sure we have an value */ requiredArgument(_index, OREF_positional, ARG_TWO); /* make sure we have an index */ /* try to place in existing hashtab */ return this->put(_value, _index); }
RexxObject *RexxHashTableCollection::addRexx( RexxObject *_value, /* object to add */ RexxObject *_index) /* added index */ /******************************************************************************/ /* Arguments: Value, index */ /* */ /* Returned: Nothing */ /******************************************************************************/ { requiredArgument(_value, OREF_positional, ARG_ONE); /* make sure we have an value */ requiredArgument(_index, OREF_positional, ARG_TWO); /* make sure we have an index */ return add(_value, _index); }
/** * Exported method to remove an item specified by value. * * @param target The target object. * * @return The target object again. */ RexxObject *RexxHashTableCollection::removeItemRexx(RexxObject *target) { // required argument requiredArgument(target, OREF_positional, ARG_ONE); // the actual target class may use different semantics for this. return this->removeItem(target); }
/** * Queue an item on this queue. * * @param item The item to add to the queue. * * @return Returns nothing. */ RexxObject *QueueClass::queueRexx(RexxObject *item) { requiredArgument(item, ARG_ONE); queue(item); return OREF_NULL; }
/** * Resolve the "stem.[a,b,c]=" to the equivalent stem.a.b.c= form, * with all of the indices taken as constants * * @param tailElements * The array of arguments. the first argument is the * assigned value. All additional arguments are the * tail pieces. * @param argCount The count of arguments. * * @return Returns nothing. */ RexxObject *StemClass::bracketEqual(RexxObject **tailElements, size_t argCount) { // no value to set? This is an error if (argCount == 0) { reportException(Error_Incorrect_method_noarg, IntegerOne); } RexxObject *newValue = requiredArgument(tailElements[0], ARG_ONE); // if the argument count is 1, we're just setting the default value if (argCount == 1) { // stem value as default? don't allow this as it leads to recursion loops if (isStem(newValue)) { reportException(Error_Execution_nostem); } setField(value, newValue); // this clears out all of our elements and gets marked as having an // explicit value. tails.clear(); dropped = false; return OREF_NULL; } // create a searchable tail from the array elements // and set the variable value CompoundVariableTail resolved_tail((RexxInternalObject **)(tailElements + 1), argCount - 1); CompoundTableElement *variable = getCompoundVariable(resolved_tail); variable->set(newValue); return OREF_NULL; }
/** * Test for the existence of an index in the collection. * This uses the get() virtual function to determine if * the item exists. * * @param _index The target index. * * @return True if the index exists, false if the index does not * exist. */ RexxObject *RexxHashTableCollection::hasIndexRexx(RexxObject *_index) { requiredArgument(_index, OREF_positional, ARG_ONE); /* make sure we have an index */ /* try to get the item */ RexxObject *_value = this->get(_index); /* tell caller if we succeeded */ return(_value != OREF_NULL) ? (RexxObject *)TheTrueObject : (RexxObject *)TheFalseObject; }
/** * Exported get() accessor for a hash table collection. * This delegates to a virtual method defined by the * target collection. * * @param _index The target index. * * @return The fetched object, or .nil if the index does not * exist in the collection. */ RexxObject *RexxHashTableCollection::getRexx(RexxObject *_index) { requiredArgument(_index, OREF_positional, ARG_ONE); /* make sure we have an index */ RexxObject *object = this->get(_index); /* get the item */ if (object == OREF_NULL) /* If nothing found, give back .nil */ { return TheNilObject; /* (never return OREF_NULL to REXX) */ } return object; /* return the item */ }
RexxObject *RexxHashTableCollection::allAt( RexxObject *_index) /* target index */ /******************************************************************************/ /* Arguments: Index */ /* */ /* Returned: Array of all values with the same index */ /******************************************************************************/ { requiredArgument(_index, OREF_positional, ARG_ONE); /* make sure we have an index */ /* do the get */ return this->contents->getAll(_index); }
/** * The exported remove() method for hash collection * classes. This is the Rexx stub method. The removal * operation is delegated to the virtual method defined * by the implementing class. * * @param _index The target removal index. * * @return The removed object, or .nil if the index was not found. */ RexxObject *RexxHashTableCollection::removeRexx(RexxObject *_index) { requiredArgument(_index, OREF_positional, ARG_ONE); /* make sure we have an index */ RexxObject *removedItem = this->remove(_index); /* remove the item */ if (removedItem == OREF_NULL) /* If nothing found, give back .nil */ { /* (never return OREF_NULL to REXX) */ return TheNilObject; } return removedItem; /* return removed value */ }
/** * The Rexx stub for the Queue PUT method. replaces the Array * version because it has slightly different semantics for index * validation. The only valid indexes are those within range * and the size is not adjusted for a put out of bounds. * * @param arguments The array of all arguments sent to the * method (variable arguments allowed * here...the first argument is the item being * added, all other arguments are the index). * @param argCount The number of arguments in the method call. * * @return Always return nothing. */ RexxObject *QueueClass::putRexx(RexxObject *value, RexxObject *index) { requiredArgument(value, ARG_ONE); // make sure we have an index specified before trying to decode this. requiredArgument(index, ARG_TWO); // Validate the index argument, but don't allow expansion. size_t position; if (!validateIndex(&index, 1, ARG_TWO, IndexAccess, position)) { reportException(Error_Incorrect_method_index, index); } // we can only update assigned items, so make sure this is within bounds. checkInsertIndex(position); // set the new value and return nothing put(value, position); return OREF_NULL; }
/** * Retrieve an index for a given item. Which index is returned * is indeterminate. * * @param target The target object. * * @return The index for the target object, or .nil if no object was * found. */ RexxObject *RexxHashTableCollection::indexRexx(RexxObject *target) { // required argument requiredArgument(target, OREF_positional, ARG_ONE); // retrieve this from the hash table RexxObject *result = this->getIndex(target); // not found, return .nil if (result == OREF_NULL) { return TheNilObject; } return result; }
/** * Supplier initializer for suppliers created via * .supplier~new(values, indexes). * * @param values The values array object * @param indexes The indexes array object * * @return Nothing */ RexxObject *RexxSupplier::initRexx(RexxArray *_values, RexxArray *_indexes) { requiredArgument(_values, ARG_ONE); // both values are required requiredArgument(_indexes, ARG_TWO); // now verify both values RexxArray *new_values = REQUEST_ARRAY(_values); RexxArray *new_indexes = REQUEST_ARRAY(_indexes); if (new_values == (RexxArray *)TheNilObject || new_values->getDimension() != 1) { reportException(Error_Incorrect_method_noarray, values); } if (new_indexes == (RexxArray *)TheNilObject || new_indexes->getDimension() != 1) { reportException(Error_Incorrect_method_noarray, indexes); } OrefSet(this, this->values, new_values); OrefSet(this, this->indexes, new_indexes); this->position = 1; return OREF_NULL; }
/** * Perform the Arithmetic power operation * * @param PowerObj The power we're raising this number to. * * @return The power result. */ NumberString *NumberString::power(RexxObject *powerObj) { requiredArgument(powerObj, ARG_ONE); wholenumber_t powerValue; if (!powerObj->numberValue(powerValue, number_digits())) { reportException(Error_Invalid_whole_number_power, powerObj); } bool negativePower = false; // if the power is negative, we'll first calculate the power // as a positive and take the reciprical at the end. if (powerValue < 0) { negativePower = true; powerValue = -powerValue; } wholenumber_t digits = number_digits(); // get a potential copy of this, truncated to have at most digits + 1 digits. NumberString *left = prepareOperatorNumber(digits + 1, digits, NOROUND); // if we are raising zero to a power, there are some special rules in play here. if (left->isZero()) { // if the power is negative, this is an overflow error if (negativePower) { reportException(Error_Overflow_power); } // mathematically, 0**0 is undefined. Rexx defines this as 1 else if (powerValue == 0) { return (NumberString *)IntegerOne; } // zero to a non-zero power is zero else { return (NumberString *)IntegerZero; } } // we figure out ahead of time if this will overflow without having to // do all of the calculation work. This tests if we can even start the // process because it will required too many bits to calculate. This is // more likely to fail with 32-bit compiles than 64-bit because we have // fewer bits to work with. if ((highBits(Numerics::abs(left->numberExponent + left->digitsCount - 1)) + highBits(Numerics::abs(powerValue)) + 1) > SIZEBITS ) { reportException(Error_Overflow_overflow, this, GlobalNames::POWER, powerObj); } // we can also calculate the exponent magnitude ahead of time and fail this early. if (Numerics::abs(left->numberExponent + left->digitsCount - 1) * powerValue > Numerics::MAX_EXPONENT) { reportException(Error_Overflow_overflow, this, GlobalNames::POWER, powerObj); } // anything raised to the 0th power is 1, this is an easy one. if (powerValue == 0) { return (NumberString *)IntegerOne; } // we create a dummy numberstring object and initialize it from the target number NumberStringBase accumNumber = *left; NumberStringBase *accumObj = &accumNumber; // Find out how many digits are in power value, needed for actual // precision value to be used in the computation. wholenumber_t extra = 0; wholenumber_t oldNorm = powerValue; // keep dividing the value by 10 until we hit zero. That will be the number of // powers of 10 we have in the number. for (; oldNorm != 0; extra++) { oldNorm /= 10; } // add these extra digits into the working digits setting digits += (extra + 1); // and this is the size of the buffers we need for our accumulators wholenumber_t accumLen = (2 * (digits + 1)) + 1; // get a single buffer object with space for two values of this size char *outPtr = new_buffer(accumLen * 2)->getData(); char *accumBuffer = outPtr + accumLen; char *accumPtr = accumBuffer; // copy the the initial number data into the buffer memcpy(accumPtr, left->numberDigits, left->digitsCount); // the power operation is defined to use bitwise reduction size_t numBits = SIZEBITS; // get the first non-zero bit shifted to the top of the number // this will both position us to start the process and // also give us the a count of how many bits we're working with. while (!((size_t)powerValue & HIBIT)) { powerValue <<= 1; numBits--; } // turn off this 1st 1-bit, already take care of by // the starting accumulator (essentially, a multiply by 1) powerValue = (wholenumber_t) ((size_t)powerValue & LOWBITS); // ok, we know how many passes we need to make on this number. while (numBits--) { // if this bit is on, then we need to multiply the // number by the accumulator. if ((size_t) powerValue & HIBIT) { // do the multiply and get the new high position back accumPtr = multiplyPower(accumPtr, accumObj, left->numberDigits, left, outPtr, accumLen, digits); // We now call AdjustNumber to make sure we stay within the required // precision and move the Accum data back to Accum. accumPtr = accumObj->adjustNumber(accumPtr, accumBuffer, accumLen, digits); } // if we will be making another pass through this loop, we need // to square the accumulator if (numBits > 0) { accumPtr = multiplyPower(accumPtr, accumObj, accumPtr, accumObj, outPtr, accumLen, digits); // and adjust the result again accumPtr = accumObj->adjustNumber(accumPtr, accumBuffer, accumLen, digits); } // and shift to the next bit position powerValue <<= 1; } // if this was actually a negative power, take the reciprical now if (negativePower) { accumPtr = dividePower(accumPtr, accumObj, accumBuffer, digits); } // reset the digits to the original and remove all leading zeros digits -= (extra +1); // reset digits setting to original; accumPtr = accumObj->stripLeadingZeros(accumPtr); // Is result bigger than digits? if (accumObj->digitsCount > digits) { // adjust to the shorter length and round if needed accumObj->numberExponent += (accumObj->digitsCount - digits); accumObj->digitsCount = digits; accumObj->mathRound(accumPtr); } // we now remove any trailing zeros in the result (same rules as // division) char *tempPtr = accumPtr + accumObj->digitsCount - 1; /* While there are trailing zeros */ while (*tempPtr == 0 && accumObj->digitsCount > 0) { tempPtr--; accumObj->digitsCount--; accumObj->numberExponent++; } // finally build a result object. NumberString *result = new (accumObj->digitsCount) NumberString (accumObj->digitsCount); result->numberSign = accumObj->numberSign; result->numberExponent = accumObj->numberExponent; result->digitsCount = accumObj->digitsCount; memcpy(result->numberDigits, accumPtr, result->digitsCount); return result; }
/** * Test if a given item exists in the collection. * * @param target The target object. * * @return .true if the object exists, .false otherwise. */ RexxObject *RexxHashTableCollection::hasItemRexx(RexxObject *target) { requiredArgument(target, OREF_positional, ARG_ONE); return this->hasItem(target); }