예제 #1
0
/*! \brief
 * Parses the values for a parameter that takes a variable number of values.
 *
 * \param[in] values List of values.
 * \param     param  Parameter to parse.
 * \param     root   Selection element to which child expressions are added.
 * \param[in] scanner Scanner data structure.
 *
 * For integer ranges, the sequence of numbers from the first to second value
 * is stored, each as a separate value.
 */
static void
parse_values_varnum(const SelectionParserValueList    &values,
                    gmx_ana_selparam_t                *param,
                    const SelectionTreeElementPointer &root,
                    void                              *scanner)
{
    int                 i, j;

    param->flags &= ~SPAR_DYNAMIC;
    /* Compute number of values, considering also integer ranges. */
    int valueCount = static_cast<int>(values.size());
    if (param->val.type == INT_VALUE)
    {
        SelectionParserValueList::const_iterator value;
        for (value = values.begin(); value != values.end(); ++value)
        {
            if (value->type == INT_VALUE && !value->hasExpressionValue())
            {
                valueCount += abs(value->u.i.i2 - value->u.i.i1);
            }
        }
    }

    /* Check that the value type is actually implemented */
    if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE
        && param->val.type != STR_VALUE && param->val.type != POS_VALUE)
    {
        GMX_THROW(InternalError("Variable-count value type not implemented"));
    }

    /* Reserve appropriate amount of memory */
    if (param->val.type == POS_VALUE)
    {
        gmx_ana_pos_reserve(param->val.u.p, valueCount, 0);
        gmx_ana_indexmap_init(&param->val.u.p->m, NULL, NULL, INDEX_UNKNOWN);
        gmx_ana_pos_set_nr(param->val.u.p, valueCount);
    }
    else
    {
        _gmx_selvalue_reserve(&param->val, valueCount);
    }
    /* Create a dummy child element to store the string values.
     * This element is responsible for freeing the values, but carries no
     * other function. */
    if (param->val.type == STR_VALUE)
    {
        SelectionTreeElementPointer child(
                new SelectionTreeElement(SEL_CONST, SelectionLocation::createEmpty()));
        _gmx_selelem_set_vtype(child, STR_VALUE);
        child->setName(param->name);
        child->flags &= ~SEL_ALLOCVAL;
        child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA;
        child->v.nr   = valueCount;
        _gmx_selvalue_setstore(&child->v, param->val.u.s);
        /* Because the child is not group-valued, the u union is not used
         * for anything, so we can abuse it by storing the parameter value
         * as place_child() expects, but this is really ugly... */
        child->u.param = param;
        place_child(root, child, param);
    }
    param->val.nr = valueCount;

    i     = 0;
    SelectionParserValueList::const_iterator value;
    for (value = values.begin(); value != values.end(); ++value)
    {
        GMX_RELEASE_ASSERT(value->type == param->val.type,
                           "Invalid value type (should have been caught earlier)");
        if (value->hasExpressionValue())
        {
            std::string       text(_gmx_sel_lexer_get_text(scanner, value->location()));
            std::string       message("Selection expressions are not supported in this "
                                      "context when multiple values are provided");
            InvalidInputError ex(message);
            ex.prependContext(formatString("Invalid expression '%s'", text.c_str()));
            GMX_THROW(ex);
        }
        switch (param->val.type)
        {
            case INT_VALUE:
                if (value->u.i.i1 <= value->u.i.i2)
                {
                    for (j = value->u.i.i1; j <= value->u.i.i2; ++j)
                    {
                        param->val.u.i[i++] = j;
                    }
                }
                else
                {
                    for (j = value->u.i.i1; j >= value->u.i.i2; --j)
                    {
                        param->val.u.i[i++] = j;
                    }
                }
                break;
            case REAL_VALUE:
                if (value->u.r.r1 != value->u.r.r2)
                {
                    std::string text(_gmx_sel_lexer_get_text(scanner, value->location()));
                    std::string message
                        = formatString("Real range ('%s') is not supported in this context",
                                       text.c_str());
                    InvalidInputError ex(message);
                    GMX_THROW(ex);
                }
                param->val.u.r[i++] = value->u.r.r1;
                break;
            case STR_VALUE:
                param->val.u.s[i++] = gmx_strdup(value->stringValue().c_str());
                break;
            case POS_VALUE:  copy_rvec(value->u.x, param->val.u.p->x[i++]); break;
            default: /* Should not be reached */
                GMX_RELEASE_ASSERT(false, "Variable-count value type not implemented");
        }
    }
    GMX_RELEASE_ASSERT(i == valueCount,
                       "Inconsistent value count wrt. the actual value population");
    if (param->nvalptr)
    {
        *param->nvalptr = param->val.nr;
    }
    param->nvalptr = NULL;
}
예제 #2
0
/*! \brief
 * Parses the values for a parameter that takes a constant number of values.
 *
 * \param[in] values List of values.
 * \param     param  Parameter to parse.
 * \param     root   Selection element to which child expressions are added.
 * \param[in] scanner Scanner data structure.
 *
 * For integer ranges, the sequence of numbers from the first to second value
 * is stored, each as a separate value.
 */
static void
parse_values_std(const SelectionParserValueList &values,
                 gmx_ana_selparam_t *param,
                 const SelectionTreeElementPointer &root, void *scanner)
{
    int                i, j;
    bool               bDynamic;

    /* Handle atom-valued parameters */
    if (param->flags & SPAR_ATOMVAL)
    {
        if (values.size() > 1)
        {
            GMX_THROW(InvalidInputError(
                              "Only a single value or a single expression is "
                              "supported in this context"));
        }
        if (values.front().hasExpressionValue())
        {
            SelectionTreeElementPointer child
                          = add_child(root, param, values.front().expr, scanner);
            child->flags |= SEL_ALLOCVAL;
            if (child->v.type != GROUP_VALUE && (child->flags & SEL_ATOMVAL))
            {
                /* Rest of the initialization is done during compilation in
                 * init_method(). */
                /* TODO: Positions are not correctly handled */
                param->val.nr = -1;
                if (param->nvalptr)
                {
                    *param->nvalptr = -1;
                }
                return;
            }
            param->flags  &= ~SPAR_ATOMVAL;
            param->val.nr  = 1;
            if (param->nvalptr)
            {
                *param->nvalptr = 1;
            }
            param->nvalptr = NULL;
            if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
                || param->val.type == STR_VALUE)
            {
                _gmx_selvalue_reserve(&param->val, 1);
            }
            set_expr_value_store(child, param, 0, scanner);
            return;
        }
        /* If we reach here, proceed with normal parameter handling */
        param->val.nr = 1;
        if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
            || param->val.type == STR_VALUE)
        {
            _gmx_selvalue_reserve(&param->val, 1);
        }
        param->flags &= ~SPAR_ATOMVAL;
        param->flags &= ~SPAR_DYNAMIC;
    }

    i        = 0;
    bDynamic = false;
    SelectionParserValueList::const_iterator value;
    for (value = values.begin(); value != values.end() && i < param->val.nr; ++value)
    {
        GMX_RELEASE_ASSERT(value->type == param->val.type,
                           "Invalid value type (should have been caught earlier)");
        if (value->hasExpressionValue())
        {
            SelectionTreeElementPointer child
                = add_child(root, param, value->expr, scanner);
            set_expr_value_store(child, param, i, scanner);
            if (child->flags & SEL_DYNAMIC)
            {
                bDynamic = true;
            }
        }
        else
        {
            /* Value is not an expression */
            switch (value->type)
            {
                case INT_VALUE:
                {
                    bool bTooManyValues;
                    if (value->u.i.i1 <= value->u.i.i2)
                    {
                        for (j = value->u.i.i1; j <= value->u.i.i2 && i < param->val.nr; ++j)
                        {
                            param->val.u.i[i++] = j;
                        }
                        bTooManyValues = (j != value->u.i.i2 + 1);
                    }
                    else
                    {
                        for (j = value->u.i.i1; j >= value->u.i.i2 && i < param->val.nr; --j)
                        {
                            param->val.u.i[i++] = j;
                        }
                        bTooManyValues = (j != value->u.i.i2 - 1);
                    }
                    if (bTooManyValues)
                    {
                        std::string text(_gmx_sel_lexer_get_text(scanner, value->location()));
                        std::string message
                            = formatString("Range ('%s') produces more values than is "
                                           "accepted in this context",
                                           text.c_str());
                        GMX_THROW(InvalidInputError(message));
                    }
                    --i;
                    break;
                }
                case REAL_VALUE:
                    if (value->u.r.r1 != value->u.r.r2)
                    {
                        std::string text(_gmx_sel_lexer_get_text(scanner, value->location()));
                        std::string message
                            = formatString("Real range ('%s') is not supported in this context",
                                           text.c_str());
                        GMX_THROW(InvalidInputError(message));
                    }
                    param->val.u.r[i] = value->u.r.r1;
                    break;
                case STR_VALUE:
                    param->val.u.s[i] = gmx_strdup(value->stringValue().c_str());
                    break;
                case POS_VALUE:
                    gmx_ana_pos_init_const(&param->val.u.p[i], value->u.x);
                    break;
                case NO_VALUE:
                case GROUP_VALUE:
                    GMX_THROW(InternalError("Invalid non-expression value type"));
            }
        }
        ++i;
    }
    if (value != values.end())
    {
        std::string message
            = formatString("Too many values provided, expected %d",
                           param->val.nr);
        GMX_THROW(InvalidInputError(message));
    }
    if (i < param->val.nr)
    {
        std::string message
            = formatString("Too few values provided, expected %d",
                           param->val.nr);
        GMX_THROW(InvalidInputError(message));
    }
    if (!bDynamic)
    {
        param->flags &= ~SPAR_DYNAMIC;
    }
    if (param->nvalptr)
    {
        *param->nvalptr = param->val.nr;
    }
    param->nvalptr = NULL;
}
예제 #3
0
/*! \brief
 * Parses the values for a parameter that takes integer or real ranges.
 *
 * \param[in] values List of values.
 * \param     param  Parameter to parse.
 * \param[in] scanner Scanner data structure.
 */
static void
parse_values_range(const SelectionParserValueList &values,
                   gmx_ana_selparam_t *param, void *scanner)
{
    int                 i, j, n;

    param->flags &= ~SPAR_DYNAMIC;
    GMX_RELEASE_ASSERT(param->val.type == INT_VALUE || param->val.type == REAL_VALUE,
                       "Invalid range parameter type");
    int                *idata = NULL;
    real               *rdata = NULL;
    scoped_guard_sfree  dataGuard;
    if (param->val.type == INT_VALUE)
    {
        snew(idata, values.size()*2);
        dataGuard.reset(idata);
    }
    else
    {
        snew(rdata, values.size()*2);
        dataGuard.reset(rdata);
    }
    i = 0;
    SelectionParserValueList::const_iterator value;
    for (value = values.begin(); value != values.end(); ++value)
    {
        GMX_RELEASE_ASSERT(value->type == param->val.type,
                           "Invalid range value type (should have been caught earlier)");
        if (value->hasExpressionValue())
        {
            std::string       text(_gmx_sel_lexer_get_text(scanner, value->location()));
            std::string       message("Only simple values or 'A to B' ranges are "
                                      "supported in this context");
            InvalidInputError ex(message);
            ex.prependContext(formatString("Invalid expression '%s'", text.c_str()));
            GMX_THROW(ex);
        }
        if (param->val.type == INT_VALUE)
        {
            int i1 = std::min(value->u.i.i1, value->u.i.i2);
            int i2 = std::max(value->u.i.i1, value->u.i.i2);
            /* Check if the new range overlaps or extends the previous one */
            if (i > 0 && i1 <= idata[i-1]+1 && i2 >= idata[i-2]-1)
            {
                idata[i-2] = std::min(idata[i-2], i1);
                idata[i-1] = std::max(idata[i-1], i2);
            }
            else
            {
                idata[i++] = i1;
                idata[i++] = i2;
            }
        }
        else
        {
            real r1 = std::min(value->u.r.r1, value->u.r.r2);
            real r2 = std::max(value->u.r.r1, value->u.r.r2);
            /* Check if the new range overlaps or extends the previous one */
            if (i > 0 && r1 <= rdata[i-1] && r2 >= rdata[i-2])
            {
                rdata[i-2] = std::min(rdata[i-2], r1);
                rdata[i-1] = std::max(rdata[i-1], r2);
            }
            else
            {
                rdata[i++] = r1;
                rdata[i++] = r2;
            }
        }
    }
    n = i/2;
    /* Sort the ranges and merge consequent ones */
    if (param->val.type == INT_VALUE)
    {
        qsort(idata, n, 2*sizeof(int), &cmp_int_range);
        for (i = j = 2; i < 2*n; i += 2)
        {
            if (idata[j-1]+1 >= idata[i])
            {
                if (idata[i+1] > idata[j-1])
                {
                    idata[j-1] = idata[i+1];
                }
            }
            else
            {
                idata[j]   = idata[i];
                idata[j+1] = idata[i+1];
                j         += 2;
            }
        }
    }
    else
    {
        qsort(rdata, n, 2*sizeof(real), &cmp_real_range);
        for (i = j = 2; i < 2*n; i += 2)
        {
            if (rdata[j-1] >= rdata[i])
            {
                if (rdata[i+1] > rdata[j-1])
                {
                    rdata[j-1] = rdata[i+1];
                }
            }
            else
            {
                rdata[j]   = rdata[i];
                rdata[j+1] = rdata[i+1];
                j         += 2;
            }
        }
    }
    n = j/2;
    /* Store the values */
    if (param->flags & SPAR_VARNUM)
    {
        dataGuard.release();
        param->val.nr  = n;
        if (param->val.type == INT_VALUE)
        {
            srenew(idata, j);
            _gmx_selvalue_setstore_alloc(&param->val, idata, j);
        }
        else
        {
            srenew(rdata, j);
            _gmx_selvalue_setstore_alloc(&param->val, rdata, j);
        }
    }
    else
    {
        if (n != param->val.nr)
        {
            GMX_ASSERT(n == 1,
                       "Range parameters with a fixed count > 1 do not make sense");
            GMX_THROW(InvalidInputError("Only one value or 'A to B' range is "
                                        "supported in this context"));
        }
        if (param->val.type == INT_VALUE)
        {
            memcpy(param->val.u.i, idata, 2*n*sizeof(int));
        }
        else
        {
            memcpy(param->val.u.r, rdata, 2*n*sizeof(real));
        }
    }
    if (param->nvalptr)
    {
        *param->nvalptr = param->val.nr;
    }
    param->nvalptr = NULL;
}