// FIXME/TODO: Do we still need the VAL_GVAR_INTERN macro, or can we replace // it by ValGVar everywhere? The difference is of course the memory barrier, // which might cause a performance penalty (OTOH, not using it right now might // or might not be a bug?!?) #define VAL_GVAR_INTERN(gvar) (PtrGVars[GVAR_BUCKET(gvar)] \
[GVAR_INDEX(gvar)-1])
typedefstruct { // 'gvarWriteFlag' is a value of type GVarWriteFlag which denotes whether // the variable is assignable, read-only, or constant. unsignedchar gvarWriteFlag : 2;
// 'hasExprCopiesFopies' indicates whether the variable has ever had a // non-default value assigned to ExprGVars, CopiesGVars or FopiesGVars. // Note that this value is never cleared at present, so it can be set to 1 // while these three arrays all have their default value, but if it is 0 // these arrays definitely have their default values. unsignedchar hasExprCopiesFopies : 1;
// 'isDeclared' indicates whether the variable was marked by // 'DeclareGlobalName' in which case no "Unbound global variable" syntax // warnings should be issued for it. unsignedchar isDeclared : 1;
} GVarFlagInfo;
// If this size increases, the type used in GetGVarFlags and // SetGVarFlags below must be changed
GAP_STATIC_ASSERT(sizeof(GVarFlagInfo) == sizeof(unsignedchar), "GVarFlagInfo size mismatch");
static GVarFlagInfo GetGVarFlagInfo(Int gvar)
{ unsignedchar val = INT_INTOBJ(ELM_GVAR_LIST(FlagsGVars, gvar));
GVarFlagInfo info; // This is technically the safest way of converting a struct to an integer // and is optimised away by the compiler
memcpy(&info, &val, sizeof(GVarFlagInfo)); return info;
}
staticvoid SetGVarFlagInfo(Int gvar, GVarFlagInfo info)
{ unsignedchar val; // This is technically the safest way of converting an integer into a // struct and is optimised away by the compiler
memcpy(&val, &info, sizeof(GVarFlagInfo));
SET_ELM_GVAR_LIST(FlagsGVars, gvar, INTOBJ_INT(val));
}
staticvoid InitGVarFlagInfo(Int gvar)
{ // This is equal to setting all members of GVarFlagInfo to 0
SET_ELM_GVAR_LIST(FlagsGVars, gvar, INTOBJ_INT(0));
}
// Helper functions to more easily set members of GVarFlagInfo staticvoid SetGVarWriteState(Int gvar, GVarWriteFlag w)
{
GVarFlagInfo info = GetGVarFlagInfo(gvar);
info.gvarWriteFlag = w;
SetGVarFlagInfo(gvar, info);
}
static Obj REREADING; // Copy of GAP global variable REREADING
// We store pointers to C global variables as GAP immediate integers. static Obj * ELM_COPS_PLIST(Obj cops, UInt i)
{
UInt val = UInt_ObjInt(ELM_PLIST(cops, i));
val <<= 2; return (Obj *)val;
}
// Assign 'val' to name 'gvar'. 'hasExprCopiesFopies' can be false if this // variable has a non-default value assigned to ExprGVars, CopiesGVars or // FopiesGVars (this is a performance optimisation). If 'giveNameToFunc' // is TRUE then if 'val' is a function without a name it will be given the // name 'gvar'. staticvoid AssGVarInternal(UInt gvar,
Obj val, BOOL hasExprCopiesFopies, BOOL giveNameToFunc)
{
Obj cops; // list of internal copies
Obj * copy; // one copy
UInt i; // loop variable
Obj onam; // object of <name>
// assign the value to the global variable #ifdef HPCGAP if (!VAL_GVAR_INTERN(gvar)) {
Obj expr = ExprGVar(gvar); if (IS_INTOBJ(expr)) {
AssTLRecord(TLVars, INT_INTOBJ(expr), val); return;
}
}
MEMBAR_WRITE(); #endif
VAL_GVAR_INTERN(gvar) = val;
CHANGED_GVAR_LIST( ValGVars, gvar );
// assign name to a function #ifdef HPCGAP if (IS_BAG_REF(val) && REGION(val) == 0) { // public region? #endif if (giveNameToFunc && val != 0 && TNUM_OBJ(val) == T_FUNCTION &&
NAME_FUNC(val) == 0) {
onam = CopyToStringRep(NameGVar(gvar));
MakeImmutable(onam);
SET_NAME_FUNC(val, onam);
CHANGED_BAG(val);
} #ifdef HPCGAP
} #endif
if (!hasExprCopiesFopies) { // No need to perform any of the remaining checks return;
}
// if the global variable was automatic, convert it to normal
SET_ELM_GVAR_LIST( ExprGVars, gvar, 0 );
// assign the value to all the internal copies
cops = ELM_GVAR_LIST( CopiesGVars, gvar ); if ( cops != 0 ) { for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
copy = ELM_COPS_PLIST(cops, i);
*copy = val;
}
}
// if the value is a function, assign it to all the internal fopies
cops = ELM_GVAR_LIST( FopiesGVars, gvar ); #ifdef HPCGAP if (IS_BAG_REF(val) && REGION(val) == 0) { // public region? #endif if ( cops != 0 && val != 0 && TNUM_OBJ(val) == T_FUNCTION ) { for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
copy = ELM_COPS_PLIST(cops, i);
*copy = val;
}
} #ifdef HPCGAP
} #endif
// if the values is not a function, assign the error function elseif ( cops != 0 && val != 0/* && TNUM_OBJ(val) != T_FUNCTION */ ) { for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
copy = ELM_COPS_PLIST(cops, i);
*copy = ErrorMustEvalToFuncFunc;
}
}
// if this was an unbind, assign the other error function elseif ( cops != 0/* && val == 0 */ ) { for ( i = 1; i <= LEN_PLIST(cops); i++ ) {
copy = ELM_COPS_PLIST(cops, i);
*copy = ErrorMustHaveAssObjFunc;
}
}
}
void AssGVar(UInt gvar, Obj val)
{
GVarFlagInfo info = GetGVarFlagInfo(gvar);
if (info.gvarWriteFlag != GVarAssignable) { // make certain that the variable is not read only if ((REREADING != True) && info.gvarWriteFlag == GVarReadOnly) {
ErrorMayQuit("Variable: '%g' is read only", (Int)NameGVar(gvar), 0);
}
// Make certain variable is not constant if (info.gvarWriteFlag == GVarConstant) {
ErrorMayQuit("Variable: '%g' is constant", (Int)NameGVar(gvar), 0);
}
}
// This is a kernel-only variant of AssGVar which will change read-only // variables, which is used for constants like: // Time, MemoryAllocated, last, last2, last3 // Does not automatically give a name to functions based on variable name, // as these names are not given by users. void AssGVarWithoutReadOnlyCheck(UInt gvar, Obj val)
{
GVarFlagInfo info = GetGVarFlagInfo(gvar);
// Make certain variable is not constant if (info.gvarWriteFlag == GVarConstant) {
ErrorMayQuit("Variable: '%g' is constant", (Int)NameGVar(gvar), 0);
}
/**************************************************************************** ** *FValAutoGVar(<gvar>)........valueofanautomaticglobalvariable ** **'ValAutoGVar'returnsthevalueoftheglobalvariable<gvar>.Thiswill **be0if<gvar>hasnoassignedvalue.Itwillalsocauseafunction **call,if<gvar>isautomatic.
*/
Obj ValAutoGVar (
UInt gvar )
{
Obj val;
Obj expr;
Obj func; // function to call for automatic
Obj arg; // argument to pass for automatic
val = ValGVar(gvar);
// if this is an automatic variable, make the function call if ( val == 0 && (expr = ExprGVar(gvar)) != 0 ) {
#ifdef HPCGAP if (IS_INTOBJ(expr)) { // thread-local variable return GetTLRecordField(TLVars, INT_INTOBJ(expr));
} #endif // make the function call
func = ELM_PLIST( expr, 1 );
arg = ELM_PLIST( expr, 2 );
CALL_1ARGS( func, arg );
// if this is still an automatic variable, this is an error
val = ValGVar(gvar); if (val == 0) {
ErrorMayQuit("Variable: automatic variable '%g' must get a value " "by function call",
(Int)NameGVar(gvar), 0);
}
/**************************************************************************** ** *FGVarName(<name>)..............globalvariableforaname ** **'GVarName'returnstheglobalvariablewiththename<name>.
*/
UInt GVarName(constChar * name)
{ Char gvarbuf[1024]; // temporary copy for namespace constChar * cns; // pointer to current namespace
// First see whether it could be namespace-local:
cns = STATE(CurrNamespace) ? CONST_CSTR_STRING(STATE(CurrNamespace)) : ""; if (*cns) { // only if a namespace is set
size_t len = strlen(name); if (name[len-1] == NSCHAR) {
gap_strlcpy(gvarbuf, name, 512);
gap_strlcat(gvarbuf, cns, sizeof(gvarbuf));
name = gvarbuf;
}
}
/**************************************************************************** ** *FFuncAUTO().............makeautomaticglobalvariables ** **'FuncAUTO'implementstheinternalfunction'AUTO'. ** **'AUTO(<func>,<arg>,<name1>,...)' ** **'AUTO'makestheglobalvariables,whosenamesaregiventhestrings **<name1>,<name2>,...,automatic.Thatmeansthatwhenthevalueofone **ofthoseglobalvariablesisrequested,thenthefunction<func>is **calledandtheargument<arg>ispassed.Thisfunctioncallshould, **causetheexecutionofanassignmenttothatglobalvariable,otherwise **anerrorissignalled.
*/ static Obj FuncAUTO(Obj self, Obj args)
{
Obj func; // the function to call
Obj arg; // the argument to pass
Obj list; // function and argument list
Obj name; // one name (as a GAP string)
UInt gvar; // one global variable
UInt i; // loop variable
// get and check the function
func = ELM_LIST( args, 1 );
RequireFunction(SELF_NAME, func);
// get the argument
arg = ELM_LIST( args, 2 );
// make the list of function and argument
list = NewPlistFromArgs(func, arg);
// make the global variables automatic for ( i = 3; i <= LEN_LIST(args); i++ ) {
name = ELM_LIST( args, i );
RequireStringRep(SELF_NAME, name);
gvar = GVarName( CONST_CSTR_STRING(name) );
SET_ELM_GVAR_LIST( ValGVars, gvar, 0 );
SET_ELM_GVAR_LIST( ExprGVars, gvar, list );
SetHasExprCopiesFopies(gvar, 1);
CHANGED_GVAR_LIST( ExprGVars, gvar );
}
numGVars = LengthSymbolTable(&GVarSymbolTable);
next = 0; for ( i = 1; i <= numGVars; i++ ) { // consider only variables which are currently bound for completion if ( VAL_GVAR_INTERN( i ) || ELM_GVAR_LIST( ExprGVars, i )) {
curr = CONST_CSTR_STRING( NameGVar( i ) ); for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ; if ( k < len || curr[k] <= name[k] ) continue; if ( next != 0 ) { for ( k = 0; curr[k] != '\0' && curr[k] == next[k]; k++ ) ; if ( k < len || next[k] < curr[k] ) continue;
}
next = curr;
}
}
if ( next != 0 ) { for ( k = 0; next[k] != '\0'; k++ )
name[k] = next[k];
name[k] = '\0';
}
copy = NEW_PLIST_IMM( T_PLIST, numGVars ); for ( i = 1; i <= numGVars; i++ ) { /* Copy the string here, because we do not want members of NameGVars
* accessible to users, as these strings must not be changed */
strcopy = CopyToStringRep( NameGVar( i ) );
SET_ELM_PLIST( copy, i, strcopy );
CHANGED_BAG( copy );
}
SET_LEN_PLIST( copy, numGVars ); return copy;
}
// append the copy to the copies list // As C global variables are 4-byte aligned, // we shift them down to make it more likely they // will fit in an immediate integer.
GAP_ASSERT(((UInt)copy & 3) == 0);
PushPlist(cops, ObjInt_UInt((UInt)copy >> 2));
// now copy the value of <gvar> to <cvar>
Obj val = ValGVar(gvar); if ( CopyAndFopyGVars[NCopyAndFopyDone].isFopy ) { if ( val != 0 && IS_FUNC(val) ) {
*copy = val;
} elseif ( val != 0 ) {
*copy = ErrorMustEvalToFuncFunc;
} else {
*copy = ErrorMustHaveAssObjFunc;
}
} else {
*copy = val;
}
} #ifdef HPCGAP
DeclareAllGVars();
UnlockSymbolTable(&GVarSymbolTable); #endif
}
for (k = 0; k < ARRAY_SIZE(CopiesGVars); ++k) { if (CopiesGVars[k] == 0) continue;
l = LEN_PLIST(CopiesGVars[k]); for ( i = 1; i <= l; i++ )
SET_ELM_PLIST( CopiesGVars[k], i, 0 );
}
for (k = 0; k < ARRAY_SIZE(FopiesGVars); ++k) { if (FopiesGVars[k] == 0) continue;
l = LEN_PLIST(FopiesGVars[k]); for ( i = 1; i <= l; i++ )
SET_ELM_PLIST( FopiesGVars[k], i, 0 );
}
#else
UInt i, l;
l = LEN_PLIST(CopiesGVars); for ( i = 1; i <= l; i++ )
SET_ELM_GVAR_LIST( CopiesGVars, i, 0 );
l = LEN_PLIST(FopiesGVars); for ( i = 1; i <= l; i++ )
SET_ELM_GVAR_LIST( FopiesGVars, i, 0 ); #endif
Obj GVarObj(GVarDescriptor *gvar)
{
Obj result = *(gvar->ref); if (!result)
ErrorQuit("Global variable '%s' not initialized", (UInt)(gvar->name), 0);
MEMBAR_READ(); return result;
}
Obj GVarFunction(GVarDescriptor *gvar)
{
Obj result = *(gvar->ref); if (!result)
ErrorQuit("Global variable '%s' not initialized", (UInt)(gvar->name), 0); if (REGION(result))
ErrorQuit("Global variable '%s' is not a function", (UInt)(gvar->name), 0);
ImpliedWriteGuard(result); if (TNUM_OBJ(result) != T_FUNCTION)
ErrorQuit("Global variable '%s' is not a function", (UInt)(gvar->name), 0);
MEMBAR_READ(); return result;
}
Obj GVarOptFunction(GVarDescriptor *gvar)
{
Obj result = *(gvar->ref); if (!result) return (Obj) 0; if (REGION(result)) return (Obj) 0;
ImpliedWriteGuard(result); if (TNUM_OBJ(result) != T_FUNCTION) return (Obj) 0;
MEMBAR_READ(); return result;
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.45Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.