/**
 * 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;
}
Exemple #11
0
/**
 * 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;
}
Exemple #12
0
/**
 * 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;
}
Exemple #14
0
/**
 * 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);
}