Use smart pointers to manage the selection tree.
authorTeemu Murtola <teemu.murtola@gmail.com>
Thu, 2 Aug 2012 04:14:25 +0000 (07:14 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Tue, 28 Aug 2012 03:33:42 +0000 (06:33 +0300)
Changed t_selelem to gmx::SelectionTreeElement and t_selelem * to
gmx::SelectionTreeElementPointer (or a const reference).  The latter is
a boost::shared_ptr because there may be multiple references to some
elements in the evaluation tree.  Some exceptions to the above rule are
present, because it was not straightforward to change those parts.

Prerequisite for using exceptions throughout the selection code, which
in turn is a prerequisite for many tasks that would introduce more C++
there.

There are some parts that are not yet exception-safe, but may throw
std::bad_alloc as the result of these changes.  Will fix those in
subsequent commits.

Related to #655 and #880.

Change-Id: Ib36c08bac1ab2c9818604e45e2eb14a90069efdb

23 files changed:
src/gromacs/selection/compiler.cpp
src/gromacs/selection/evaluate.cpp
src/gromacs/selection/evaluate.h
src/gromacs/selection/keywords.h
src/gromacs/selection/params.cpp
src/gromacs/selection/parser.cpp
src/gromacs/selection/parser.h
src/gromacs/selection/parser.y
src/gromacs/selection/parsetree.cpp
src/gromacs/selection/parsetree.h
src/gromacs/selection/scanner_internal.cpp
src/gromacs/selection/selection.cpp
src/gromacs/selection/selection.h
src/gromacs/selection/selectioncollection-impl.h
src/gromacs/selection/selectioncollection.cpp
src/gromacs/selection/selelem.cpp
src/gromacs/selection/selelem.h
src/gromacs/selection/sm_insolidangle.cpp
src/gromacs/selection/sm_keywords.cpp
src/gromacs/selection/sm_position.cpp
src/gromacs/selection/sm_same.cpp
src/gromacs/selection/symrec.cpp
src/gromacs/selection/symrec.h

index 0522a803550fa4094aae227f6577380d4ddb961d..a54a173b201ba9a9b287a2d06c1872e4d75f5216 100644 (file)
  * Hence, all the selections should be parsed before the compiler can be
  * called.
  *
- * The compiler initializes all fields in \c t_selelem not initialized by
- * the parser: \c t_selelem::v (some fields have already been initialized by
- * the parser), \c t_selelem::evaluate, and \c t_selelem::u (again, some
- * elements have been initialized in the parser).
- * The \c t_selelem::cdata field is used during the compilation to store
+ * The compiler initializes all fields in gmx::SelectionTreeElement not
+ * initialized by the parser: gmx::SelectionTreeElement::v (some fields have
+ * already been initialized by the parser),
+ * gmx::SelectionTreeElement::evaluate, and gmx::SelectionTreeElement::u
+ * (again, some elements have been initialized in the parser).
+ * The gmx::SelectionTreeElement::cdata field is used during the compilation to store
  * internal data, but the data is freed when the compiler returns.
  *
  * In addition to initializing the elements, the compiler reorganizes the tree
@@ -71,7 +72,7 @@
  *
  * The compiler is invoked using gmx::SelectionCompiler.
  * The gmx::SelectionCompiler::compile() method does the compilation in several
- * passes over the \c t_selelem tree.
+ * passes over the gmx::SelectionTreeElement tree.
  *  -# Defaults are set for the position type and flags of position calculation
  *     methods that were not explicitly specified in the user input.
  *  -# Subexpressions are extracted: a separate root is created for each
@@ -91,8 +92,8 @@
  *       passes, because some flags are set recursively based on which elements
  *       refer to an element, and these flags need to be set to initialize
  *       other fields.
- *    -# The \c t_selelem::evaluate field is set to the correct evaluation
- *       function from evaluate.h.
+ *    -# The gmx::SelectionTreeElement::evaluate field is set to the correct
+ *       evaluation function from evaluate.h.
  *    .
  *  -# The evaluation function of all elements is replaced with the
  *     analyze_static() function to be able to initialize the element before
  *
  * After the compilation, the selection element tree is suitable for
  * gmx_ana_selcollection_evaluate().
- * Enough memory has been allocated for \ref t_selelem::v
- * (and \ref t_selelem::cgrp for \ref SEL_SUBEXPR elements) to allow the
- * selection to be evaluated without allocating any memory.
+ * Enough memory has been allocated for gmx::SelectionTreeElement::v
+ * (and gmx::SelectionTreeElement::cgrp for \ref SEL_SUBEXPR elements) to allow
+ * the selection to be evaluated without allocating any memory.
  *
  *
  * \subsection selcompiler_tree_root Root elements
  * These are used for two purposes:
  *  -# A selection that should be evaluated.
  *     These elements appear in the same order as the selections in the input.
- *     For these elements, \ref t_selelem::v has been set to the maximum
- *     possible group that the selection can evaluate to (only for dynamic
- *     selections), and \ref t_selelem::cgrp has been set to use a NULL group
- *     for evaluation.
+ *     For these elements, gmx::SelectionTreeElement::v has been set to the
+ *     maximum possible group that the selection can evaluate to (only for
+ *     dynamic selections), and gmx::SelectionTreeElement::cgrp has been set to
+ *     use a NULL group for evaluation.
  *  -# A subexpression that appears in one or more selections.
  *     Each selection that gives a value for a method parameter is a
  *     potential subexpression, as is any variable value.
  *     Only subexpressions that require evaluation for each frame are left
  *     after the selection is compiled.
  *     Each subexpression appears in the chain before any references to it.
- *     For these elements, \c t_selelem::cgrp has been set to the group
- *     that should be used to evaluate the subexpression.
- *     If \c t_selelem::cgrp is empty, the total evaluation group is not known
- *     in advance or it is more efficient to evaluate the subexpression only
- *     when it is referenced.  If this is the case, \c t_selelem::evaluate is
- *     also NULL.
+ *     For these elements, gmx::SelectionTreeElement::cgrp has been set to the
+ *     group that should be used to evaluate the subexpression.
+ *     If gmx::SelectionTreeElement::cgrp is empty, the total evaluation group
+ *     is not known in advance or it is more efficient to evaluate the
+ *     subexpression only when it is referenced.  If this is the case,
+ *     gmx::SelectionTreeElement::evaluate is also NULL.
  *
  * The children of the \ref SEL_ROOT elements can be used to distinguish
  * the two types of root elements from each other; the rules are the same
  * replaced with \ref SEL_CONST elements.
  * Constant elements from the parser are also retained if present in
  * dynamic parts of the selections.
- * Several constant elements with a NULL \c t_selelem::evaluate are left for
- * debugging purposes; of these, only the ones for \ref BOOL_OR expressions are
- * used during evaluation.
+ * Several constant elements with a NULL gmx::SelectionTreeElement::evaluate
+ * are left for debugging purposes; of these, only the ones for \ref BOOL_OR
+ * expressions are used during evaluation.
  *
- * The value is stored in \c t_selelem::v, and for group values with an
- * evaluation function set, also in \c t_selelem::cgrp.
+ * The value is stored in gmx::SelectionTreeElement::v, and for group values
+ * with an evaluation function set, also in gmx::SelectionTreeElement::cgrp.
  * For \ref GROUP_VALUE elements, unnecessary atoms (i.e., atoms that
  * could never be selected) have been removed from the value.
  *
  * \subsection selcompiler_tree_method Method evaluation elements
  *
  * All selection methods that need to be evaluated dynamically are described
- * by a \ref SEL_EXPRESSION element. The \c t_selelem::method and
- * \c t_selelem::mdata fields have already been initialized by the parser,
+ * by a \ref SEL_EXPRESSION element. The gmx::SelectionTreeElement::method and
+ * gmx::SelectionTreeElement::mdata fields have already been initialized by the parser,
  * and the compiler only calls the initialization functions in the method
  * data structure to do some additional initialization of these fields at
- * appropriate points. If the \c t_selelem::pc data field has been created by
- * the parser, the compiler initializes the data structure properly once the
- * required positions are known. If the \c t_selelem::pc field is NULL after
- * the parser, but the method provides only sel_updatefunc_pos(), an
- * appropriate position calculation data structure is created.
- * If \c t_selelem::pc is not NULL, \c t_selelem::pos is also initialized
- * to hold the positions calculated.
+ * appropriate points. If the gmx::SelectionTreeElement::pc data field has been
+ * created by the parser, the compiler initializes the data structure properly
+ * once the required positions are known. If the gmx::SelectionTreeElement::pc
+ * field is NULL after the parser, but the method provides only
+ * sel_updatefunc_pos(), an appropriate position calculation data structure is
+ * created.  If gmx::SelectionTreeElement::pc is not NULL,
+ * gmx::SelectionTreeElement::pos is also initialized to hold the positions
+ * calculated.
  *
  * Children of these elements are of type \ref SEL_SUBEXPRREF, and describe
  * parameter values that need to be evaluated for each frame. See the next
  * help in debugging.
  *
  * For \ref SEL_SUBEXPR elements, memory has been allocated for
- * \c t_selelem::cgrp to store the group for which the expression has been
- * evaluated during the current frame.  This is only done if full subexpression
- * evaluation by _gmx_sel_evaluate_subexpr() is needed; the other evaluation
- * functions do not require this memory.
+ * gmx::SelectionTreeElement::cgrp to store the group for which the expression
+ * has been evaluated during the current frame.  This is only done if full
+ * subexpression evaluation by _gmx_sel_evaluate_subexpr() is needed; the other
+ * evaluation functions do not require this memory.
  *
  * \ref SEL_SUBEXPRREF elements are used to describe references to
  * subexpressions. They have always a single child, which is the
 #include "selelem.h"
 
 using std::min;
+using gmx::SelectionTreeElement;
+using gmx::SelectionTreeElementPointer;
 
 /*! \internal \brief
  * Compiler flags.
@@ -333,7 +337,7 @@ enum
 typedef struct t_compiler_data
 {
     /** The real evaluation method. */
-    sel_evalfunc     evaluate;
+    gmx::sel_evalfunc evaluate;
     /** Number of references to a \ref SEL_SUBEXPR element. */
     int              refcount;
     /** Flags for specifying how to treat this element during compilation. */
@@ -353,18 +357,20 @@ typedef struct t_compiler_data
  * Helper method for printing out debug information about a min/max group.
  */
 static void
-print_group_info(FILE *fp, const char *name, t_selelem *sel, gmx_ana_index_t *g)
+print_group_info(FILE *fp, const char *name,
+                 const SelectionTreeElement &sel,
+                 gmx_ana_index_t *g)
 {
     fprintf(fp, " %s=", name);
     if (!g)
     {
         fprintf(fp, "(null)");
     }
-    else if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
+    else if (sel.cdata->flags & SEL_CDATA_MINMAXALLOC)
     {
         fprintf(fp, "(%d atoms, %p)", g->isize, (void*)g);
     }
-    else if (sel->v.type == GROUP_VALUE && g == sel->v.u.g)
+    else if (sel.v.type == GROUP_VALUE && g == sel.v.u.g)
     {
         fprintf(fp, "(static, %p)", (void*)g);
     }
@@ -380,83 +386,81 @@ print_group_info(FILE *fp, const char *name, t_selelem *sel, gmx_ana_index_t *g)
  * \param[in] level   Indentation level, starting from zero.
  */
 void
-_gmx_selelem_print_compiler_info(FILE *fp, t_selelem *sel, int level)
+_gmx_selelem_print_compiler_info(FILE *fp, const SelectionTreeElement &sel,
+                                 int level)
 {
-    if (!sel->cdata)
+    if (!sel.cdata)
     {
         return;
     }
     fprintf(fp, "%*c cdata: flg=", level*2+1, ' ');
-    if (sel->cdata->flags & SEL_CDATA_FULLEVAL)
+    if (sel.cdata->flags & SEL_CDATA_FULLEVAL)
     {
         fprintf(fp, "F");
     }
-    if (!(sel->cdata->flags & SEL_CDATA_STATIC))
+    if (!(sel.cdata->flags & SEL_CDATA_STATIC))
     {
         fprintf(fp, "D");
     }
-    if (sel->cdata->flags & SEL_CDATA_STATICEVAL)
+    if (sel.cdata->flags & SEL_CDATA_STATICEVAL)
     {
         fprintf(fp, "S");
     }
-    if (sel->cdata->flags & SEL_CDATA_EVALMAX)
+    if (sel.cdata->flags & SEL_CDATA_EVALMAX)
     {
         fprintf(fp, "M");
     }
-    if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
+    if (sel.cdata->flags & SEL_CDATA_MINMAXALLOC)
     {
         fprintf(fp, "A");
     }
-    if (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+    if (sel.cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
     {
         fprintf(fp, "Ss");
     }
-    if (sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
+    if (sel.cdata->flags & SEL_CDATA_COMMONSUBEXPR)
     {
         fprintf(fp, "Sc");
     }
-    if (!sel->cdata->flags)
+    if (!sel.cdata->flags)
     {
         fprintf(fp, "0");
     }
-    if (sel->cdata->refcount > 0)
+    if (sel.cdata->refcount > 0)
     {
-        fprintf(fp, " refc=%d", sel->cdata->refcount);
+        fprintf(fp, " refc=%d", sel.cdata->refcount);
     }
     fprintf(fp, " eval=");
-    _gmx_sel_print_evalfunc_name(fp, sel->cdata->evaluate);
-    print_group_info(fp, "gmin", sel, sel->cdata->gmin);
-    print_group_info(fp, "gmax", sel, sel->cdata->gmax);
+    _gmx_sel_print_evalfunc_name(fp, sel.cdata->evaluate);
+    print_group_info(fp, "gmin", sel, sel.cdata->gmin);
+    print_group_info(fp, "gmax", sel, sel.cdata->gmax);
     fprintf(fp, "\n");
 }
 
-/*!
- * \param  sel Selection to free.
- *
- * This function only frees the data for the given selection, not its children.
- * It is safe to call the function when compiler data has not been allocated
- * or has already been freed; in such a case, nothing is done.
- */
-void
-_gmx_selelem_free_compiler_data(t_selelem *sel)
+namespace gmx
+{
+
+void SelectionTreeElement::freeCompilerData()
 {
-    if (sel->cdata)
+    if (cdata)
     {
-        sel->evaluate = sel->cdata->evaluate;
-        if (sel->cdata->flags & SEL_CDATA_MINMAXALLOC)
+        evaluate = cdata->evaluate;
+        if (cdata->flags & SEL_CDATA_MINMAXALLOC)
         {
-            sel->cdata->gmin->name = NULL;
-            sel->cdata->gmax->name = NULL;
-            gmx_ana_index_deinit(sel->cdata->gmin);
-            gmx_ana_index_deinit(sel->cdata->gmax);
-            sfree(sel->cdata->gmin);
-            sfree(sel->cdata->gmax);
+            cdata->gmin->name = NULL;
+            cdata->gmax->name = NULL;
+            gmx_ana_index_deinit(cdata->gmin);
+            gmx_ana_index_deinit(cdata->gmax);
+            sfree(cdata->gmin);
+            sfree(cdata->gmax);
         }
-        sfree(sel->cdata);
+        sfree(cdata);
     }
-    sel->cdata = NULL;
+    cdata = NULL;
 }
 
+} // namespace gmx
+
 /*! \brief
  * Allocates memory for storing the evaluated value of a selection element.
  *
@@ -468,7 +472,8 @@ _gmx_selelem_free_compiler_data(t_selelem *sel)
  * maximum of the \p isize values can be stored.
  */
 static void
-alloc_selection_data(t_selelem *sel, int isize, bool bChildEval)
+alloc_selection_data(const SelectionTreeElementPointer &sel,
+                     int isize, bool bChildEval)
 {
     int        nalloc;
 
@@ -487,13 +492,11 @@ alloc_selection_data(t_selelem *sel, int isize, bool bChildEval)
     }
     else /* sel->flags should contain SEL_VARNUMVAL */
     {
-        t_selelem *child;
-
         if (!bChildEval)
         {
             return;
         }
-        child = sel;
+        SelectionTreeElementPointer child = sel;
         if (sel->type == SEL_SUBEXPRREF)
         {
             GMX_RELEASE_ASSERT(sel->child && sel->child->type == SEL_SUBEXPR,
@@ -538,12 +541,13 @@ alloc_selection_data(t_selelem *sel, int isize, bool bChildEval)
  * \param[in] eval The new evaluation function.
  */
 static void
-set_evaluation_function(t_selelem *sel, sel_evalfunc eval)
+set_evaluation_function(const SelectionTreeElementPointer &sel,
+                        gmx::sel_evalfunc eval)
 {
     sel->evaluate = eval;
     if (sel->type != SEL_SUBEXPRREF)
     {
-        t_selelem *child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             set_evaluation_function(child, eval);
@@ -567,7 +571,8 @@ set_evaluation_function(t_selelem *sel, sel_evalfunc eval)
  *      for, or NULL if the element is an internal element.
  */
 static void
-init_pos_keyword_defaults(t_selelem *root, const char *spost, const char *rpost,
+init_pos_keyword_defaults(SelectionTreeElement *root,
+                          const char *spost, const char *rpost,
                           const gmx::internal::SelectionData *sel)
 {
     /* Selections use largest static group by default, while
@@ -601,10 +606,10 @@ init_pos_keyword_defaults(t_selelem *root, const char *spost, const char *rpost,
         sel = NULL;
     }
     /* Recurse into children */
-    t_selelem *child = root->child;
+    SelectionTreeElementPointer child = root->child;
     while (child)
     {
-        init_pos_keyword_defaults(child, spost, rpost, sel);
+        init_pos_keyword_defaults(child.get(), spost, rpost, sel);
         child = child->next;
     }
 }
@@ -620,18 +625,14 @@ init_pos_keyword_defaults(t_selelem *root, const char *spost, const char *rpost,
  * \param   root First selection in the whole selection chain.
  * \returns The new first element for the chain.
  */
-static t_selelem *
-reverse_selelem_chain(t_selelem *root)
+static SelectionTreeElementPointer
+reverse_selelem_chain(const SelectionTreeElementPointer &root)
 {
-    t_selelem *item;
-    t_selelem *prev;
-    t_selelem *next;
-
-    prev = NULL;
-    item = root;
+    SelectionTreeElementPointer prev;
+    SelectionTreeElementPointer item = root;
     while (item)
     {
-        next = item->next;
+        SelectionTreeElementPointer next = item->next;
         item->next = prev;
         prev = item;
         item = next;
@@ -648,33 +649,28 @@ reverse_selelem_chain(t_selelem *root)
  * The elements are processed in reverse order to correctly detect
  * subexpressions only referred to by other subexpressions.
  */
-static t_selelem *
-remove_unused_subexpressions(t_selelem *root)
+static SelectionTreeElementPointer
+remove_unused_subexpressions(SelectionTreeElementPointer root)
 {
-    t_selelem *item;
-    t_selelem *prev;
-    t_selelem *next;
-
-    if (root == NULL)
+    if (!root)
     {
-        return NULL;
+        return SelectionTreeElementPointer();
     }
     root = reverse_selelem_chain(root);
-    while (root->child->type == SEL_SUBEXPR && root->child->refcount == 1)
+    while (root->child->type == SEL_SUBEXPR && root->child.unique())
     {
-        next = root->next;
-        _gmx_selelem_free(root);
-        root = next;
+        // Frees the root element.
+        root = root->next;
     }
-    prev = root;
-    item = root->next;
+    SelectionTreeElementPointer prev = root;
+    SelectionTreeElementPointer item = root->next;
     while (item)
     {
-        next = item->next;
-        if (item->child->type == SEL_SUBEXPR && item->child->refcount == 1)
+        SelectionTreeElementPointer next = item->next;
+        if (item->child->type == SEL_SUBEXPR && item->child.unique())
         {
+            // Frees the current item when it goes out of scope.
             prev->next = next;
-            _gmx_selelem_free(item);
         }
         else
         {
@@ -693,11 +689,11 @@ remove_unused_subexpressions(t_selelem *root)
  *
  * The name of the selection becomes "SubExpr N", where N is \p i;
  * Memory is allocated for the name and the name is stored both in
- * \c t_selelem::name and \c t_selelem::u::cgrp::name; the latter
+ * gmx::SelectionTreeElement::name and gmx::SelectionTreeElement::u::cgrp::name; the latter
  * is freed by _gmx_selelem_free().
  */
 static void
-create_subexpression_name(t_selelem *sel, int i)
+create_subexpression_name(const SelectionTreeElementPointer &sel, int i)
 {
     char *name = strdup(gmx::formatString("SubExpr %d", i).c_str());
 
@@ -718,15 +714,14 @@ create_subexpression_name(t_selelem *sel, int i)
  * that contain the subexpression as their children and returns the first
  * of these root elements.
  */
-static t_selelem *
-extract_item_subselections(t_selelem *sel, int *subexprn)
+static SelectionTreeElementPointer
+extract_item_subselections(const SelectionTreeElementPointer &sel,
+                           int *subexprn)
 {
-    t_selelem *root;
-    t_selelem *subexpr;
-    t_selelem *child;
+    SelectionTreeElementPointer root;
+    SelectionTreeElementPointer subexpr;
+    SelectionTreeElementPointer child = sel->child;
 
-    root = subexpr = NULL;
-    child = sel->child;
     while (child)
     {
         if (!root)
@@ -755,18 +750,19 @@ extract_item_subselections(t_selelem *sel, int *subexprn)
             /* Create the root element for the subexpression */
             if (!root)
             {
-                root = subexpr = _gmx_selelem_create(SEL_ROOT);
+                root.reset(new SelectionTreeElement(SEL_ROOT));
+                subexpr = root;
             }
             else
             {
-                subexpr->next = _gmx_selelem_create(SEL_ROOT);
-                subexpr       = subexpr->next;
+                subexpr->next.reset(new SelectionTreeElement(SEL_ROOT));
+                subexpr = subexpr->next;
             }
             /* Create the subexpression element and/or
              * move the actual subexpression under the created element. */
             if (child->child->type != SEL_SUBEXPR)
             {
-                subexpr->child = _gmx_selelem_create(SEL_SUBEXPR);
+                subexpr->child.reset(new SelectionTreeElement(SEL_SUBEXPR));
                 _gmx_selelem_set_vtype(subexpr->child, child->v.type);
                 subexpr->child->child = child->child;
                 child->child          = subexpr->child;
@@ -776,7 +772,6 @@ extract_item_subselections(t_selelem *sel, int *subexprn)
                 subexpr->child = child->child;
             }
             create_subexpression_name(subexpr->child, ++*subexprn);
-            subexpr->child->refcount++;
             /* Set the flags for the created elements */
             subexpr->flags          |= (child->flags & SEL_VALFLAGMASK);
             subexpr->child->flags   |= (child->flags & SEL_VALFLAGMASK);
@@ -800,18 +795,16 @@ extract_item_subselections(t_selelem *sel, int *subexprn)
  * and inserted into the selection chain before the expressions that
  * refer to them.
  */
-static t_selelem *
-extract_subexpressions(t_selelem *sel)
+static SelectionTreeElementPointer
+extract_subexpressions(SelectionTreeElementPointer sel)
 {
-    t_selelem   *root, *item, *next;
-    int          subexprn;
-
-    subexprn = 0;
-    root = NULL;
-    next = sel;
+    SelectionTreeElementPointer root;
+    SelectionTreeElementPointer next = sel;
+    int subexprn = 0;
     while (next)
     {
-        item = extract_item_subselections(next, &subexprn);
+        SelectionTreeElementPointer item
+            = extract_item_subselections(next, &subexprn);
         if (item)
         {
             if (!root)
@@ -852,15 +845,13 @@ extract_subexpressions(t_selelem *sel)
  * a single OR operation with three operands).
  */
 static void
-optimize_boolean_expressions(t_selelem *sel)
+optimize_boolean_expressions(const SelectionTreeElementPointer &sel)
 {
-    t_selelem *child, *prev;
-
     /* Do recursively for children */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        prev  = NULL;
-        child = sel->child;
+        SelectionTreeElementPointer prev;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             optimize_boolean_expressions(child);
@@ -880,10 +871,7 @@ optimize_boolean_expressions(t_selelem *sel)
                     prev       = prev->next;
                 }
                 child->child->child->next = child->next;
-                /* Remove the two negations */
-                child->child->child = NULL;
-                child->next         = NULL;
-                _gmx_selelem_free(child);
+                // Discards the two negations.
                 child = prev;
             }
             prev  = child;
@@ -895,8 +883,8 @@ optimize_boolean_expressions(t_selelem *sel)
         return;
     }
     /* Merge subsequent binary operations */
-    prev  = NULL;
-    child = sel->child;
+    SelectionTreeElementPointer prev;
+    SelectionTreeElementPointer child = sel->child;
     while (child)
     {
         if (child->type == SEL_BOOLEAN && child->u.boolt == sel->u.boolt)
@@ -915,8 +903,7 @@ optimize_boolean_expressions(t_selelem *sel)
                 prev = prev->next;
             }
             prev->next = child->next;
-            sfree(child->v.u.g);
-            sfree(child);
+            // Discards the old child.
             child = prev->next;
         }
         else
@@ -937,14 +924,12 @@ optimize_boolean_expressions(t_selelem *sel)
  * The same is true for the dynamic expressions.
  */
 static void
-reorder_boolean_static_children(t_selelem *sel)
+reorder_boolean_static_children(const SelectionTreeElementPointer &sel)
 {
-    t_selelem *child, *prev, *next;
-
     /* Do recursively for children */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             reorder_boolean_static_children(child);
@@ -955,16 +940,17 @@ reorder_boolean_static_children(t_selelem *sel)
     /* Reorder boolean expressions such that static selections come first */
     if (sel->type == SEL_BOOLEAN && (sel->flags & SEL_DYNAMIC))
     {
-        t_selelem  start;
-
-        start.next = sel->child;
-        prev  = &start;
-        child = &start;
+        // Add a dummy head element that precedes the first child.
+        SelectionTreeElementPointer dummy(
+                new SelectionTreeElement(SEL_BOOLEAN));
+        dummy->next = sel->child;
+        SelectionTreeElementPointer prev  = dummy;
+        SelectionTreeElementPointer child = dummy;
         while (child->next)
         {
             /* child is the last handled static expression */
             /* prev is the last handled non-static expression */
-            next = prev->next;
+            SelectionTreeElementPointer next = prev->next;
             while (next && (next->flags & SEL_DYNAMIC))
             {
                 prev = next;
@@ -990,7 +976,7 @@ reorder_boolean_static_children(t_selelem *sel)
             child = next;
         }
 
-        sel->child = start.next;
+        sel->child = dummy->next;
     }
 }
 
@@ -1008,14 +994,12 @@ reorder_boolean_static_children(t_selelem *sel)
  * within arithmetic expressions.
  */
 static void
-optimize_arithmetic_expressions(t_selelem *sel)
+optimize_arithmetic_expressions(const SelectionTreeElementPointer &sel)
 {
-    t_selelem  *child;
-
     /* Do recursively for children. */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             optimize_arithmetic_expressions(child);
@@ -1029,7 +1013,7 @@ optimize_arithmetic_expressions(t_selelem *sel)
     }
 
     /* Convert integer constants to reals. */
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     while (child)
     {
         if (child->v.type == INT_VALUE)
@@ -1064,18 +1048,16 @@ optimize_arithmetic_expressions(t_selelem *sel)
  *
  * \param[in,out] sel Root of the selection subtree to process.
  *
- * This function sets the evaluation function (\c t_selelem::evaluate)
- * for the selection elements.
+ * This function sets the evaluation function
+ * (gmx::SelectionTreeElement::evaluate) for the selection elements.
  */
 static void
-init_item_evalfunc(t_selelem *sel)
+init_item_evalfunc(const SelectionTreeElementPointer &sel)
 {
     /* Process children. */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        t_selelem *child;
-
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             init_item_evalfunc(child);
@@ -1154,13 +1136,12 @@ init_item_evalfunc(t_selelem *sel)
  * \param[in] mempool  Memory pool to use.
  */
 static void
-setup_memory_pooling(t_selelem *sel, gmx_sel_mempool_t *mempool)
+setup_memory_pooling(const SelectionTreeElementPointer &sel,
+                     gmx_sel_mempool_t *mempool)
 {
     if (sel->type != SEL_SUBEXPRREF)
     {
-        t_selelem         *child;
-
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             if ((sel->type == SEL_BOOLEAN && (child->flags & SEL_DYNAMIC))
@@ -1191,7 +1172,7 @@ setup_memory_pooling(t_selelem *sel, gmx_sel_mempool_t *mempool)
  * structure if required.
  */
 static void
-init_item_evaloutput(t_selelem *sel)
+init_item_evaloutput(const SelectionTreeElementPointer &sel)
 {
     GMX_ASSERT(!(sel->child == NULL &&
                  (sel->type == SEL_SUBEXPRREF || sel->type == SEL_SUBEXPR)),
@@ -1200,9 +1181,7 @@ init_item_evaloutput(t_selelem *sel)
     /* Process children. */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        t_selelem *child;
-
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             init_item_evaloutput(child);
@@ -1237,7 +1216,7 @@ init_item_evaloutput(t_selelem *sel)
         if (sel->v.u.ptr)
         {
             _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
-            _gmx_selelem_free_values(sel->child->child);
+            sel->child->child->freeValues();
             sel->child->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
             sel->child->child->flags |= (sel->flags & SEL_ALLOCDATA);
             _gmx_selvalue_setstore(&sel->child->child->v, sel->v.u.ptr);
@@ -1271,10 +1250,8 @@ init_item_evaloutput(t_selelem *sel)
  * \param sel Root of the selection subtree to process.
  */
 static void
-init_item_compilerdata(t_selelem *sel)
+init_item_compilerdata(const SelectionTreeElementPointer &sel)
 {
-    t_selelem   *child;
-
     /* Allocate the compiler data structure */
     snew(sel->cdata, 1);
 
@@ -1299,7 +1276,7 @@ init_item_compilerdata(t_selelem *sel)
      * access its compilation flags.*/
     if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             if (!(child->flags & SEL_ATOMVAL) && child->child)
@@ -1317,7 +1294,7 @@ init_item_compilerdata(t_selelem *sel)
     /* Initialize children */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             init_item_compilerdata(child);
@@ -1332,7 +1309,7 @@ init_item_compilerdata(t_selelem *sel)
         bool  bEvalMax;
 
         bEvalMax = (sel->u.boolt == BOOL_AND);
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             if (bEvalMax)
@@ -1349,7 +1326,7 @@ init_item_compilerdata(t_selelem *sel)
     else if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER
              || sel->type == SEL_SUBEXPR)
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             child->cdata->flags |= SEL_CDATA_EVALMAX;
@@ -1370,10 +1347,8 @@ init_item_compilerdata(t_selelem *sel)
  * reorder_boolean_static_children() should have been called.
  */
 static void
-init_item_staticeval(t_selelem *sel)
+init_item_staticeval(const SelectionTreeElementPointer &sel)
 {
-    t_selelem   *child;
-
     /* Subexpressions with full evaluation should always have bStaticEval,
      * so don't do anything if a reference to them is encountered. */
     if (sel->type == SEL_SUBEXPRREF
@@ -1385,7 +1360,7 @@ init_item_staticeval(t_selelem *sel)
     /* Propagate the bStaticEval flag to children if it is not set */
     if (!(sel->cdata->flags & SEL_CDATA_STATICEVAL))
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             if ((sel->type != SEL_EXPRESSION && sel->type != SEL_MODIFIER)
@@ -1406,7 +1381,7 @@ init_item_staticeval(t_selelem *sel)
          * expression should not have bStaticEval. */
         if (sel->type == SEL_BOOLEAN)
         {
-            child = sel->child;
+            SelectionTreeElementPointer child = sel->child;
             while (child && !(child->flags & SEL_DYNAMIC))
             {
                 child = child->next;
@@ -1423,7 +1398,7 @@ init_item_staticeval(t_selelem *sel)
         }
 
         /* Process the children */
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             init_item_staticeval(child);
@@ -1438,7 +1413,7 @@ init_item_staticeval(t_selelem *sel)
  * \param sel Root of the selection subtree to process.
  */
 static void
-init_item_subexpr_refcount(t_selelem *sel)
+init_item_subexpr_refcount(const SelectionTreeElementPointer &sel)
 {
     // Reset the counter when the subexpression is first encountered.
     if (sel->type == SEL_ROOT && sel->child->type == SEL_SUBEXPR
@@ -1453,7 +1428,7 @@ init_item_subexpr_refcount(t_selelem *sel)
     }
     else
     {
-        t_selelem *child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             init_item_subexpr_refcount(child);
@@ -1468,7 +1443,7 @@ init_item_subexpr_refcount(t_selelem *sel)
  * \param sel Root of the selection subtree to process.
  */
 static void
-init_item_subexpr_flags(t_selelem *sel)
+init_item_subexpr_flags(const SelectionTreeElementPointer &sel)
 {
     if (sel->type == SEL_SUBEXPR)
     {
@@ -1493,8 +1468,7 @@ init_item_subexpr_flags(t_selelem *sel)
         || ((sel->cdata->flags & SEL_CDATA_COMMONSUBEXPR)
             && !(sel->child->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)))
     {
-        t_selelem *child = sel->child;
-
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             if (!(child->cdata->flags & SEL_CDATA_COMMONSUBEXPR))
@@ -1517,14 +1491,12 @@ init_item_subexpr_flags(t_selelem *sel)
  * \param sel Root of the selection subtree to process.
  */
 static void
-init_item_minmax_groups(t_selelem *sel)
+init_item_minmax_groups(const SelectionTreeElementPointer &sel)
 {
     /* Process children. */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        t_selelem *child;
-
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             init_item_minmax_groups(child);
@@ -1576,12 +1548,10 @@ init_item_minmax_groups(t_selelem *sel)
 static void
 initialize_evalgrps(gmx_ana_selcollection_t *sc)
 {
-    t_selelem   *root;
-
-    root = sc->root;
+    SelectionTreeElementPointer root = sc->root;
     while (root)
     {
-        GMX_RELEASE_ASSERT(root->child != NULL,
+        GMX_RELEASE_ASSERT(root->child,
                            "Root elements should always have a child");
         if (root->child->type != SEL_SUBEXPR
             || (root->child->cdata->flags & SEL_CDATA_FULLEVAL))
@@ -1610,10 +1580,9 @@ initialize_evalgrps(gmx_ana_selcollection_t *sc)
  * are evaluated for each atom.
  */
 static void
-mark_subexpr_dynamic(t_selelem *sel, bool bDynamic)
+mark_subexpr_dynamic(const SelectionTreeElementPointer &sel,
+                     bool bDynamic)
 {
-    t_selelem *child;
-
     if (!bDynamic && !(sel->flags & SEL_DYNAMIC))
     {
         sel->cdata->flags |= SEL_CDATA_STATIC;
@@ -1622,7 +1591,7 @@ mark_subexpr_dynamic(t_selelem *sel, bool bDynamic)
     {
         sel->cdata->flags &= ~SEL_CDATA_STATIC;
     }
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     while (child)
     {
         if (sel->type != SEL_EXPRESSION || child->type != SEL_SUBEXPRREF
@@ -1647,26 +1616,25 @@ mark_subexpr_dynamic(t_selelem *sel, bool bDynamic)
  * function. Later compilation passes remove the stub elements.
  */
 static void
-release_subexpr_memory(t_selelem *sel)
+release_subexpr_memory(const SelectionTreeElementPointer &sel)
 {
-    if (sel->type == SEL_SUBEXPR)
+    if (sel->type == SEL_SUBEXPRREF)
     {
-        if (sel->refcount == 2)
+        const SelectionTreeElementPointer &subexpr = sel->child;
+        if (subexpr.use_count() == 2)
         {
-            release_subexpr_memory(sel->child);
-            sel->name = NULL;
-            _gmx_selelem_free_chain(sel->child);
-            _gmx_selelem_free_values(sel);
-            _gmx_selelem_free_exprdata(sel);
-            _gmx_selelem_free_compiler_data(sel);
-            sel->child = NULL;
+            release_subexpr_memory(subexpr);
+            subexpr->name = NULL;
+            // Free children.
+            subexpr->child.reset();
+            subexpr->freeValues();
+            subexpr->freeExpressionData();
+            subexpr->freeCompilerData();
         }
     }
     else
     {
-        t_selelem *child;
-
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             release_subexpr_memory(child);
@@ -1685,7 +1653,7 @@ release_subexpr_memory(t_selelem *sel)
  * deleted.
  */
 static void
-make_static(t_selelem *sel)
+make_static(const SelectionTreeElementPointer &sel)
 {
     /* If this is a subexpression reference and the data is stored in the
      * child, we transfer data ownership before doing anything else. */
@@ -1707,17 +1675,17 @@ make_static(t_selelem *sel)
     }
     /* Free the children. */
     release_subexpr_memory(sel);
-    _gmx_selelem_free_chain(sel->child);
-    sel->child           = NULL;
+    sel->child.reset();
     /* Free the expression data as it is no longer needed */
-    _gmx_selelem_free_exprdata(sel);
+    sel->freeExpressionData();
     /* Make the item static */
     sel->name            = NULL;
     sel->type            = SEL_CONST;
     sel->evaluate        = NULL;
     sel->cdata->evaluate = NULL;
     /* Set the group value.
-     * free_exprdata above frees the cgrp group, so we can just override it. */
+     * freeExpressionData() frees the cgrp group, so we can just override it.
+     * */
     if (sel->v.type == GROUP_VALUE)
     {
         gmx_ana_index_set(&sel->u.cgrp, sel->v.u.g->isize, sel->v.u.g->index, NULL, 0);
@@ -1733,7 +1701,9 @@ make_static(t_selelem *sel)
  * \returns       0 on success, a non-zero error code on error.
  */
 static void
-process_const(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+process_const(gmx_sel_evaluate_t *data,
+              const SelectionTreeElementPointer &sel,
+              gmx_ana_index_t *g)
 {
     if (sel->v.type == GROUP_VALUE)
     {
@@ -1759,7 +1729,7 @@ process_const(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
  * \ref SPAR_ATOMVAL, the function returns immediately.
  */
 static void
-store_param_val(t_selelem *sel)
+store_param_val(const SelectionTreeElementPointer &sel)
 {
     /* Return immediately if there is no parameter. */
     if (sel->type != SEL_SUBEXPRREF || !sel->u.param)
@@ -1794,14 +1764,11 @@ store_param_val(t_selelem *sel)
  * is prevented by using \ref SEL_METHODINIT and \ref SEL_OUTINIT flags.
  */
 static void
-init_method(t_selelem *sel, t_topology *top, int isize)
+init_method(const SelectionTreeElementPointer &sel, t_topology *top, int isize)
 {
-    t_selelem *child;
-    bool       bAtomVal;
-
     /* Find out whether there are any atom-valued parameters */
-    bAtomVal = false;
-    child = sel->child;
+    bool bAtomVal = false;
+    SelectionTreeElementPointer child = sel->child;
     while (child)
     {
         if (child->flags & SEL_ATOMVAL)
@@ -1883,13 +1850,12 @@ init_method(t_selelem *sel, t_topology *top, int isize)
  * reorder_item_static_children() should have been called.
  */
 static void
-evaluate_boolean_static_part(gmx_sel_evaluate_t *data, t_selelem *sel,
+evaluate_boolean_static_part(gmx_sel_evaluate_t *data,
+                             const SelectionTreeElementPointer &sel,
                              gmx_ana_index_t *g)
 {
-    t_selelem *child, *next;
-
     /* Find the last static subexpression */
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     while (child->next && (child->next->cdata->flags & SEL_CDATA_STATIC))
     {
         child = child->next;
@@ -1902,13 +1868,11 @@ evaluate_boolean_static_part(gmx_sel_evaluate_t *data, t_selelem *sel,
     /* Evalute the static part if there is more than one expression */
     if (child != sel->child)
     {
-        next  = child->next;
-        child->next = NULL;
+        SelectionTreeElementPointer next = child->next;
+        child->next.reset();
         sel->cdata->evaluate(data, sel, g);
         /* Replace the subexpressions with the result */
-        _gmx_selelem_free_chain(sel->child);
-        snew(child, 1);
-        child->type       = SEL_CONST;
+        child.reset(new SelectionTreeElement(SEL_CONST));
         child->flags      = SEL_FLAGSSET | SEL_SINGLEVAL | SEL_ALLOCVAL | SEL_ALLOCDATA;
         _gmx_selelem_set_vtype(child, GROUP_VALUE);
         child->evaluate   = NULL;
@@ -1919,6 +1883,7 @@ evaluate_boolean_static_part(gmx_sel_evaluate_t *data, t_selelem *sel,
         child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
         child->cdata->flags |= sel->cdata->flags & SEL_CDATA_STATICEVAL;
         child->next = next;
+        // Frees the old static subexpressions.
         sel->child = child;
     }
     else if (child->evaluate)
@@ -1982,10 +1947,11 @@ evaluate_boolean_static_part(gmx_sel_evaluate_t *data, t_selelem *sel,
  * problem.
  */
 static void
-evaluate_boolean_minmax_grps(t_selelem *sel, gmx_ana_index_t *g,
+evaluate_boolean_minmax_grps(const SelectionTreeElementPointer &sel,
+                             gmx_ana_index_t *g,
                              gmx_ana_index_t *gmin, gmx_ana_index_t *gmax)
 {
-    t_selelem *child;
+    SelectionTreeElementPointer child;
 
     switch (sel->u.boolt)
     {
@@ -2075,8 +2041,8 @@ evaluate_boolean_minmax_grps(t_selelem *sel, gmx_ana_index_t *g,
  * \param[in]     g    Group for which \p sel should be evaluated.
  * \returns       0 on success, a non-zero error code on error.
  *
- * This function is used as the replacement for the \c t_selelem::evaluate
- * function pointer.
+ * This function is used as the replacement for the
+ * gmx::SelectionTreeElement::evaluate function pointer.
  * It does the single most complex task in the compiler: after all elements
  * have been processed, the \p gmin and \p gmax fields of \p t_compiler_data
  * have been properly initialized, enough memory has been allocated for
@@ -2087,7 +2053,9 @@ evaluate_boolean_minmax_grps(t_selelem *sel, gmx_ana_index_t *g,
  * once and whose evaluation group is not known in advance.
  */
 static void
-analyze_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+analyze_static(gmx_sel_evaluate_t *data,
+               const SelectionTreeElementPointer &sel,
+               gmx_ana_index_t *g)
 {
     bool             bDoMinMax;
 
@@ -2327,12 +2295,10 @@ analyze_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
  * evaluation group.
  */
 static void
-init_root_item(t_selelem *root, gmx_ana_index_t *gall)
+init_root_item(const SelectionTreeElementPointer &root,
+               gmx_ana_index_t *gall)
 {
-    t_selelem   *expr;
-    char        *name;
-
-    expr = root->child;
+    const SelectionTreeElementPointer &expr = root->child;
     /* Subexpressions with non-static evaluation group should not be
      * evaluated by the root, and neither should be single-reference
      * subexpressions that don't evaluate for all atoms. */
@@ -2349,7 +2315,7 @@ init_root_item(t_selelem *root, gmx_ana_index_t *gall)
     }
 
     /* Set the evaluation group */
-    name = root->u.cgrp.name;
+    char *name = root->u.cgrp.name;
     if (root->evaluate)
     {
         /* Non-atom-valued non-group expressions don't care about the group, so
@@ -2373,7 +2339,7 @@ init_root_item(t_selelem *root, gmx_ana_index_t *gall)
          * element (unused otherwise). */
         if (expr->type != SEL_SUBEXPR && expr->v.u.p->g)
         {
-            t_selelem *child = expr;
+            SelectionTreeElementPointer child = expr;
 
             /* TODO: This code is copied from parsetree.c; it would be better
              * to have this hardcoded only in one place. */
@@ -2419,7 +2385,7 @@ init_root_item(t_selelem *root, gmx_ana_index_t *gall)
  * referenced once.
  */
 static void
-postprocess_item_subexpressions(t_selelem *sel)
+postprocess_item_subexpressions(const SelectionTreeElementPointer &sel)
 {
     GMX_ASSERT(!(sel->child == NULL &&
                  (sel->type == SEL_SUBEXPRREF || sel->type == SEL_SUBEXPR)),
@@ -2428,9 +2394,7 @@ postprocess_item_subexpressions(t_selelem *sel)
     /* Process children. */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        t_selelem *child;
-
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             postprocess_item_subexpressions(child);
@@ -2456,7 +2420,7 @@ postprocess_item_subexpressions(t_selelem *sel)
         sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
         sel->cdata->evaluate = sel->evaluate;
 
-        _gmx_selelem_free_values(sel->child);
+        sel->child->freeValues();
         sel->child->mempool = NULL;
         _gmx_selvalue_setstore(&sel->child->v, sel->v.u.ptr);
         sel->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
@@ -2514,11 +2478,10 @@ postprocess_item_subexpressions(t_selelem *sel)
  * the method also defines the \c gmx_ana_selmethod_t::update method.
  */
 static void
-init_item_comg(t_selelem *sel, gmx::PositionCalculationCollection *pcc,
+init_item_comg(const SelectionTreeElementPointer &sel,
+               gmx::PositionCalculationCollection *pcc,
                e_poscalc_t type, int flags)
 {
-    t_selelem *child;
-
     /* Initialize COM calculation for dynamic selections now that we know the maximal evaluation group */
     if (sel->type == SEL_EXPRESSION && sel->u.expr.method
         && sel->u.expr.method->pupdate)
@@ -2549,7 +2512,7 @@ init_item_comg(t_selelem *sel, gmx::PositionCalculationCollection *pcc,
     /* Call recursively for all children unless the children have already been processed */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             init_item_comg(child, pcc, type, flags);
@@ -2571,17 +2534,15 @@ init_item_comg(t_selelem *sel, gmx::PositionCalculationCollection *pcc,
  * Frees the data allocated for the compilation process.
  */
 static void
-free_item_compilerdata(t_selelem *sel)
+free_item_compilerdata(const SelectionTreeElementPointer &sel)
 {
-    t_selelem *child;
-
     /* Free compilation data */
-    _gmx_selelem_free_compiler_data(sel);
+    sel->freeCompilerData();
 
     /* Call recursively for all children unless the children have already been processed */
     if (sel->type != SEL_SUBEXPRREF)
     {
-        child = sel->child;
+        SelectionTreeElementPointer child = sel->child;
         while (child)
         {
             free_item_compilerdata(child);
@@ -2620,7 +2581,7 @@ SelectionCompiler::compile(SelectionCollection *coll)
 {
     gmx_ana_selcollection_t *sc = &coll->impl_->sc_;
     gmx_sel_evaluate_t  evaldata;
-    t_selelem   *item;
+    SelectionTreeElementPointer item;
     e_poscalc_t  post;
     size_t       i;
     int          flags;
@@ -2645,7 +2606,7 @@ SelectionCompiler::compile(SelectionCollection *coll)
     for (i = 0; i < sc->sel.size(); ++i)
     {
         gmx::internal::SelectionData &sel = *sc->sel[i];
-        init_pos_keyword_defaults(sel.rootElement(),
+        init_pos_keyword_defaults(&sel.rootElement(),
                                   coll->impl_->spost_.c_str(),
                                   coll->impl_->rpost_.c_str(),
                                   &sel);
index ec33ed5243dc8b17d57ff05b868f5ddd6b442c8d..0fce0a9e2bda327bcb60bddb857aa62a53228712 100644 (file)
@@ -52,9 +52,9 @@
 
 #include <string.h>
 
-#include "maths.h"
-#include "smalloc.h"
-#include "vec.h"
+#include "gromacs/legacyheaders/maths.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/vec.h"
 
 #include "gromacs/selection/indexutil.h"
 #include "gromacs/selection/poscalc.h"
@@ -68,6 +68,9 @@
 #include "selectioncollection-impl.h"
 #include "selelem.h"
 
+using gmx::SelectionTreeElement;
+using gmx::SelectionTreeElementPointer;
+
 namespace
 {
 
@@ -83,7 +86,7 @@ class MempoolSelelemReserver
 {
     public:
         //! Constructs a reserver without initial reservation.
-        MempoolSelelemReserver() : sel_(NULL) {}
+        MempoolSelelemReserver() {}
         /*! \brief
          * Constructs a reserver with initial reservation.
          *
@@ -92,17 +95,16 @@ class MempoolSelelemReserver
          *
          * \see reserve()
          */
-        MempoolSelelemReserver(t_selelem *sel, int count)
-            : sel_(NULL)
+        MempoolSelelemReserver(const SelectionTreeElementPointer &sel, int count)
         {
             reserve(sel, count);
         }
         //! Frees any memory allocated using this reserver.
         ~MempoolSelelemReserver()
         {
-            if (sel_ != NULL)
+            if (sel_)
             {
-                _gmx_selelem_mempool_release(sel_);
+                sel_->mempoolRelease();
             }
         }
 
@@ -117,15 +119,16 @@ class MempoolSelelemReserver
          * memory pool.  Type of values to allocate is automatically determined
          * from \p sel.
          */
-        void reserve(t_selelem *sel, int count)
+        void reserve(const SelectionTreeElementPointer &sel, int count)
         {
-            GMX_RELEASE_ASSERT(sel_ == NULL, "Can only reserve one element with one instance");
-            _gmx_selelem_mempool_reserve(sel, count);
+            GMX_RELEASE_ASSERT(!sel_,
+                    "Can only reserve one element with one instance");
+            sel->mempoolReserve(count);
             sel_ = sel;
         }
 
     private:
-        t_selelem              *sel_;
+        SelectionTreeElementPointer     sel_;
 };
 
 /*! \internal \brief
@@ -191,7 +194,7 @@ class SelelemTemporaryValueAssigner
     public:
         //! Constructs an assigner without an initial assignment.
         SelelemTemporaryValueAssigner()
-            : sel_(NULL), old_ptr_(NULL), old_nalloc_(0)
+            : old_ptr_(NULL), old_nalloc_(0)
         {
         }
         /*! \brief
@@ -202,15 +205,15 @@ class SelelemTemporaryValueAssigner
          *
          * \see assign()
          */
-        SelelemTemporaryValueAssigner(t_selelem *sel, t_selelem *vsource)
-            : sel_(NULL)
+        SelelemTemporaryValueAssigner(const SelectionTreeElementPointer &sel,
+                                      const SelectionTreeElement &vsource)
         {
             assign(sel, vsource);
         }
         //! Undoes any temporary assignment done using this assigner.
         ~SelelemTemporaryValueAssigner()
         {
-            if (sel_ != NULL)
+            if (sel_)
             {
                 _gmx_selvalue_setstore_alloc(&sel_->v, old_ptr_, old_nalloc_);
             }
@@ -226,22 +229,23 @@ class SelelemTemporaryValueAssigner
          * \p vsource, i.e., any access/modification to values in \p sel
          * actually accesses values in \p vsource.
          */
-        void assign(t_selelem *sel, t_selelem *vsource)
+        void assign(const SelectionTreeElementPointer &sel,
+                    const SelectionTreeElement &vsource)
         {
-            GMX_RELEASE_ASSERT(sel_ == NULL,
+            GMX_RELEASE_ASSERT(!sel_,
                                "Can only assign one element with one instance");
-            GMX_RELEASE_ASSERT(sel->v.type == vsource->v.type,
+            GMX_RELEASE_ASSERT(sel->v.type == vsource.v.type,
                                "Mismatching selection value types");
             old_ptr_ = sel->v.u.ptr;
             old_nalloc_ = sel->v.nalloc;
-            _gmx_selvalue_setstore(&sel->v, vsource->v.u.ptr);
+            _gmx_selvalue_setstore(&sel->v, vsource.v.u.ptr);
             sel_ = sel;
         }
 
     private:
-        t_selelem              *sel_;
-        void                   *old_ptr_;
-        int                     old_nalloc_;
+        SelectionTreeElementPointer     sel_;
+        void                           *old_ptr_;
+        int                             old_nalloc_;
 };
 
 } // namespace
@@ -251,7 +255,7 @@ class SelelemTemporaryValueAssigner
  * \param[in] evalfunc Function pointer to print.
  */
 void
-_gmx_sel_print_evalfunc_name(FILE *fp, sel_evalfunc evalfunc)
+_gmx_sel_print_evalfunc_name(FILE *fp, gmx::sel_evalfunc evalfunc)
 {
     if (!evalfunc)
         fprintf(fp, "none");
@@ -317,7 +321,7 @@ _gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
  * The \ref SEL_EVALFRAME flag is cleared for all elements.
  */
 static void
-init_frame_eval(t_selelem *sel)
+init_frame_eval(SelectionTreeElementPointer sel)
 {
     while (sel)
     {
@@ -364,11 +368,10 @@ SelectionEvaluator::evaluate(SelectionCollection *coll,
 {
     gmx_ana_selcollection_t *sc = &coll->impl_->sc_;
     gmx_sel_evaluate_t  data;
-    t_selelem          *sel;
 
     _gmx_sel_evaluate_init(&data, sc->mempool, &sc->gall, sc->top, fr, pbc);
     init_frame_eval(sc->root);
-    sel = sc->root;
+    SelectionTreeElementPointer sel = sc->root;
     while (sel)
     {
         /* Clear the evaluation group of subexpressions */
@@ -431,12 +434,11 @@ SelectionEvaluator::evaluateFinal(SelectionCollection *coll, int nframes)
  * Evaluates each child of \p sel in \p g.
  */
 void
-_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data, t_selelem *sel,
+_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data,
+                           const SelectionTreeElementPointer &sel,
                            gmx_ana_index_t *g)
 {
-    t_selelem  *child;
-
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     while (child)
     {
         if (child->evaluate)
@@ -459,11 +461,13 @@ _gmx_sel_evaluate_children(gmx_sel_evaluate_t *data, t_selelem *sel,
  * The value of \p sel is not touched (root elements do not evaluate to
  * values).
  *
- * This function can be used as \c t_selelem::evaluate for \ref SEL_ROOT
- * elements.
+ * This function can be used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_ROOT elements.
  */
 void
-_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data,
+                       const SelectionTreeElementPointer &sel,
+                       gmx_ana_index_t *g)
 {
     if (sel->u.cgrp.isize == 0 || !sel->child->evaluate)
     {
@@ -482,11 +486,13 @@ _gmx_sel_evaluate_root(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t
  *
  * Sets the value of \p sel to the intersection of \p g and \p sel->u.cgrp.
  *
- * This function can be used as \c t_selelem::evaluate for \ref SEL_CONST
- * elements with value type \ref GROUP_VALUE.
+ * This function can be used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_CONST elements with value type \ref GROUP_VALUE.
  */
 void
-_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data,
+                         const SelectionTreeElementPointer &sel,
+                         gmx_ana_index_t *g)
 {
     gmx_ana_index_intersection(sel->v.u.g, &sel->u.cgrp, g);
 }
@@ -506,12 +512,14 @@ _gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index
  * The compiler has taken care that the child actually stores the evaluated
  * value in the value pointer of this element.
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
- * elements that are used only once, and hence do not need full subexpression
- * handling.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_SUBEXPR elements that are used only once, and hence do not need
+ * full subexpression handling.
  */
 void
-_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data,
+                                 const SelectionTreeElementPointer &sel,
+                                 gmx_ana_index_t *g)
 {
     if (sel->child->evaluate)
     {
@@ -532,12 +540,14 @@ _gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_a
  * value in the value pointer of this element.
  * Assumes that \p g is persistent for the duration of the whole evaluation.
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPR
- * elements that have a static evaluation group, and hence do not need full
- * subexpression handling.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_SUBEXPR elements that have a static evaluation group, and hence do
+ * not need full subexpression handling.
  */
 void
-_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data,
+                                     const SelectionTreeElementPointer &sel,
+                                     gmx_ana_index_t *g)
 {
     if (sel->u.cgrp.isize == 0)
     {
@@ -568,7 +578,9 @@ _gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, g
  * major problem.
  */
 void
-_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data,
+                          const SelectionTreeElementPointer &sel,
+                          gmx_ana_index_t *g)
 {
     gmx_ana_index_t  gmiss;
 
@@ -576,7 +588,7 @@ _gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_inde
     if (sel->u.cgrp.isize == 0)
     {
         {
-            SelelemTemporaryValueAssigner assigner(sel->child, sel);
+            SelelemTemporaryValueAssigner assigner(sel->child, *sel);
             sel->child->evaluate(data, sel->child, g);
         }
         /* We need to keep the name for the cgrp across the copy to avoid
@@ -676,11 +688,14 @@ _gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_inde
  * 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.
+ * This function is used as gmx::SelectionTreeElement: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)
+_gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data,
+                                    const SelectionTreeElementPointer &sel,
+                                    gmx_ana_index_t *g)
 {
     if (g)
     {
@@ -713,20 +728,21 @@ _gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gm
  * group \p g, and the value of the child is then copied.
  * There should be only one child element.
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_SUBEXPRREF
- * elements.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_SUBEXPRREF elements.
  */
 void
-_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data,
+                             const SelectionTreeElementPointer &sel,
+                             gmx_ana_index_t *g)
 {
-    t_selelem *expr;
     int        i, j;
 
     if (g)
     {
         sel->child->evaluate(data, sel->child, g);
     }
-    expr = sel->child;
+    const SelectionTreeElementPointer &expr = sel->child;
     switch (sel->v.type)
     {
         case INT_VALUE:
@@ -837,15 +853,15 @@ _gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_i
  * Evaluates each child of a \ref SEL_EXPRESSION element.
  * The value of \p sel is not touched.
  *
- * This function is not used as \c t_selelem::evaluate,
+ * This function is not used as gmx::SelectionTreeElement::evaluate,
  * but is used internally.
  */
 void
-_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data,
+                                const SelectionTreeElementPointer &sel,
+                                gmx_ana_index_t *g)
 {
-    t_selelem *child;
-
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     while (child)
     {
         if (child->evaluate && !(child->flags & SEL_EVALFRAME))
@@ -878,11 +894,13 @@ _gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_an
  * the positions are also updated, and sel_updatefunc_pos() is used to
  * evaluate the value. Otherwise, sel_updatefunc() is used.
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_EXPRESSION
- * elements.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_EXPRESSION elements.
  */
 void
-_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data,
+                         const SelectionTreeElementPointer &sel,
+                         gmx_ana_index_t *g)
 {
     _gmx_sel_evaluate_method_params(data, sel, g);
     if (sel->flags & SEL_INITFRAME)
@@ -918,11 +936,13 @@ _gmx_sel_evaluate_method(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index
  * the frame, sel_framefunc() callback is called if one is provided.
  * The modifier is then evaluated using sel_updatefunc_pos().
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_MODIFIER
- * elements.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_MODIFIER elements.
  */
 void
-_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data,
+                           const SelectionTreeElementPointer &sel,
+                           gmx_ana_index_t *g)
 {
     _gmx_sel_evaluate_method_params(data, sel, g);
     if (sel->flags & SEL_INITFRAME)
@@ -957,11 +977,13 @@ _gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_ind
  * \p g, and then sets the value of \p sel to the complement of the 
  * child value.
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
- * elements with \ref BOOL_NOT.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_BOOLEAN elements with \ref BOOL_NOT.
  */
 void
-_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data,
+                      const SelectionTreeElementPointer &sel,
+                      gmx_ana_index_t *g)
 {
     MempoolSelelemReserver reserver(sel->child, g->isize);
     sel->child->evaluate(data, sel->child, g);
@@ -990,15 +1012,15 @@ _gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t
  * of the constant group
  * (currently, the compiler never detects this).
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
- * elements with \ref BOOL_AND.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_BOOLEAN elements with \ref BOOL_AND.
  */
 void
-_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data,
+                      const SelectionTreeElementPointer &sel,
+                      gmx_ana_index_t *g)
 {
-    t_selelem *child;
-
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     /* Skip the first child if it does not have an evaluation function. */
     if (!child->evaluate)
     {
@@ -1043,16 +1065,17 @@ _gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t
  * In this case, the compiler has taken care of that the child value is a
  * subset of \p g, making it unnecessary to evaluate it.
  *
- * This function is used as \c t_selelem::evaluate for \ref SEL_BOOLEAN
- * elements with \ref BOOL_OR.
+ * This function is used as gmx::SelectionTreeElement::evaluate for
+ * \ref SEL_BOOLEAN elements with \ref BOOL_OR.
  */
 void
-_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g)
+_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data,
+                     const SelectionTreeElementPointer &sel,
+                     gmx_ana_index_t *g)
 {
-    t_selelem     *child;
     gmx_ana_index_t  tmp, tmp2;
 
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     if (child->evaluate)
     {
         MempoolSelelemReserver reserver(child, g->isize);
@@ -1092,20 +1115,21 @@ _gmx_sel_evaluate_or(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *
  * \returns   0 on success, a non-zero error code on error.
  */
 void
-_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel,
+_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data,
+                             const SelectionTreeElementPointer &sel,
                              gmx_ana_index_t *g)
 {
     int         n, i, i1, i2;
     real        lval, rval=0., val=0.;
 
-    t_selelem  *const left  = sel->child;
-    t_selelem  *const right = left->next;
+    const SelectionTreeElementPointer &left  = sel->child;
+    const SelectionTreeElementPointer &right = left->next;
 
     SelelemTemporaryValueAssigner assigner;
     MempoolSelelemReserver reserver;
     if (left->mempool)
     {
-        assigner.assign(left, sel);
+        assigner.assign(left, *sel);
         if (right)
         {
             reserver.reserve(right, g->isize);
@@ -1113,7 +1137,7 @@ _gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel,
     }
     else if (right && right->mempool)
     {
-        assigner.assign(right, sel);
+        assigner.assign(right, *sel);
     }
     _gmx_sel_evaluate_children(data, sel, g);
 
index 3947e434e58c9f28f60a5a997d895085330bca9d..6fab6d4bea3ea5018eec50abf0da937b14cf9004 100644 (file)
@@ -37,7 +37,7 @@
  * selections.
  *
  * The functions defined in this header file are all the possible values
- * for the \c t_selelem::evaluate field (in addition to NULL).
+ * for the gmx::SelectionTreeElement::evaluate field (in addition to NULL).
  *
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_selection
@@ -80,10 +80,14 @@ _gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
                        t_topology *top, t_trxframe *fr, t_pbc *pbc);
 /** Evaluates the children of a general selection element. */
 void
-_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data,
+                           const gmx::SelectionTreeElementPointer &sel,
+                           gmx_ana_index_t *g);
 /** Evaluates the children of a \ref SEL_EXPRESSION element. */
 void
-_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data,
+                                const gmx::SelectionTreeElementPointer &sel,
+                                gmx_ana_index_t *g);
 /*@}*/
 
 /*! \name Misc. evaluation functions
@@ -91,13 +95,19 @@ _gmx_sel_evaluate_method_params(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_an
 /*@{*/
 /** Evaluates a root selection element. */
 void
-_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_root(gmx_sel_evaluate_t *data,
+                       const gmx::SelectionTreeElementPointer &sel,
+                       gmx_ana_index_t *g);
 /** Evaluates a static group selection element. */
 void
-_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_static(gmx_sel_evaluate_t *data,
+                         const gmx::SelectionTreeElementPointer &sel,
+                         gmx_ana_index_t *g);
 /** Evaluates an arithmetic expression element. */
 void
-_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data,
+                             const gmx::SelectionTreeElementPointer &sel,
+                             gmx_ana_index_t *g);
 /*@}*/
 
 /*! \name Subexpression evaluation functions
@@ -105,19 +115,29 @@ _gmx_sel_evaluate_arithmetic(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_i
 /*@{*/
 /** Evaluates a subexpression when there is only one reference. */
 void
-_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_subexpr_simple(gmx_sel_evaluate_t *data,
+                                 const gmx::SelectionTreeElementPointer &sel,
+                                 gmx_ana_index_t *g);
 /** Evaluates a subexpression when the evaluation group is static. */
 void
-_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_subexpr_staticeval(gmx_sel_evaluate_t *data,
+                                     const gmx::SelectionTreeElementPointer &sel,
+                                     gmx_ana_index_t *g);
 /** Evaluates a subexpression. */
 void
-_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_subexpr(gmx_sel_evaluate_t *data,
+                          const gmx::SelectionTreeElementPointer &sel,
+                          gmx_ana_index_t *g);
 /** Evaluates a subexpression reference when there are no other references. */
 void
-_gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_subexprref_simple(gmx_sel_evaluate_t *data,
+                                    const gmx::SelectionTreeElementPointer &sel,
+                                    gmx_ana_index_t *g);
 /** Evaluates a subexpression reference. */
 void
-_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data,
+                             const gmx::SelectionTreeElementPointer &sel,
+                             gmx_ana_index_t *g);
 /*@}*/
 
 /*! \name Method evaluation functions
@@ -126,10 +146,14 @@ _gmx_sel_evaluate_subexprref(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_i
 
 /** Evaluates a method expression. */
 void
-_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_method(gmx_sel_evaluate_t *data,
+                         const gmx::SelectionTreeElementPointer &sel,
+                         gmx_ana_index_t *g);
 /** Evaluates a modifier expression. */
 void
-_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data,
+                           const gmx::SelectionTreeElementPointer &sel,
+                           gmx_ana_index_t *g);
 /*@}*/
 
 /*! \name Boolean evaluation functions
@@ -137,13 +161,19 @@ _gmx_sel_evaluate_modifier(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_ind
 /*@{*/
 /** Evaluates a boolean NOT element. */
 void
-_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_not(gmx_sel_evaluate_t *data,
+                      const gmx::SelectionTreeElementPointer &sel,
+                      gmx_ana_index_t *g);
 /** Evaluates a boolean AND element with short-circuiting. */
 void
-_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_and(gmx_sel_evaluate_t *data,
+                      const gmx::SelectionTreeElementPointer &sel,
+                      gmx_ana_index_t *g);
 /** Evaluates a boolean OR element with short-circuiting. */
 void
-_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data, t_selelem *sel, gmx_ana_index_t *g);
+_gmx_sel_evaluate_or(gmx_sel_evaluate_t *data,
+                     const gmx::SelectionTreeElementPointer &sel,
+                     gmx_ana_index_t *g);
 /*@}*/
 
 #endif
index 3e8e9ad80654d7838c23ed712fb27bdd5680e1e1..e5e63a9467ecfd41e2fd84ee775ed9409092dbe8 100644 (file)
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_selection
  */
-#ifndef SELECTION_KEYWORDS_H
-#define SELECTION_KEYWORDS_H
+#ifndef GMX_SELECTION_KEYWORDS_H
+#define GMX_SELECTION_KEYWORDS_H
+
+#include "selelem.h"
 
 struct gmx_ana_selmethod_t;
-struct t_selelem;
 struct t_selexpr_param;
 
 /** Selection method data for comparison expression evaluation. */
@@ -62,10 +63,10 @@ _gmx_selelem_print_compare_info(FILE *fp, void *data);
 
 /** Sets the position type for position keyword evaluation. */
 void
-_gmx_selelem_set_kwpos_type(struct t_selelem *sel, const char *type);
+_gmx_selelem_set_kwpos_type(gmx::SelectionTreeElement *sel, const char *type);
 /** Sets the flags for position keyword evaluation. */
 void
-_gmx_selelem_set_kwpos_flags(struct t_selelem *sel, int flags);
+_gmx_selelem_set_kwpos_flags(gmx::SelectionTreeElement *sel, int flags);
 
 /** Does custom processing for parameters of the \c same selection method. */
 int
@@ -73,9 +74,8 @@ _gmx_selelem_custom_init_same(struct gmx_ana_selmethod_t **method,
                               struct t_selexpr_param *params, void *scanner);
 
 /** Initializes a selection element for evaluating a keyword in a given group. */
-int
-_gmx_sel_init_keyword_evaluator(struct t_selelem **sel,
-                                struct gmx_ana_selmethod_t *method,
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_keyword_evaluator(struct gmx_ana_selmethod_t *method,
                                 struct t_selexpr_param *param, void *scanner);
 
 #endif
index 84f2b112cb2bbec474d48211096e458fbcc6f098..a533180de2c4cbd0fba6cd9f2f698283f3e31528 100644 (file)
 
 #include <algorithm>
 
-#include "smalloc.h"
-#include "string2.h"
-#include "vec.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/string2.h"
+#include "gromacs/legacyheaders/vec.h"
 
 #include "gromacs/selection/position.h"
 #include "gromacs/selection/selmethod.h"
 #include "gromacs/selection/selparam.h"
 #include "gromacs/utility/errorcodes.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/messagestringcollector.h"
 #include "gromacs/utility/stringutil.h"
@@ -61,6 +62,9 @@
 using std::min;
 using std::max;
 
+using gmx::SelectionTreeElement;
+using gmx::SelectionTreeElementPointer;
+
 /*!
  * \param[in] name   Name of the parameter to search.
  * \param[in] nparam Number of parameters in the \p param array.
@@ -122,15 +126,16 @@ convert_value(t_selexpr_value *value, e_selvalue_t type, void *scanner)
     {
         return 0;
     }
-    if (value->bExpr)
+    if (value->hasExpressionValue())
     {
         /* Conversion from atom selection to position using default
          * reference positions. */
         if (value->type == GROUP_VALUE && type == POS_VALUE)
         {
-            value->u.expr =
-                _gmx_sel_init_position(value->u.expr, NULL, scanner);
-            if (value->u.expr == NULL)
+            value->expr =
+                _gmx_sel_init_position(value->expr, NULL, scanner);
+            // FIXME: Use exceptions
+            if (!value->expr)
             {
                 return -1;
             }
@@ -207,7 +212,9 @@ convert_values(t_selexpr_value *values, e_selvalue_t type, void *scanner)
  * in the same order as the corresponding parameters.
  */
 static void
-place_child(t_selelem *root, t_selelem *child, gmx_ana_selparam_t *param)
+place_child(const SelectionTreeElementPointer &root,
+            const SelectionTreeElementPointer &child,
+            gmx_ana_selparam_t *param)
 {
     gmx_ana_selparam_t *ps;
     int                 n;
@@ -222,9 +229,7 @@ place_child(t_selelem *root, t_selelem *child, gmx_ana_selparam_t *param)
     }
     else
     {
-        t_selelem *prev;
-
-        prev = root->child;
+        SelectionTreeElementPointer prev = root->child;
         while (prev->next && prev->next->u.param - ps >= n)
         {
             prev = prev->next;
@@ -328,7 +333,7 @@ parse_values_range(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
     i = 0;
     while (value)
     {
-        if (value->bExpr)
+        if (value->hasExpressionValue())
         {
             _gmx_selparser_error(scanner, "expressions not supported within range parameters");
             return false;
@@ -484,7 +489,9 @@ parse_values_range(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
  */
 static bool
 parse_values_varnum(int nval, t_selexpr_value *values,
-                    gmx_ana_selparam_t *param, t_selelem *root, void *scanner)
+                    gmx_ana_selparam_t *param,
+                    const SelectionTreeElementPointer &root,
+                    void *scanner)
 {
     t_selexpr_value    *value;
     int                 i, j;
@@ -496,7 +503,7 @@ parse_values_varnum(int nval, t_selexpr_value *values,
         value = values;
         while (value)
         {
-            if (value->type == INT_VALUE && !value->bExpr)
+            if (value->type == INT_VALUE && !value->hasExpressionValue())
             {
                 nval += abs(value->u.i.i2 - value->u.i.i1);
             }
@@ -529,7 +536,7 @@ parse_values_varnum(int nval, t_selexpr_value *values,
     i     = 0;
     while (value)
     {
-        if (value->bExpr)
+        if (value->hasExpressionValue())
         {
             _gmx_selparser_error(scanner, "expressions not supported within value lists");
             return false;
@@ -584,9 +591,7 @@ parse_values_varnum(int nval, t_selexpr_value *values,
      * other function. */
     if (param->val.type == STR_VALUE)
     {
-        t_selelem *child;
-
-        child = _gmx_selelem_create(SEL_CONST);
+        SelectionTreeElementPointer child(new SelectionTreeElement(SEL_CONST));
         _gmx_selelem_set_vtype(child, STR_VALUE);
         child->name = param->name;
         child->flags &= ~SEL_ALLOCVAL;
@@ -617,19 +622,13 @@ parse_values_varnum(int nval, t_selexpr_value *values,
  * If \p expr is already a \ref SEL_SUBEXPRREF, it is used as it is.
  * \ref SEL_ALLOCVAL is cleared for the returned element.
  */
-static t_selelem *
-add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr,
-          void *scanner)
+static SelectionTreeElementPointer
+add_child(const SelectionTreeElementPointer &root, gmx_ana_selparam_t *param,
+          const SelectionTreeElementPointer &expr, void *scanner)
 {
-    t_selelem          *child;
-    int                 rc;
-
-    if (root->type != SEL_EXPRESSION && root->type != SEL_MODIFIER)
-    {
-        GMX_ERROR_NORET(gmx::eeInternalError,
-                        "Unsupported root element for selection parameter parser");
-        return NULL;
-    }
+    GMX_RELEASE_ASSERT(root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER,
+                       "Unsupported root element for selection parameter parser");
+    SelectionTreeElementPointer child;
     /* Create a subexpression reference element if necessary */
     if (expr->type == SEL_SUBEXPRREF)
     {
@@ -637,11 +636,7 @@ add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr,
     }
     else
     {
-        child = _gmx_selelem_create(SEL_SUBEXPRREF);
-        if (!child)
-        {
-            return NULL;
-        }
+        child.reset(new SelectionTreeElement(SEL_SUBEXPRREF));
         _gmx_selelem_set_vtype(child, expr->v.type);
         child->child  = expr;
     }
@@ -651,17 +646,15 @@ add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr,
     if (child->v.type != param->val.type)
     {
         _gmx_selparser_error(scanner, "invalid expression value");
-        goto on_error;
-    }
-    rc = _gmx_selelem_update_flags(child, scanner);
-    if (rc != 0)
-    {
-        goto on_error;
+        // FIXME: Use exceptions.
+        return SelectionTreeElementPointer();
     }
+    _gmx_selelem_update_flags(child, scanner);
     if ((child->flags & SEL_DYNAMIC) && !(param->flags & SPAR_DYNAMIC))
     {
         _gmx_selparser_error(scanner, "dynamic values not supported");
-        goto on_error;
+        // FIXME: Use exceptions.
+        return SelectionTreeElementPointer();
     }
     if (!(child->flags & SEL_DYNAMIC))
     {
@@ -670,13 +663,6 @@ add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr,
     /* Put the child element in the correct place */
     place_child(root, child, param);
     return child;
-
-on_error:
-    if (child != expr)
-    {
-        _gmx_selelem_free(child);
-    }
-    return NULL;
 }
 
 /*! \brief
@@ -691,21 +677,19 @@ on_error:
  */
 static bool
 parse_values_varnum_expr(int nval, t_selexpr_value *values,
-                         gmx_ana_selparam_t *param, t_selelem *root,
+                         gmx_ana_selparam_t *param,
+                         const SelectionTreeElementPointer &root,
                          void *scanner)
 {
-    t_selexpr_value    *value;
-    t_selelem          *child;
-
-    if (nval != 1 || !values->bExpr)
+    if (nval != 1 || !values->hasExpressionValue())
     {
         GMX_ERROR_NORET(gmx::eeInternalError, "Invalid expression value");
         return false;
     }
 
-    value = values;
-    child = add_child(root, param, value->u.expr, scanner);
-    value->u.expr = NULL;
+    t_selexpr_value *value = values;
+    SelectionTreeElementPointer child
+        = add_child(root, param, value->expr, scanner);
     if (!child)
     {
         return false;
@@ -755,8 +739,8 @@ parse_values_varnum_expr(int nval, t_selexpr_value *values,
  * This function is used internally by parse_values_std().
  */
 static bool
-set_expr_value_store(t_selelem *sel, gmx_ana_selparam_t *param, int i,
-                     void *scanner)
+set_expr_value_store(const SelectionTreeElementPointer &sel,
+                     gmx_ana_selparam_t *param, int i, void *scanner)
 {
     if (sel->v.type != GROUP_VALUE && !(sel->flags & SEL_SINGLEVAL))
     {
@@ -794,10 +778,9 @@ set_expr_value_store(t_selelem *sel, gmx_ana_selparam_t *param, int i,
  */
 static bool
 parse_values_std(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
-                 t_selelem *root, void *scanner)
+                 const SelectionTreeElementPointer &root, void *scanner)
 {
     t_selexpr_value   *value;
-    t_selelem         *child;
     int                i, j;
     bool               bDynamic;
 
@@ -810,10 +793,10 @@ parse_values_std(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
             return false;
         }
         value = values;
-        if (value->bExpr)
+        if (value->hasExpressionValue())
         {
-            child = add_child(root, param, value->u.expr, scanner);
-            value->u.expr = NULL;
+            SelectionTreeElementPointer child
+                = add_child(root, param, value->expr, scanner);
             if (!child)
             {
                 return false;
@@ -867,11 +850,10 @@ parse_values_std(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
             value = value->next;
             continue;
         }
-        if (value->bExpr)
+        if (value->hasExpressionValue())
         {
-            child = add_child(root, param, value->u.expr, scanner);
-            /* Clear the expression from the value once it is stored */
-            value->u.expr = NULL;
+            SelectionTreeElementPointer child
+                = add_child(root, param, value->expr, scanner);
             /* Check that the expression is valid */
             if (!child)
             {
@@ -1039,7 +1021,7 @@ parse_values_enum(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
         GMX_ERROR_NORET(gmx::eeInternalError, "Invalid enum parameter");
         return false;
     }
-    if (values->bExpr)
+    if (values->hasExpressionValue())
     {
         _gmx_selparser_error(scanner, "expression value for enumerated parameter not supported");
         return false;
@@ -1084,11 +1066,11 @@ convert_const_values(t_selexpr_value *values)
     val = values;
     while (val)
     {
-        if (val->bExpr && val->u.expr->v.type != GROUP_VALUE &&
-            val->u.expr->type == SEL_CONST)
+        if (val->hasExpressionValue() && val->expr->v.type != GROUP_VALUE &&
+            val->expr->type == SEL_CONST)
         {
-            t_selelem *expr = val->u.expr;
-            val->bExpr = false;
+            SelectionTreeElementPointer expr = val->expr;
+            val->expr.reset();
             switch (expr->v.type)
             {
                 case INT_VALUE:
@@ -1108,7 +1090,6 @@ convert_const_values(t_selexpr_value *values)
                                     "Unsupported value type");
                     break;
             }
-            _gmx_selelem_free(expr);
         }
         val = val->next;
     }
@@ -1131,7 +1112,7 @@ convert_const_values(t_selexpr_value *values)
  */
 bool
 _gmx_sel_parse_params(t_selexpr_param *pparams, int nparam, gmx_ana_selparam_t *params,
-                      t_selelem *root, void *scanner)
+                      const SelectionTreeElementPointer &root, void *scanner)
 {
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
     t_selexpr_param    *pparam;
@@ -1249,7 +1230,7 @@ _gmx_sel_parse_params(t_selexpr_param *pparams, int nparam, gmx_ana_selparam_t *
         }
         else if (oparam->flags & SPAR_VARNUM)
         {
-            if (pparam->nval == 1 && pparam->value->bExpr)
+            if (pparam->nval == 1 && pparam->value->hasExpressionValue())
             {
                 rc = parse_values_varnum_expr(pparam->nval, pparam->value, oparam, root, scanner);
             }
index 13a81e46f5638aed6081b8211c0677c58adf48fc..f7c10fadec77ce2a3184864dcfa31ed18a0ac5cf 100644 (file)
@@ -95,6 +95,7 @@
 
 #include <exception>
 
+#include "gromacs/legacyheaders/smalloc.h"
 #include "gromacs/legacyheaders/string2.h"
 
 #include "parsetree.h"
 
 #include "scanner.h"
 
+using gmx::scoped_ptr_sfree;
+using gmx::SelectionTreeElement;
+using gmx::SelectionTreeElementPointer;
+
 //! Helper method to reorder a list of parameter values and to count the values.
 static t_selexpr_value *
 process_value_list(t_selexpr_value *values, int *nr);
@@ -109,6 +114,63 @@ process_value_list(t_selexpr_value *values, int *nr);
 static t_selexpr_param *
 process_param_list(t_selexpr_param *params);
 
+/*! \brief
+ * Retrieves a selection tree pointer from a semantic value.
+ *
+ * \param[in] src  Semantic value to get the tree from.
+ * \returns   Pointer to the selection tree.
+ *
+ * There should be no statements that may throw exceptions in actions before
+ * this function has been called for all semantic values that have a tree
+ * argument.  Together with set(), this function abstracts away exception
+ * safety issues that arise from the use of a plain pointer for storing the
+ * selection tree semantic values.
+ *
+ * Does not throw.
+ */
+static SelectionTreeElementPointer
+get(SelectionTreeElementPointer *src)
+{
+    SelectionTreeElementPointer result;
+    if (src != NULL)
+    {
+        result.swap(*src);
+        delete src;
+    }
+    return result;
+}
+/*! \brief
+ * Sets a selection tree pointer to a semantic value.
+ *
+ * \param[out] dest  Semantic value to set the tree to.
+ * \param[in]  value Pointer to the selection tree to set.
+ * \throws     std::bad_alloc if out of memory.
+ *
+ * This should be the last statement before ::END_ACTION, except for a
+ * possible ::CHECK_SEL.
+ */
+static void
+set(SelectionTreeElementPointer *&dest,
+        const SelectionTreeElementPointer &value)
+{
+    dest = new SelectionTreeElementPointer(value);
+}
+/*! \brief
+ * Checks that a valid tree was set.
+ *
+ * Should be called after set() if it was used to set a value where NULL
+ * pointer indicates an error.
+ *
+ * \todo
+ * Get rid of this macro.  It should now be possible to handle all errors using
+ * exceptions.
+ */
+#define CHECK_SEL(sel) \
+    if (!*(sel)) { \
+        delete sel; \
+        YYERROR; \
+    }
+
 //! Error handler needed by Bison.
 static void
 yyerror(yyscan_t, char const *s);
@@ -146,7 +208,7 @@ yyerror(yyscan_t, char const *s);
 
 
 /* Line 268 of yacc.c  */
-#line 150 "parser.cpp"
+#line 212 "parser.cpp"
 
 /* Enabling traces.  */
 #ifndef YYDEBUG
@@ -166,6 +228,17 @@ yyerror(yyscan_t, char const *s);
 # define YYTOKEN_TABLE 0
 #endif
 
+/* "%code requires" blocks.  */
+
+/* Line 288 of yacc.c  */
+#line 166 "parser.y"
+
+#include "selelem.h"
+
+
+
+/* Line 288 of yacc.c  */
+#line 242 "parser.cpp"
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -216,14 +289,14 @@ typedef union YYSTYPE
 {
 
 /* Line 293 of yacc.c  */
-#line 104 "parser.y"
+#line 170 "parser.y"
 
     int                         i;
     real                        r;
     char                       *str;
     struct gmx_ana_selmethod_t *meth;
 
-    struct t_selelem           *sel;
+    gmx::SelectionTreeElementPointer *sel;
 
     struct t_selexpr_value     *val;
     struct t_selexpr_param     *param;
@@ -231,7 +304,7 @@ typedef union YYSTYPE
 
 
 /* Line 293 of yacc.c  */
-#line 235 "parser.cpp"
+#line 308 "parser.cpp"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
@@ -267,7 +340,7 @@ void yypstate_delete ();
 
 
 /* Line 343 of yacc.c  */
-#line 271 "parser.cpp"
+#line 344 "parser.cpp"
 
 #ifdef short
 # undef short
@@ -566,16 +639,16 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   220,   220,   221,   232,   233,   255,   261,   262,   273,
-     285,   291,   297,   303,   309,   319,   327,   328,   338,   339,
-     346,   347,   361,   362,   366,   367,   370,   371,   374,   375,
-     383,   391,   399,   407,   411,   421,   429,   439,   440,   444,
-     451,   458,   468,   482,   491,   503,   510,   520,   526,   532,
-     538,   544,   550,   556,   563,   572,   586,   595,   599,   609,
-     622,   630,   638,   651,   653,   658,   659,   664,   673,   674,
-     675,   679,   680,   682,   687,   688,   692,   693,   695,   699,
-     705,   711,   717,   723,   727,   734,   741,   748,   752,   759,
-     766
+       0,   285,   285,   286,   297,   298,   320,   326,   327,   339,
+     352,   358,   365,   372,   379,   390,   398,   399,   409,   410,
+     417,   418,   432,   433,   437,   438,   441,   442,   445,   446,
+     454,   465,   476,   487,   491,   501,   509,   519,   520,   524,
+     531,   538,   548,   562,   573,   587,   594,   604,   610,   616,
+     622,   628,   634,   640,   647,   658,   672,   681,   685,   695,
+     708,   716,   724,   737,   739,   744,   745,   750,   759,   760,
+     761,   765,   766,   768,   773,   774,   778,   779,   781,   785,
+     791,   797,   803,   809,   813,   820,   827,   834,   838,   845,
+     852
 };
 #endif
 
@@ -1369,218 +1442,227 @@ yydestruct (yymsg, yytype, yyvaluep, scanner)
       case 5: /* "HELP_TOPIC" */
 
 /* Line 1391 of yacc.c  */
-#line 199 "parser.y"
+#line 265 "parser.y"
        { free((yyvaluep->str));                     };
 
 /* Line 1391 of yacc.c  */
-#line 1377 "parser.cpp"
+#line 1450 "parser.cpp"
        break;
       case 8: /* "STR" */
 
 /* Line 1391 of yacc.c  */
-#line 199 "parser.y"
+#line 265 "parser.y"
        { free((yyvaluep->str));                     };
 
 /* Line 1391 of yacc.c  */
-#line 1386 "parser.cpp"
+#line 1459 "parser.cpp"
        break;
       case 9: /* "IDENTIFIER" */
 
 /* Line 1391 of yacc.c  */
-#line 199 "parser.y"
+#line 265 "parser.y"
        { free((yyvaluep->str));                     };
 
 /* Line 1391 of yacc.c  */
-#line 1395 "parser.cpp"
+#line 1468 "parser.cpp"
        break;
       case 25: /* "PARAM" */
 
 /* Line 1391 of yacc.c  */
-#line 200 "parser.y"
+#line 266 "parser.y"
        { if((yyvaluep->str)) free((yyvaluep->str));              };
 
 /* Line 1391 of yacc.c  */
-#line 1404 "parser.cpp"
+#line 1477 "parser.cpp"
        break;
       case 28: /* "CMP_OP" */
 
 /* Line 1391 of yacc.c  */
-#line 199 "parser.y"
+#line 265 "parser.y"
        { free((yyvaluep->str));                     };
 
 /* Line 1391 of yacc.c  */
-#line 1413 "parser.cpp"
+#line 1486 "parser.cpp"
+       break;
+      case 50: /* "commands" */
+
+/* Line 1391 of yacc.c  */
+#line 267 "parser.y"
+       { delete (yyvaluep->sel);                    };
+
+/* Line 1391 of yacc.c  */
+#line 1495 "parser.cpp"
        break;
       case 51: /* "command" */
 
 /* Line 1391 of yacc.c  */
-#line 201 "parser.y"
-       { if((yyvaluep->sel)) _gmx_selelem_free((yyvaluep->sel)); };
+#line 267 "parser.y"
+       { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1422 "parser.cpp"
+#line 1504 "parser.cpp"
        break;
       case 52: /* "cmd_plain" */
 
 /* Line 1391 of yacc.c  */
-#line 201 "parser.y"
-       { if((yyvaluep->sel)) _gmx_selelem_free((yyvaluep->sel)); };
+#line 267 "parser.y"
+       { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1431 "parser.cpp"
+#line 1513 "parser.cpp"
        break;
       case 54: /* "help_topic" */
 
 /* Line 1391 of yacc.c  */
-#line 207 "parser.y"
+#line 272 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1440 "parser.cpp"
+#line 1522 "parser.cpp"
        break;
       case 55: /* "selection" */
 
 /* Line 1391 of yacc.c  */
-#line 202 "parser.y"
-       { _gmx_selelem_free_chain((yyvaluep->sel));  };
+#line 267 "parser.y"
+       { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1449 "parser.cpp"
+#line 1531 "parser.cpp"
        break;
       case 59: /* "string" */
 
 /* Line 1391 of yacc.c  */
-#line 199 "parser.y"
+#line 265 "parser.y"
        { free((yyvaluep->str));                     };
 
 /* Line 1391 of yacc.c  */
-#line 1458 "parser.cpp"
+#line 1540 "parser.cpp"
        break;
       case 60: /* "sel_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 203 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 268 "parser.y"
+       { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1467 "parser.cpp"
+#line 1549 "parser.cpp"
        break;
       case 62: /* "num_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 203 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 268 "parser.y"
+       { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1476 "parser.cpp"
+#line 1558 "parser.cpp"
        break;
       case 63: /* "str_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 203 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 268 "parser.y"
+       { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1485 "parser.cpp"
+#line 1567 "parser.cpp"
        break;
       case 64: /* "pos_expr" */
 
 /* Line 1391 of yacc.c  */
-#line 203 "parser.y"
-       { _gmx_selelem_free((yyvaluep->sel));        };
+#line 268 "parser.y"
+       { delete (yyvaluep->sel);                    };
 
 /* Line 1391 of yacc.c  */
-#line 1494 "parser.cpp"
+#line 1576 "parser.cpp"
        break;
       case 65: /* "method_params" */
 
 /* Line 1391 of yacc.c  */
-#line 204 "parser.y"
+#line 269 "parser.y"
        { _gmx_selexpr_free_params((yyvaluep->param)); };
 
 /* Line 1391 of yacc.c  */
-#line 1503 "parser.cpp"
+#line 1585 "parser.cpp"
        break;
       case 66: /* "method_param_list" */
 
 /* Line 1391 of yacc.c  */
-#line 204 "parser.y"
+#line 269 "parser.y"
        { _gmx_selexpr_free_params((yyvaluep->param)); };
 
 /* Line 1391 of yacc.c  */
-#line 1512 "parser.cpp"
+#line 1594 "parser.cpp"
        break;
       case 67: /* "method_param" */
 
 /* Line 1391 of yacc.c  */
-#line 204 "parser.y"
+#line 269 "parser.y"
        { _gmx_selexpr_free_params((yyvaluep->param)); };
 
 /* Line 1391 of yacc.c  */
-#line 1521 "parser.cpp"
+#line 1603 "parser.cpp"
        break;
       case 68: /* "value_list" */
 
 /* Line 1391 of yacc.c  */
-#line 205 "parser.y"
+#line 270 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1530 "parser.cpp"
+#line 1612 "parser.cpp"
        break;
       case 69: /* "value_list_contents" */
 
 /* Line 1391 of yacc.c  */
-#line 205 "parser.y"
+#line 270 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1539 "parser.cpp"
+#line 1621 "parser.cpp"
        break;
       case 70: /* "basic_value_list" */
 
 /* Line 1391 of yacc.c  */
-#line 206 "parser.y"
+#line 271 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1548 "parser.cpp"
+#line 1630 "parser.cpp"
        break;
       case 71: /* "basic_value_list_contents" */
 
 /* Line 1391 of yacc.c  */
-#line 206 "parser.y"
+#line 271 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1557 "parser.cpp"
+#line 1639 "parser.cpp"
        break;
       case 72: /* "value_item" */
 
 /* Line 1391 of yacc.c  */
-#line 205 "parser.y"
+#line 270 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1566 "parser.cpp"
+#line 1648 "parser.cpp"
        break;
       case 73: /* "basic_value_item" */
 
 /* Line 1391 of yacc.c  */
-#line 206 "parser.y"
+#line 271 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1575 "parser.cpp"
+#line 1657 "parser.cpp"
        break;
       case 74: /* "value_item_range" */
 
 /* Line 1391 of yacc.c  */
-#line 205 "parser.y"
+#line 270 "parser.y"
        { _gmx_selexpr_free_values((yyvaluep->val)); };
 
 /* Line 1391 of yacc.c  */
-#line 1584 "parser.cpp"
+#line 1666 "parser.cpp"
        break;
 
       default:
@@ -1929,17 +2011,17 @@ yyreduce:
         case 2:
 
 /* Line 1806 of yacc.c  */
-#line 220 "parser.y"
+#line 285 "parser.y"
     { (yyval.sel) = NULL; }
     break;
 
   case 3:
 
 /* Line 1806 of yacc.c  */
-#line 222 "parser.y"
+#line 287 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_append_selection((yyvsp[(2) - (2)].sel), (yyvsp[(1) - (2)].sel), scanner);
+                 set((yyval.sel), _gmx_sel_append_selection(get((yyvsp[(2) - (2)].sel)), get((yyvsp[(1) - (2)].sel)), scanner));
                  if (_gmx_sel_parser_should_finish(scanner))
                      YYACCEPT;
                  END_ACTION;
@@ -1949,14 +2031,14 @@ yyreduce:
   case 4:
 
 /* Line 1806 of yacc.c  */
-#line 232 "parser.y"
+#line 297 "parser.y"
     { (yyval.sel) = (yyvsp[(1) - (2)].sel); }
     break;
 
   case 5:
 
 /* Line 1806 of yacc.c  */
-#line 234 "parser.y"
+#line 299 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.sel) = NULL;
@@ -1979,7 +2061,7 @@ yyreduce:
   case 6:
 
 /* Line 1806 of yacc.c  */
-#line 255 "parser.y"
+#line 320 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.sel) = NULL;
@@ -1991,22 +2073,23 @@ yyreduce:
   case 7:
 
 /* Line 1806 of yacc.c  */
-#line 261 "parser.y"
+#line 326 "parser.y"
     { (yyval.sel) = NULL; }
     break;
 
   case 8:
 
 /* Line 1806 of yacc.c  */
-#line 263 "parser.y"
+#line 328 "parser.y"
     {
                  BEGIN_ACTION;
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_id((yyvsp[(1) - (1)].i), scanner);
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 (yyval.sel) = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+                 SelectionTreeElementPointer s
+                        = _gmx_sel_init_group_by_id((yyvsp[(1) - (1)].i), scanner);
+                 if (!s) YYERROR;
+                 SelectionTreeElementPointer p
+                        = _gmx_sel_init_position(s, NULL, scanner);
+                 if (!p) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_selection(s->name, p, scanner));
                  END_ACTION;
              }
     break;
@@ -2014,16 +2097,17 @@ yyreduce:
   case 9:
 
 /* Line 1806 of yacc.c  */
-#line 274 "parser.y"
+#line 340 "parser.y"
     {
                  BEGIN_ACTION;
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_name((yyvsp[(1) - (1)].str), scanner);
-                 free((yyvsp[(1) - (1)].str));
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 (yyval.sel) = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+                 scoped_ptr_sfree nameGuard((yyvsp[(1) - (1)].str));
+                 SelectionTreeElementPointer s
+                        = _gmx_sel_init_group_by_name((yyvsp[(1) - (1)].str), scanner);
+                 if (!s) YYERROR;
+                 SelectionTreeElementPointer p
+                        = _gmx_sel_init_position(s, NULL, scanner);
+                 if (!p) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_selection(s->name, p, scanner));
                  END_ACTION;
              }
     break;
@@ -2031,10 +2115,10 @@ yyreduce:
   case 10:
 
 /* Line 1806 of yacc.c  */
-#line 286 "parser.y"
+#line 353 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_selection(NULL, (yyvsp[(1) - (1)].sel), scanner);
+                 set((yyval.sel), _gmx_sel_init_selection(NULL, get((yyvsp[(1) - (1)].sel)), scanner));
                  END_ACTION;
              }
     break;
@@ -2042,10 +2126,11 @@ yyreduce:
   case 11:
 
 /* Line 1806 of yacc.c  */
-#line 292 "parser.y"
+#line 359 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_selection((yyvsp[(1) - (2)].str), (yyvsp[(2) - (2)].sel), scanner);
+                 scoped_ptr_sfree nameGuard((yyvsp[(1) - (2)].str));
+                 set((yyval.sel), _gmx_sel_init_selection((yyvsp[(1) - (2)].str), get((yyvsp[(2) - (2)].sel)), scanner));
                  END_ACTION;
              }
     break;
@@ -2053,10 +2138,11 @@ yyreduce:
   case 12:
 
 /* Line 1806 of yacc.c  */
-#line 298 "parser.y"
+#line 366 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);
+                 scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
                  END_ACTION;
              }
     break;
@@ -2064,10 +2150,11 @@ yyreduce:
   case 13:
 
 /* Line 1806 of yacc.c  */
-#line 304 "parser.y"
+#line 373 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);
+                 scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
                  END_ACTION;
              }
     break;
@@ -2075,10 +2162,11 @@ yyreduce:
   case 14:
 
 /* Line 1806 of yacc.c  */
-#line 310 "parser.y"
+#line 380 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), (yyvsp[(3) - (3)].sel), scanner);
+                 scoped_ptr_sfree nameGuard((yyvsp[(1) - (3)].str));
+                 set((yyval.sel), _gmx_sel_assign_variable((yyvsp[(1) - (3)].str), get((yyvsp[(3) - (3)].sel)), scanner));
                  END_ACTION;
              }
     break;
@@ -2086,7 +2174,7 @@ yyreduce:
   case 15:
 
 /* Line 1806 of yacc.c  */
-#line 320 "parser.y"
+#line 391 "parser.y"
     {
                  BEGIN_ACTION;
                  _gmx_sel_handle_help_cmd(process_value_list((yyvsp[(2) - (2)].val), NULL), scanner);
@@ -2097,14 +2185,14 @@ yyreduce:
   case 16:
 
 /* Line 1806 of yacc.c  */
-#line 327 "parser.y"
+#line 398 "parser.y"
     { (yyval.val) = NULL; }
     break;
 
   case 17:
 
 /* Line 1806 of yacc.c  */
-#line 329 "parser.y"
+#line 400 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.val) = _gmx_selexpr_create_value(STR_VALUE);
@@ -2116,18 +2204,18 @@ yyreduce:
   case 18:
 
 /* Line 1806 of yacc.c  */
-#line 338 "parser.y"
+#line 409 "parser.y"
     { (yyval.sel) = (yyvsp[(1) - (1)].sel); }
     break;
 
   case 19:
 
 /* Line 1806 of yacc.c  */
-#line 340 "parser.y"
+#line 411 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_position((yyvsp[(1) - (1)].sel), NULL, scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(1) - (1)].sel)), NULL, scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2135,18 +2223,18 @@ yyreduce:
   case 20:
 
 /* Line 1806 of yacc.c  */
-#line 346 "parser.y"
+#line 417 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 21:
 
 /* Line 1806 of yacc.c  */
-#line 348 "parser.y"
+#line 419 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].sel), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_modifier((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), get((yyvsp[(1) - (3)].sel)), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2154,68 +2242,71 @@ yyreduce:
   case 22:
 
 /* Line 1806 of yacc.c  */
-#line 361 "parser.y"
+#line 432 "parser.y"
     { (yyval.i) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 23:
 
 /* Line 1806 of yacc.c  */
-#line 362 "parser.y"
+#line 433 "parser.y"
     { (yyval.i) = -(yyvsp[(2) - (2)].i); }
     break;
 
   case 24:
 
 /* Line 1806 of yacc.c  */
-#line 366 "parser.y"
+#line 437 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 25:
 
 /* Line 1806 of yacc.c  */
-#line 367 "parser.y"
+#line 438 "parser.y"
     { (yyval.r) = -(yyvsp[(2) - (2)].r); }
     break;
 
   case 26:
 
 /* Line 1806 of yacc.c  */
-#line 370 "parser.y"
+#line 441 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].i); }
     break;
 
   case 27:
 
 /* Line 1806 of yacc.c  */
-#line 371 "parser.y"
+#line 442 "parser.y"
     { (yyval.r) = (yyvsp[(1) - (1)].r); }
     break;
 
   case 28:
 
 /* Line 1806 of yacc.c  */
-#line 374 "parser.y"
+#line 445 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 29:
 
 /* Line 1806 of yacc.c  */
-#line 375 "parser.y"
+#line 446 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str); }
     break;
 
   case 30:
 
 /* Line 1806 of yacc.c  */
-#line 384 "parser.y"
+#line 455 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
-                 (yyval.sel)->u.boolt = BOOL_NOT;
-                 (yyval.sel)->child = (yyvsp[(2) - (2)].sel);
+                 SelectionTreeElementPointer arg(get((yyvsp[(2) - (2)].sel)));
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_BOOLEAN));
+                 sel->u.boolt = BOOL_NOT;
+                 sel->child = arg;
+                 set((yyval.sel), sel);
                  END_ACTION;
              }
     break;
@@ -2223,12 +2314,15 @@ yyreduce:
   case 31:
 
 /* Line 1806 of yacc.c  */
-#line 392 "parser.y"
+#line 466 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
-                 (yyval.sel)->u.boolt = BOOL_AND;
-                 (yyval.sel)->child = (yyvsp[(1) - (3)].sel); (yyval.sel)->child->next = (yyvsp[(3) - (3)].sel);
+                 SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_BOOLEAN));
+                 sel->u.boolt = BOOL_AND;
+                 sel->child = arg1; sel->child->next = arg2;
+                 set((yyval.sel), sel);
                  END_ACTION;
              }
     break;
@@ -2236,12 +2330,15 @@ yyreduce:
   case 32:
 
 /* Line 1806 of yacc.c  */
-#line 400 "parser.y"
+#line 477 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_selelem_create(SEL_BOOLEAN);
-                 (yyval.sel)->u.boolt = BOOL_OR;
-                 (yyval.sel)->child = (yyvsp[(1) - (3)].sel); (yyval.sel)->child->next = (yyvsp[(3) - (3)].sel);
+                 SelectionTreeElementPointer arg1(get((yyvsp[(1) - (3)].sel))), arg2(get((yyvsp[(3) - (3)].sel)));
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_BOOLEAN));
+                 sel->u.boolt = BOOL_OR;
+                 sel->child = arg1; sel->child->next = arg2;
+                 set((yyval.sel), sel);
                  END_ACTION;
              }
     break;
@@ -2249,18 +2346,18 @@ yyreduce:
   case 33:
 
 /* Line 1806 of yacc.c  */
-#line 407 "parser.y"
+#line 487 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 34:
 
 /* Line 1806 of yacc.c  */
-#line 412 "parser.y"
+#line 492 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_comparison((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), (yyvsp[(2) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_comparison(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), (yyvsp[(2) - (3)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2268,12 +2365,12 @@ yyreduce:
   case 35:
 
 /* Line 1806 of yacc.c  */
-#line 422 "parser.y"
+#line 502 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_group_by_name((yyvsp[(2) - (2)].str), scanner);
-                 free((yyvsp[(2) - (2)].str));
-                 if ((yyval.sel) == NULL) YYERROR;
+                 scoped_ptr_sfree nameGuard((yyvsp[(2) - (2)].str));
+                 set((yyval.sel), _gmx_sel_init_group_by_name((yyvsp[(2) - (2)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2281,11 +2378,11 @@ yyreduce:
   case 36:
 
 /* Line 1806 of yacc.c  */
-#line 430 "parser.y"
+#line 510 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_group_by_id((yyvsp[(2) - (2)].i), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2293,25 +2390,25 @@ yyreduce:
   case 37:
 
 /* Line 1806 of yacc.c  */
-#line 439 "parser.y"
+#line 519 "parser.y"
     { (yyval.str) = NULL; }
     break;
 
   case 38:
 
 /* Line 1806 of yacc.c  */
-#line 440 "parser.y"
+#line 520 "parser.y"
     { (yyval.str) = (yyvsp[(1) - (1)].str);   }
     break;
 
   case 39:
 
 /* Line 1806 of yacc.c  */
-#line 445 "parser.y"
+#line 525 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2319,11 +2416,11 @@ yyreduce:
   case 40:
 
 /* Line 1806 of yacc.c  */
-#line 452 "parser.y"
+#line 532 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2331,11 +2428,11 @@ yyreduce:
   case 41:
 
 /* Line 1806 of yacc.c  */
-#line 459 "parser.y"
+#line 539 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (3)].meth), process_value_list((yyvsp[(3) - (3)].val), NULL), (yyvsp[(1) - (3)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2343,11 +2440,11 @@ yyreduce:
   case 42:
 
 /* Line 1806 of yacc.c  */
-#line 469 "parser.y"
+#line 549 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2355,13 +2452,15 @@ yyreduce:
   case 43:
 
 /* Line 1806 of yacc.c  */
-#line 483 "parser.y"
+#line 563 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype((yyval.sel), INT_VALUE);
-                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
-                 (yyval.sel)->v.u.i[0] = (yyvsp[(1) - (1)].i);
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_CONST));
+                 _gmx_selelem_set_vtype(sel, INT_VALUE);
+                 _gmx_selvalue_reserve(&sel->v, 1);
+                 sel->v.u.i[0] = (yyvsp[(1) - (1)].i);
+                 set((yyval.sel), sel);
                  END_ACTION;
              }
     break;
@@ -2369,13 +2468,15 @@ yyreduce:
   case 44:
 
 /* Line 1806 of yacc.c  */
-#line 492 "parser.y"
+#line 574 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype((yyval.sel), REAL_VALUE);
-                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
-                 (yyval.sel)->v.u.r[0] = (yyvsp[(1) - (1)].r);
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_CONST));
+                 _gmx_selelem_set_vtype(sel, REAL_VALUE);
+                 _gmx_selvalue_reserve(&sel->v, 1);
+                 sel->v.u.r[0] = (yyvsp[(1) - (1)].r);
+                 set((yyval.sel), sel);
                  END_ACTION;
              }
     break;
@@ -2383,11 +2484,11 @@ yyreduce:
   case 45:
 
 /* Line 1806 of yacc.c  */
-#line 504 "parser.y"
+#line 588 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2395,11 +2496,11 @@ yyreduce:
   case 46:
 
 /* Line 1806 of yacc.c  */
-#line 511 "parser.y"
+#line 595 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(2) - (3)].meth), (yyvsp[(3) - (3)].param), (yyvsp[(1) - (3)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2407,10 +2508,10 @@ yyreduce:
   case 47:
 
 /* Line 1806 of yacc.c  */
-#line 521 "parser.y"
+#line 605 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '+', scanner);
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '+', scanner));
                  END_ACTION;
              }
     break;
@@ -2418,10 +2519,10 @@ yyreduce:
   case 48:
 
 /* Line 1806 of yacc.c  */
-#line 527 "parser.y"
+#line 611 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '-', scanner);
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '-', scanner));
                  END_ACTION;
              }
     break;
@@ -2429,10 +2530,10 @@ yyreduce:
   case 49:
 
 /* Line 1806 of yacc.c  */
-#line 533 "parser.y"
+#line 617 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '*', scanner);
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '*', scanner));
                  END_ACTION;
              }
     break;
@@ -2440,10 +2541,10 @@ yyreduce:
   case 50:
 
 /* Line 1806 of yacc.c  */
-#line 539 "parser.y"
+#line 623 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '/', scanner);
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '/', scanner));
                  END_ACTION;
              }
     break;
@@ -2451,10 +2552,10 @@ yyreduce:
   case 51:
 
 /* Line 1806 of yacc.c  */
-#line 545 "parser.y"
+#line 629 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(2) - (2)].sel), NULL, '-', scanner);
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(2) - (2)].sel)), SelectionTreeElementPointer(), '-', scanner));
                  END_ACTION;
              }
     break;
@@ -2462,10 +2563,10 @@ yyreduce:
   case 52:
 
 /* Line 1806 of yacc.c  */
-#line 551 "parser.y"
+#line 635 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_arithmetic((yyvsp[(1) - (3)].sel), (yyvsp[(3) - (3)].sel), '^', scanner);
+                 set((yyval.sel), _gmx_sel_init_arithmetic(get((yyvsp[(1) - (3)].sel)), get((yyvsp[(3) - (3)].sel)), '^', scanner));
                  END_ACTION;
              }
     break;
@@ -2473,20 +2574,22 @@ yyreduce:
   case 53:
 
 /* Line 1806 of yacc.c  */
-#line 556 "parser.y"
+#line 640 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 54:
 
 /* Line 1806 of yacc.c  */
-#line 564 "parser.y"
+#line 648 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype((yyval.sel), STR_VALUE);
-                 _gmx_selvalue_reserve(&(yyval.sel)->v, 1);
-                 (yyval.sel)->v.u.s[0] = (yyvsp[(1) - (1)].str);
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_CONST));
+                 _gmx_selelem_set_vtype(sel, STR_VALUE);
+                 _gmx_selvalue_reserve(&sel->v, 1);
+                 sel->v.u.s[0] = (yyvsp[(1) - (1)].str);
+                 set((yyval.sel), sel);
                  END_ACTION;
              }
     break;
@@ -2494,11 +2597,11 @@ yyreduce:
   case 55:
 
 /* Line 1806 of yacc.c  */
-#line 573 "parser.y"
+#line 659 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_keyword((yyvsp[(2) - (2)].meth), NULL, (yyvsp[(1) - (2)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2506,10 +2609,10 @@ yyreduce:
   case 56:
 
 /* Line 1806 of yacc.c  */
-#line 587 "parser.y"
+#line 673 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r));
+                 set((yyval.sel), _gmx_sel_init_const_position((yyvsp[(2) - (7)].r), (yyvsp[(4) - (7)].r), (yyvsp[(6) - (7)].r)));
                  END_ACTION;
              }
     break;
@@ -2517,18 +2620,18 @@ yyreduce:
   case 57:
 
 /* Line 1806 of yacc.c  */
-#line 595 "parser.y"
+#line 681 "parser.y"
     { (yyval.sel) = (yyvsp[(2) - (3)].sel); }
     break;
 
   case 58:
 
 /* Line 1806 of yacc.c  */
-#line 600 "parser.y"
+#line 686 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_method((yyvsp[(1) - (2)].meth), (yyvsp[(2) - (2)].param), NULL, scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_method((yyvsp[(1) - (2)].meth), (yyvsp[(2) - (2)].param), NULL, scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2536,11 +2639,11 @@ yyreduce:
   case 59:
 
 /* Line 1806 of yacc.c  */
-#line 610 "parser.y"
+#line 696 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_position((yyvsp[(3) - (3)].sel), (yyvsp[(1) - (3)].str), scanner);
-                 if ((yyval.sel) == NULL) YYERROR;
+                 set((yyval.sel), _gmx_sel_init_position(get((yyvsp[(3) - (3)].sel)), (yyvsp[(1) - (3)].str), scanner));
+                 CHECK_SEL((yyval.sel));
                  END_ACTION;
              }
     break;
@@ -2548,10 +2651,10 @@ yyreduce:
   case 60:
 
 /* Line 1806 of yacc.c  */
-#line 623 "parser.y"
+#line 709 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
                  END_ACTION;
              }
     break;
@@ -2559,10 +2662,10 @@ yyreduce:
   case 61:
 
 /* Line 1806 of yacc.c  */
-#line 631 "parser.y"
+#line 717 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
                  END_ACTION;
              }
     break;
@@ -2570,10 +2673,10 @@ yyreduce:
   case 62:
 
 /* Line 1806 of yacc.c  */
-#line 639 "parser.y"
+#line 725 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.sel) = _gmx_sel_init_variable_ref((yyvsp[(1) - (1)].sel));
+                 set((yyval.sel), _gmx_sel_init_variable_ref(get((yyvsp[(1) - (1)].sel))));
                  END_ACTION;
              }
     break;
@@ -2581,35 +2684,35 @@ yyreduce:
   case 63:
 
 /* Line 1806 of yacc.c  */
-#line 652 "parser.y"
+#line 738 "parser.y"
     { (yyval.param) = process_param_list((yyvsp[(1) - (1)].param)); }
     break;
 
   case 64:
 
 /* Line 1806 of yacc.c  */
-#line 654 "parser.y"
+#line 740 "parser.y"
     { (yyval.param) = process_param_list((yyvsp[(1) - (2)].param)); }
     break;
 
   case 65:
 
 /* Line 1806 of yacc.c  */
-#line 658 "parser.y"
+#line 744 "parser.y"
     { (yyval.param) = NULL;              }
     break;
 
   case 66:
 
 /* Line 1806 of yacc.c  */
-#line 660 "parser.y"
+#line 746 "parser.y"
     { (yyvsp[(2) - (2)].param)->next = (yyvsp[(1) - (2)].param); (yyval.param) = (yyvsp[(2) - (2)].param); }
     break;
 
   case 67:
 
 /* Line 1806 of yacc.c  */
-#line 665 "parser.y"
+#line 751 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.param) = _gmx_selexpr_create_param((yyvsp[(1) - (2)].str));
@@ -2621,87 +2724,87 @@ yyreduce:
   case 68:
 
 /* Line 1806 of yacc.c  */
-#line 673 "parser.y"
+#line 759 "parser.y"
     { (yyval.val) = NULL; }
     break;
 
   case 69:
 
 /* Line 1806 of yacc.c  */
-#line 674 "parser.y"
+#line 760 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val);   }
     break;
 
   case 70:
 
 /* Line 1806 of yacc.c  */
-#line 675 "parser.y"
+#line 761 "parser.y"
     { (yyval.val) = (yyvsp[(2) - (3)].val);   }
     break;
 
   case 71:
 
 /* Line 1806 of yacc.c  */
-#line 679 "parser.y"
+#line 765 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 72:
 
 /* Line 1806 of yacc.c  */
-#line 681 "parser.y"
+#line 767 "parser.y"
     { (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); }
     break;
 
   case 73:
 
 /* Line 1806 of yacc.c  */
-#line 683 "parser.y"
+#line 769 "parser.y"
     { (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); }
     break;
 
   case 74:
 
 /* Line 1806 of yacc.c  */
-#line 687 "parser.y"
+#line 773 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 75:
 
 /* Line 1806 of yacc.c  */
-#line 688 "parser.y"
+#line 774 "parser.y"
     { (yyval.val) = (yyvsp[(2) - (3)].val); }
     break;
 
   case 76:
 
 /* Line 1806 of yacc.c  */
-#line 692 "parser.y"
+#line 778 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 77:
 
 /* Line 1806 of yacc.c  */
-#line 694 "parser.y"
+#line 780 "parser.y"
     { (yyvsp[(2) - (2)].val)->next = (yyvsp[(1) - (2)].val); (yyval.val) = (yyvsp[(2) - (2)].val); }
     break;
 
   case 78:
 
 /* Line 1806 of yacc.c  */
-#line 696 "parser.y"
+#line 782 "parser.y"
     { (yyvsp[(3) - (3)].val)->next = (yyvsp[(1) - (3)].val); (yyval.val) = (yyvsp[(3) - (3)].val); }
     break;
 
   case 79:
 
 /* Line 1806 of yacc.c  */
-#line 700 "parser.y"
+#line 786 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel));
+                 (yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
                  END_ACTION;
              }
     break;
@@ -2709,10 +2812,10 @@ yyreduce:
   case 80:
 
 /* Line 1806 of yacc.c  */
-#line 706 "parser.y"
+#line 792 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel));
+                 (yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
                  END_ACTION;
              }
     break;
@@ -2720,10 +2823,10 @@ yyreduce:
   case 81:
 
 /* Line 1806 of yacc.c  */
-#line 712 "parser.y"
+#line 798 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel));
+                 (yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
                  END_ACTION;
              }
     break;
@@ -2731,10 +2834,10 @@ yyreduce:
   case 82:
 
 /* Line 1806 of yacc.c  */
-#line 718 "parser.y"
+#line 804 "parser.y"
     {
                  BEGIN_ACTION;
-                 (yyval.val) = _gmx_selexpr_create_value_expr((yyvsp[(1) - (1)].sel));
+                 (yyval.val) = _gmx_selexpr_create_value_expr(get((yyvsp[(1) - (1)].sel)));
                  END_ACTION;
              }
     break;
@@ -2742,14 +2845,14 @@ yyreduce:
   case 83:
 
 /* Line 1806 of yacc.c  */
-#line 723 "parser.y"
+#line 809 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 84:
 
 /* Line 1806 of yacc.c  */
-#line 728 "parser.y"
+#line 814 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
@@ -2761,7 +2864,7 @@ yyreduce:
   case 85:
 
 /* Line 1806 of yacc.c  */
-#line 735 "parser.y"
+#line 821 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
@@ -2773,7 +2876,7 @@ yyreduce:
   case 86:
 
 /* Line 1806 of yacc.c  */
-#line 742 "parser.y"
+#line 828 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.val) = _gmx_selexpr_create_value(STR_VALUE);
@@ -2785,14 +2888,14 @@ yyreduce:
   case 87:
 
 /* Line 1806 of yacc.c  */
-#line 748 "parser.y"
+#line 834 "parser.y"
     { (yyval.val) = (yyvsp[(1) - (1)].val); }
     break;
 
   case 88:
 
 /* Line 1806 of yacc.c  */
-#line 753 "parser.y"
+#line 839 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.val) = _gmx_selexpr_create_value(INT_VALUE);
@@ -2804,7 +2907,7 @@ yyreduce:
   case 89:
 
 /* Line 1806 of yacc.c  */
-#line 760 "parser.y"
+#line 846 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
@@ -2816,7 +2919,7 @@ yyreduce:
   case 90:
 
 /* Line 1806 of yacc.c  */
-#line 767 "parser.y"
+#line 853 "parser.y"
     {
                  BEGIN_ACTION;
                  (yyval.val) = _gmx_selexpr_create_value(REAL_VALUE);
@@ -2828,7 +2931,7 @@ yyreduce:
 
 
 /* Line 1806 of yacc.c  */
-#line 2832 "parser.cpp"
+#line 2935 "parser.cpp"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -3062,7 +3165,7 @@ yypushreturn:
 
 
 /* Line 2067 of yacc.c  */
-#line 775 "parser.y"
+#line 861 "parser.y"
 
 
 static t_selexpr_value *
index f42ba490213f7200b9e2c7da4b93f517a051ca4d..4c03669668cd16833479ea21f0369f662600282a 100644 (file)
    This special exception was added by the Free Software Foundation in
    version 2.2 of Bison.  */
 
+/* "%code requires" blocks.  */
+
+/* Line 2068 of yacc.c  */
+#line 166 "parser.y"
+
+#include "selelem.h"
+
+
+
+/* Line 2068 of yacc.c  */
+#line 44 "parser.h"
 
 /* Tokens.  */
 #ifndef YYTOKENTYPE
@@ -80,14 +91,14 @@ typedef union YYSTYPE
 {
 
 /* Line 2068 of yacc.c  */
-#line 104 "parser.y"
+#line 170 "parser.y"
 
     int                         i;
     real                        r;
     char                       *str;
     struct gmx_ana_selmethod_t *meth;
 
-    struct t_selelem           *sel;
+    gmx::SelectionTreeElementPointer *sel;
 
     struct t_selexpr_value     *val;
     struct t_selexpr_param     *param;
@@ -95,7 +106,7 @@ typedef union YYSTYPE
 
 
 /* Line 2068 of yacc.c  */
-#line 99 "parser.h"
+#line 110 "parser.h"
 } YYSTYPE;
 # define YYSTYPE_IS_TRIVIAL 1
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
index aa3ca3b4d07828cc33d733498a655a354a242e51..a2bba48276fa7224869b264a7d9d635a552ff858 100644 (file)
@@ -51,6 +51,7 @@
 
 #include <exception>
 
+#include "gromacs/legacyheaders/smalloc.h"
 #include "gromacs/legacyheaders/string2.h"
 
 #include "parsetree.h"
 
 #include "scanner.h"
 
+using gmx::scoped_ptr_sfree;
+using gmx::SelectionTreeElement;
+using gmx::SelectionTreeElementPointer;
+
 //! Helper method to reorder a list of parameter values and to count the values.
 static t_selexpr_value *
 process_value_list(t_selexpr_value *values, int *nr);
@@ -65,6 +70,63 @@ process_value_list(t_selexpr_value *values, int *nr);
 static t_selexpr_param *
 process_param_list(t_selexpr_param *params);
 
+/*! \brief
+ * Retrieves a selection tree pointer from a semantic value.
+ *
+ * \param[in] src  Semantic value to get the tree from.
+ * \returns   Pointer to the selection tree.
+ *
+ * There should be no statements that may throw exceptions in actions before
+ * this function has been called for all semantic values that have a tree
+ * argument.  Together with set(), this function abstracts away exception
+ * safety issues that arise from the use of a plain pointer for storing the
+ * selection tree semantic values.
+ *
+ * Does not throw.
+ */
+static SelectionTreeElementPointer
+get(SelectionTreeElementPointer *src)
+{
+    SelectionTreeElementPointer result;
+    if (src != NULL)
+    {
+        result.swap(*src);
+        delete src;
+    }
+    return result;
+}
+/*! \brief
+ * Sets a selection tree pointer to a semantic value.
+ *
+ * \param[out] dest  Semantic value to set the tree to.
+ * \param[in]  value Pointer to the selection tree to set.
+ * \throws     std::bad_alloc if out of memory.
+ *
+ * This should be the last statement before ::END_ACTION, except for a
+ * possible ::CHECK_SEL.
+ */
+static void
+set(SelectionTreeElementPointer *&dest,
+        const SelectionTreeElementPointer &value)
+{
+    dest = new SelectionTreeElementPointer(value);
+}
+/*! \brief
+ * Checks that a valid tree was set.
+ *
+ * Should be called after set() if it was used to set a value where NULL
+ * pointer indicates an error.
+ *
+ * \todo
+ * Get rid of this macro.  It should now be possible to handle all errors using
+ * exceptions.
+ */
+#define CHECK_SEL(sel) \
+    if (!*(sel)) { \
+        delete sel; \
+        YYERROR; \
+    }
+
 //! Error handler needed by Bison.
 static void
 yyerror(yyscan_t, char const *s);
@@ -101,13 +163,17 @@ yyerror(yyscan_t, char const *s);
 //!\}
 %}
 
+%code requires{
+#include "selelem.h"
+}
+
 %union{
     int                         i;
     real                        r;
     char                       *str;
     struct gmx_ana_selmethod_t *meth;
 
-    struct t_selelem           *sel;
+    gmx::SelectionTreeElementPointer *sel;
 
     struct t_selexpr_value     *val;
     struct t_selexpr_param     *param;
@@ -198,9 +264,8 @@ yyerror(yyscan_t, char const *s);
 
 %destructor { free($$);                     } HELP_TOPIC STR IDENTIFIER CMP_OP string
 %destructor { if($$) free($$);              } PARAM
-%destructor { if($$) _gmx_selelem_free($$); } command cmd_plain
-%destructor { _gmx_selelem_free_chain($$);  } selection
-%destructor { _gmx_selelem_free($$);        } sel_expr num_expr str_expr pos_expr
+%destructor { delete $$;                    } commands command cmd_plain selection
+%destructor { delete $$;                    } sel_expr num_expr str_expr pos_expr
 %destructor { _gmx_selexpr_free_params($$); } method_params method_param_list method_param
 %destructor { _gmx_selexpr_free_values($$); } value_list value_list_contents value_item value_item_range
 %destructor { _gmx_selexpr_free_values($$); } basic_value_list basic_value_list_contents basic_value_item
@@ -221,7 +286,7 @@ commands:    /* empty */        { $$ = NULL; }
            | commands command
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_append_selection($2, $1, scanner);
+                 set($$, _gmx_sel_append_selection(get($2), get($1), scanner));
                  if (_gmx_sel_parser_should_finish(scanner))
                      YYACCEPT;
                  END_ACTION;
@@ -262,54 +327,60 @@ cmd_plain:   /* empty */
            | TOK_INT
              {
                  BEGIN_ACTION;
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_id($1, scanner);
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 $$ = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+                 SelectionTreeElementPointer s
+                        = _gmx_sel_init_group_by_id($1, scanner);
+                 if (!s) YYERROR;
+                 SelectionTreeElementPointer p
+                        = _gmx_sel_init_position(s, NULL, scanner);
+                 if (!p) YYERROR;
+                 set($$, _gmx_sel_init_selection(s->name, p, scanner));
                  END_ACTION;
              }
            | string
              {
                  BEGIN_ACTION;
-                 t_selelem *s, *p;
-                 s = _gmx_sel_init_group_by_name($1, scanner);
-                 free($1);
-                 if (s == NULL) YYERROR;
-                 p = _gmx_sel_init_position(s, NULL, scanner);
-                 if (p == NULL) YYERROR;
-                 $$ = _gmx_sel_init_selection(strdup(s->name), p, scanner);
+                 scoped_ptr_sfree nameGuard($1);
+                 SelectionTreeElementPointer s
+                        = _gmx_sel_init_group_by_name($1, scanner);
+                 if (!s) YYERROR;
+                 SelectionTreeElementPointer p
+                        = _gmx_sel_init_position(s, NULL, scanner);
+                 if (!p) YYERROR;
+                 set($$, _gmx_sel_init_selection(s->name, p, scanner));
                  END_ACTION;
              }
            | selection
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_selection(NULL, $1, scanner);
+                 set($$, _gmx_sel_init_selection(NULL, get($1), scanner));
                  END_ACTION;
              }
            | string selection
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_selection($1, $2, scanner);
+                 scoped_ptr_sfree nameGuard($1);
+                 set($$, _gmx_sel_init_selection($1, get($2), scanner));
                  END_ACTION;
              }
            | IDENTIFIER '=' sel_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_assign_variable($1, $3, scanner);
+                 scoped_ptr_sfree nameGuard($1);
+                 set($$, _gmx_sel_assign_variable($1, get($3), scanner));
                  END_ACTION;
              }
            | IDENTIFIER '=' num_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_assign_variable($1, $3, scanner);
+                 scoped_ptr_sfree nameGuard($1);
+                 set($$, _gmx_sel_assign_variable($1, get($3), scanner));
                  END_ACTION;
              }
            | IDENTIFIER '=' pos_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_assign_variable($1, $3, scanner);
+                 scoped_ptr_sfree nameGuard($1);
+                 set($$, _gmx_sel_assign_variable($1, get($3), scanner));
                  END_ACTION;
              }
 ;
@@ -339,16 +410,16 @@ selection:   pos_expr           { $$ = $1; }
            | sel_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_position($1, NULL, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_position(get($1), NULL, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
            | '(' selection ')'  { $$ = $2; }
            | selection MODIFIER method_params
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_modifier($2, $3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_modifier($2, $3, get($1), scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -383,25 +454,34 @@ string:      STR                { $$ = $1; }
 sel_expr:    NOT sel_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
-                 $$->u.boolt = BOOL_NOT;
-                 $$->child = $2;
+                 SelectionTreeElementPointer arg(get($2));
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_BOOLEAN));
+                 sel->u.boolt = BOOL_NOT;
+                 sel->child = arg;
+                 set($$, sel);
                  END_ACTION;
              }
            | sel_expr AND sel_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
-                 $$->u.boolt = BOOL_AND;
-                 $$->child = $1; $$->child->next = $3;
+                 SelectionTreeElementPointer arg1(get($1)), arg2(get($3));
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_BOOLEAN));
+                 sel->u.boolt = BOOL_AND;
+                 sel->child = arg1; sel->child->next = arg2;
+                 set($$, sel);
                  END_ACTION;
              }
            | sel_expr OR  sel_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selelem_create(SEL_BOOLEAN);
-                 $$->u.boolt = BOOL_OR;
-                 $$->child = $1; $$->child->next = $3;
+                 SelectionTreeElementPointer arg1(get($1)), arg2(get($3));
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_BOOLEAN));
+                 sel->u.boolt = BOOL_OR;
+                 sel->child = arg1; sel->child->next = arg2;
+                 set($$, sel);
                  END_ACTION;
              }
            | '(' sel_expr ')'   { $$ = $2; }
@@ -411,8 +491,8 @@ sel_expr:    NOT sel_expr
 sel_expr:    num_expr CMP_OP num_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_comparison($1, $3, $2, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_comparison(get($1), get($3), $2, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -421,16 +501,16 @@ sel_expr:    num_expr CMP_OP num_expr
 sel_expr:    GROUP string
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_group_by_name($2, scanner);
-                 free($2);
-                 if ($$ == NULL) YYERROR;
+                 scoped_ptr_sfree nameGuard($2);
+                 set($$, _gmx_sel_init_group_by_name($2, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
            | GROUP TOK_INT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_group_by_id($2, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_group_by_id($2, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -444,22 +524,22 @@ pos_mod:     EMPTY_POSMOD       { $$ = NULL; }
 sel_expr:    pos_mod KEYWORD_GROUP
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_keyword($2, NULL, $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
            | pos_mod KEYWORD_STR basic_value_list
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
            | pos_mod KEYWORD_NUMERIC basic_value_list
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_keyword($2, process_value_list($3, NULL), $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -468,8 +548,8 @@ sel_expr:    pos_mod KEYWORD_GROUP
 sel_expr:    pos_mod METHOD_GROUP method_params
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_method($2, $3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_method($2, $3, $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -482,19 +562,23 @@ sel_expr:    pos_mod METHOD_GROUP method_params
 num_expr:    TOK_INT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype($$, INT_VALUE);
-                 _gmx_selvalue_reserve(&$$->v, 1);
-                 $$->v.u.i[0] = $1;
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_CONST));
+                 _gmx_selelem_set_vtype(sel, INT_VALUE);
+                 _gmx_selvalue_reserve(&sel->v, 1);
+                 sel->v.u.i[0] = $1;
+                 set($$, sel);
                  END_ACTION;
              }
            | TOK_REAL
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype($$, REAL_VALUE);
-                 _gmx_selvalue_reserve(&$$->v, 1);
-                 $$->v.u.r[0] = $1;
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_CONST));
+                 _gmx_selelem_set_vtype(sel, REAL_VALUE);
+                 _gmx_selvalue_reserve(&sel->v, 1);
+                 sel->v.u.r[0] = $1;
+                 set($$, sel);
                  END_ACTION;
              }
 ;
@@ -503,15 +587,15 @@ num_expr:    TOK_INT
 num_expr:    pos_mod KEYWORD_NUMERIC    %prec NUM_REDUCT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_keyword($2, NULL, $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
            | pos_mod METHOD_NUMERIC method_params
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_method($2, $3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_method($2, $3, $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -520,37 +604,37 @@ num_expr:    pos_mod KEYWORD_NUMERIC    %prec NUM_REDUCT
 num_expr:    num_expr '+' num_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_arithmetic($1, $3, '+', scanner);
+                 set($$, _gmx_sel_init_arithmetic(get($1), get($3), '+', scanner));
                  END_ACTION;
              }
            | num_expr '-' num_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_arithmetic($1, $3, '-', scanner);
+                 set($$, _gmx_sel_init_arithmetic(get($1), get($3), '-', scanner));
                  END_ACTION;
              }
            | num_expr '*' num_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_arithmetic($1, $3, '*', scanner);
+                 set($$, _gmx_sel_init_arithmetic(get($1), get($3), '*', scanner));
                  END_ACTION;
              }
            | num_expr '/' num_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_arithmetic($1, $3, '/', scanner);
+                 set($$, _gmx_sel_init_arithmetic(get($1), get($3), '/', scanner));
                  END_ACTION;
              }
            | '-' num_expr %prec UNARY_NEG
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_arithmetic($2, NULL, '-', scanner);
+                 set($$, _gmx_sel_init_arithmetic(get($2), SelectionTreeElementPointer(), '-', scanner));
                  END_ACTION;
              }
            | num_expr '^' num_expr
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_arithmetic($1, $3, '^', scanner);
+                 set($$, _gmx_sel_init_arithmetic(get($1), get($3), '^', scanner));
                  END_ACTION;
              }
            | '(' num_expr ')'   { $$ = $2; }
@@ -563,17 +647,19 @@ num_expr:    num_expr '+' num_expr
 str_expr:    string
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selelem_create(SEL_CONST);
-                 _gmx_selelem_set_vtype($$, STR_VALUE);
-                 _gmx_selvalue_reserve(&$$->v, 1);
-                 $$->v.u.s[0] = $1;
+                 SelectionTreeElementPointer sel(
+                        new SelectionTreeElement(SEL_CONST));
+                 _gmx_selelem_set_vtype(sel, STR_VALUE);
+                 _gmx_selvalue_reserve(&sel->v, 1);
+                 sel->v.u.s[0] = $1;
+                 set($$, sel);
                  END_ACTION;
              }
            | pos_mod KEYWORD_STR
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_keyword($2, NULL, $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_keyword($2, NULL, $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -586,7 +672,7 @@ str_expr:    string
 pos_expr:    '[' number ',' number ',' number ']'
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_const_position($2, $4, $6);
+                 set($$, _gmx_sel_init_const_position($2, $4, $6));
                  END_ACTION;
              }
 ;
@@ -599,8 +685,8 @@ pos_expr:    '(' pos_expr ')'   { $$ = $2; }
 pos_expr:    METHOD_POS method_params
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_method($1, $2, NULL, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_method($1, $2, NULL, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -609,8 +695,8 @@ pos_expr:    METHOD_POS method_params
 pos_expr:    KEYWORD_POS OF sel_expr    %prec PARAM_REDUCT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_position($3, $1, scanner);
-                 if ($$ == NULL) YYERROR;
+                 set($$, _gmx_sel_init_position(get($3), $1, scanner));
+                 CHECK_SEL($$);
                  END_ACTION;
              }
 ;
@@ -622,7 +708,7 @@ pos_expr:    KEYWORD_POS OF sel_expr    %prec PARAM_REDUCT
 sel_expr:    VARIABLE_GROUP
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_variable_ref($1);
+                 set($$, _gmx_sel_init_variable_ref(get($1)));
                  END_ACTION;
              }
 ;
@@ -630,7 +716,7 @@ sel_expr:    VARIABLE_GROUP
 num_expr:    VARIABLE_NUMERIC
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_variable_ref($1);
+                 set($$, _gmx_sel_init_variable_ref(get($1)));
                  END_ACTION;
              }
 ;
@@ -638,7 +724,7 @@ num_expr:    VARIABLE_NUMERIC
 pos_expr:    VARIABLE_POS
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_sel_init_variable_ref($1);
+                 set($$, _gmx_sel_init_variable_ref(get($1)));
                  END_ACTION;
              }
 ;
@@ -699,25 +785,25 @@ basic_value_list_contents:
 value_item:  sel_expr            %prec PARAM_REDUCT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selexpr_create_value_expr($1);
+                 $$ = _gmx_selexpr_create_value_expr(get($1));
                  END_ACTION;
              }
            | pos_expr            %prec PARAM_REDUCT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selexpr_create_value_expr($1);
+                 $$ = _gmx_selexpr_create_value_expr(get($1));
                  END_ACTION;
              }
            | num_expr            %prec PARAM_REDUCT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selexpr_create_value_expr($1);
+                 $$ = _gmx_selexpr_create_value_expr(get($1));
                  END_ACTION;
              }
            | str_expr            %prec PARAM_REDUCT
              {
                  BEGIN_ACTION;
-                 $$ = _gmx_selexpr_create_value_expr($1);
+                 $$ = _gmx_selexpr_create_value_expr(get($1));
                  END_ACTION;
              }
            | value_item_range    { $$ = $1; }
index 98b2d35b6e0de7d684f425bb2484d58a7bfa4592..09e09710a7a46c1bb62b82e81c01811d5c9a5345 100644 (file)
  * and bookkeeping are done by functions in scanner_internal.cpp) and uses the
  * grammar rules to decide what to do with them. Whenever a grammar rule
  * matches, a corresponding function in parsetree.cpp is called to construct
- * either a temporary representation for the object or a ::t_selelem object
+ * either a temporary representation for the object or a
+ * gmx::SelectionTreeElement object
  * (some simple rules are handled internally in parser.y).
  * When a complete selection has been parsed, the functions in parsetree.cpp
  * also take care of updating the ::gmx_ana_selcollection_t structure
  * appropriately.
  *
- * The rest of this page describes the resulting ::t_selelem object tree.
+ * The rest of this page describes the resulting gmx::SelectionTreeElement
+ * object tree.
  * Before the selections can be evaluated, this tree needs to be passed to
  * the selection compiler, which is described on a separate page:
  * \ref page_module_selection_compiler
  * \section selparser_tree Element tree constructed by the parser
  *
  * The parser initializes the following fields in all selection elements:
- * \c t_selelem::name, \c t_selelem::type, \c t_selelem::v\c .type,
- * \c t_selelem::flags, \c t_selelem::child, \c t_selelem::next, and
- * \c t_selelem::refcount.
+ * gmx::SelectionTreeElement::name, gmx::SelectionTreeElement::type,
+ * gmx::SelectionTreeElement::v\c .type,
+ * gmx::SelectionTreeElement::flags, gmx::SelectionTreeElement::child, and
+ * gmx::SelectionTreeElement::next.
  * Some other fields are also initialized for particular element types as
  * discussed below.
  * Fields that are not initialized are set to zero, NULL, or other similar
  *    The rest of the children are \ref SEL_MODIFIER elements with
  *    \ref NO_VALUE, in the order given by the user.
  *  .
- * The name of the selection/variable is stored in \c t_selelem::cgrp\c .name.
+ * The name of the selection/variable is stored in
+ * gmx::SelectionTreeElement::cgrp\c .name.
  * It is set to either the name provided by the user or the selection string
  * for selections not explicitly named by the user.
  * \ref SEL_ROOT or \ref SEL_SUBEXPR elements do not appear anywhere else.
  *  - \ref GROUP_VALUE method parameters if provided using external index
  *    groups,
  *  .
- * For group-valued elements, the value is stored in \c t_selelem::cgrp;
- * other types of values are stored in \c t_selelem::v.
+ * For group-valued elements, the value is stored in
+ * gmx::SelectionTreeElement::cgrp; other types of values are stored in
+ * gmx::SelectionTreeElement::v.
  * Constants that appear as parameters for selection methods are not present
  * in the selection tree unless they have \ref GROUP_VALUE.
  * \ref SEL_CONST elements have no children.
  *
  * \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements are treated very
  * similarly. The \c gmx_ana_selmethod_t structure corresponding to the
- * evaluation method is in \c t_selelem::method, and the method data in
- * \c t_selelem::mdata has been allocated using sel_datafunc().
- * If a non-standard reference position type was set, \c t_selelem::pc has
- * also been created, but only the type has been set.
+ * evaluation method is in gmx::SelectionTreeElement::method, and the method
+ * data in gmx::SelectionTreeElement::mdata has been allocated using
+ * sel_datafunc().
+ * If a non-standard reference position type was set,
+ * gmx::SelectionTreeElement::pc has also been created, but only the type has
+ * been set.
  * All children of these elements are of the type \ref SEL_SUBEXPRREF, and
  * each describes a selection that needs to be evaluated to obtain a value
  * for one parameter of the method.
  * \subsection selparser_tree_subexpr Subexpression elements
  *
  * \ref SEL_SUBEXPR elements only appear for variables, as described above.
- * \c t_selelem::name points to the name of the variable (from the
+ * gmx::SelectionTreeElement::name points to the name of the variable (from the
  * \ref SEL_ROOT element).
  * The element always has exactly one child, which represents the value of
  * the variable.
- * \ref SEL_SUBEXPR element is the only element type that can have
- * \c t_selelem::refcount different from 1.
  *
  * \ref SEL_SUBEXPRREF elements are used for two purposes:
  *  - Variable references that need to be evaluated (i.e., there is a
  *    \ref SEL_SUBEXPR element for the variable) are represented using
  *    \ref SEL_SUBEXPRREF elements.
- *    In this case, \c t_selelem::param is NULL, and the first and only
- *    child of the element is the \ref SEL_SUBEXPR element of the variable.
+ *    In this case, gmx::SelectionTreeElement::param is NULL, and the first and
+ *    only child of the element is the \ref SEL_SUBEXPR element of the
+ *    variable.
  *    Such references can appear anywhere where the variable value
  *    (the child of the \ref SEL_SUBEXPR element) would be valid.
  *  - Children of \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements are
- *    always of this type. For these elements, \c t_selelem::param is
- *    initialized to point to the parameter that receives the value from
+ *    always of this type. For these elements, gmx::SelectionTreeElement::param
+ *    is initialized to point to the parameter that receives the value from
  *    the expression.
  *    Each such element has exactly one child, which can be of any type;
  *    the \ref SEL_SUBEXPR element of a variable is used if the value comes
  *
  * One \ref SEL_BOOLEAN element is created for each boolean keyword in the
  * input, and the tree structure represents the evaluation order.
- * The \c t_selelem::boolt type gives the type of the operation.
+ * The gmx::SelectionTreeElement::boolt type gives the type of the operation.
  * Each element has exactly two children (one for \ref BOOL_NOT elements),
  * which are in the order given in the input.
  * The children always have \ref GROUP_VALUE, but different element types
  *
  * One \ref SEL_ARITHMETIC element is created for each arithmetic operation in
  * the input, and the tree structure represents the evaluation order.
- * The \c t_selelem::optype type gives the name of the operation.
+ * The gmx::SelectionTreeElement::optype type gives the name of the operation.
  * Each element has exactly two children (one for unary negation elements),
  * which are in the order given in the input.
  */
 #include <boost/exception_ptr.hpp>
 #include <boost/shared_ptr.hpp>
 
-#include "futil.h"
-#include "smalloc.h"
-#include "string2.h"
+#include "gromacs/legacyheaders/futil.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/string2.h"
 
 #include "gromacs/onlinehelp/helpmanager.h"
 #include "gromacs/onlinehelp/helpwritercontext.h"
 
 #include "scanner.h"
 
+using gmx::SelectionTreeElement;
+using gmx::SelectionTreeElementPointer;
+
 void
 _gmx_selparser_error(yyscan_t scanner, const char *fmt, ...)
 {
@@ -269,10 +278,9 @@ _gmx_selparser_handle_exception(yyscan_t scanner, const std::exception &/*ex*/)
 t_selexpr_value *
 _gmx_selexpr_create_value(e_selvalue_t type)
 {
-    t_selexpr_value *value;
-    snew(value, 1);
+    t_selexpr_value *value = new t_selexpr_value();
     value->type  = type;
-    value->bExpr = false;
+    memset(&value->u, 0, sizeof(value->u));
     value->next  = NULL;
     return value;
 }
@@ -282,13 +290,12 @@ _gmx_selexpr_create_value(e_selvalue_t type)
  * \returns   Pointer to the newly allocated value.
  */
 t_selexpr_value *
-_gmx_selexpr_create_value_expr(t_selelem *expr)
+_gmx_selexpr_create_value_expr(const SelectionTreeElementPointer &expr)
 {
-    t_selexpr_value *value;
-    snew(value, 1);
+    t_selexpr_value *value = new t_selexpr_value();
     value->type   = expr->v.type;
-    value->bExpr  = true;
-    value->u.expr = expr;
+    value->expr   = expr;
+    memset(&value->u, 0, sizeof(value->u));
     value->next   = NULL;
     return value;
 }
@@ -318,24 +325,16 @@ _gmx_selexpr_create_param(char *name)
 void
 _gmx_selexpr_free_values(t_selexpr_value *value)
 {
-    t_selexpr_value *old;
 
     while (value)
     {
-        if (value->bExpr)
-        {
-            if (value->u.expr)
-            {
-                _gmx_selelem_free(value->u.expr);
-            }
-        }
-        else if (value->type == STR_VALUE)
+        if (!value->expr && value->type == STR_VALUE)
         {
             sfree(value->u.s);
         }
-        old = value;
+        t_selexpr_value *old = value;
         value = value->next;
-        sfree(old);
+        delete old;
     }
 }
 
@@ -378,18 +377,17 @@ _gmx_selexpr_free_params(t_selexpr_param *param)
  * is set for an element, the function returns immediately, and the recursive
  * operation does not descend beyond such elements.
  */
-int
-_gmx_selelem_update_flags(t_selelem *sel, yyscan_t scanner)
+void
+_gmx_selelem_update_flags(const SelectionTreeElementPointer &sel,
+                          yyscan_t scanner)
 {
-    t_selelem          *child;
-    int                 rc;
     bool                bUseChildType=false;
     bool                bOnlySingleChildren;
 
     /* Return if the flags have already been set */
     if (sel->flags & SEL_FLAGSSET)
     {
-        return 0;
+        return;
     }
     /* Set the flags based on the current element type */
     switch (sel->type)
@@ -445,15 +443,11 @@ _gmx_selelem_update_flags(t_selelem *sel, yyscan_t scanner)
     }
     /* Loop through children to propagate their flags upwards */
     bOnlySingleChildren = true;
-    child = sel->child;
+    SelectionTreeElementPointer child = sel->child;
     while (child)
     {
         /* Update the child */
-        rc = _gmx_selelem_update_flags(child, scanner);
-        if (rc != 0)
-        {
-            return rc;
-        }
+        _gmx_selelem_update_flags(child, scanner);
         /* Propagate the dynamic flag */
         sel->flags |= (child->flags & SEL_DYNAMIC);
         /* Propagate the type flag if necessary and check for problems */
@@ -463,7 +457,8 @@ _gmx_selelem_update_flags(t_selelem *sel, yyscan_t scanner)
                 && !(sel->flags & child->flags & SEL_VALTYPEMASK))
             {
                 _gmx_selparser_error(scanner, "invalid combination of selection expressions");
-                return gmx::eeInvalidInput;
+                // FIXME: Use an exception.
+                return;
             }
             sel->flags |= (child->flags & SEL_VALTYPEMASK);
         }
@@ -489,7 +484,6 @@ _gmx_selelem_update_flags(t_selelem *sel, yyscan_t scanner)
     }
     /* Mark that the flags are set */
     sel->flags |= SEL_FLAGSSET;
-    return 0;
 }
 
 /*!
@@ -501,7 +495,8 @@ _gmx_selelem_update_flags(t_selelem *sel, yyscan_t scanner)
  * Calls sel_datafunc() if one is specified for the method.
  */
 void
-_gmx_selelem_init_method_params(t_selelem *sel, yyscan_t scanner)
+_gmx_selelem_init_method_params(const SelectionTreeElementPointer &sel,
+                                yyscan_t scanner)
 {
     int                 nparams;
     gmx_ana_selparam_t *orgparam;
@@ -566,7 +561,8 @@ _gmx_selelem_init_method_params(t_selelem *sel, yyscan_t scanner)
  * and calls _gmx_selelem_init_method_params();
  */
 void
-_gmx_selelem_set_method(t_selelem *sel, gmx_ana_selmethod_t *method,
+_gmx_selelem_set_method(const SelectionTreeElementPointer &sel,
+                        gmx_ana_selmethod_t *method,
                         yyscan_t scanner)
 {
     _gmx_selelem_set_vtype(sel, method->type);
@@ -587,7 +583,8 @@ _gmx_selelem_set_method(t_selelem *sel, gmx_ana_selmethod_t *method,
  * \returns       0 on success, a non-zero error code on error.
  */
 static void
-set_refpos_type(gmx::PositionCalculationCollection *pcc, t_selelem *sel,
+set_refpos_type(gmx::PositionCalculationCollection *pcc,
+                const SelectionTreeElementPointer &sel,
                 const char *rpost, yyscan_t scanner)
 {
     if (!rpost)
@@ -616,19 +613,15 @@ set_refpos_type(gmx::PositionCalculationCollection *pcc, t_selelem *sel,
  * \param[in]  scanner Scanner data structure.
  * \returns    The created selection element.
  *
- * This function handles the creation of a \c t_selelem object for
+ * This function handles the creation of a gmx::SelectionTreeElement object for
  * arithmetic expressions.
  */
-t_selelem *
-_gmx_sel_init_arithmetic(t_selelem *left, t_selelem *right, char op,
-                         yyscan_t scanner)
+SelectionTreeElementPointer
+_gmx_sel_init_arithmetic(const SelectionTreeElementPointer &left,
+                         const SelectionTreeElementPointer &right,
+                         char op, yyscan_t scanner)
 {
-    t_selelem         *sel;
-    char               buf[2];
-
-    buf[0] = op;
-    buf[1] = 0;
-    sel = _gmx_selelem_create(SEL_ARITHMETIC);
+    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_ARITHMETIC));
     sel->v.type        = REAL_VALUE;
     switch(op)
     {
@@ -638,6 +631,9 @@ _gmx_sel_init_arithmetic(t_selelem *left, t_selelem *right, char op,
         case '/': sel->u.arith.type = ARITH_DIV;  break;
         case '^': sel->u.arith.type = ARITH_EXP;  break;
     }
+    char               buf[2];
+    buf[0] = op;
+    buf[1] = 0;
     sel->u.arith.opstr = strdup(buf);
     sel->name          = sel->u.arith.opstr;
     sel->child         = left;
@@ -652,21 +648,21 @@ _gmx_sel_init_arithmetic(t_selelem *left, t_selelem *right, char op,
  * \param[in]  scanner Scanner data structure.
  * \returns    The created selection element.
  *
- * This function handles the creation of a \c t_selelem object for
+ * This function handles the creation of a gmx::SelectionTreeElement object for
  * comparison expressions.
  */
-t_selelem *
-_gmx_sel_init_comparison(t_selelem *left, t_selelem *right, char *cmpop,
-                         yyscan_t scanner)
+SelectionTreeElementPointer
+_gmx_sel_init_comparison(const SelectionTreeElementPointer &left,
+                         const SelectionTreeElementPointer &right,
+                         char *cmpop, yyscan_t scanner)
 {
-    t_selelem         *sel;
     t_selexpr_param   *params, *param;
     const char        *name;
 
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
     gmx::MessageStringContext  context(errors, "In comparison initialization");
 
-    sel = _gmx_selelem_create(SEL_EXPRESSION);
+    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(sel, &sm_compare, scanner);
     /* Create the parameter for the left expression */
     name               = left->v.type == INT_VALUE ? "int1" : "real1";
@@ -688,8 +684,7 @@ _gmx_sel_init_comparison(t_selelem *left, t_selelem *right, char *cmpop,
     if (!_gmx_sel_parse_params(params, sel->u.expr.method->nparams,
                                sel->u.expr.method->param, sel, scanner))
     {
-        _gmx_selelem_free(sel);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
 
     return sel;
@@ -702,15 +697,14 @@ _gmx_sel_init_comparison(t_selelem *left, t_selelem *right, char *cmpop,
  * \param[in]  scanner Scanner data structure.
  * \returns    The created selection element.
  *
- * This function handles the creation of a \c t_selelem object for
+ * This function handles the creation of a gmx::SelectionTreeElement object for
  * selection methods that do not take parameters.
  */
-t_selelem *
+SelectionTreeElementPointer
 _gmx_sel_init_keyword(gmx_ana_selmethod_t *method, t_selexpr_value *args,
                       const char *rpost, yyscan_t scanner)
 {
     gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    t_selelem         *root, *child;
     t_selexpr_param   *params, *param;
     t_selexpr_value   *arg;
     int                nargs;
@@ -722,13 +716,13 @@ _gmx_sel_init_keyword(gmx_ana_selmethod_t *method, t_selexpr_value *args,
 
     if (method->nparams > 0)
     {
-        GMX_ERROR_NORET(gmx::eeInternalError,
-                        "Keyword initialization called with non-keyword method");
-        return NULL;
+        // TODO: Would assert be better?
+        GMX_THROW(gmx::InternalError(
+                "Keyword initialization called with non-keyword method"));
     }
 
-    root = _gmx_selelem_create(SEL_EXPRESSION);
-    child = root;
+    SelectionTreeElementPointer root(new SelectionTreeElement(SEL_EXPRESSION));
+    SelectionTreeElementPointer child = root;
     _gmx_selelem_set_method(child, method, scanner);
 
     /* Initialize the evaluation of keyword matching if values are provided */
@@ -741,10 +735,9 @@ _gmx_sel_init_keyword(gmx_ana_selmethod_t *method, t_selexpr_value *args,
             case REAL_VALUE: kwmethod = &sm_keyword_real; break;
             case STR_VALUE:  kwmethod = &sm_keyword_str;  break;
             default:
-                GMX_ERROR_NORET(gmx::eeInternalError,
-                                "Unknown type for keyword selection");
                 _gmx_selexpr_free_values(args);
-                goto on_error;
+                GMX_THROW(gmx::InternalError(
+                        "Unknown type for keyword selection"));
         }
         /* Count the arguments */
         nargs = 0;
@@ -755,7 +748,7 @@ _gmx_sel_init_keyword(gmx_ana_selmethod_t *method, t_selexpr_value *args,
             arg = arg->next;
         }
         /* Initialize the selection element */
-        root = _gmx_selelem_create(SEL_EXPRESSION);
+        root.reset(new SelectionTreeElement(SEL_EXPRESSION));
         _gmx_selelem_set_method(root, kwmethod, scanner);
         params = param = _gmx_selexpr_create_param(NULL);
         param->nval    = 1;
@@ -767,25 +760,12 @@ _gmx_sel_init_keyword(gmx_ana_selmethod_t *method, t_selexpr_value *args,
         if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
                                    root->u.expr.method->param, root, scanner))
         {
-            goto on_error;
+            return SelectionTreeElementPointer();
         }
     }
-    try
-    {
-        set_refpos_type(&sc->pcc, child, rpost, scanner);
-    }
-    catch (const std::exception &)
-    {
-        _gmx_selelem_free(root);
-        throw;
-    }
+    set_refpos_type(&sc->pcc, child, rpost, scanner);
 
     return root;
-
-/* On error, free all memory and return NULL. */
-on_error:
-    _gmx_selelem_free(root);
-    return NULL;
 }
 
 /*!
@@ -795,7 +775,7 @@ on_error:
  * \param[in]  scanner Scanner data structure.
  * \returns    The created selection element.
  *
- * This function handles the creation of a \c t_selelem object for
+ * This function handles the creation of a gmx::SelectionTreeElement object for
  * selection methods that take parameters.
  *
  * Part of the behavior of the \c same selection keyword is hardcoded into
@@ -803,12 +783,11 @@ on_error:
  * use of any keyword in \c "same KEYWORD as" without requiring special
  * handling somewhere else (or sacrificing the simple syntax).
  */
-t_selelem *
+SelectionTreeElementPointer
 _gmx_sel_init_method(gmx_ana_selmethod_t *method, t_selexpr_param *params,
                      const char *rpost, yyscan_t scanner)
 {
     gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
-    t_selelem       *root;
     int              rc;
 
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
@@ -822,26 +801,17 @@ _gmx_sel_init_method(gmx_ana_selmethod_t *method, t_selexpr_param *params,
     if (rc != 0)
     {
         _gmx_selexpr_free_params(params);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
-    root = _gmx_selelem_create(SEL_EXPRESSION);
+    SelectionTreeElementPointer root(new SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(root, method, scanner);
     /* Process the parameters */
     if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
                                root->u.expr.method->param, root, scanner))
     {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
-    try
-    {
-        set_refpos_type(&sc->pcc, root, rpost, scanner);
-    }
-    catch (const std::exception &)
-    {
-        _gmx_selelem_free(root);
-        throw;
+        return SelectionTreeElementPointer();
     }
+    set_refpos_type(&sc->pcc, root, rpost, scanner);
 
     return root;
 }
@@ -853,30 +823,25 @@ _gmx_sel_init_method(gmx_ana_selmethod_t *method, t_selexpr_param *params,
  * \param[in]  scanner Scanner data structure.
  * \returns    The created selection element.
  *
- * This function handles the creation of a \c t_selelem object for
+ * This function handles the creation of a gmx::SelectionTreeElement object for
  * selection modifiers.
  */
-t_selelem *
+SelectionTreeElementPointer
 _gmx_sel_init_modifier(gmx_ana_selmethod_t *method, t_selexpr_param *params,
-                       t_selelem *sel, yyscan_t scanner)
+                       const SelectionTreeElementPointer &sel, yyscan_t scanner)
 {
-    t_selelem         *root;
-    t_selelem         *mod;
-    t_selexpr_param   *vparam;
-
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
     char  buf[128];
     sprintf(buf, "In keyword '%s'", method->name);
     gmx::MessageStringContext  context(errors, buf);
 
     _gmx_sel_finish_method(scanner);
-    mod = _gmx_selelem_create(SEL_MODIFIER);
+    SelectionTreeElementPointer mod(new SelectionTreeElement(SEL_MODIFIER));
     _gmx_selelem_set_method(mod, method, scanner);
+    SelectionTreeElementPointer root;
     if (method->type == NO_VALUE)
     {
-        t_selelem *child;
-
-        child = sel;
+        SelectionTreeElementPointer child = sel;
         while (child->next)
         {
             child = child->next;
@@ -886,6 +851,8 @@ _gmx_sel_init_modifier(gmx_ana_selmethod_t *method, t_selexpr_param *params,
     }
     else
     {
+        t_selexpr_param *vparam;
+
         vparam        = _gmx_selexpr_create_param(NULL);
         vparam->nval  = 1;
         vparam->value = _gmx_selexpr_create_value_expr(sel);
@@ -897,8 +864,7 @@ _gmx_sel_init_modifier(gmx_ana_selmethod_t *method, t_selexpr_param *params,
     if (!_gmx_sel_parse_params(params, mod->u.expr.method->nparams,
                                mod->u.expr.method->param, mod, scanner))
     {
-        _gmx_selelem_free(mod);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
 
     return root;
@@ -910,13 +876,13 @@ _gmx_sel_init_modifier(gmx_ana_selmethod_t *method, t_selexpr_param *params,
  * \param[in]  scanner Scanner data structure.
  * \returns    The created selection element.
  *
- * This function handles the creation of a \c t_selelem object for
+ * This function handles the creation of a gmx::SelectionTreeElement object for
  * evaluation of reference positions.
  */
-t_selelem *
-_gmx_sel_init_position(t_selelem *expr, const char *type, yyscan_t scanner)
+SelectionTreeElementPointer
+_gmx_sel_init_position(const SelectionTreeElementPointer &expr,
+                       const char *type, yyscan_t scanner)
 {
-    t_selelem       *root;
     t_selexpr_param *params;
 
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
@@ -924,9 +890,9 @@ _gmx_sel_init_position(t_selelem *expr, const char *type, yyscan_t scanner)
     sprintf(buf, "In position evaluation");
     gmx::MessageStringContext  context(errors, buf);
 
-    root = _gmx_selelem_create(SEL_EXPRESSION);
+    SelectionTreeElementPointer root(new SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(root, &sm_keyword_pos, scanner);
-    _gmx_selelem_set_kwpos_type(root, type);
+    _gmx_selelem_set_kwpos_type(root.get(), type);
     /* Create the parameters for the parameter parser. */
     params        = _gmx_selexpr_create_param(NULL);
     params->nval  = 1;
@@ -935,8 +901,7 @@ _gmx_sel_init_position(t_selelem *expr, const char *type, yyscan_t scanner)
     if (!_gmx_sel_parse_params(params, root->u.expr.method->nparams,
                                root->u.expr.method->param, root, scanner))
     {
-        _gmx_selelem_free(root);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
 
     return root;
@@ -946,13 +911,12 @@ _gmx_sel_init_position(t_selelem *expr, const char *type, yyscan_t scanner)
  * \param[in] x,y,z  Coordinates for the position.
  * \returns   The creates selection element.
  */
-t_selelem *
+SelectionTreeElementPointer
 _gmx_sel_init_const_position(real x, real y, real z)
 {
-    t_selelem *sel;
     rvec       pos;
 
-    sel = _gmx_selelem_create(SEL_CONST);
+    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_CONST));
     _gmx_selelem_set_vtype(sel, POS_VALUE);
     _gmx_selvalue_reserve(&sel->v, 1);
     pos[XX] = x;
@@ -971,34 +935,32 @@ _gmx_sel_init_const_position(real x, real y, real z)
  * See gmx_ana_indexgrps_find() for information on how \p name is matched
  * against the index groups.
  */
-t_selelem *
+SelectionTreeElementPointer
 _gmx_sel_init_group_by_name(const char *name, yyscan_t scanner)
 {
     gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
-    t_selelem *sel;
 
     if (!_gmx_sel_lexer_has_groups_set(scanner))
     {
-        sel = _gmx_selelem_create(SEL_GROUPREF);
+        SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_GROUPREF));
         _gmx_selelem_set_vtype(sel, GROUP_VALUE);
         sel->u.gref.name = strdup(name);
         sel->u.gref.id = -1;
-        sel->name = name;
+        sel->name = sel->u.gref.name;
         return sel;
     }
     if (!grps)
     {
         _gmx_selparser_error(scanner, "No index groups set; cannot match 'group %s'", name);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
-    sel = _gmx_selelem_create(SEL_CONST);
-    _gmx_selelem_set_vtype(sel, GROUP_VALUE); 
+    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_CONST));
+    _gmx_selelem_set_vtype(sel, GROUP_VALUE);
     /* FIXME: The constness should not be cast away */
     if (!gmx_ana_indexgrps_find(&sel->u.cgrp, grps, (char *)name))
     {
         _gmx_selparser_error(scanner, "Cannot match 'group %s'", name);
-        _gmx_selelem_free(sel);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
     sel->name = sel->u.cgrp.name;
     return sel;
@@ -1010,15 +972,14 @@ _gmx_sel_init_group_by_name(const char *name, yyscan_t scanner)
  * \returns   The created constant selection element, or NULL if no matching
  *     index group found.
  */
-t_selelem *
+SelectionTreeElementPointer
 _gmx_sel_init_group_by_id(int id, yyscan_t scanner)
 {
     gmx_ana_indexgrps_t *grps = _gmx_sel_lexer_indexgrps(scanner);
-    t_selelem *sel;
 
     if (!_gmx_sel_lexer_has_groups_set(scanner))
     {
-        sel = _gmx_selelem_create(SEL_GROUPREF);
+        SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_GROUPREF));
         _gmx_selelem_set_vtype(sel, GROUP_VALUE);
         sel->u.gref.name = NULL;
         sel->u.gref.id = id;
@@ -1027,15 +988,14 @@ _gmx_sel_init_group_by_id(int id, yyscan_t scanner)
     if (!grps)
     {
         _gmx_selparser_error(scanner, "No index groups set; cannot match 'group %d'", id);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
-    sel = _gmx_selelem_create(SEL_CONST);
+    SelectionTreeElementPointer sel(new SelectionTreeElement(SEL_CONST));
     _gmx_selelem_set_vtype(sel, GROUP_VALUE);
     if (!gmx_ana_indexgrps_extract(&sel->u.cgrp, grps, id))
     {
         _gmx_selparser_error(scanner, "Cannot match 'group %d'", id);
-        _gmx_selelem_free(sel);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
     sel->name = sel->u.cgrp.name;
     return sel;
@@ -1048,10 +1008,10 @@ _gmx_sel_init_group_by_id(int id, yyscan_t scanner)
  * The reference count of \p sel is updated, but no other modifications are
  * made.
  */
-t_selelem *
-_gmx_sel_init_variable_ref(t_selelem *sel)
+SelectionTreeElementPointer
+_gmx_sel_init_variable_ref(const SelectionTreeElementPointer &sel)
 {
-    t_selelem *ref;
+    SelectionTreeElementPointer ref;
 
     if (sel->v.type == POS_VALUE && sel->type == SEL_CONST)
     {
@@ -1059,12 +1019,11 @@ _gmx_sel_init_variable_ref(t_selelem *sel)
     }
     else
     {
-        ref = _gmx_selelem_create(SEL_SUBEXPRREF);
+        ref.reset(new SelectionTreeElement(SEL_SUBEXPRREF));
         _gmx_selelem_set_vtype(ref, sel->v.type);
         ref->name  = sel->name;
         ref->child = sel;
     }
-    sel->refcount++;
     return ref;
 }
 
@@ -1075,15 +1034,14 @@ _gmx_sel_init_variable_ref(t_selelem *sel)
  * \param      scanner  Scanner data structure.
  * \returns    The created root selection element.
  *
- * This function handles the creation of root (\ref SEL_ROOT) \c t_selelem
- * objects for selections.
+ * This function handles the creation of root (\ref SEL_ROOT)
+ * gmx::SelectionTreeElement objects for selections.
  */
-t_selelem *
-_gmx_sel_init_selection(char *name, t_selelem *sel, yyscan_t scanner)
+SelectionTreeElementPointer
+_gmx_sel_init_selection(const char *name,
+                        const SelectionTreeElementPointer &sel,
+                        yyscan_t scanner)
 {
-    t_selelem               *root;
-    int                      rc;
-
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
     char  buf[1024];
     sprintf(buf, "In selection '%s'", _gmx_sel_lexer_pselstr(scanner));
@@ -1091,35 +1049,26 @@ _gmx_sel_init_selection(char *name, t_selelem *sel, yyscan_t scanner)
 
     if (sel->v.type != POS_VALUE)
     {
-        GMX_ERROR_NORET(gmx::eeInternalError,
-                        "Each selection must evaluate to a position");
         /* FIXME: Better handling of this error */
-        sfree(name);
-        return NULL;
+        GMX_THROW(gmx::InternalError(
+                "Each selection must evaluate to a position"));
     }
 
-    root = _gmx_selelem_create(SEL_ROOT);
+    SelectionTreeElementPointer root(new SelectionTreeElement(SEL_ROOT));
     root->child = sel;
-    /* Assign the name (this is done here to free it automatically in the case
-     * of an error below). */
     if (name)
     {
-        root->name = root->u.cgrp.name = name;
+        root->name = root->u.cgrp.name = strdup(name);
     }
     /* Update the flags */
-    rc = _gmx_selelem_update_flags(root, scanner);
-    if (rc != 0)
-    {
-        _gmx_selelem_free(root);
-        return NULL;
-    }
+    _gmx_selelem_update_flags(root, scanner);
 
     /* If there is no name provided by the user, check whether the actual
      * selection given was from an external group, and if so, use the name
      * of the external group. */
     if (!root->name)
     {
-        t_selelem *child = root->child;
+        SelectionTreeElementPointer child = root->child;
         while (child->type == SEL_MODIFIER)
         {
             if (!child->child || child->child->type != SEL_SUBEXPRREF
@@ -1158,48 +1107,38 @@ _gmx_sel_init_selection(char *name, t_selelem *sel, yyscan_t scanner)
 
 
 /*!
- * \param[in]  name     Name of the variable (should not be freed after this
- *   function).
+ * \param[in]  name     Name of the variable.
  * \param[in]  expr     The selection element that evaluates the variable.
  * \param      scanner  Scanner data structure.
  * \returns    The created root selection element.
  *
- * This function handles the creation of root \c t_selelem objects for
- * variable assignments. A \ref SEL_ROOT element and a \ref SEL_SUBEXPR
+ * This function handles the creation of root gmx::SelectionTreeElement objects
+ * for variable assignments. A \ref SEL_ROOT element and a \ref SEL_SUBEXPR
  * element are both created.
  */
-t_selelem *
-_gmx_sel_assign_variable(char *name, t_selelem *expr, yyscan_t scanner)
+SelectionTreeElementPointer
+_gmx_sel_assign_variable(const char *name,
+                         const SelectionTreeElementPointer &expr,
+                         yyscan_t scanner)
 {
     gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
     const char              *pselstr = _gmx_sel_lexer_pselstr(scanner);
-    t_selelem               *root = NULL;
-    int                      rc;
+    SelectionTreeElementPointer root;
 
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
     char  buf[1024];
     sprintf(buf, "In selection '%s'", pselstr);
     gmx::MessageStringContext  context(errors, buf);
 
-    rc = _gmx_selelem_update_flags(expr, scanner);
-    if (rc != 0)
-    {
-        sfree(name);
-        _gmx_selelem_free(expr);
-        return NULL;
-    }
+    _gmx_selelem_update_flags(expr, scanner);
     /* Check if this is a constant non-group value */
     if (expr->type == SEL_CONST && expr->v.type != GROUP_VALUE)
     {
         /* If so, just assign the constant value to the variable */
         if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr))
         {
-            _gmx_selelem_free(expr);
-            sfree(name);
-            return NULL;
+            return SelectionTreeElementPointer();
         }
-        _gmx_selelem_free(expr);
-        sfree(name);
         goto finish;
     }
     /* Check if we are assigning a variable to another variable */
@@ -1208,35 +1147,28 @@ _gmx_sel_assign_variable(char *name, t_selelem *expr, yyscan_t scanner)
         /* If so, make a simple alias */
         if (!_gmx_sel_add_var_symbol(sc->symtab, name, expr->child))
         {
-            _gmx_selelem_free(expr);
-            sfree(name);
-            return NULL;
+            return SelectionTreeElementPointer();
         }
-        _gmx_selelem_free(expr);
-        sfree(name);
         goto finish;
     }
     /* Create the root element */
-    root = _gmx_selelem_create(SEL_ROOT);
-    root->name          = name;
-    root->u.cgrp.name   = name;
+    root.reset(new SelectionTreeElement(SEL_ROOT));
     /* Create the subexpression element */
-    root->child = _gmx_selelem_create(SEL_SUBEXPR);
+    root->child.reset(new SelectionTreeElement(SEL_SUBEXPR));
     _gmx_selelem_set_vtype(root->child, expr->v.type);
-    root->child->name   = name;
-    root->child->child  = expr;
-    /* Update flags */
-    rc = _gmx_selelem_update_flags(root, scanner);
-    if (rc != 0)
     {
-        _gmx_selelem_free(root);
-        return NULL;
+        char *newName = strdup(name);
+        root->name          = newName;
+        root->u.cgrp.name   = newName;
+        root->child->name   = newName;
     }
+    root->child->child  = expr;
+    /* Update flags */
+    _gmx_selelem_update_flags(root, scanner);
     /* Add the variable to the symbol table */
     if (!_gmx_sel_add_var_symbol(sc->symtab, name, root->child))
     {
-        _gmx_selelem_free(root);
-        return NULL;
+        return SelectionTreeElementPointer();
     }
 finish:
     srenew(sc->varstrs, sc->nvars + 1);
@@ -1259,8 +1191,10 @@ finish:
  * Appends \p sel after the last root element, and returns either \p sel
  * (if it was non-NULL) or the last element (if \p sel was NULL).
  */
-t_selelem *
-_gmx_sel_append_selection(t_selelem *sel, t_selelem *last, yyscan_t scanner)
+SelectionTreeElementPointer
+_gmx_sel_append_selection(const SelectionTreeElementPointer &sel,
+                          SelectionTreeElementPointer last,
+                          yyscan_t scanner)
 {
     gmx_ana_selcollection_t *sc = _gmx_sel_lexer_selcollection(scanner);
 
@@ -1294,7 +1228,7 @@ _gmx_sel_append_selection(t_selelem *sel, t_selelem *last, yyscan_t scanner)
         {
             gmx::SelectionDataPointer selPtr(
                     new gmx::internal::SelectionData(
-                        sel, _gmx_sel_lexer_pselstr(scanner)));
+                        sel.get(), _gmx_sel_lexer_pselstr(scanner)));
             sc->sel.push_back(gmx::move(selPtr));
         }
     }
index 41e2d1dbe28f687de3e2b2e4df269d10fad79277..5ab6f004882cd65a307c63d3cbae513303e99ee2 100644 (file)
@@ -35,8 +35,8 @@
  * The data types declared in this header are used by the parser to store
  * intermediate data when constructing method expressions.
  * In particular, the parameters for the method are stored.
- * The intermediate data is freed once a \c t_selelem object can be
- * constructed.
+ * The intermediate data is freed once a gmx::SelectionTreeElement object can
+ * be constructed.
  *
  * This is an implementation header: there should be no need to use it outside
  * this directory.
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_selection
  */
-#ifndef SELECTION_PARSETREE_H
-#define SELECTION_PARSETREE_H
+#ifndef GMX_SELECTION_PARSETREE_H
+#define GMX_SELECTION_PARSETREE_H
 
 #include <exception>
 
-#include <types/simple.h>
+#include "gromacs/legacyheaders/types/simple.h"
 
-#include "gromacs/selection/selvalue.h"
+#include "selelem.h"
+#include "selvalue.h"
 
-struct t_selelem;
 struct gmx_ana_indexgrps_t;
 struct gmx_ana_selmethod_t;
 struct gmx_ana_selparam_t;
 
 /*! \internal \brief
  * Describes a parsed value, possibly resulting from expression evaluation.
+ *
+ * \todo
+ * Make this a proper class.
  */
 typedef struct t_selexpr_value
 {
-    /** Type of the value. */
+    //! Returns true if the value comes from expression evaluation.
+    bool hasExpressionValue() const { return expr; }
+
+    //! Type of the value.
     e_selvalue_t            type;
-    /** true if the value is the result of an expression. */
-    bool                    bExpr;
-    /** The actual value. */
+    //! Expression pointer if the value is the result of an expression.
+    gmx::SelectionTreeElementPointer expr;
+    //! The actual value if \p expr is NULL.
     union {
         /** The integer value/range (\p type INT_VALUE); */
         struct {
@@ -87,8 +93,6 @@ typedef struct t_selexpr_value
         char               *s;
         /** The position value (\p type POS_VALUE); */
         rvec                x;
-        /** The expression if \p bExpr is true. */
-        struct t_selelem   *expr;
     }                       u;
     /** Pointer to the next value. */
     struct t_selexpr_value *next;
@@ -121,7 +125,7 @@ t_selexpr_value *
 _gmx_selexpr_create_value(e_selvalue_t type);
 /** Allocates and initializes an expression \c t_selexpr_value. */
 t_selexpr_value *
-_gmx_selexpr_create_value_expr(struct t_selelem *expr);
+_gmx_selexpr_create_value_expr(const gmx::SelectionTreeElementPointer &expr);
 /** Allocates and initializes a \c t_selexpr_param. */
 t_selexpr_param *
 _gmx_selexpr_create_param(char *name);
@@ -134,65 +138,76 @@ void
 _gmx_selexpr_free_params(t_selexpr_param *param);
 
 /** Propagates the flags for selection elements. */
-int
-_gmx_selelem_update_flags(struct t_selelem *sel, void *scanner);
+void
+_gmx_selelem_update_flags(const gmx::SelectionTreeElementPointer &sel,
+                          void *scanner);
 
 /** Initializes the method parameter data of \ref SEL_EXPRESSION and
  * \ref SEL_MODIFIER elements. */
 void
-_gmx_selelem_init_method_params(struct t_selelem *sel, void *scanner);
+_gmx_selelem_init_method_params(const gmx::SelectionTreeElementPointer &sel,
+                                void *scanner);
 /** Initializes the method for a \ref SEL_EXPRESSION selection element. */
 void
-_gmx_selelem_set_method(struct t_selelem *sel,
+_gmx_selelem_set_method(const gmx::SelectionTreeElementPointer &sel,
                         struct gmx_ana_selmethod_t *method, void *scanner);
 
-/** Creates a \c t_selelem for arithmetic expression evaluation. */
-struct t_selelem *
-_gmx_sel_init_arithmetic(struct t_selelem *left, struct t_selelem *right,
+/** Creates a gmx::SelectionTreeElement for arithmetic expression evaluation. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_arithmetic(const gmx::SelectionTreeElementPointer &left,
+                         const gmx::SelectionTreeElementPointer &right,
                          char op, void *scanner);
-/** Creates a \c t_selelem for comparsion expression evaluation. */
-struct t_selelem *
-_gmx_sel_init_comparison(struct t_selelem *left, struct t_selelem *right,
+/** Creates a gmx::SelectionTreeElement for comparsion expression evaluation. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_comparison(const gmx::SelectionTreeElementPointer &left,
+                         const gmx::SelectionTreeElementPointer &right,
                          char *cmpop, void *scanner);
-/** Creates a \c t_selelem for a keyword expression from the parsed data. */
-struct t_selelem *
+/** Creates a gmx::SelectionTreeElement for a keyword expression from the parsed data. */
+gmx::SelectionTreeElementPointer
 _gmx_sel_init_keyword(struct gmx_ana_selmethod_t *method,
                       t_selexpr_value *args, const char *rpost, void *scanner);
-/** Creates a \c t_selelem for a method expression from the parsed data. */
-struct t_selelem *
+/** Creates a gmx::SelectionTreeElement for a method expression from the parsed data. */
+gmx::SelectionTreeElementPointer
 _gmx_sel_init_method(struct gmx_ana_selmethod_t *method,
                      t_selexpr_param *params, const char *rpost,
                      void *scanner);
-/** Creates a \c t_selelem for a modifier expression from the parsed data. */
-struct t_selelem *
+/** Creates a gmx::SelectionTreeElement for a modifier expression from the parsed data. */
+gmx::SelectionTreeElementPointer
 _gmx_sel_init_modifier(struct gmx_ana_selmethod_t *mod, t_selexpr_param *params,
-                       struct t_selelem *sel, void *scanner);
-/** Creates a \c t_selelem for evaluation of reference positions. */
-struct t_selelem *
-_gmx_sel_init_position(struct t_selelem *expr, const char *type, void *scanner);
-
-/** Creates a \c t_selelem for a constant position. */
-struct t_selelem *
+                       const gmx::SelectionTreeElementPointer &sel,
+                       void *scanner);
+/** Creates a gmx::SelectionTreeElement for evaluation of reference positions. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_position(const gmx::SelectionTreeElementPointer &expr,
+                       const char *type, void *scanner);
+
+/** Creates a gmx::SelectionTreeElement for a constant position. */
+gmx::SelectionTreeElementPointer
 _gmx_sel_init_const_position(real x, real y, real z);
-/** Creates a \c t_selelem for a index group expression using group name. */
-struct t_selelem *
+/** Creates a gmx::SelectionTreeElement for a index group expression using group name. */
+gmx::SelectionTreeElementPointer
 _gmx_sel_init_group_by_name(const char *name, void *scanner);
-/** Creates a \c t_selelem for a index group expression using group index. */
-struct t_selelem *
+/** Creates a gmx::SelectionTreeElement for a index group expression using group index. */
+gmx::SelectionTreeElementPointer
 _gmx_sel_init_group_by_id(int id, void *scanner);
-/** Creates a \c t_selelem for a variable reference */
-struct t_selelem *
-_gmx_sel_init_variable_ref(struct t_selelem *sel);
-
-/** Creates a root \c t_selelem for a selection. */
-struct t_selelem *
-_gmx_sel_init_selection(char *name, struct t_selelem *sel, void *scanner);
-/** Creates a root \c t_selelem elements for a variable assignment. */
-struct t_selelem *
-_gmx_sel_assign_variable(char *name, struct t_selelem *expr, void *scanner);
-/** Appends a root \c t_selelem to a selection collection. */
-struct t_selelem *
-_gmx_sel_append_selection(struct t_selelem *sel, struct t_selelem *last,
+/** Creates a gmx::SelectionTreeElement for a variable reference */
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_variable_ref(const gmx::SelectionTreeElementPointer &sel);
+
+/** Creates a root gmx::SelectionTreeElement for a selection. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_selection(const char *name,
+                        const gmx::SelectionTreeElementPointer &sel,
+                        void *scanner);
+/** Creates a root gmx::SelectionTreeElement elements for a variable assignment. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_assign_variable(const char *name,
+                         const gmx::SelectionTreeElementPointer &expr,
+                         void *scanner);
+/** Appends a root gmx::SelectionTreeElement to a selection collection. */
+gmx::SelectionTreeElementPointer
+_gmx_sel_append_selection(const gmx::SelectionTreeElementPointer &sel,
+                          gmx::SelectionTreeElementPointer last,
                           void *scanner);
 /** Check whether the parser should finish. */
 bool
@@ -209,7 +224,8 @@ _gmx_sel_handle_help_cmd(t_selexpr_value *topic, void *scanner);
 /** Initializes an array of parameters based on input from the selection parser. */
 bool
 _gmx_sel_parse_params(t_selexpr_param *pparams, int nparam,
-                      struct gmx_ana_selparam_t *param, struct t_selelem *root,
+                      struct gmx_ana_selparam_t *param,
+                      const gmx::SelectionTreeElementPointer &root,
                       void *scanner);
 
 #endif
index 4229b36f987f7f0ad2cede073b56e435a3c62b5c..d7a2c791d74f56d35aee4f82eaa7c8f95206c3c7 100644 (file)
@@ -294,9 +294,7 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
     /* For variable symbols, return the type of the variable value */
     if (symtype == SYMBOL_VARIABLE)
     {
-        t_selelem *var;
-
-        var = _gmx_sel_sym_value_var(symbol);
+        gmx::SelectionTreeElementPointer var = _gmx_sel_sym_value_var(symbol);
         /* Return simple tokens for constant variables */
         if (var->type == SEL_CONST)
         {
@@ -316,7 +314,7 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
                     return INVALID;
             }
         }
-        yylval->sel = var;
+        yylval->sel = new gmx::SelectionTreeElementPointer(var);
         switch (var->v.type)
         {
             case INT_VALUE:   return VARIABLE_NUMERIC;
@@ -324,10 +322,12 @@ _gmx_sel_lexer_process_identifier(YYSTYPE *yylval, char *yytext, size_t yyleng,
             case POS_VALUE:   return VARIABLE_POS;
             case GROUP_VALUE: return VARIABLE_GROUP;
             default:
+                delete yylval->sel;
                 GMX_ERROR_NORET(gmx::eeInternalError,
                                 "Unsupported variable type");
                 return INVALID;
         }
+        delete yylval->sel;
         return INVALID; /* Should not be reached. */
     }
     /* For method symbols, return the correct type */
index d8a91583c41121200fb085e2d10bc997b1181046..b41574178511b6d25cd76cedb09687f3d8830a4e 100644 (file)
@@ -47,9 +47,10 @@ namespace gmx
 namespace internal
 {
 
-SelectionData::SelectionData(t_selelem *elem, const char *selstr)
+SelectionData::SelectionData(SelectionTreeElement *elem,
+                             const char *selstr)
     : name_(elem->name), selectionText_(selstr),
-      rootElement_(elem), coveredFractionType_(CFRAC_NONE),
+      rootElement_(*elem), coveredFractionType_(CFRAC_NONE),
       coveredFraction_(1.0), averageCoveredFraction_(1.0),
       bDynamic_(false), bDynamicCoveredFraction_(false)
 {
@@ -62,9 +63,7 @@ SelectionData::SelectionData(t_selelem *elem, const char *selstr)
     }
     else
     {
-        t_selelem *child;
-
-        child = elem->child;
+        SelectionTreeElementPointer child = elem->child;
         child->flags     &= ~SEL_ALLOCVAL;
         _gmx_selvalue_setstore(&child->v, &rawPositions_);
         /* We should also skip any modifiers to determine the dynamic
@@ -107,11 +106,11 @@ bool
 SelectionData::initCoveredFraction(e_coverfrac_t type)
 {
     coveredFractionType_ = type;
-    if (type == CFRAC_NONE || rootElement_ == NULL)
+    if (type == CFRAC_NONE)
     {
         bDynamicCoveredFraction_ = false;
     }
-    else if (!_gmx_selelem_can_estimate_cover(rootElement_))
+    else if (!_gmx_selelem_can_estimate_cover(rootElement()))
     {
         coveredFractionType_ = CFRAC_NONE;
         bDynamicCoveredFraction_ = false;
@@ -198,7 +197,7 @@ SelectionData::restoreOriginalPositions()
     if (isDynamic())
     {
         gmx_ana_pos_t &p = rawPositions_;
-        gmx_ana_index_copy(p.g, rootElement_->v.u.g, false);
+        gmx_ana_index_copy(p.g, rootElement().v.u.g, false);
         p.g->name = NULL;
         gmx_ana_indexmap_update(&p.m, p.g, hasFlag(gmx::efSelection_DynamicMask));
         p.nr = p.m.nr;
index 19b90395205d70f804081453f36b9b878a77cf68..40c87572d3a6810159407decf87ec79dacd6fba0 100644 (file)
 #include "indexutil.h"
 #include "selectionenums.h"
 
-struct t_selelem;
-
 namespace gmx
 {
 
 class SelectionOptionStorage;
+class SelectionTreeElement;
 
 class Selection;
 class SelectionPosition;
@@ -89,7 +88,7 @@ class SelectionData
          * \param[in] selstr String that was parsed to produce this selection.
          * \throws    std::bad_alloc if out of memory.
          */
-        SelectionData(t_selelem *elem, const char *selstr);
+        SelectionData(SelectionTreeElement *elem, const char *selstr);
         ~SelectionData();
 
         //! Returns the string that was parsed to produce this selection.
@@ -99,7 +98,7 @@ class SelectionData
         //! Number of positions in the selection.
         int posCount() const { return rawPositions_.nr; }
         //! Returns the root of the evaluation tree for this selection.
-        t_selelem *rootElement() { return rootElement_; }
+        SelectionTreeElement &rootElement() { return rootElement_; }
 
         //! Returns whether the covered fraction can change between frames.
         bool isCoveredFractionDynamic() const { return bDynamicCoveredFraction_; }
@@ -192,8 +191,8 @@ class SelectionData
         //! Information for all possible positions.
         std::vector<PositionInfo> originalPosInfo_;
         SelectionFlags          flags_;
-        //! Pointer to the root of the selection evaluation tree.
-        t_selelem              *rootElement_;
+        //! Root of the selection evaluation tree.
+        SelectionTreeElement   &rootElement_;
         //! Type of the covered fraction.
         e_coverfrac_t           coveredFractionType_;
         //! Covered fraction of the selection for the current frame.
index 75187e4cf850f56b870aedec78dc92d4fa1c4095..cc8391e89980d9989e14ab3a4fba37897090a2f0 100644 (file)
@@ -52,6 +52,7 @@
 #include "poscalc.h"
 #include "selection.h" // For gmx::SelectionList
 #include "selectioncollection.h"
+#include "selelem.h"
 
 namespace gmx
 {
@@ -68,8 +69,10 @@ typedef std::vector<SelectionDataPointer> SelectionDataList;
  */
 struct gmx_ana_selcollection_t
 {
-    /** Root of the selection element tree. */
-    struct t_selelem           *root;
+    //! Position calculation collection used for selection position evaluation.
+    gmx::PositionCalculationCollection  pcc;
+    //! Root of the selection element tree.
+    gmx::SelectionTreeElementPointer    root;
     /*! \brief
      * Array of compiled selections.
      *
@@ -87,8 +90,6 @@ struct gmx_ana_selcollection_t
     t_topology                    *top;
     /** Index group that contains all the atoms. */
     struct gmx_ana_index_t         gall;
-    /** Position calculation collection used for selection position evaluation. */
-    gmx::PositionCalculationCollection  pcc;
     /** Memory pool used for selection evaluation. */
     struct gmx_sel_mempool_t      *mempool;
     /** Parser symbol table. */
@@ -139,7 +140,7 @@ class SelectionCollection::Impl
          * Does not throw currently, but this is subject to change when more
          * underlying code is converted to C++.
          */
-        void resolveExternalGroups(struct t_selelem *root,
+        void resolveExternalGroups(const gmx::SelectionTreeElementPointer &root,
                                    MessageStringCollector *errors);
 
         //! Internal data, used for interfacing with old C code.
index 068ce141e3eaa7a1685a6b78d5f589f152b18bff..d09998094fa66dd2badbf92be72423d54e1cd6fc 100644 (file)
@@ -78,7 +78,6 @@ namespace gmx
 SelectionCollection::Impl::Impl()
     : debugLevel_(0), bExternalGroupsSet_(false), grps_(NULL)
 {
-    sc_.root      = NULL;
     sc_.nvars     = 0;
     sc_.varstrs   = NULL;
     sc_.top       = NULL;
@@ -93,8 +92,8 @@ SelectionCollection::Impl::Impl()
 
 SelectionCollection::Impl::~Impl()
 {
-    _gmx_selelem_free_chain(sc_.root);
     sc_.sel.clear();
+    sc_.root.reset();
     for (int i = 0; i < sc_.nvars; ++i)
     {
         sfree(sc_.varstrs[i]);
@@ -278,7 +277,8 @@ early_termination:
 
 
 void SelectionCollection::Impl::resolveExternalGroups(
-        t_selelem *root, MessageStringCollector *errors)
+        const SelectionTreeElementPointer &root,
+        MessageStringCollector *errors)
 {
 
     if (root->type == SEL_GROUPREF)
@@ -321,8 +321,8 @@ void SelectionCollection::Impl::resolveExternalGroups(
         }
     }
 
-    t_selelem *child = root->child;
-    while (child != NULL)
+    SelectionTreeElementPointer child = root->child;
+    while (child)
     {
         resolveExternalGroups(child, errors);
         child = child->next;
@@ -435,8 +435,8 @@ SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps)
     impl_->bExternalGroupsSet_ = true;
 
     MessageStringCollector errors;
-    t_selelem *root = impl_->sc_.root;
-    while (root != NULL)
+    SelectionTreeElementPointer root = impl_->sc_.root;
+    while (root)
     {
         impl_->resolveExternalGroups(root, &errors);
         root = root->next;
@@ -451,7 +451,6 @@ SelectionCollection::setIndexGroups(gmx_ana_indexgrps_t *grps)
 bool
 SelectionCollection::requiresTopology() const
 {
-    t_selelem   *sel;
     e_poscalc_t  type;
     int          flags;
 
@@ -478,10 +477,10 @@ SelectionCollection::requiresTopology() const
         }
     }
 
-    sel = impl_->sc_.root;
+    SelectionTreeElementPointer sel = impl_->sc_.root;
     while (sel)
     {
-        if (_gmx_selelem_requires_top(sel))
+        if (_gmx_selelem_requires_top(*sel))
         {
             return true;
         }
@@ -594,12 +593,10 @@ SelectionCollection::evaluateFinal(int nframes)
 void
 SelectionCollection::printTree(FILE *fp, bool bValues) const
 {
-    t_selelem *sel;
-
-    sel = impl_->sc_.root;
+    SelectionTreeElementPointer sel = impl_->sc_.root;
     while (sel)
     {
-        _gmx_selelem_print_tree(fp, sel, bValues, 0);
+        _gmx_selelem_print_tree(fp, *sel, bValues, 0);
         sel = sel->next;
     }
 }
index 55b8a5e53f292a637bd5ecbcf1ca682dc878b021..f5e179fea025e613e40a943b5b6baad15ce255fa 100644 (file)
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_selection
  */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include <cstring>
 
-#include "gmx_fatal.h"
-#include "smalloc.h"
+#include "gromacs/legacyheaders/smalloc.h"
 
 #include "gromacs/selection/indexutil.h"
 #include "gromacs/selection/poscalc.h"
 #include "gromacs/selection/position.h"
 #include "gromacs/selection/selmethod.h"
 #include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
 
 #include "keywords.h"
 #include "mempool.h"
@@ -61,9 +59,9 @@
  * The function returns NULL if \p sel->type is not one of the valid values.
  */
 const char *
-_gmx_selelem_type_str(t_selelem *sel)
+_gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
 {
-    switch (sel->type)
+    switch (sel.type)
     {
         case SEL_CONST:      return "CONST";
         case SEL_EXPRESSION: return "EXPR";
@@ -86,7 +84,7 @@ _gmx_selelem_type_str(t_selelem *sel)
  * The return value points to a string constant and should not be \p free'd.
  */
 const char *
-_gmx_sel_value_type_str(gmx_ana_selvalue_t *val)
+_gmx_sel_value_type_str(const gmx_ana_selvalue_t *val)
 {
     switch (val->type)
     {
@@ -102,9 +100,9 @@ _gmx_sel_value_type_str(gmx_ana_selvalue_t *val)
 
 /*! \copydoc _gmx_selelem_type_str() */
 const char *
-_gmx_selelem_boolean_type_str(t_selelem *sel)
+_gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel)
 {
-    switch (sel->u.boolt)
+    switch (sel.u.boolt)
     {
         case BOOL_NOT:  return "NOT"; break;
         case BOOL_AND:  return "AND"; break;
@@ -114,107 +112,148 @@ _gmx_selelem_boolean_type_str(t_selelem *sel)
     return NULL;
 }
 
-/*!
- * \param[in] type Type of selection element to allocate.
- * \returns   Pointer to the newly allocated and initialized element.
- *
- * \c t_selelem::type is set to \p type,
- * \c t_selelem::v::type is set to \ref GROUP_VALUE for boolean and comparison
- * expressions and \ref NO_VALUE for others,
- * \ref SEL_ALLOCVAL is set for non-root elements (\ref SEL_ALLOCDATA is also
- * set for \ref SEL_BOOLEAN elements),
- * and \c t_selelem::refcount is set to one.
- * All the pointers are set to NULL.
- */
-t_selelem *
-_gmx_selelem_create(e_selelem_t type)
+
+namespace gmx
 {
-    t_selelem *sel;
 
-    snew(sel, 1);
-    sel->name       = NULL;
-    sel->type       = type;
-    sel->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
+SelectionTreeElement::SelectionTreeElement(e_selelem_t type)
+{
+    this->name       = NULL;
+    this->type       = type;
+    this->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
     if (type == SEL_BOOLEAN)
     {
-        sel->v.type = GROUP_VALUE;
-        sel->flags |= SEL_ALLOCDATA;
+        this->v.type = GROUP_VALUE;
+        this->flags |= SEL_ALLOCDATA;
     }
     else
     {
-        sel->v.type = NO_VALUE;
+        this->v.type = NO_VALUE;
     }
-    _gmx_selvalue_clear(&sel->v);
-    sel->evaluate   = NULL;
-    sel->mempool    = NULL;
-    sel->child      = NULL;
-    sel->next       = NULL;
-    sel->refcount   = 1;
+    _gmx_selvalue_clear(&this->v);
+    std::memset(&this->u, 0, sizeof(this->u));
+    this->evaluate   = NULL;
+    this->mempool    = NULL;
+    this->cdata      = NULL;
+}
 
-    return sel;
+SelectionTreeElement::~SelectionTreeElement()
+{
+    /* Free the children.
+     * Must be done before freeing other data, because the children may hold
+     * references to data in this element. */
+    child.reset();
+
+    freeValues();
+    freeExpressionData();
+    freeCompilerData();
 }
 
-/*!
- * \param[in,out] sel   Selection element to set the type for.
- * \param[in]     vtype Value type for the selection element.
- * \returns       0 on success, EINVAL if the value type is invalid.
- *
- * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
- * \ref SEL_ALLOCDATA flag is also set.
- *
- * This function should only be called at most once for each element,
- * preferably right after calling _gmx_selelem_create().
- */
-int
-_gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype)
+void SelectionTreeElement::freeValues()
 {
-    if (sel->type == SEL_BOOLEAN && vtype != GROUP_VALUE)
+    mempoolRelease();
+    if ((flags & SEL_ALLOCDATA) && v.u.ptr)
     {
-        gmx_bug("internal error");
-        return EINVAL;
+        /* 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. */
+        int n = (v.nalloc > 0) ? v.nalloc : v.nr;
+        switch (v.type)
+        {
+            case STR_VALUE:
+                GMX_RELEASE_ASSERT(v.nalloc != 0,
+                        "SEL_ALLOCDATA should only be set for allocated "
+                        "STR_VALUE values");
+                for (int i = 0; i < n; ++i)
+                {
+                    sfree(v.u.s[i]);
+                }
+                break;
+            case POS_VALUE:
+                for (int i = 0; i < n; ++i)
+                {
+                    gmx_ana_pos_deinit(&v.u.p[i]);
+                }
+                break;
+            case GROUP_VALUE:
+                for (int i = 0; i < n; ++i)
+                {
+                    gmx_ana_index_deinit(&v.u.g[i]);
+                }
+                break;
+            default: /* No special handling for other types */
+                break;
+        }
     }
-    if (sel->v.type != NO_VALUE && vtype != sel->v.type)
+    if (flags & SEL_ALLOCVAL)
     {
-        gmx_call("_gmx_selelem_set_vtype() called more than once");
-        return EINVAL;
+        sfree(v.u.ptr);
     }
-    sel->v.type = vtype;
-    if (vtype == GROUP_VALUE || vtype == POS_VALUE)
+    _gmx_selvalue_setstore(&v, NULL);
+    if (type == SEL_SUBEXPRREF && u.param)
     {
-        sel->flags |= SEL_ALLOCDATA;
+        u.param->val.u.ptr = NULL;
     }
-    return 0;
 }
 
-/*!
- * \param[in,out] sel   Selection element to reserve.
- * \param[in]     count Number of values to reserve memory for.
- * \returns       0 on success or if no memory pool, non-zero on error.
- *
- * Reserves memory 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_reserve(t_selelem *sel, int count)
+SelectionTreeElement::freeExpressionData()
+{
+    if (type == SEL_EXPRESSION || type == SEL_MODIFIER)
+    {
+        _gmx_selelem_free_method(u.expr.method, u.expr.mdata);
+        u.expr.mdata = NULL;
+        u.expr.method = NULL;
+        /* Free position data */
+        if (u.expr.pos)
+        {
+            gmx_ana_pos_free(u.expr.pos);
+            u.expr.pos = NULL;
+        }
+        /* Free position calculation data */
+        if (u.expr.pc)
+        {
+            gmx_ana_poscalc_free(u.expr.pc);
+            u.expr.pc = NULL;
+        }
+    }
+    if (type == SEL_ARITHMETIC)
+    {
+        sfree(u.arith.opstr);
+        u.arith.opstr = NULL;
+    }
+    if (type == SEL_SUBEXPR || type == SEL_ROOT
+        || (type == SEL_CONST && v.type == GROUP_VALUE))
+    {
+        gmx_ana_index_deinit(&u.cgrp);
+    }
+    if (type == SEL_GROUPREF)
+    {
+        sfree(u.gref.name);
+    }
+}
+
+void SelectionTreeElement::mempoolReserve(int count)
 {
-    if (!sel->mempool)
+    if (!mempool)
     {
         return;
     }
-    switch (sel->v.type)
+    switch (v.type)
     {
         case INT_VALUE:
-            sel->v.u.i = static_cast<int *>(
-                    _gmx_sel_mempool_alloc(sel->mempool, sizeof(*sel->v.u.i)*count));
+            v.u.i = static_cast<int *>(
+                    _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.i)*count));
             break;
 
         case REAL_VALUE:
-            sel->v.u.r = static_cast<real *>(
-                    _gmx_sel_mempool_alloc(sel->mempool, sizeof(*sel->v.u.r)*count));
+            v.u.r = static_cast<real *>(
+                    _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.r)*count));
             break;
 
         case GROUP_VALUE:
-            _gmx_sel_mempool_alloc_group(sel->mempool, sel->v.u.g, count);
+            _gmx_sel_mempool_alloc_group(mempool, v.u.g, count);
             break;
 
         default:
@@ -222,31 +261,24 @@ _gmx_selelem_mempool_reserve(t_selelem *sel, int count)
     }
 }
 
-/*!
- * \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)
+void SelectionTreeElement::mempoolRelease()
 {
-    if (!sel->mempool)
+    if (!mempool)
     {
         return;
     }
-    switch (sel->v.type)
+    switch (v.type)
     {
         case INT_VALUE:
         case REAL_VALUE:
-            _gmx_sel_mempool_free(sel->mempool, sel->v.u.ptr);
-            _gmx_selvalue_setstore(&sel->v, NULL);
+            _gmx_sel_mempool_free(mempool, v.u.ptr);
+            _gmx_selvalue_setstore(&v, NULL);
             break;
 
         case GROUP_VALUE:
-            if (sel->v.u.g)
+            if (v.u.g)
             {
-                _gmx_sel_mempool_free_group(sel->mempool, sel->v.u.g);
+                _gmx_sel_mempool_free_group(mempool, v.u.g);
             }
             break;
 
@@ -255,59 +287,30 @@ _gmx_selelem_mempool_release(t_selelem *sel)
     }
 }
 
+} // namespace gmx
+
 /*!
- * \param[in] sel Selection to free.
+ * \param[in,out] sel   Selection element to set the type for.
+ * \param[in]     vtype Value type for the selection element.
+ *
+ * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
+ * \ref SEL_ALLOCDATA flag is also set.
+ *
+ * This function should only be called at most once for each element,
+ * preferably right after calling _gmx_selelem_create().
  */
 void
-_gmx_selelem_free_values(t_selelem *sel)
+_gmx_selelem_set_vtype(const gmx::SelectionTreeElementPointer &sel,
+                       e_selvalue_t vtype)
 {
-    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)
+    GMX_RELEASE_ASSERT(sel->type != SEL_BOOLEAN || vtype == GROUP_VALUE,
+                       "Boolean elements must have a group value");
+    GMX_RELEASE_ASSERT(sel->v.type == NO_VALUE || vtype == sel->v.type,
+                       "_gmx_selelem_set_vtype() called more than once");
+    sel->v.type = vtype;
+    if (vtype == GROUP_VALUE || vtype == POS_VALUE)
     {
-        sel->u.param->val.u.ptr = NULL;
+        sel->flags |= SEL_ALLOCDATA;
     }
 }
 
@@ -377,100 +380,6 @@ _gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
     }
 }
 
-/*!
- * \param[in] sel Selection to free.
- */
-void
-_gmx_selelem_free_exprdata(t_selelem *sel)
-{
-    if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
-    {
-        _gmx_selelem_free_method(sel->u.expr.method, sel->u.expr.mdata);
-        sel->u.expr.mdata = NULL;
-        sel->u.expr.method = NULL;
-        /* Free position data */
-        if (sel->u.expr.pos)
-        {
-            gmx_ana_pos_free(sel->u.expr.pos);
-            sel->u.expr.pos = NULL;
-        }
-        /* Free position calculation data */
-        if (sel->u.expr.pc)
-        {
-            gmx_ana_poscalc_free(sel->u.expr.pc);
-            sel->u.expr.pc = NULL;
-        }
-    }
-    if (sel->type == SEL_ARITHMETIC)
-    {
-        sfree(sel->u.arith.opstr);
-        sel->u.arith.opstr = NULL;
-    }
-    if (sel->type == SEL_SUBEXPR || sel->type == SEL_ROOT
-        || (sel->type == SEL_CONST && sel->v.type == GROUP_VALUE))
-    {
-        gmx_ana_index_deinit(&sel->u.cgrp);
-    }
-    if (sel->type == SEL_GROUPREF)
-    {
-        sfree(sel->u.gref.name);
-    }
-}
-
-/*!
- * \param[in] sel Selection to free.
- *
- * Decrements \ref t_selelem::refcount "sel->refcount" and frees the
- * memory allocated for \p sel and all its children if the reference count
- * reaches zero.
- */
-void
-_gmx_selelem_free(t_selelem *sel)
-{
-    /* Decrement the reference counter and do nothing if references remain */
-    sel->refcount--;
-    if (sel->refcount > 0)
-    {
-        return;
-    }
-
-    /* Free the children.
-     * Must be done before freeing other data, because the children may hold
-     * references to data in this element. */
-    _gmx_selelem_free_chain(sel->child);
-
-    /* Free value storage */
-    _gmx_selelem_free_values(sel);
-
-    /* Free other storage */
-    _gmx_selelem_free_exprdata(sel);
-
-    /* Free temporary compiler data if present */
-    _gmx_selelem_free_compiler_data(sel);
-
-    sfree(sel);
-}
-
-/*!
- * \param[in] first First selection to free.
- *
- * Frees \p first and all selections accessible through the
- * \ref t_selelem::next "first->next" pointer.
- */
-void
-_gmx_selelem_free_chain(t_selelem *first)
-{
-    t_selelem *child, *prev;
-
-    child = first;
-    while (child)
-    {
-        prev = child;
-        child = child->next;
-        _gmx_selelem_free(prev);
-    }
-}
-
 /*!
  * \param[in] fp      File handle to receive the output.
  * \param[in] sel     Root of the selection subtree to print.
@@ -479,94 +388,90 @@ _gmx_selelem_free_chain(t_selelem *first)
  * \param[in] level   Indentation level, starting from zero.
  */
 void
-_gmx_selelem_print_tree(FILE *fp, t_selelem *sel, bool bValues, int level)
+_gmx_selelem_print_tree(FILE *fp, const gmx::SelectionTreeElement &sel,
+                        bool bValues, int level)
 {
-    t_selelem *child;
     int          i;
 
     fprintf(fp, "%*c %s %s", level*2+1, '*',
-            _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel->v));
-    if (sel->name)
+            _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel.v));
+    if (sel.name)
     {
-        fprintf(fp, " \"%s\"", sel->name);
+        fprintf(fp, " \"%s\"", sel.name);
     }
     fprintf(fp, " flg=");
-    if (sel->flags & SEL_FLAGSSET)
+    if (sel.flags & SEL_FLAGSSET)
     {
         fprintf(fp, "s");
     }
-    if (sel->flags & SEL_SINGLEVAL)
+    if (sel.flags & SEL_SINGLEVAL)
     {
         fprintf(fp, "S");
     }
-    if (sel->flags & SEL_ATOMVAL)
+    if (sel.flags & SEL_ATOMVAL)
     {
         fprintf(fp, "A");
     }
-    if (sel->flags & SEL_VARNUMVAL)
+    if (sel.flags & SEL_VARNUMVAL)
     {
         fprintf(fp, "V");
     }
-    if (sel->flags & SEL_DYNAMIC)
+    if (sel.flags & SEL_DYNAMIC)
     {
         fprintf(fp, "D");
     }
-    if (!(sel->flags & SEL_VALFLAGMASK))
+    if (!(sel.flags & SEL_VALFLAGMASK))
     {
         fprintf(fp, "0");
     }
-    if (sel->mempool)
+    if (sel.mempool)
     {
         fprintf(fp, "P");
     }
-    if (sel->type == SEL_CONST)
+    if (sel.type == SEL_CONST)
     {
-        if (sel->v.type == INT_VALUE)
+        if (sel.v.type == INT_VALUE)
         {
-            fprintf(fp, " %d", sel->v.u.i[0]);
+            fprintf(fp, " %d", sel.v.u.i[0]);
         }
-        else if (sel->v.type == REAL_VALUE)
+        else if (sel.v.type == REAL_VALUE)
         {
-            fprintf(fp, " %f", sel->v.u.r[0]);
+            fprintf(fp, " %f", sel.v.u.r[0]);
         }
-        else if (sel->v.type == GROUP_VALUE)
+        else if (sel.v.type == GROUP_VALUE)
         {
-            gmx_ana_index_t *g = sel->v.u.g;
+            const gmx_ana_index_t *g = sel.v.u.g;
             if (!g || g->isize == 0)
-                g = &sel->u.cgrp;
+                g = &sel.u.cgrp;
             fprintf(fp, " (%d atoms)", g->isize);
         }
     }
-    else if (sel->type == SEL_BOOLEAN)
+    else if (sel.type == SEL_BOOLEAN)
     {
         fprintf(fp, " %s", _gmx_selelem_boolean_type_str(sel));
     }
-    else if (sel->type == SEL_EXPRESSION
-             && sel->u.expr.method->name == sm_compare.name)
+    else if (sel.type == SEL_EXPRESSION
+             && sel.u.expr.method->name == sm_compare.name)
     {
-        _gmx_selelem_print_compare_info(fp, sel->u.expr.mdata);
+        _gmx_selelem_print_compare_info(fp, sel.u.expr.mdata);
     }
-    if (sel->evaluate)
+    if (sel.evaluate)
     {
         fprintf(fp, " eval=");
-        _gmx_sel_print_evalfunc_name(fp, sel->evaluate);
+        _gmx_sel_print_evalfunc_name(fp, sel.evaluate);
     }
-    if (sel->refcount > 1)
-    {
-        fprintf(fp, " refc=%d", sel->refcount);
-    }
-    if (!(sel->flags & SEL_ALLOCVAL))
+    if (!(sel.flags & SEL_ALLOCVAL))
     {
         fprintf(fp, " (ext. output)");
     }
     fprintf(fp, "\n");
 
-    if ((sel->type == SEL_CONST && sel->v.type == GROUP_VALUE) || sel->type == SEL_ROOT)
+    if ((sel.type == SEL_CONST && sel.v.type == GROUP_VALUE) || sel.type == SEL_ROOT)
     {
-        gmx_ana_index_t *g = sel->v.u.g;
-        if (!g || g->isize == 0 || sel->evaluate != NULL)
+        const gmx_ana_index_t *g = sel.v.u.g;
+        if (!g || g->isize == 0 || sel.evaluate != NULL)
         {
-            g = &sel->u.cgrp;
+            g = &sel.u.cgrp;
         }
         if (g->isize < 0)
         {
@@ -589,34 +494,34 @@ _gmx_selelem_print_tree(FILE *fp, t_selelem *sel, bool bValues, int level)
             fprintf(fp, "\n");
         }
     }
-    else if (sel->type == SEL_EXPRESSION)
+    else if (sel.type == SEL_EXPRESSION)
     {
-        if (sel->u.expr.pc)
+        if (sel.u.expr.pc)
         {
             fprintf(fp, "%*c COM", level*2+3, '*');
             fprintf(fp, "\n");
         }
     }
 
-    if (sel->cdata)
+    if (sel.cdata)
     {
         _gmx_selelem_print_compiler_info(fp, sel, level);
     }
 
-    if (bValues && sel->type != SEL_CONST && sel->type != SEL_ROOT && sel->v.u.ptr)
+    if (bValues && sel.type != SEL_CONST && sel.type != SEL_ROOT && sel.v.u.ptr)
     {
         fprintf(fp, "%*c value: ", level*2+1, ' ');
-        switch (sel->v.type)
+        switch (sel.v.type)
         {
             case POS_VALUE:
                 /* In normal use, the pointer should never be NULL, but it's
                  * useful to have the check for debugging to avoid accidental
                  * segfaults when printing the selection tree. */
-                if (sel->v.u.p->x)
+                if (sel.v.u.p->x)
                 {
                     fprintf(fp, "(%f, %f, %f)",
-                            sel->v.u.p->x[0][XX], sel->v.u.p->x[0][YY],
-                            sel->v.u.p->x[0][ZZ]);
+                            sel.v.u.p->x[0][XX], sel.v.u.p->x[0][YY],
+                            sel.v.u.p->x[0][ZZ]);
                 }
                 else
                 {
@@ -624,16 +529,16 @@ _gmx_selelem_print_tree(FILE *fp, t_selelem *sel, bool bValues, int level)
                 }
                 break;
             case GROUP_VALUE:
-                fprintf(fp, "%d atoms", sel->v.u.g->isize);
-                if (sel->v.u.g->isize < 20)
+                fprintf(fp, "%d atoms", sel.v.u.g->isize);
+                if (sel.v.u.g->isize < 20)
                 {
-                    if (sel->v.u.g->isize > 0)
+                    if (sel.v.u.g->isize > 0)
                     {
                         fprintf(fp, ":");
                     }
-                    for (i = 0; i < sel->v.u.g->isize; ++i)
+                    for (i = 0; i < sel.v.u.g->isize; ++i)
                     {
-                        fprintf(fp, " %d", sel->v.u.g->index[i] + 1);
+                        fprintf(fp, " %d", sel.v.u.g->index[i] + 1);
                     }
                 }
                 break;
@@ -645,12 +550,12 @@ _gmx_selelem_print_tree(FILE *fp, t_selelem *sel, bool bValues, int level)
     }
 
     /* Print the subexpressions with one more level of indentation */
-    child = sel->child;
+    gmx::SelectionTreeElementPointer child = sel.child;
     while (child)
     {
-        if (!(sel->type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
+        if (!(sel.type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
         {
-            _gmx_selelem_print_tree(fp, child, bValues, level+1);
+            _gmx_selelem_print_tree(fp, *child, bValues, level+1);
         }
         child = child->next;
     }
@@ -662,25 +567,23 @@ _gmx_selelem_print_tree(FILE *fp, t_selelem *sel, bool bValues, int level)
  *   information, false otherwise.
  */
 bool
-_gmx_selelem_requires_top(t_selelem *root)
+_gmx_selelem_requires_top(const gmx::SelectionTreeElement &root)
 {
-    t_selelem *child;
-
-    if (root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER)
+    if (root.type == SEL_EXPRESSION || root.type == SEL_MODIFIER)
     {
-        if (root->u.expr.method && (root->u.expr.method->flags & SMETH_REQTOP))
+        if (root.u.expr.method && (root.u.expr.method->flags & SMETH_REQTOP))
         {
             return true;
         }
-        if (root->u.expr.pc && gmx_ana_poscalc_requires_top(root->u.expr.pc))
+        if (root.u.expr.pc && gmx_ana_poscalc_requires_top(root.u.expr.pc))
         {
             return true;
         }
     }
-    child = root->child;
+    gmx::SelectionTreeElementPointer child = root.child;
     while (child)
     {
-        if (_gmx_selelem_requires_top(child))
+        if (_gmx_selelem_requires_top(*child))
         {
             return true;
         }
index a06d296881256a62804f0b97dd7221279178eb81..3b8c8bbf30714e0366fd0a1e5d74bb509a6a31d4 100644 (file)
@@ -30,7 +30,7 @@
  */
 /*! \internal \file
  * \brief
- * Declares ::t_selelem and related things.
+ * Declares gmx::SelectionTreeElement and related things.
  *
  * The selection element trees constructed by the parser and the compiler
  * are described on the respective pages:
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_selection
  */
-#ifndef SELECTION_ELEMENT_H
-#define SELECTION_ELEMENT_H
+#ifndef GMX_SELECTION_SELELEM_H
+#define GMX_SELECTION_SELELEM_H
 
-#include <types/simple.h>
+#include <boost/shared_ptr.hpp>
 
-#include "gromacs/selection/indexutil.h"
-#include "gromacs/selection/selvalue.h"
+#include "gromacs/legacyheaders/types/simple.h"
+#include "gromacs/utility/common.h"
+
+#include "indexutil.h"
+#include "selvalue.h"
 
 struct gmx_ana_poscalc_t;
 struct gmx_ana_selparam_t;
@@ -56,14 +59,23 @@ struct gmx_ana_selmethod_t;
 
 struct gmx_sel_evaluate_t;
 struct gmx_sel_mempool_t;
-struct t_selelem;
+
+struct t_compiler_data;
+
+namespace gmx
+{
+class SelectionTreeElement;
+
+//! Smart pointer type for selection tree element pointers.
+typedef boost::shared_ptr<SelectionTreeElement> SelectionTreeElementPointer;
+} // namespace gmx
 
 /********************************************************************/
 /*! \name Enumerations for expression types
  ********************************************************************/
-/*@{*/
+//!\{
 
-/** Defines the type of a \c t_selelem object. */
+/** Defines the type of a gmx::SelectionTreeElement object. */
 typedef enum
 {
     /** Constant-valued expression. */
@@ -86,7 +98,7 @@ typedef enum
     SEL_MODIFIER
 } e_selelem_t;
 
-/** Defines the boolean operation of \c t_selelem objects with type \ref SEL_BOOLEAN. */
+/** Defines the boolean operation of gmx::SelectionTreeElement objects with type \ref SEL_BOOLEAN. */
 typedef enum
 {
     BOOL_NOT,           /**< Not */
@@ -95,7 +107,7 @@ typedef enum
     BOOL_XOR            /**< Xor (not implemented). */
 } e_boolean_t;
 
-/** Defines the arithmetic operation of \c t_selelem objects with type \ref SEL_ARITHMETIC. */
+/** Defines the arithmetic operation of gmx::SelectionTreeElement objects with type \ref SEL_ARITHMETIC. */
 typedef enum
 {
     ARITH_PLUS,         /**< + */
@@ -106,24 +118,24 @@ typedef enum
     ARITH_EXP           /**< ^ (to power) */
 } e_arithmetic_t;
 
-/** Returns a string representation of the type of a \c t_selelem. */
+/** Returns a string representation of the type of a gmx::SelectionTreeElement. */
 extern const char *
-_gmx_selelem_type_str(struct t_selelem *sel);
-/** Returns a string representation of the boolean type of a \ref SEL_BOOLEAN \c t_selelem. */
+_gmx_selelem_type_str(const gmx::SelectionTreeElement &sel);
+/** Returns a string representation of the boolean type of a \ref SEL_BOOLEAN gmx::SelectionTreeElement. */
 extern const char *
-_gmx_selelem_boolean_type_str(struct t_selelem *sel);
+_gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel);
 /** Returns a string representation of the type of a \c gmx_ana_selvalue_t. */
 extern const char *
-_gmx_sel_value_type_str(gmx_ana_selvalue_t *val);
+_gmx_sel_value_type_str(const gmx_ana_selvalue_t *val);
 
-/*@}*/
+//!\}
 
 
 /********************************************************************/
 /*! \name Selection expression flags
  * \anchor selelem_flags
  ********************************************************************/
-/*@{*/
+//!\{
 /*! \brief
  * Selection value flags are set.
  *
@@ -209,176 +221,207 @@ _gmx_sel_value_type_str(gmx_ana_selvalue_t *val);
  * This flag is also used for \ref SEL_SUBEXPRREF elements.
  */
 #define SEL_OUTINIT     (1<<13)
-/*@}*/
+//!\}
 
 
-/********************************************************************/
-/*! \name Selection expression data structures and functions
- ********************************************************************/
-/*@{*/
-
-struct t_selelem;
+namespace gmx
+{
 
 /*! \brief
- * Function pointer for evaluating a \c t_selelem.
+ * Function pointer for evaluating a gmx::SelectionTreeElement.
  */
 typedef void (*sel_evalfunc)(struct gmx_sel_evaluate_t *data,
-                             struct t_selelem *sel, gmx_ana_index_t *g);
+                             const SelectionTreeElementPointer &sel,
+                             gmx_ana_index_t *g);
 
 /*! \internal \brief
  * Represents an element of a selection expression.
  */
-typedef struct t_selelem
+class SelectionTreeElement
 {
-    /*! \brief Name of the element.
-     *
-     * This field is only used for informative purposes.
-     * It is always either NULL or a pointer to a string.
-     * Memory is never allocated for it directly.
-     */
-    const char                         *name;
-    /** Type of the element. */
-    e_selelem_t                         type;
-    /*! \brief
-     * Value storage of the element.
-     *
-     * This field contains the evaluated value of the element, as well as
-     * the output value type.
-     */
-    gmx_ana_selvalue_t                  v;
-    /*! \brief
-     * Evaluation function for the element.
-     *
-     * Can be either NULL (if the expression is a constant and does not require
-     * evaluation) or point to one of the functions defined in evaluate.h.
-     */
-    sel_evalfunc                        evaluate;
-    /*! \brief
-     * Information flags about the element.
-     *
-     * Allowed flags are listed here:
-     * \ref selelem_flags "flags for \c t_selelem".
-     */
-    int                                 flags;
-    /** Data required by the evaluation function. */
-    union {
-        /*! \brief Index group data for several element types.
+    public:
+        /*! \brief
+         * Allocates memory and performs common initialization.
+         *
+         * \param[in] type Type of selection element to create.
+         *
+         * \a type is set to \p type,
+         * \a v::type is set to \ref GROUP_VALUE for boolean and comparison
+         * expressions and \ref NO_VALUE for others, and
+         * \ref SEL_ALLOCVAL is set for non-root elements (\ref SEL_ALLOCDATA
+         * is also set for \ref SEL_BOOLEAN elements).
+         * All the pointers are set to NULL.
+         */
+        explicit SelectionTreeElement(e_selelem_t type);
+        ~SelectionTreeElement();
+
+        //! Frees the memory allocated for the \a v union.
+        void freeValues();
+        //! Frees the memory allocated for the \a u union.
+        void freeExpressionData();
+        /* In compiler.cpp */
+        /*! \brief
+         * Frees the memory allocated for the selection compiler.
+         *
+         * This function only frees the data for the given selection, not its
+         * children.  It is safe to call the function when compiler data has
+         * not been allocated or has already been freed; in such a case,
+         * nothing is done.
+         */
+        void freeCompilerData();
+
+        /*! \brief
+         * Reserves memory for value from a memory pool.
+         *
+         * \param[in]     count Number of values to reserve memory for.
+         *
+         * Reserves memory for the values of this element from the \a mempool
+         * memory pool.
+         * If no memory pool is set, nothing is done.
+         */
+        void mempoolReserve(int count);
+        /*! \brief
+         * Releases memory pool used for value.
+         *
+         * Releases the memory allocated for the values of this element from the
+         * \a mempool memory pool.
+         * If no memory pool is set, nothing is done.
+         */
+        void mempoolRelease();
+
+        /*! \brief Name of the element.
+         *
+         * This field is only used for informative purposes.
+         * It is always either NULL or a pointer to a string.
+         * Memory is never allocated for it directly.
+         */
+        const char                         *name;
+        //! Type of the element.
+        e_selelem_t                         type;
+        /*! \brief
+         * Value storage of the element.
+         *
+         * This field contains the evaluated value of the element, as well as
+         * the output value type.
+         */
+        gmx_ana_selvalue_t                  v;
+        /*! \brief
+         * Evaluation function for the element.
+         *
+         * Can be either NULL (if the expression is a constant and does not
+         * require evaluation) or point to one of the functions defined in
+         * evaluate.h.
+         */
+        sel_evalfunc                        evaluate;
+        /*! \brief
+         * Information flags about the element.
+         *
+         * Allowed flags are listed here:
+         * \ref selelem_flags "flags for gmx::SelectionTreeElement".
+         */
+        int                                 flags;
+        //! Data required by the evaluation function.
+        union {
+            /*! \brief Index group data for several element types.
+             *
+             *  - \ref SEL_CONST : if the value type is \ref GROUP_VALUE,
+             *    this field holds the unprocessed group value.
+             *  - \ref SEL_ROOT : holds the group value for which the
+             *    selection subtree should be evaluated.
+             *  - \ref SEL_SUBEXPR : holds the group for which the subexpression
+             *    has been evaluated.
+             */
+            gmx_ana_index_t                 cgrp;
+            //! Data for \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements.
+            struct {
+                //! Pointer the the method used in this expression.
+                struct gmx_ana_selmethod_t *method;
+                //! Pointer to the data allocated by the method's \p init_data (see sel_datafunc()).
+                void                       *mdata;
+                //! Pointer to the position data passed to the method.
+                struct gmx_ana_pos_t       *pos;
+                //! Pointer to the evaluation data for \p pos.
+                struct gmx_ana_poscalc_t   *pc;
+            }                               expr;
+            //! Operation type for \ref SEL_BOOLEAN elements.
+            e_boolean_t                     boolt;
+            //! Operation type for \ref SEL_ARITHMETIC elements.
+            struct {
+                //! Operation type.
+                e_arithmetic_t              type;
+                //! String representation.
+                char                       *opstr;
+            }                               arith;
+            //! Associated selection parameter for \ref SEL_SUBEXPRREF elements.
+            struct gmx_ana_selparam_t      *param;
+            //! The string/number used to reference the group.
+            struct {
+                //! Name of the referenced external group.
+                char                       *name;
+                //! If \a name is NULL, the index number of the referenced group.
+                int                         id;
+            }                               gref;
+        }                                   u;
+        //! Memory pool to use for values, or NULL if standard memory handling.
+        struct gmx_sel_mempool_t           *mempool;
+        //! Internal data for the selection compiler.
+        t_compiler_data                    *cdata;
+
+        /*! \brief The first child element.
          *
-         *  - \ref SEL_CONST : if the value type is \ref GROUP_VALUE,
-         *    this field holds the unprocessed group value.
-         *  - \ref SEL_ROOT : holds the group value for which the
-         *    selection subtree should be evaluated.
-         *  - \ref SEL_SUBEXPR : holds the group for which the subexpression
-         *    has been evaluated.
+         * Other children can be accessed through the \p next field of \p child.
          */
-        gmx_ana_index_t                 cgrp;
-        /** Data for \ref SEL_EXPRESSION and \ref SEL_MODIFIER elements. */
-        struct {
-            /** Pointer the the method used in this expression. */
-            struct gmx_ana_selmethod_t *method;
-            /** Pointer to the data allocated by the method's \p init_data (see sel_datafunc()). */
-            void                       *mdata;
-            /** Pointer to the position data passed to the method. */
-            struct gmx_ana_pos_t       *pos;
-            /** Pointer to the evaluation data for \p pos. */
-            struct gmx_ana_poscalc_t   *pc;
-        }                               expr;
-        /** Operation type for \ref SEL_BOOLEAN elements. */
-        e_boolean_t                     boolt;
-        /** Operation type for \ref SEL_ARITHMETIC elements. */
-        struct {
-            /** Operation type. */
-            e_arithmetic_t              type;
-            /** String representation. */
-            char                       *opstr;
-        }                               arith;
-        /** Associated selection parameter for \ref SEL_SUBEXPRREF elements. */
-        struct gmx_ana_selparam_t      *param;
-        /** The string/number used to reference the group. */
-        struct {
-            /** Name of the referenced external group. */
-            char                       *name;
-            /** If \a name is NULL, the index number of the referenced group. */
-            int                         id;
-        }                               gref;
-    }                                   u;
-    /** Memory pool to use for values, or NULL if standard memory handling. */
-    struct gmx_sel_mempool_t           *mempool;
-    /** Internal data for the selection compiler. */
-    struct t_compiler_data             *cdata;
-    
-    /*! \brief The first child element.
-     *
-     * Other children can be accessed through the \p next field of \p child.
-     */
-    struct t_selelem                    *child;
-    /** The next sibling element. */
-    struct t_selelem                    *next;
-    /*! \brief Number of references to this element.
-     *
-     * Should be larger than one only for \ref SEL_SUBEXPR elements.
-     */
-    int                                  refcount;
-} t_selelem;
+        SelectionTreeElementPointer         child;
+        //! The next sibling element.
+        SelectionTreeElementPointer         next;
+
+    private:
+        GMX_DISALLOW_COPY_AND_ASSIGN(SelectionTreeElement);
+};
+
+} // namespace gmx
+
+/********************************************************************/
+/*! \name Selection expression functions
+ */
+//!\{
 
 /* In evaluate.c */
 /** Writes out a human-readable name for an evaluation function. */
-extern void
-_gmx_sel_print_evalfunc_name(FILE *fp, sel_evalfunc evalfunc);
-
-/** Allocates memory and performs some common initialization for a \c t_selelem. */
-extern t_selelem *
-_gmx_selelem_create(e_selelem_t type);
-/** Sets the value type of a \c t_selelem. */
-extern int
-_gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype);
-/** Reserves memory for value of a \c t_selelem from a memory pool. */
-extern void
-_gmx_selelem_mempool_reserve(t_selelem *sel, int count);
-/** Releases memory pool used for value of a \c t_selelem. */
-extern void
-_gmx_selelem_mempool_release(t_selelem *sel);
-/** Frees the memory allocated for a \c t_selelem structure and all its children. */
-extern void
-_gmx_selelem_free(t_selelem *sel);
-/** Frees the memory allocated for a \c t_selelem structure, all its children, and also all structures referenced through t_selelem::next fields. */
-extern void
-_gmx_selelem_free_chain(t_selelem *first);
-
-/** Frees the memory allocated for the \c t_selelem::d union. */
-extern void
-_gmx_selelem_free_values(t_selelem *sel);
+void
+_gmx_sel_print_evalfunc_name(FILE *fp, gmx::sel_evalfunc evalfunc);
+
+/** Sets the value type of a gmx::SelectionTreeElement. */
+void
+_gmx_selelem_set_vtype(const gmx::SelectionTreeElementPointer &sel,
+                       e_selvalue_t vtype);
+
 /** Frees the memory allocated for a selection method. */
-extern void
+void
 _gmx_selelem_free_method(struct gmx_ana_selmethod_t *method, void *mdata);
-/** Frees the memory allocated for the \c t_selelem::u field. */
-extern void
-_gmx_selelem_free_exprdata(t_selelem *sel);
-/* In compiler.c */
-/** Frees the memory allocated for the selection compiler. */
-extern void
-_gmx_selelem_free_compiler_data(t_selelem *sel);
 
 /** Prints a human-readable version of a selection element subtree. */
-extern void
-_gmx_selelem_print_tree(FILE *fp, t_selelem *root, bool bValues, int level);
-/* In compile.c */
+void
+_gmx_selelem_print_tree(FILE *fp, const gmx::SelectionTreeElement &sel,
+                        bool bValues, int level);
+/* In compiler.c */
 /** Prints a human-readable version of the internal compiler data structure. */
-extern void
-_gmx_selelem_print_compiler_info(FILE *fp, t_selelem *sel, int level);
+void
+_gmx_selelem_print_compiler_info(FILE *fp, const gmx::SelectionTreeElement &sel,
+                                 int level);
 
 /** Returns true if the selection element subtree requires topology information for evaluation. */
-extern bool
-_gmx_selelem_requires_top(t_selelem *root);
+bool
+_gmx_selelem_requires_top(const gmx::SelectionTreeElement &root);
 
 /* In sm_insolidangle.c */
 /** Returns true if the covered fraction of the selection can be calculated. */
-extern bool
-_gmx_selelem_can_estimate_cover(t_selelem *sel);
+bool
+_gmx_selelem_can_estimate_cover(const gmx::SelectionTreeElement &sel);
 /** Returns the covered fraction of the selection for the current frame. */
-extern real
-_gmx_selelem_estimate_coverfrac(t_selelem *sel);
+real
+_gmx_selelem_estimate_coverfrac(const gmx::SelectionTreeElement &sel);
 
-/*@}*/
+//!\}
 
 #endif
index 3f0c683e682e889c99f61a3e1324e95ae5dcdde0..dd020b3bd16cb710fab21580f196855ba27cc871 100644 (file)
@@ -495,19 +495,15 @@ evaluate_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  *   _gmx_selelem_estimate_coverfrac(), false otherwise.
  */
 bool
-_gmx_selelem_can_estimate_cover(t_selelem *sel)
+_gmx_selelem_can_estimate_cover(const gmx::SelectionTreeElement &sel)
 {
-    t_selelem   *child;
-    bool         bFound;
-    bool         bDynFound;
-
-    if (sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_OR)
+    if (sel.type == SEL_BOOLEAN && sel.u.boolt == BOOL_OR)
     {
         return false;
     }
-    bFound    = false;
-    bDynFound = false;
-    child     = sel->child;
+    bool bFound    = false;
+    bool bDynFound = false;
+    gmx::SelectionTreeElementPointer child = sel.child;
     while (child)
     {
         if (child->type == SEL_EXPRESSION)
@@ -530,7 +526,7 @@ _gmx_selelem_can_estimate_cover(t_selelem *sel)
                 bDynFound = true;
             }
         }
-        else if (!_gmx_selelem_can_estimate_cover(child))
+        else if (!_gmx_selelem_can_estimate_cover(*child))
         {
             return false;
         }
@@ -549,23 +545,22 @@ _gmx_selelem_can_estimate_cover(t_selelem *sel)
  * frame.
  */
 real
-_gmx_selelem_estimate_coverfrac(t_selelem *sel)
+_gmx_selelem_estimate_coverfrac(const gmx::SelectionTreeElement &sel)
 {
-    t_selelem   *child;
     real         cfrac;
 
-    if (sel->type == SEL_EXPRESSION && sel->u.expr.method->name == sm_insolidangle.name)
+    if (sel.type == SEL_EXPRESSION && sel.u.expr.method->name == sm_insolidangle.name)
     {
-        t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)sel->u.expr.mdata;
+        t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)sel.u.expr.mdata;
         if (d->cfrac < 0)
         {
-            d->cfrac = estimate_covered_fraction(d);        
+            d->cfrac = estimate_covered_fraction(d);
         }
         return d->cfrac;
     }
-    if (sel->type == SEL_BOOLEAN && sel->u.boolt == BOOL_NOT)
+    if (sel.type == SEL_BOOLEAN && sel.u.boolt == BOOL_NOT)
     {
-        cfrac = _gmx_selelem_estimate_coverfrac(sel->child);
+        cfrac = _gmx_selelem_estimate_coverfrac(*sel.child);
         if (cfrac < 1.0)
         {
             return 1 - cfrac;
@@ -574,10 +569,10 @@ _gmx_selelem_estimate_coverfrac(t_selelem *sel)
     }
 
     /* Here, we assume that the selection is simple enough */
-    child = sel->child;
+    gmx::SelectionTreeElementPointer child = sel.child;
     while (child)
     {
-        cfrac = _gmx_selelem_estimate_coverfrac(child); 
+        cfrac = _gmx_selelem_estimate_coverfrac(*child);
         if (cfrac < 1.0)
         {
             return cfrac;
index 9c777e21b47ced5466bb173052568754df76d663..247e3d5c9a430cb5f09d3447d826c0f8670b2c73 100644 (file)
 #define USE_REGEX
 #endif
 
-#include "macros.h"
-#include "smalloc.h"
-#include "string2.h"
+#include "gromacs/legacyheaders/macros.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/string2.h"
 
 #include "gromacs/selection/selmethod.h"
-#include "gromacs/utility/errorcodes.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/messagestringcollector.h"
 
 #include "keywords.h"
@@ -680,24 +680,18 @@ evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
 }
 
 /*!
- * \param[out]  selp    Pointer to receive a pointer to the created selection
- *      element (set to NULL on error).
  * \param[in]   method  Keyword selection method to evaluate.
  * \param[in]   param   Parameter that gives the group to evaluate \p method in.
  * \param[in]   scanner Scanner data structure.
- * \returns     0 on success, non-zero error code on error.
+ * \returns     Pointer to the created selection element (NULL on error).
  *
- * Creates a \ref SEL_EXPRESSION selection element (pointer put in \c *selp)
- * that evaluates the keyword method given by \p method in the group given by
- * \p param.
+ * Creates a \ref SEL_EXPRESSION selection element that evaluates the keyword
+ * method given by \p method in the group given by \p param.
  */
-int
-_gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_keyword_evaluator(gmx_ana_selmethod_t *method,
                                 t_selexpr_param *param, void *scanner)
 {
-    t_selelem            *sel;
-    t_methoddata_kweval  *data;
-
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
     char  buf[1024];
     sprintf(buf, "In evaluation of '%s'", method->name);
@@ -707,14 +701,15 @@ _gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
         || method->outinit || method->pupdate)
     {
         _gmx_selexpr_free_params(param);
-        GMX_ERROR(gmx::eeInternalError,
-                  "Unsupported keyword method for arbitrary group evaluation");
+        GMX_THROW(gmx::InternalError(
+                "Unsupported keyword method for arbitrary group evaluation"));
     }
 
-    *selp = NULL;
-    sel = _gmx_selelem_create(SEL_EXPRESSION);
+    gmx::SelectionTreeElementPointer sel(
+            new gmx::SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(sel, method, scanner);
 
+    t_methoddata_kweval  *data;
     snew(data, 1);
     data->kwmethod = sel->u.expr.method;
     data->kwmdata  = sel->u.expr.mdata;
@@ -743,9 +738,7 @@ _gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
     if (!_gmx_sel_parse_params(param, sel->u.expr.method->nparams,
                                sel->u.expr.method->param, sel, scanner))
     {
-        _gmx_selelem_free(sel);
-        return -1;
+        return gmx::SelectionTreeElementPointer();
     }
-    *selp = sel;
-    return 0;
+    return sel;
 }
index 99af3684188f0fc876fedd4783d4f41354c6f087..53e1dc7819313996cd1caa429a9c86d7aa677015 100644 (file)
@@ -201,7 +201,7 @@ set_poscoll_pos(gmx::PositionCalculationCollection *pcc, void *data)
  * are neglected.
  */
 void
-_gmx_selelem_set_kwpos_type(t_selelem *sel, const char *type)
+_gmx_selelem_set_kwpos_type(gmx::SelectionTreeElement *sel, const char *type)
 {
     t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
 
@@ -231,7 +231,7 @@ _gmx_selelem_set_kwpos_type(t_selelem *sel, const char *type)
  * are neglected.
  */
 void
-_gmx_selelem_set_kwpos_flags(t_selelem *sel, int flags)
+_gmx_selelem_set_kwpos_flags(gmx::SelectionTreeElement *sel, int flags)
 {
     t_methoddata_pos *d = (t_methoddata_pos *)sel->u.expr.mdata;
 
index c2a6903ceed0cd061a885b25dc6e4d3614416016..3f7d4d80a2a547b3971eba31f4dbe5b7c86075f9 100644 (file)
@@ -209,10 +209,8 @@ _gmx_selelem_custom_init_same(gmx_ana_selmethod_t **method,
                               void *scanner)
 {
     gmx_ana_selmethod_t *kwmethod;
-    t_selelem           *kwelem;
     t_selexpr_param     *param;
     char                *pname;
-    int                  rc;
 
     /* Do nothing if this is not a same method. */
     if (!*method || (*method)->name != sm_same.name)
@@ -220,13 +218,13 @@ _gmx_selelem_custom_init_same(gmx_ana_selmethod_t **method,
         return 0;
     }
 
-    if (params->nval != 1 || !params->value->bExpr
-        || params->value->u.expr->type != SEL_EXPRESSION)
+    if (params->nval != 1 || !params->value->hasExpressionValue()
+        || params->value->expr->type != SEL_EXPRESSION)
     {
         _gmx_selparser_error(scanner, "'same' should be followed by a single keyword");
         return -1;
     }
-    kwmethod = params->value->u.expr->u.expr.method;
+    kwmethod = params->value->expr->u.expr.method;
 
     if (kwmethod->type == STR_VALUE)
     {
@@ -239,17 +237,19 @@ _gmx_selelem_custom_init_same(gmx_ana_selmethod_t **method,
     params->next = NULL;
     pname        = param->name;
     param->name  = NULL;
+    gmx::scoped_ptr_sfree pnameGuard(pname);
     /* Create a second keyword evaluation element for the keyword given as
      * the first parameter, evaluating the keyword in the group given by the
      * second parameter. */
-    rc = _gmx_sel_init_keyword_evaluator(&kwelem, kwmethod, param, scanner);
-    if (rc != 0)
+    gmx::SelectionTreeElementPointer kwelem
+        = _gmx_sel_init_keyword_evaluator(kwmethod, param, scanner);
+    // FIXME: Use exceptions.
+    if (!kwelem)
     {
-        sfree(pname);
-        return rc;
+        return -1;
     }
     /* Replace the second parameter with one with a value from \p kwelem. */
-    param        = _gmx_selexpr_create_param(pname);
+    param        = _gmx_selexpr_create_param(strdup(pname));
     param->nval  = 1;
     param->value = _gmx_selexpr_create_value_expr(kwelem);
     params->next = param;
index 4fba00d570f79b3300263d0eb0c62cde40df6d0c..36648878fb6d18cd344e12e896dd267087d2705d 100644 (file)
 #include <config.h>
 #endif
 
-#include <macros.h>
-#include <smalloc.h>
-#include <string2.h>
-#include <typedefs.h>
-#include <gmx_fatal.h>
+#include "gromacs/legacyheaders/macros.h"
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/string2.h"
 
 #include "gromacs/selection/poscalc.h"
+#include "gromacs/utility/gmxassert.h"
 
 #include "selelem.h"
 #include "symrec.h"
@@ -61,6 +60,9 @@ struct gmx_sel_symtab_t
 
 /*! \internal \brief
  * Single symbol for the selection parser.
+ *
+ * \todo
+ * Make this a proper class.
  */
 struct gmx_sel_symrec_t
 {
@@ -68,13 +70,10 @@ struct gmx_sel_symrec_t
     char                           *name;
     /** Type of the symbol. */
     e_symbol_t                      type;
-    /** Value of the symbol. */
-    union {
-        /** Pointer to the method structure (\ref SYMBOL_METHOD). */
-        struct gmx_ana_selmethod_t *meth;
-        /** Pointer to the variable value (\ref SYMBOL_VARIABLE). */
-        struct t_selelem           *var;
-    }                               u;
+    /** Pointer to the method structure (\ref SYMBOL_METHOD). */
+    struct gmx_ana_selmethod_t         *meth;
+    /** Pointer to the variable value (\ref SYMBOL_VARIABLE). */
+    gmx::SelectionTreeElementPointer    var;
     /** Pointer to the next symbol. */
     struct gmx_sel_symrec_t        *next;
 };
@@ -124,12 +123,9 @@ _gmx_sel_sym_type(gmx_sel_symrec_t *sym)
 struct gmx_ana_selmethod_t *
 _gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
 {
-    if (sym->type != SYMBOL_METHOD)
-    {
-        gmx_call("symbol is not a method symbol");
-        return NULL;
-    }
-    return sym->u.meth;
+    GMX_RELEASE_ASSERT(sym->type == SYMBOL_METHOD,
+            "Attempting to get method handle for a non-method symbol");
+    return sym->meth;
 }
 
 /*!
@@ -137,15 +133,12 @@ _gmx_sel_sym_value_method(gmx_sel_symrec_t *sym)
  * \returns   The variable expression associated with \p sym, or NULL if
  *   \p sym is not a \ref SYMBOL_VARIABLE symbol.
  */
-struct t_selelem *
+const gmx::SelectionTreeElementPointer &
 _gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
 {
-    if (sym->type != SYMBOL_VARIABLE)
-    {
-        gmx_call("symbol is not a variable symbol");
-        return NULL;
-    }
-    return sym->u.var;
+    GMX_RELEASE_ASSERT(sym->type == SYMBOL_VARIABLE,
+            "Attempting to get variable value for a non-variable symbol");
+    return sym->var;
 }
 
 /*! \brief
@@ -158,16 +151,16 @@ _gmx_sel_sym_value_var(gmx_sel_symrec_t *sym)
 static void
 add_reserved_symbols(gmx_sel_symtab_t *tab)
 {
-    gmx_sel_symrec_t *sym;
     gmx_sel_symrec_t *last;
     size_t            i;
 
     last = NULL;
     for (i = 0; i < asize(sym_reserved); ++i)
     {
-        snew(sym, 1);
+        gmx_sel_symrec_t *sym = new gmx_sel_symrec_t();
         sym->name = strdup(sym_reserved[i]);
         sym->type = SYMBOL_RESERVED;
+        sym->meth = NULL;
         sym->next = NULL;
         if (last)
         {
@@ -189,7 +182,6 @@ add_reserved_symbols(gmx_sel_symtab_t *tab)
 static void
 add_position_symbols(gmx_sel_symtab_t *tab)
 {
-    gmx_sel_symrec_t  *sym;
     gmx_sel_symrec_t  *last;
     int                i;
 
@@ -202,9 +194,10 @@ add_position_symbols(gmx_sel_symtab_t *tab)
     }
     for (i = 0; postypes[i] != NULL; ++i)
     {
-        snew(sym, 1);
+        gmx_sel_symrec_t  *sym = new gmx_sel_symrec_t();
         sym->name = strdup(postypes[i]);
         sym->type = SYMBOL_POS;
+        sym->meth = NULL;
         sym->next = NULL;
         if (last)
         {
@@ -249,12 +242,8 @@ _gmx_sel_symtab_free(gmx_sel_symtab_t *tab)
     {
         sym = tab->first;
         tab->first = sym->next;
-        if (sym->type == SYMBOL_VARIABLE)
-        {
-            _gmx_selelem_free(sym->u.var);
-        }
         sfree(sym->name);
-        sfree(sym);
+        delete sym;
     }
     sfree(tab);
 }
@@ -413,15 +402,17 @@ add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
     /* Create a new symbol record */
     if (psym == NULL)
     {
-        snew(tab->first, 1);
+        tab->first = new gmx_sel_symrec_t();
         sym = tab->first;
     }
     else
     {
-        snew(psym->next, 1);
+        psym->next = new gmx_sel_symrec_t();
         sym = psym->next;
     }
     sym->name = strdup(name);
+    sym->meth = NULL;
+    sym->next = NULL;
     return sym;
 }
 
@@ -434,7 +425,7 @@ add_symbol(gmx_sel_symtab_t *tab, const char *name, e_symbol_t *ctype)
  */
 gmx_sel_symrec_t *
 _gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
-                        struct t_selelem *sel)
+                        const gmx::SelectionTreeElementPointer &sel)
 {
     gmx_sel_symrec_t *sym;
     e_symbol_t        ctype;
@@ -462,8 +453,7 @@ _gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
     }
 
     sym->type  = SYMBOL_VARIABLE;
-    sym->u.var = sel;
-    sel->refcount++;
+    sym->var = sel;
     return sym;
 }
 
@@ -504,6 +494,6 @@ _gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,
     }
 
     sym->type   = SYMBOL_METHOD;
-    sym->u.meth = method;
+    sym->meth = method;
     return sym;
 }
index 23b7a15deb93147da96fa16030e7bfc3c40a36fb..4fcdf7f8ca6eeeb7413df8ef48ee5186010f60e1 100644 (file)
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_selection
  */
-#ifndef SELECTION_SYMREC_H
-#define SELECTION_SYMREC_H
+#ifndef GMX_SELECTION_SYMREC_H
+#define GMX_SELECTION_SYMREC_H
+
+#include "selelem.h"
 
-struct t_selelem;
 struct gmx_ana_selmethod_t;
 
 /** Defines the type of the symbol. */
@@ -66,8 +67,8 @@ _gmx_sel_sym_type(gmx_sel_symrec_t *sym);
 /** Returns the method associated with a \ref SYMBOL_METHOD symbol. */
 struct gmx_ana_selmethod_t *
 _gmx_sel_sym_value_method(gmx_sel_symrec_t *sym);
-/** Returns the method associated with a \ref SYMBOL_VARIABLE symbol. */
-struct t_selelem *
+/** Returns the selection tree associated with a \ref SYMBOL_VARIABLE symbol. */
+const gmx::SelectionTreeElementPointer &
 _gmx_sel_sym_value_var(gmx_sel_symrec_t *sym);
 
 /** Creates a new symbol table. */
@@ -92,7 +93,7 @@ _gmx_sel_next_symbol(gmx_sel_symrec_t *after, e_symbol_t type);
 /** Adds a new variable symbol. */
 gmx_sel_symrec_t *
 _gmx_sel_add_var_symbol(gmx_sel_symtab_t *tab, const char *name,
-                        struct t_selelem *sel);
+                        const gmx::SelectionTreeElementPointer &sel);
 /** Adds a new method symbol. */
 gmx_sel_symrec_t *
 _gmx_sel_add_method_symbol(gmx_sel_symtab_t *tab, const char *name,