Basic selection memory pooling.
[gromacs.git] / src / gmxlib / selection / selelem.c
blob311f5923d854527e4e7806fa45efceedb5f8c1ae
1 /*
3 * This source code is part of
5 * G R O M A C S
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
31 /*! \internal \file
32 * \brief Implementation of functions in selelem.h.
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
38 #include <smalloc.h>
39 #include <gmx_fatal.h>
41 #include <indexutil.h>
42 #include <poscalc.h>
43 #include <position.h>
44 #include <selmethod.h>
46 #include "evaluate.h"
47 #include "keywords.h"
48 #include "mempool.h"
49 #include "selelem.h"
51 /*!
52 * \param[in] sel Selection for which the string is requested
53 * \returns Pointer to a string that corresponds to \p sel->type.
55 * The return value points to a string constant and should not be \p free'd.
57 * The function returns NULL if \p sel->type is not one of the valid values.
59 const char *
60 _gmx_selelem_type_str(t_selelem *sel)
62 switch (sel->type)
64 case SEL_CONST: return "CONST";
65 case SEL_EXPRESSION: return "EXPR";
66 case SEL_BOOLEAN: return "BOOL";
67 case SEL_ARITHMETIC: return "ARITH";
68 case SEL_ROOT: return "ROOT";
69 case SEL_SUBEXPR: return "SUBEXPR";
70 case SEL_SUBEXPRREF: return "REF";
71 case SEL_MODIFIER: return "MODIFIER";
73 return NULL;
76 /*!
77 * \param[in] val Value structore for which the string is requested.
78 * \returns Pointer to a string that corresponds to \p val->type,
79 * NULL if the type value is invalid.
81 * The return value points to a string constant and should not be \p free'd.
83 const char *
84 _gmx_sel_value_type_str(gmx_ana_selvalue_t *val)
86 switch (val->type)
88 case NO_VALUE: return "NONE";
89 case INT_VALUE: return "INT";
90 case REAL_VALUE: return "REAL";
91 case STR_VALUE: return "STR";
92 case POS_VALUE: return "VEC";
93 case GROUP_VALUE: return "GROUP";
95 return NULL;
98 /*! \copydoc _gmx_selelem_type_str() */
99 const char *
100 _gmx_selelem_boolean_type_str(t_selelem *sel)
102 switch (sel->u.boolt)
104 case BOOL_NOT: return "NOT"; break;
105 case BOOL_AND: return "AND"; break;
106 case BOOL_OR: return "OR"; break;
107 case BOOL_XOR: return "XOR"; break;
109 return NULL;
113 * \param[in] type Type of selection element to allocate.
114 * \returns Pointer to the newly allocated and initialized element.
116 * \c t_selelem::type is set to \p type,
117 * \c t_selelem::v::type is set to \ref GROUP_VALUE for boolean and comparison
118 * expressions and \ref NO_VALUE for others,
119 * \ref SEL_ALLOCVAL is set for non-root elements (\ref SEL_ALLOCDATA is also
120 * set for \ref SEL_BOOLEAN elements),
121 * and \c t_selelem::refcount is set to one.
122 * All the pointers are set to NULL.
124 t_selelem *
125 _gmx_selelem_create(e_selelem_t type)
127 t_selelem *sel;
129 snew(sel, 1);
130 sel->name = NULL;
131 sel->type = type;
132 sel->flags = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
133 if (type == SEL_BOOLEAN)
135 sel->v.type = GROUP_VALUE;
136 sel->flags |= SEL_ALLOCDATA;
138 else
140 sel->v.type = NO_VALUE;
142 _gmx_selvalue_clear(&sel->v);
143 sel->evaluate = NULL;
144 sel->mempool = NULL;
145 sel->child = NULL;
146 sel->next = NULL;
147 sel->refcount = 1;
149 return sel;
153 * \param[in,out] sel Selection element to set the type for.
154 * \param[in] vtype Value type for the selection element.
155 * \returns 0 on success, EINVAL if the value type is invalid.
157 * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
158 * \ref SEL_ALLOCDATA flag is also set.
160 * This function should only be called at most once for each element,
161 * preferably right after calling _gmx_selelem_create().
164 _gmx_selelem_set_vtype(t_selelem *sel, e_selvalue_t vtype)
166 if (sel->type == SEL_BOOLEAN && vtype != GROUP_VALUE)
168 gmx_bug("internal error");
169 return EINVAL;
171 if (sel->v.type != NO_VALUE && vtype != sel->v.type)
173 gmx_call("_gmx_selelem_set_vtype() called more than once");
174 return EINVAL;
176 sel->v.type = vtype;
177 if (vtype == GROUP_VALUE || vtype == POS_VALUE)
179 sel->flags |= SEL_ALLOCDATA;
181 return 0;
185 * \param[in,out] sel Selection element to reserve.
186 * \param[in] count Number of values to reserve memory for.
187 * \returns 0 on success or if no memory pool, non-zero on error.
189 * Reserves memory for the values of \p sel from the \p sel->mempool
190 * memory pool. If no memory pool is set, nothing is done.
193 _gmx_selelem_mempool_reserve(t_selelem *sel, int count)
195 int rc = 0;
197 if (!sel->mempool)
199 return 0;
201 switch (sel->v.type)
203 case GROUP_VALUE:
204 rc = _gmx_sel_mempool_alloc_group(sel->mempool, sel->v.u.g, count);
205 break;
207 default:
208 gmx_bug("mem pooling not implemented for non-group values");
209 return -1;
211 return rc;
215 * \param[in,out] sel Selection element to release.
217 * Releases the memory allocated for the values of \p sel from the
218 * \p sel->mempool memory pool. If no memory pool is set, nothing is done.
220 void
221 _gmx_selelem_mempool_release(t_selelem *sel)
223 if (!sel->mempool)
225 return;
227 switch (sel->v.type)
229 case GROUP_VALUE:
230 if (sel->v.u.g)
232 _gmx_sel_mempool_free(sel->mempool, sel->v.u.g->index);
233 sel->v.u.g->index = NULL;
235 break;
237 default:
238 gmx_bug("mem pooling not implemented for non-group values");
239 break;
244 * \param[in] sel Selection to free.
246 void
247 _gmx_selelem_free_values(t_selelem *sel)
249 int i, n;
251 _gmx_selelem_mempool_release(sel);
252 if ((sel->flags & SEL_ALLOCDATA) && sel->v.u.ptr)
254 /* The number of position/group structures is constant, so the
255 * backup of using sel->v.nr should work for them.
256 * For strings, we report an error if we don't know the allocation
257 * size here. */
258 n = (sel->v.nalloc > 0) ? sel->v.nalloc : sel->v.nr;
259 switch (sel->v.type)
261 case STR_VALUE:
262 if (sel->v.nalloc == 0)
264 gmx_bug("SEL_ALLOCDATA should only be set for allocated STR_VALUE values");
265 break;
267 for (i = 0; i < n; ++i)
269 sfree(sel->v.u.s[i]);
271 break;
272 case POS_VALUE:
273 for (i = 0; i < n; ++i)
275 gmx_ana_pos_deinit(&sel->v.u.p[i]);
277 break;
278 case GROUP_VALUE:
279 for (i = 0; i < n; ++i)
281 gmx_ana_index_deinit(&sel->v.u.g[i]);
283 break;
284 default: /* No special handling for other types */
285 break;
288 if (sel->flags & SEL_ALLOCVAL)
290 sfree(sel->v.u.ptr);
292 _gmx_selvalue_setstore(&sel->v, NULL);
296 * \param[in] method Method to free.
297 * \param[in] mdata Method data to free.
298 * \param[in] bFreeParamData If TRUE, free also the values of parameters.
300 void
301 _gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata,
302 bool bFreeParamData)
304 /* Free method data */
305 if (mdata)
307 if (method && method->free)
309 method->free(mdata);
311 sfree(mdata);
313 /* Free the method itself */
314 if (method)
316 int i;
318 /* If the method has not yet been initialized, we must free the
319 * memory allocated for parameter values here. */
320 if (bFreeParamData)
322 for (i = 0; i < method->nparams; ++i)
324 gmx_ana_selparam_t *param = &method->param[i];
326 if ((param->flags & (SPAR_VARNUM | SPAR_ATOMVAL))
327 && param->val.type != GROUP_VALUE
328 && param->val.type != POS_VALUE)
330 /* We don't need to check for enum values here, because
331 * SPAR_ENUMVAL cannot be combined with the flags
332 * required above. If it ever will be, this results
333 * in a double free within this function, which should
334 * be relatively easy to debug.
336 if (param->val.type == STR_VALUE)
338 int j;
340 for (j = 0; j < param->val.nr; ++j)
342 sfree(param->val.u.s[j]);
345 sfree(param->val.u.ptr);
349 /* And even if it is, the arrays allocated for enum values need
350 * to be freed. */
351 for (i = 0; i < method->nparams; ++i)
353 gmx_ana_selparam_t *param = &method->param[i];
355 if (param->flags & SPAR_ENUMVAL)
357 sfree(param->val.u.ptr);
361 sfree(method->param);
362 sfree(method);
367 * \param[in] sel Selection to free.
369 void
370 _gmx_selelem_free_exprdata(t_selelem *sel)
372 if (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
374 _gmx_selelem_free_method(sel->u.expr.method, sel->u.expr.mdata,
375 !(sel->flags & SEL_METHODINIT));
376 sel->u.expr.mdata = NULL;
377 sel->u.expr.method = NULL;
378 /* Free position data */
379 if (sel->u.expr.pos)
381 gmx_ana_pos_free(sel->u.expr.pos);
382 sel->u.expr.pos = NULL;
384 /* Free position calculation data */
385 if (sel->u.expr.pc)
387 gmx_ana_poscalc_free(sel->u.expr.pc);
388 sel->u.expr.pc = NULL;
391 if (sel->type == SEL_ARITHMETIC)
393 sfree(sel->u.arith.opstr);
394 sel->u.arith.opstr = NULL;
396 if (sel->type == SEL_SUBEXPR || sel->type == SEL_ROOT
397 || (sel->type == SEL_CONST && sel->v.type == GROUP_VALUE))
399 gmx_ana_index_deinit(&sel->u.cgrp);
404 * \param[in] sel Selection to free.
406 * Decrements \ref t_selelem::refcount "sel->refcount" and frees the
407 * memory allocated for \p sel and all its children if the reference count
408 * reaches zero.
410 void
411 _gmx_selelem_free(t_selelem *sel)
413 t_selelem *child, *prev;
415 /* Decrement the reference counter and do nothing if references remain */
416 sel->refcount--;
417 if (sel->refcount > 0)
419 return;
422 /* Free the children */
423 child = sel->child;
424 while (child)
426 prev = child;
427 child = child->next;
428 _gmx_selelem_free(prev);
431 /* Free value storage */
432 _gmx_selelem_free_values(sel);
434 /* Free other storage */
435 _gmx_selelem_free_exprdata(sel);
437 /* Free temporary compiler data if present */
438 _gmx_selelem_free_compiler_data(sel);
440 sfree(sel);
444 * \param[in] first First selection to free.
446 * Frees \p first and all selections accessible through the
447 * \ref t_selelem::next "first->next" pointer.
449 void
450 _gmx_selelem_free_chain(t_selelem *first)
452 t_selelem *child, *prev;
454 child = first;
455 while (child)
457 prev = child;
458 child = child->next;
459 _gmx_selelem_free(prev);
463 /*! \brief
464 * Writes out a human-readable name for the evaluation function.
466 * \param[in] fp File handle to receive the output.
467 * \param[in] sel Selection element for which the evaluation function is printed.
469 static void
470 print_evaluation_func(FILE *fp, t_selelem *sel)
472 fprintf(fp, " eval=");
473 if (!sel->evaluate)
474 fprintf(fp, "none");
475 else if (sel->evaluate == &_gmx_sel_evaluate_root)
476 fprintf(fp, "root");
477 else if (sel->evaluate == &_gmx_sel_evaluate_static)
478 fprintf(fp, "static");
479 else if (sel->evaluate == &_gmx_sel_evaluate_subexpr_pass)
480 fprintf(fp, "subexpr_pass");
481 else if (sel->evaluate == &_gmx_sel_evaluate_subexpr)
482 fprintf(fp, "subexpr");
483 else if (sel->evaluate == &_gmx_sel_evaluate_subexprref_pass)
484 fprintf(fp, "ref_pass");
485 else if (sel->evaluate == &_gmx_sel_evaluate_subexprref)
486 fprintf(fp, "ref");
487 else if (sel->evaluate == &_gmx_sel_evaluate_method)
488 fprintf(fp, "method");
489 else if (sel->evaluate == &_gmx_sel_evaluate_modifier)
490 fprintf(fp, "mod");
491 else if (sel->evaluate == &_gmx_sel_evaluate_not)
492 fprintf(fp, "not");
493 else if (sel->evaluate == &_gmx_sel_evaluate_and)
494 fprintf(fp, "and");
495 else if (sel->evaluate == &_gmx_sel_evaluate_or)
496 fprintf(fp, "or");
497 else if (sel->evaluate == &_gmx_sel_evaluate_arithmetic)
498 fprintf(fp, "arithmetic");
499 else
500 fprintf(fp, "%p", (void*)(sel->evaluate));
504 * \param[in] fp File handle to receive the output.
505 * \param[in] sel Root of the selection subtree to print.
506 * \param[in] bValues If TRUE, the evaluated values of selection elements
507 * are printed as well.
508 * \param[in] level Indentation level, starting from zero.
510 void
511 _gmx_selelem_print_tree(FILE *fp, t_selelem *sel, bool bValues, int level)
513 t_selelem *child;
514 int i;
516 fprintf(fp, "%*c %s %s", level*2+1, '*',
517 _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel->v));
518 if (sel->name)
520 fprintf(fp, " \"%s\"", sel->name);
522 fprintf(fp, " flg=");
523 if (sel->flags & SEL_FLAGSSET)
525 fprintf(fp, "s");
527 if (sel->flags & SEL_SINGLEVAL)
529 fprintf(fp, "S");
531 if (sel->flags & SEL_ATOMVAL)
533 fprintf(fp, "A");
535 if (sel->flags & SEL_VARNUMVAL)
537 fprintf(fp, "V");
539 if (sel->flags & SEL_DYNAMIC)
541 fprintf(fp, "D");
543 if (!(sel->flags & SEL_VALFLAGMASK))
545 fprintf(fp, "0");
547 if (sel->mempool)
549 fprintf(fp, "P");
551 if (sel->type == SEL_CONST)
553 if (sel->v.type == INT_VALUE)
555 fprintf(fp, " %d", sel->v.u.i[0]);
557 else if (sel->v.type == REAL_VALUE)
559 fprintf(fp, " %f", sel->v.u.r[0]);
561 else if (sel->v.type == GROUP_VALUE)
563 gmx_ana_index_t *g = sel->v.u.g;
564 if (!g || g->isize == 0)
565 g = &sel->u.cgrp;
566 fprintf(fp, " (%d atoms)", g->isize);
569 else if (sel->type == SEL_BOOLEAN)
571 fprintf(fp, " %s", _gmx_selelem_boolean_type_str(sel));
573 else if (sel->type == SEL_EXPRESSION
574 && sel->u.expr.method->name == sm_compare.name)
576 _gmx_selelem_print_compare_info(fp, sel->u.expr.mdata);
578 if (sel->evaluate)
580 print_evaluation_func(fp, sel);
582 if (sel->refcount > 1)
584 fprintf(fp, " refc=%d", sel->refcount);
586 if (!(sel->flags & SEL_ALLOCVAL))
588 fprintf(fp, " (ext. output)");
590 fprintf(fp, "\n");
592 if ((sel->type == SEL_CONST && sel->v.type == GROUP_VALUE) || sel->type == SEL_ROOT)
594 gmx_ana_index_t *g = sel->v.u.g;
595 if (!g || g->isize == 0 || sel->evaluate != NULL)
597 g = &sel->u.cgrp;
599 if (g->isize > 0)
601 fprintf(fp, "%*c group:", level*2+1, ' ');
602 if (g->isize <= 20)
604 for (i = 0; i < g->isize; ++i)
606 fprintf(fp, " %d", g->index[i] + 1);
609 else
611 fprintf(fp, " %d atoms", g->isize);
613 fprintf(fp, "\n");
616 else if (sel->type == SEL_EXPRESSION)
618 if (sel->u.expr.pc)
620 fprintf(fp, "%*c COM", level*2+3, '*');
621 fprintf(fp, "\n");
625 if (bValues && sel->type != SEL_CONST && sel->type != SEL_ROOT && sel->v.u.ptr)
627 fprintf(fp, "%*c value: ", level*2+1, ' ');
628 switch (sel->v.type)
630 case POS_VALUE:
631 /* In normal use, the pointer should never be NULL, but it's
632 * useful to have the check for debugging to avoid accidental
633 * segfaults when printing the selection tree. */
634 if (sel->v.u.p->x)
636 fprintf(fp, "(%f, %f, %f)",
637 sel->v.u.p->x[0][XX], sel->v.u.p->x[0][YY],
638 sel->v.u.p->x[0][ZZ]);
640 else
642 fprintf(fp, "(null)");
644 break;
645 case GROUP_VALUE:
646 fprintf(fp, "%d atoms", sel->v.u.g->isize);
647 if (sel->v.u.g->isize < 20)
649 if (sel->v.u.g->isize > 0)
651 fprintf(fp, ":");
653 for (i = 0; i < sel->v.u.g->isize; ++i)
655 fprintf(fp, " %d", sel->v.u.g->index[i] + 1);
658 break;
659 default:
660 fprintf(fp, "???");
661 break;
663 fprintf(fp, "\n");
666 /* Print the subexpressions with one more level of indentation */
667 child = sel->child;
668 while (child)
670 if (!(sel->type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
672 _gmx_selelem_print_tree(fp, child, bValues, level+1);
674 child = child->next;
679 * \param[in] root Root of the subtree to query.
680 * \returns TRUE if \p root or any any of its elements require topology
681 * information, FALSE otherwise.
683 bool
684 _gmx_selelem_requires_top(t_selelem *root)
686 t_selelem *child;
688 if (root->type == SEL_EXPRESSION || root->type == SEL_MODIFIER)
690 if (root->u.expr.method && (root->u.expr.method->flags & SMETH_REQTOP))
692 return TRUE;
694 if (root->u.expr.pc && gmx_ana_poscalc_requires_top(root->u.expr.pc))
696 return TRUE;
699 child = root->child;
700 while (child)
702 if (_gmx_selelem_requires_top(child))
704 return TRUE;
706 child = child->next;
708 return FALSE;