DEFINITION MODULE SysVariants;
(*******************************************************************
Module SysVariants (ISIS_Version_1.2)
Copyright (c) 1997-2006 by Andreas Fischlin and ETH Zurich.
Purpose Support the management of subsystem variants,
e.g. of model equation versions or of changing
data structures.
Remarks Specifically useful while working with complex,
structured systems.
This module belongs to ISIS
Integrative Systems Implementation Software.
Programming
o Design
Andreas Fischlin 17/01/1997
o Implementation
Andreas Fischlin 17/01/1997
ETH Zurich
Systems Ecology
CHN E 35.1
Universitaetstrasse 16
8092 Zurich
SWITZERLAND
URLs:
<mailto:RAMSES@env.ethz.ch>
<http://www.sysecol.ethz.ch>
<http://www.sysecol.ethz.ch/SimSoftware/RAMSES>
Last revision of definition: 18/06/1998 AF
*******************************************************************)
FROM SYSTEM IMPORT ADDRESS;
(******************************)
(*##### Variant Sets #####*)
(******************************)
TYPE
VariantSet;
VariantOrd = INTEGER;
VariantAttribute = ADDRESS;
VSRemoveHandler = PROCEDURE (VariantSet);
VRemoveHandler = PROCEDURE (VariantAttribute);
(* optional handler used to notify a client upon
removal of a variant *)
VAR
unknownVariantSet: VariantSet; (* read only *)
CONST
undefVariant = 0; (* VariantOrd of a non existing variant *)
variDelim = "|"; (* delimiter used to separate variants in a list *)
PROCEDURE CreateVariantSet(VAR vs: VariantSet; vsDescr: ARRAY OF CHAR);
(*
This routine creates a group (set) of enumeratable
variants, e.g. used to characterize model variants,
which exclude each other. Variant sets are a sort of
dynamic enumeration types, which can be defined at run
time. vsDescr describes the variant set, e.g.
"Evapotranspiration". You may create any number of
variant sets which can then be used simultaneously to
define complex structures, called combinations. A
particular combination is given by a n-tupel, which
consists of the particular variant of each involved
variant set.
*)
PROCEDURE DiscardVariantSet(VAR vs: VariantSet);
PROCEDURE VariantSetExists(vs: VariantSet): BOOLEAN;
PROCEDURE GetVariantSetDescr(vs: VariantSet; VAR vsDescr: ARRAY OF CHAR);
(*****************************************************)
(*##### Variants = Elements in Variant Sets #####*)
(*****************************************************)
(*---------------------------*)
(*===== Declaration =====*)
(*---------------------------*)
PROCEDURE AddVariant(vs: VariantSet; VAR vord: VariantOrd;
vIdent,variDescr: ARRAY OF CHAR);
(*
Declares (adds) a specific variant to a variant set vs,
previously declared by procedure CreateVariantSet. A variant is
characterized by the string (need not be an identifier) vIdent
E.g. "Thornthwaite-Mather" or "PET by Penman-Monteith".
Alternatively a particular variant can be denoted by its order
vord. AddVariant assigns a globally (within and among all
variant sets) unique value to vord. The sequence in which
variants are declared determines the order of the variants
within the set vs (cf. procedures VSMin, VSMax, VSSucc,
VSPred). Note: Calling AddVariant several times with the same
vIdent for the same vs has no effect, in particular vord is
preserved as assigned during the very first call to AddVariant.
Consequently, within a given set vs vIdent is unique, but the
same vIdent can be added to several sets. vIdent may not be the
empty string or AddVariant fails. In the latter case AddVariant
returns vord = undefVariant.
*)
PROCEDURE VariantExists (vs: VariantSet; vIdent: ARRAY OF CHAR): BOOLEAN;
PROCEDURE DiscardVariant(vord: VariantOrd);
PROCEDURE RemoveVariant (vs: VariantSet; vIdent: ARRAY OF CHAR);
(*
Discards resp. removes the variant denoted by vord or
alternatively by vIdent from the set vs.
*)
(*-------------------------------------------*)
(*===== Ordinals (VOrd) of Variants =====*)
(*-------------------------------------------*)
(*
IMPORTANT NOTE: Ordinals (VOrd) are an integer number
denoting uniquely a single variant, regardless of its
variant set. This number must not be confounded with the
ordination number a variant has within its variant set. This
supports a random access of any variant, a feature which is
necessary for several algorithms used by ISIS.
*)
PROCEDURE VOrd(vs: VariantSet; vIdent: ARRAY OF CHAR): VariantOrd;
(*
Inverse of GetVVal: Returns the order of a particular
variant vIdent belonging to the set vs. Note: The
returned value is globally unique and different from the
ordination number of vIdent within vs (cf. procedures
OrdInVS and CurOrdInVS). Having a globally unique number
denoting any vIdent regardless to which variant set it
belongs, is e.g. useful for procedure LegalVCombination.
If vIdent does not belong to any variant set currently
known, the value undefVariant is returned.
*)
(*-------------------------------------*)
(*===== Manipulating Variants =====*)
(*-------------------------------------*)
PROCEDURE GetVVal(vord: VariantOrd;
VAR vs: VariantSet; VAR vIdent: ARRAY OF CHAR);
(*
Inverse of VOrd: Returns the variant identifier vIdent
with order vord plus the variant set to which vIdent
belongs.
*)
PROCEDURE OrdInVS (vs: VariantSet; vord: VariantOrd): INTEGER;
(*
Returns the ordination number (0, 1, ...) of the variant
denoted by vord within the variant set vs. Returns <0
in case the vord is not present in vs.
*)
PROCEDURE GetNthSubString(VAR(*speed-up*) string: ARRAY OF CHAR;
n: INTEGER; VAR subs: ARRAY OF CHAR);
(*
Returns in subs the n'th substring (n= 1, 2,...) found in
string, assuming substrings are separated by "|"
(variDelim). This string handling routine is provided for
your convenience only.
*)
PROCEDURE GetVDescriptor (vord: VariantOrd; VAR vDescr: ARRAY OF CHAR);
(*
Returns the descriptor vDescr of variant with order vord.
Returns emtpy string if variant does not exist.
*)
(*------------------------------------------------*)
(*===== Current Variant of a Variant Set =====*)
(*------------------------------------------------*)
(*
Each variant set can remember a current variant. You can ask this
module to remember the current variant (SetCurVariant, SetCurV) or
what the current variant is (GetCurVariant,CurVOrd), or to perform
a relational operation, i.e. to test if the current variant is
equal to any given variant. In all cases you have to pass an
existing variant set. There are several ways of accessing the
current variant in a set, either via the identifier
(SetCurVariant, GetCurVariant, IsCurV) or its unique ordinal
number (SetCurV, CurVOrd, IsCurVOrd). Both methods can be
combined in anyway to your liking. Finally the current variant
can also be returned as an ordination number within the set
(CurOrdInVS, CurOr1stOrd). Note, in case you have never set the
current variant, all routines return an undefined value such as
undefVariant (CurVOrd), the empty string (GetCurVariant), a
negative ordination number (CurOrdInVS), or zero (CurOr1stOrd).
*)
PROCEDURE SetCurVariant (vs: VariantSet; vIdent: ARRAY OF CHAR);
PROCEDURE SetCurV (vs: VariantSet; vord: VariantOrd);
PROCEDURE GetCurVariant (vs: VariantSet; VAR vIdent: ARRAY OF CHAR);
PROCEDURE CurVOrd (vs: VariantSet): VariantOrd;
PROCEDURE IsCurV ( vIdent: ARRAY OF CHAR; invs: VariantSet): BOOLEAN;
PROCEDURE IsCurVOrd (vord: VariantOrd; invs: VariantSet): BOOLEAN;
PROCEDURE CurOrdInVS (vs: VariantSet): INTEGER; (* can return <0 *)
PROCEDURE CurOr1stOrd (invs: VariantSet): CARDINAL;
(*
CurOr1stOrd returns the ordination number, 0,1,2.. etc., of the
current variant in the set 'invs'. In case no current has ever
been set for 'invs', CurOr1stOrd returns the ordination number
of the first variant, i.e. 0, to avoid any range errors. The
latter behavior differs from that of CurOrdInVS, which, in this
case, would return a non-defined ordination number, i.e. a
negative number like -1.
*)
(***********************************************************************)
(*##### Grouping Variant Sets to Form Combination of Variants #####*)
(***********************************************************************)
PROCEDURE VListToVCombination(vlist: ARRAY OF CHAR;
VAR combination: ARRAY OF VariantOrd);
(*
Interprets and translates a combination as given by vlist
into a combination. Individual variants within vlist have to
be separated by "|" (variDelim). If the vlist denotes a
currently illegal combination (see procedure
LegalVCombination), combination holds only undefVariant
values. IMPLEMENTATION Restriction: Well defined behavior is
not warranted unless the client makes sure all variant
identifiers are globally unique. Otherwise this routine will
interpret a variant as valid upon the first match (in
sequence of declaration), regardless of the variant set and
whether another variant with the same identifier exists also
in another variant set.
*)
PROCEDURE VCombinationToVList(combination: ARRAY OF VariantOrd;
VAR vlist: ARRAY OF CHAR);
(*
Returns a list of variant identifiers separated by "|"
(variDelim) corresponding to combination. If the combination
is illegal, only the empty string is returned in vlist.
*)
PROCEDURE ForbidVCombination(combination: ARRAY OF VariantOrd);
PROCEDURE AllowVCombination(combination: ARRAY OF VariantOrd);
(*
By default any combination of declared variants is legal.
Calling this procedure makes the combination of variants
(all belonging to different variantsets) illegal. Array
combination holds the orders of the variants. Has no
effect if any of the arguments are invalid or not all
orders denote a variant belonging to a different variant
set. Procedure AllowVCombination reverses the effect
of ForbidVCombination. Procedure LegalVCombination
provides a mean to inquire current legal status of a
given combination of variants.
*)
PROCEDURE LegalVCombination (combination: ARRAY OF VariantOrd): BOOLEAN;
(*
Returns whether the combination of variants (all
belonging to different variantsets) is legal. Array
combination holds the orders of the variants. Note:
Returns also FALSE in case of wrong arguments, e..g if
any of the variants or variant sets is unknown (an
element of combination holds undefVariant or a
variant set has never been declared) or if vs1 is not
different from vs2. However, an entirely empty
combination, characterized by holding undefVariant
in its first element, is as an exception considered to be
legal.
*)
(***************************)
(*##### Utilities #####*)
(***************************)
(*-----------------------*)
(*===== Looping =====*)
(*-----------------------*)
PROCEDURE VSDim(vs: VariantSet): INTEGER;
(* Returns current dimension of variant set vs *)
PROCEDURE VSMin(vs: VariantSet): VariantOrd;
(* Returns order of first (minimum) variant in range of variant set vs *)
PROCEDURE VSMax(vs: VariantSet): VariantOrd;
(* Returns order of last (maximum) variant in range of variant set vs *)
PROCEDURE VSucc(vs: VariantSet; vord: VariantOrd): VariantOrd;
(*
Returns order of next (successor) variant following
variant vord in variant set vs. Order is given by
sequence of declaration.
*)
PROCEDURE VPred(vs: VariantSet; vord: VariantOrd): VariantOrd;
(*
Returns order of previous (predecessor) variant
preceeding variant vord in variant set vs. Order is
given by sequence of declaration.
*)
PROCEDURE FirstVS(): VariantSet;
PROCEDURE PrevVS(vs: VariantSet): VariantSet;
PROCEDURE NextVS(vs: VariantSet): VariantSet;
PROCEDURE LastVS(): VariantSet;
(*
Makes it possible to access all currently instantiated
variant sets in the sequence they have been declared by
CreateVariantSet.
*)
(*------------------------*)
(*===== Handlers =====*)
(*------------------------*)
PROCEDURE AddVSRemoveHandler(vs: VariantSet; rmh: VSRemoveHandler);
PROCEDURE VoidVSRemoveHandler(vs: VariantSet; rmh: VSRemoveHandler);
(*
Adds (voids) a (previously added) remove handler rmh to
(from) the variant set vs. The remove handler rmh is
called when a variant set ceases to exist, i.e. when
DiscardVariantSet is called; this occurrs at a moment
when the variant set's data are still intact and all
routines (except DiscardVariantSet) from this module are
still fully functional.
*)
PROCEDURE AddVRemoveHandler(vord: VariantOrd; rmh: VRemoveHandler);
PROCEDURE VoidVRemoveHandler(vord: VariantOrd; rmh: VRemoveHandler);
(*
Adds (voids) a (previously added) remove handler rmh to
(from) the variant denoted by the order vord. The remove
handler rmh is called when a variant ceases to exist,
i.e. when DiscardVariant or RemoveVariant are called;
this occurrs at a moment when the variant's data are
still intact and all routines (except DiscardVariant or
RemoveVariant) from this module are still fully
functional.
*)
(*--------------------------*)
(*===== Attributes =====*)
(*--------------------------*)
PROCEDURE AttachVAttr (vord: VariantOrd; va: VariantAttribute);
PROCEDURE VAttr (vord: VariantOrd): VariantAttribute;
(*
Attaches respectively returns the previously attached
attribute va to the variant denoted by the order vord.
An attribute is typically a pointer to a client data
structure associated with the variant.
*)
END SysVariants.