/* ASCEND modelling environment Copyright (C) 2006 Carnegie Mellon University Copyright (C) 1996, 1997 Ben Allan Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* by Tom Epperly 8/16/89, Ben Allan Last in CVS $Revision: 1.15 $ $Date: 1998/04/07 19:52:46 $ $Author: ballan $ */ /** @file * Ascend Instance Array Functions. *
 *  When #including arrayinst.h, make sure these files are #included first:
 *         #include "utilities/ascConfig.h"
 *         #include "instance_enum.h"
 *         #include "compiler.h"
 *         #include "setvalinst.h"
 *         #include "pool.h"
 *         #include "list.h"
 *
 *  Notes on the structure implemented for ASCEND arrays.
 *
 *  ASCEND arrays are 'associative arrays.' That is they are
 *  not sequential in memory, rather they are accessed by
 *  names of the elements. So there really isn't a difference
 *  between a dense rectangular array and a sparse array except
 *  it is algorithmically easier to construct the dense array.
 *
 *  For example:
 *
 *       a[1..2]['a','f'] IS_A foo;
 *
 *  yields an internal data structure (a, uai1 and uai2
 *  are ArrayInstances as described in instance_types.h) like so:
 *
 *  a -------------------|-----------------------|    <=== gl_list_t
 *                       V                       V         *childlist.
 *                    ArrayChild{             ArrayChild{
 *                    name.int = 1            name.int = 2
 *              unnamed array inst|}    unnamed array inst|}
 *     /--------------------------/    /------------------/
 *    V                               V
 *    uai1 ------|-------|            uai2 -----|-----|  <=== gl_list_t's
 *               V       V                      V     V
 *             AC       AC                     AC     AC
 *       name.str='a'  name.str='f'      name.str='a'  name.str='f'
 *       inst --\      inst --\          inst --\      inst --\
 *              |             |                 |             |
 *              V             V                 V             V
 *        fooinst       fooinst            fooinst       fooinst
 *
 *  Unnamed array instances actually DO have a compiler generated
 *  internal name, but it is not useful for anything except avoiding
 *  core dumps in routines that assume all insts have names.
 *
 *  Navigating these structures during assembly is
 *  terribly dangerous so all that is handled by this file.
 *
 *  All the indirection in these structures makes interesting tricks
 *  for sparse and dense arrays possible.
 *
 *  One trick in particular, however, is NOT to be attempted because
 *  it plays havoc with the semantics of the ASCEND language:
 *  thou shalt not declare an array over one set and then later expand
 *  it to have more elements.  This would be trivial to implement
 *  because the elements exist in gl_lists, but so far every potential
 *  application proposed for it has been the result of sloppy and/or
 *  lazy thinking.  In the end we may find a need for a genuine
 *  multidimensional ListInstance that has much in common with arrays,
 *  but such a creature should be implemented as its own creature and
 *  not a sloppy graft on top of arrays.
 *  
*/ #ifndef ASC_ARRAYINST_H #define ASC_ARRAYINST_H /* Array child memory management */ #define CAC(acp) ((struct ArrayChild *)(acp)) extern pool_store_t g_array_child_pool; /**< * Pool of array children. * Never ever dereference this except with MALLOCPOOLAC or FREEPOOLAC(). */ #ifdef ASC_NO_POOL /* slow version for debugging */ #define MALLOCPOOLAC CAC( ascmalloc(sizeof(struct ArrayChild)) ) /**< * Get an element from the pool (slow, unpooled version). * Only call after InitInstanceNanny(). */ #define FREEPOOLAC(ac) ascfree(ac); /**< * Return element ac to the pool (slow, unpooled version). * Only call after InitInstanceNanny(). */ #else #define MALLOCPOOLAC CAC(pool_get_element(g_array_child_pool)) /**< Get an element from the pool. Only call after InitInstanceNanny(). */ #define FREEPOOLAC(ac) pool_free_element(g_array_child_pool,(ac)) /**< Return element ac to the pool. Only call after InitInstanceNanny(). */ #endif /* ASC_NO_POOL */ extern void InitInstanceNanny(void); /**< * * Sets up array child instantiation gizmos. This must be called once * before any arrays can be built, ideally at startup time. * Do not call it again unless DestroyInstanceNanny is called first. * If insufficient memory to compile anything at all, does exit(2).

* * Under no circumstances should you (an external client) be freeing * a struct ArrayChild. */ extern void DestroyInstanceNanny(void); /**< * Destroy array child instantiation gizmos. This must be called to * clean up before shutting down ASCEND. * Do attempt to instantiate anything after you call this unless you * have recalled InitInstanceNanny(). */ extern void ReportInstanceNanny(FILE *f); /**< * Reports on the array child instantiator to f. */ /* Array management */ extern struct gl_list_t *CollectArrayInstances(CONST struct Instance *i, struct gl_list_t *list); /**< * Appends pointers of the set/MODEL/ATOM/constant instances found in * the leaves of an array instance, i, sparse or dense. * If list given by user is NULL, a list to be returned is made if * necessary. * If i is not an array, list returned will be NULL if list given is NULL. * If i is an array, list returned may be empty, but not NULL. * This function recurses through all the subscripts of the array. */ typedef void (*AVProc)(struct Instance *); /**< A function taking an Instance* and having no return value. */ extern void ArrayVisitLocalLeaves(struct Instance *mch, AVProc func); /**< * This function visits the instances indicated by the name * given in the definition statement of mch.ASC_DLLSPEC(struct Instance*) ChildByChar(CONST struct Instance *i, symchar *str); /**< * This returns to the pointer to a child, c, of parent,p, named by str. * str must be a simple name. If child not found, returns NULL. * str must be from the symbol table. If AscFindSymbol(str)==NULL, * then this function should not be called because NO instance * can have a child with a name which is not in the symbol table. * func is as described in visitinst.h for VisitProc. * mch is an array instance that is the child of a MODEL. */ /* Dense array procedures. (non-relations) */ extern int RectangleArrayExpanded(CONST struct Instance *i); /**< * Test if the array is fully expanded * (i.e. all the sets for all the derefencing have been specified).

* * On sparse arrays, this operator might return a FALSE positive * because it checks down the leading member of each defined * subscript range. This error is precluded only by the fact that when * instantiating, we do sparse arrays completely in one pass, therefore * the leading members check is a sufficient test. * In general, however, this should not be used on sparse arrays. */ extern int RectangleSubscriptsMatch(CONST struct Instance *context, CONST struct Instance *ary, CONST struct Name *subscripts); /**< * Test if the ary children expected from evaluating the * nodes of subscripts (all set nodes) are all compatible * with the children of the array instance given. The set * expressions in Name elements are evaluated in the context given. * Assumes the array has been fully expanded.

* * On array subscripts not yet resolvable, returns -2; try later.
* On array shape mismatch, returns -1.
* On subscripts mismatch, returns 0.
* On match, returns 1.

* * On sparse arrays, this operator should NOT be used. * A reasonably intelligent person could rewrite this to handle sparse * arrays, with the addition of a for_table argument. */ extern unsigned long NextToExpand(CONST struct Instance *i); /**< * Return the number of the dereferencing that needs to be expanded. This * returns 0 if none are needed; 1 is the first dereference. */ extern unsigned long NumberofDereferences(CONST struct Instance *i); /**< * This returns the number of dereferences that this array instance has * before reaching what the array contains. */ extern CONST struct Set *IndexSet(CONST struct Instance *i, unsigned long num); /**< * Return the set that the num'th index is defined over. Don't make any * changes to the structure that is returned! * 1 <= num <= NumberofDereferences(i) * Will return NULL on the final subscript of an ALIASES/IS_A * inside a FOR loop. */ extern void ExpandArray(struct Instance *i, unsigned long num, struct set_t *set, struct Instance *rhsinst, struct Instance *arginst, struct gl_list_t *rhslist); /**< * This will expand the num'th index over the set of index values given by * set. set is returned unchanged.

* * If the array is being expanded by an IS_A, this may effect the pending * instance list. All the instances it adds will be added below the top.

* * If the array is being expanded by an alias, rhsinst is not NULL and * rhsinst is used as the array element and pending list is not affected.

* * If the array is being expanded by an aliases-IS_A, rhsinst is NULL, * rhslist is used as the array elements source for copying, * and the pending list is not affected. * The contents of the list is a bunch of struct ArrayChild * which should * have indices matching the last subscript of the array being expanded. * Deallocating the contents of the rhs ist is the caller's responsibility, * as is creating it -- it is copied as needed internally.

* * If the array being expanded is of a parametric type, the arginst * will be used to construct the elements and pending list may be affected. */ /* Sparse arrays stuff. */ extern struct Instance *FindOrAddIntChild(struct Instance *i, long v, struct Instance *rhsinst, struct Instance *arginst); /**< * Add sparse array child at location defined by current ForTable * after instantiating child if rhsinst is NULL (an ISA). * If instantiating, uses arginst if not NULL. * Uses rhsinst if it is not NULL (an array element defined by alias). */ extern struct Instance *FindOrAddStrChild(struct Instance *i, symchar *sym, struct Instance *rhsinst, struct Instance *arginst); /**< * Add sparse array child at location defined by current ForTable * after instantiating child if rhsinst is NULL (an ISA). * If instantiating, uses arginst if not NULL. * Uses rhsinst if it is not NULL (an array element defined by alias). */ extern int CmpArrayInsts(struct Instance *i1, struct Instance *i2); /**< * Returns 0 if the arrays i1 and i2 are defined over equivalent subscript * ranges and have leaf parts of shallowly equivalent types. * (hint: relations and models are not deeply checked.) * Returns 1 for any non-equivalency. * Doesn't return if called with something other than arrays. * NULL input --> 1 + warning, rather than exit. */ #endif /* ASC_ARRAYINST_H */