void SelectionTreeElement::mempoolRelease() { if (!mempool) { return; } switch (v.type) { case INT_VALUE: case REAL_VALUE: _gmx_sel_mempool_free(mempool, v.u.ptr); _gmx_selvalue_setstore(&v, NULL); break; case GROUP_VALUE: if (v.u.g) { _gmx_sel_mempool_free_group(mempool, v.u.g); } break; default: GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type")); } }
/*! * \param[in,out] sel Selection element to release. * * Releases the memory allocated for the values of \p sel from the * \p sel->mempool memory pool. If no memory pool is set, nothing is done. */ void _gmx_selelem_mempool_release(t_selelem *sel) { if (!sel->mempool) { return; } switch (sel->v.type) { case INT_VALUE: case REAL_VALUE: _gmx_sel_mempool_free(sel->mempool, sel->v.u.ptr); _gmx_selvalue_setstore(&sel->v, NULL); break; case GROUP_VALUE: if (sel->v.u.g) { _gmx_sel_mempool_free_group(sel->mempool, sel->v.u.g); } break; default: GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type")); } }
void assign(t_selelem *sel, t_selelem *vsource) { GMX_RELEASE_ASSERT(sel_ == NULL, "Can only assign one element with one instance"); old_ptr_ = sel->v.u.ptr; old_nalloc_ = sel->v.nalloc; _gmx_selvalue_setstore(&sel->v, vsource->v.u.ptr); sel_ = sel; }
/*! * \param[in] sel Selection to free. */ void _gmx_selelem_free_values(t_selelem *sel) { int i, n; _gmx_selelem_mempool_release(sel); if ((sel->flags & SEL_ALLOCDATA) && sel->v.u.ptr) { /* The number of position/group structures is constant, so the * backup of using sel->v.nr should work for them. * For strings, we report an error if we don't know the allocation * size here. */ n = (sel->v.nalloc > 0) ? sel->v.nalloc : sel->v.nr; switch (sel->v.type) { case STR_VALUE: if (sel->v.nalloc == 0) { gmx_bug("SEL_ALLOCDATA should only be set for allocated STR_VALUE values"); break; } for (i = 0; i < n; ++i) { sfree(sel->v.u.s[i]); } break; case POS_VALUE: for (i = 0; i < n; ++i) { gmx_ana_pos_deinit(&sel->v.u.p[i]); } break; case GROUP_VALUE: for (i = 0; i < n; ++i) { gmx_ana_index_deinit(&sel->v.u.g[i]); } break; default: /* No special handling for other types */ break; } } if (sel->flags & SEL_ALLOCVAL) { sfree(sel->v.u.ptr); } _gmx_selvalue_setstore(&sel->v, NULL); if (sel->type == SEL_SUBEXPRREF && sel->u.param) { sel->u.param->val.u.ptr = NULL; } }
/*! \brief * Parses an expression value for a parameter that takes a variable number of values. * * \param[in] nval Number of values in \p values. * \param[in] values Pointer to the list of values. * \param param Parameter to parse. * \param root Selection element to which child expressions are added. * \returns TRUE if the values were parsed successfully, FALSE otherwise. */ static gmx_bool parse_values_varnum_expr(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param, t_selelem *root) { t_selexpr_value *value; t_selelem *child; t_selelem *expr; if (nval != 1 || !values->bExpr) { gmx_bug("internal error"); return FALSE; } value = values; child = add_child(root, param, value->u.expr); value->u.expr = NULL; if (!child) { return FALSE; } /* Process single-valued expressions */ /* TODO: We should also handle SEL_SINGLEVAL expressions here */ if (child->v.type == POS_VALUE || child->v.type == GROUP_VALUE) { /* Set the value storage */ _gmx_selvalue_setstore(&child->v, param->val.u.ptr); param->val.nr = 1; if (param->nvalptr) { *param->nvalptr = param->val.nr; } param->nvalptr = NULL; return TRUE; } if (!(child->flags & SEL_VARNUMVAL)) { _gmx_selparser_error("invalid expression value for parameter '%s'", param->name); return FALSE; } child->flags |= SEL_ALLOCVAL; param->val.nr = -1; *param->nvalptr = param->val.nr; /* Rest of the initialization is done during compilation in * init_method(). */ return TRUE; }
SelectionData::SelectionData(SelectionTreeElement *elem, const char *selstr) : name_(elem->name()), selectionText_(selstr), rootElement_(*elem), coveredFractionType_(CFRAC_NONE), coveredFraction_(1.0), averageCoveredFraction_(1.0), bDynamic_(false), bDynamicCoveredFraction_(false) { gmx_ana_pos_clear(&rawPositions_); if (elem->child->type == SEL_CONST) { // TODO: This is not exception-safe if any called function throws. gmx_ana_pos_copy(&rawPositions_, elem->child->v.u.p, true); } else { SelectionTreeElementPointer child = elem->child; child->flags &= ~SEL_ALLOCVAL; _gmx_selvalue_setstore(&child->v, &rawPositions_); /* We should also skip any modifiers to determine the dynamic * status. */ while (child->type == SEL_MODIFIER) { child = child->child; if (child->type == SEL_SUBEXPRREF) { child = child->child; /* Because most subexpression elements are created * during compilation, we need to check for them * explicitly here. */ if (child->type == SEL_SUBEXPR) { child = child->child; } } } /* For variable references, we should skip the * SEL_SUBEXPRREF and SEL_SUBEXPR elements. */ if (child->type == SEL_SUBEXPRREF) { child = child->child->child; } bDynamic_ = (child->child->flags & SEL_DYNAMIC); } initCoveredFraction(CFRAC_NONE); }
/*! * \param[in] data Data for the current frame. * \param[in] sel Selection element being evaluated. * \param[in] g Group for which \p sel should be evaluated. * \returns 0 for success. * * Sets the value pointers of the child and its child to point to the same * memory as the value pointer of this element to avoid copying, and then * evaluates evaluates the child. * * This function is used as \c t_selelem:evaluate for \ref SEL_SUBEXPRREF * elements for which the \ref SEL_SUBEXPR does not have other references. */ void _gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g) { if (g) { _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr); _gmx_selvalue_setstore_alloc(&sel->child->child->v, sel->v.u.ptr, sel->child->child->v.nalloc); sel->child->evaluate(data, sel->child, g); } sel->v.nr = sel->child->v.nr; if (sel->u.param) { sel->u.param->val.nr = sel->v.nr; if (sel->u.param->nvalptr) { *sel->u.param->nvalptr = sel->u.param->val.nr; } } }
/*! \brief * Initializes the method parameter data of \ref SEL_EXPRESSION and * \ref SEL_MODIFIER elements. * * \param[in] sc Selection collection. * \param[in,out] sel Selection element to initialize. * * A deep copy of the parameters is made to allow several * expressions with the same method to coexist peacefully. * Calls sel_datafunc() if one is specified for the method. */ static void init_method_params(gmx_ana_selcollection_t *sc, t_selelem *sel) { int nparams; gmx_ana_selparam_t *orgparam; gmx_ana_selparam_t *param; int i; void *mdata; nparams = sel->u.expr.method->nparams; orgparam = sel->u.expr.method->param; snew(param, nparams); memcpy(param, orgparam, nparams*sizeof(gmx_ana_selparam_t)); for (i = 0; i < nparams; ++i) { param[i].flags &= ~SPAR_SET; _gmx_selvalue_setstore(¶m[i].val, NULL); if (param[i].flags & SPAR_VARNUM) { param[i].val.nr = -1; } } mdata = NULL; if (sel->u.expr.method->init_data) { mdata = sel->u.expr.method->init_data(nparams, param); if (mdata == NULL) { gmx_fatal(FARGS, "Method data initialization failed"); } } if (sel->u.expr.method->set_poscoll) { sel->u.expr.method->set_poscoll(sc->pcc, mdata); } /* Store the values */ sel->u.expr.method->param = param; sel->u.expr.mdata = mdata; }
/*! * \param[in,out] sc Selection collection to append to. * \param sel Selection to append to \p sc (can be NULL, in which * case nothing is done). * \param last Last selection in \p sc, or NULL if not present or not * known. * \returns The last selection in \p sc after the append. * * Appends \p sel after the last root element in \p sc, and returns either * \p sel (if it was non-NULL) or the last element in \p sc (if \p sel was * NULL). */ t_selelem * _gmx_sel_append_selection(gmx_ana_selcollection_t *sc, t_selelem *sel, t_selelem *last) { if (last) { last->next = sel; } else { if (sc->root) { last = sc->root; while (last->next) { last = last->next; } last->next = sel; } else { sc->root = sel; } } if (sel) { last = sel; /* Add the new selection to the collection if it is not a variable. */ if (sel->child->type != SEL_SUBEXPR) { int i; sc->nr++; srenew(sc->sel, sc->nr); i = sc->nr - 1; snew(sc->sel[i], 1); if (sel->child->type == SEL_CONST) { gmx_ana_pos_copy(&sc->sel[i]->p, sel->child->v.u.p, TRUE); sc->sel[i]->bDynamic = FALSE; } else { t_selelem *child; child = sel->child; child->flags &= ~SEL_ALLOCVAL; _gmx_selvalue_setstore(&child->v, &sc->sel[i]->p); /* We should also skip any modifiers to determine the dynamic * status. */ while (child->type == SEL_MODIFIER) { child = child->child; } /* For variable references, we should skip the * SEL_SUBEXPRREF and SEL_SUBEXPR elements. */ if (child->type == SEL_SUBEXPRREF) { child = child->child->child; } sc->sel[i]->bDynamic = (child->child->flags & SEL_DYNAMIC); } /* The group will be set after compilation */ sc->sel[i]->g = NULL; sc->sel[i]->selelem = sel; gmx_ana_selection_init_coverfrac(sc->sel[i], CFRAC_NONE); } } return last; }
/*! \brief * Parses the values for a parameter that takes a variable number of values. * * \param[in] nval Number of values in \p values. * \param[in] values Pointer to the list of values. * \param param Parameter to parse. * \param root Selection element to which child expressions are added. * \returns TRUE if the values were parsed successfully, FALSE otherwise. * * For integer ranges, the sequence of numbers from the first to second value * is stored, each as a separate value. */ static gmx_bool parse_values_varnum(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param, t_selelem *root) { t_selexpr_value *value; int i, j; param->flags &= ~SPAR_DYNAMIC; /* Update nval if there are integer ranges. */ if (param->val.type == INT_VALUE) { value = values; while (value) { if (value->type == INT_VALUE && !value->bExpr) { nval += abs(value->u.i.i2 - value->u.i.i1); } value = value->next; } } /* 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_bug("internal error"); return FALSE; } /* Reserve appropriate amount of memory */ if (param->val.type == POS_VALUE) { gmx_ana_pos_reserve(param->val.u.p, nval, 0); gmx_ana_pos_set_nr(param->val.u.p, nval); gmx_ana_indexmap_init(¶m->val.u.p->m, NULL, NULL, INDEX_UNKNOWN); } else { _gmx_selvalue_reserve(¶m->val, nval); } value = values; i = 0; while (value) { if (value->bExpr) { _gmx_selparser_error("expressions not supported within value lists"); return FALSE; } if (value->type != param->val.type) { gmx_bug("internal error"); return FALSE; } 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) { _gmx_selparser_error("real ranges not supported for parameter '%s'", param->name); return FALSE; } param->val.u.r[i++] = value->u.r.r1; break; case STR_VALUE: param->val.u.s[i++] = strdup(value->u.s); break; case POS_VALUE: copy_rvec(value->u.x, param->val.u.p->x[i++]); break; default: /* Should not be reached */ gmx_bug("internal error"); return FALSE; } value = value->next; } param->val.nr = i; if (param->nvalptr) { *param->nvalptr = param->val.nr; } param->nvalptr = NULL; /* 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) { t_selelem *child; child = _gmx_selelem_create(SEL_CONST); _gmx_selelem_set_vtype(child, STR_VALUE); child->name = param->name; child->flags &= ~SEL_ALLOCVAL; child->flags |= SEL_FLAGSSET | SEL_VARNUMVAL | SEL_ALLOCDATA; child->v.nr = param->val.nr; _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); } return TRUE; }