Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/src/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 18.9.2025 mit Größe 47 kB image not shown  

Quelle  gvars.c   Sprache: C

 
/****************************************************************************
**
**  This file is part of GAP, a system for computational discrete algebra.
**
**  Copyright of GAP belongs to its developers, whose names are too numerous
**  to list here. Please refer to the COPYRIGHT file for details.
**
**  SPDX-License-Identifier: GPL-2.0-or-later
**
**  This file contains the functions of the global variables package.
**
**  The global variables  package  is the   part of the  kernel that  manages
**  global variables, i.e., the global namespace.  A global variable binds an
**  identifier to a value.
**
**  A global variable can be automatic.   That means that the global variable
**  binds the  identifier to a function and  an argument.   When the value of
**  the global variable is needed, the  function is called with the argument.
**  This function call  should, as a side-effect, execute  an assignment of a
**  value to the global variable, otherwise an error is signalled.
**
**  A global variable can have a number of internal copies, i.e., C variables
**  that always reference the same value as the global variable.
**  It can also have a special type of internal copy (a fopy) only used for
**  functions,  where  the internal copies
**  only reference the same value as the global variable if it is a function.
**  Otherwise the internal copies reference functions that signal an error.
*/


#include "gvars.h"

#include "bool.h"
#include "calls.h"
#include "error.h"
#include "gapstate.h"
#include "integer.h"
#include "io.h"
#include "lists.h"
#include "modules.h"
#include "plist.h"
#include "stringobj.h"
#include "symbols.h"
#include "sysstr.h"

#ifdef HPCGAP
#include "hpc/aobjects.h"
#include "hpc/guards.h"
#include "hpc/thread.h"
#endif


#ifdef HPCGAP
#define USE_GVAR_BUCKETS
#endif


#ifdef USE_GVAR_BUCKETS

#include <stdio.h>      // for sprintf

#define GVAR_BUCKETS 1024
#define GVAR_BUCKET_SIZE 1024

#define GVAR_BUCKET(gvar) ((UInt)(gvar) / GVAR_BUCKET_SIZE)
#define GVAR_INDEX(gvar) ((UInt)(gvar) % GVAR_BUCKET_SIZE + 1)

#endif

/****************************************************************************
**
*V  ValGVars  . . . . . . . . . . . . . . . . . .  values of global variables
*V  PtrGVars  . . . . . . . . . . . . . pointer to values of global variables
**
*/

#ifdef USE_GVAR_BUCKETS
/*
**  'ValGVars' references the bags containing the values of the global
**  variables.
**
**  'PtrGVars' is a pointer  to the 'ValGVars' bag+1. This makes it faster to
**  access global variables.
*/

static Obj   ValGVars[GVAR_BUCKETS];
static Obj * PtrGVars[GVAR_BUCKETS];
#else
/*
**  'ValGVars' is the bag containing the values of the global variables.
**
**  'PtrGVars' is a pointer  to the 'ValGVars'  bag.  This makes it faster to
**  access global variables.
**
**  Since a   garbage  collection may move   this  bag around,    the pointer
**  'PtrGVars' must be  recalculated afterwards.   This is done in function
**  'GVarsAfterCollectBags' which is called by 'VarsAfterCollectBags'.
*/

static Obj   ValGVars;
static Obj * PtrGVars;
#endif

static SymbolTable GVarSymbolTable;

#ifdef HPCGAP

/****************************************************************************
**
*V  TLVars  . . . . . . . . . . . . . . . . . . . . . thread-local variables
*/

static Obj TLVars;

#endif

#ifdef USE_GVAR_BUCKETS

// 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])

#else

#define VAL_GVAR_INTERN(gvar)   PtrGVars[ (gvar) ]

#endif


inline Obj ValGVar(UInt gvar) {
  Obj result = VAL_GVAR_INTERN(gvar);
#ifdef HPCGAP
  MEMBAR_READ();
#endif
  return result;
}


/****************************************************************************
**
*V  NameGVars . . . . . . . . . . . . . . . . . . . names of global variables
*V  FlagsGVars  . . . . . . . . . . . . flags of global variables (see below)
*V  ExprGVars . . . . . . . . . .  expressions for automatic global variables
*V  CopiesGVars . . . . . . . . . . . . . internal copies of global variables
*V  FopiesGVars . . . . . . . .  internal function copies of global variables
*/

#ifdef USE_GVAR_BUCKETS
static Obj             NameGVars[GVAR_BUCKETS];
static Obj             FlagsGVars[GVAR_BUCKETS];
static Obj             ExprGVars[GVAR_BUCKETS];
static Obj             CopiesGVars[GVAR_BUCKETS];
static Obj             FopiesGVars[GVAR_BUCKETS];

#define ELM_GVAR_LIST( list, gvar ) \
    ELM_PLIST( list[GVAR_BUCKET(gvar)], GVAR_INDEX(gvar) )

#define SET_ELM_GVAR_LIST( list, gvar, val ) \
    SET_ELM_PLIST( list[GVAR_BUCKET(gvar)], GVAR_INDEX(gvar), val )

#define CHANGED_GVAR_LIST( list, gvar ) \
    CHANGED_BAG( list[GVAR_BUCKET(gvar)] );

#else   // USE_GVAR_BUCKETS

static Obj             NameGVars;
static Obj             FlagsGVars;
static Obj             ExprGVars;
static Obj             CopiesGVars;
static Obj             FopiesGVars;

#define ELM_GVAR_LIST( list, gvar ) \
    ELM_PLIST( list, gvar )

#define SET_ELM_GVAR_LIST( list, gvar, val ) \
    SET_ELM_PLIST( list, gvar, val )

#define CHANGED_GVAR_LIST( list, gvar ) \
    CHANGED_BAG( list );

#endif

// FlagsGVars contains information about global variables.
// Once cast to a GVarFlagInfo struct, this information is:
//

typedef enum {
    GVarAssignable = 0,
    GVarReadOnly = 1,
    GVarConstant = 2,
} GVarWriteFlag;

typedef struct {
    // 'gvarWriteFlag' is a value of type GVarWriteFlag which denotes whether
    // the variable is assignable, read-only, or constant.
    unsigned char 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.
    unsigned char 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.
    unsigned char isDeclared : 1;
} GVarFlagInfo;

// If this size increases, the type used in GetGVarFlags and
// SetGVarFlags below must be changed
GAP_STATIC_ASSERT(sizeof(GVarFlagInfo) == sizeof(unsigned char),
                  "GVarFlagInfo size mismatch");

static GVarFlagInfo GetGVarFlagInfo(Int gvar)
{
    unsigned char 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;
}

static void SetGVarFlagInfo(Int gvar, GVarFlagInfo info)
{
    unsigned char 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));
}

static void 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
static void SetGVarWriteState(Int gvar, GVarWriteFlag w)
{
    GVarFlagInfo info = GetGVarFlagInfo(gvar);
    info.gvarWriteFlag = w;
    SetGVarFlagInfo(gvar, info);
}

static void SetHasExprCopiesFopies(Int gvar, BOOL set)
{
    GVarFlagInfo info = GetGVarFlagInfo(gvar);
    info.hasExprCopiesFopies = set;
    SetGVarFlagInfo(gvar, info);
}

static void SetIsDeclaredName(Int gvar, BOOL set)
{
    GVarFlagInfo info = GetGVarFlagInfo(gvar);
    info.isDeclared = set;
    SetGVarFlagInfo(gvar, info);
}

BOOL IsDeclaredGVar(UInt gvar)
{
    GVarFlagInfo info = GetGVarFlagInfo(gvar);
    return info.isDeclared;
}


/****************************************************************************
**
*V  ErrorMustEvalToFuncFunc . . . . . . . . .  function that signals an error
*F  ErrorMustEvalToFuncHandler(<self>,<args>) . handler that signals an error
**
**  'ErrorMustEvalToFuncFunc' is a (variable number of  args)  function  that
**  signals the error ``Function: <func> be a function''.
**
**  'ErrorMustEvalToFuncHandler'  is  the  handler  that  signals  the  error
**  ``Function: <func> must be a function''.
*/

Obj             ErrorMustEvalToFuncFunc;

static Obj ErrorMustEvalToFuncHandler(Obj self, Obj args)
{
    ErrorQuit("Function Calls: must be a function", 0, 0);
    return 0;
}


/****************************************************************************
**
*V  ErrorMustHaveAssObjFunc . . . . . . . . .  function that signals an error
*F  ErrorMustHaveAssObjHandler(<self>,<args>) . handler that signals an error
**
**  'ErrorMustHaveAssObjFunc' is a (variable number of  args)  function  that
**  signals the error ``Variable: <<unknown>> must have an assigned value''.
**
**  'ErrorMustHaveAssObjHandler'  is  the  handler  that  signals  the  error
**  ``Variable: <<unknown>> must have an assigned value''.
*/

Obj             ErrorMustHaveAssObjFunc;

static Obj ErrorMustHaveAssObjHandler(Obj self, Obj args)
{
    ErrorQuit("Variable: <> must have an assigned value", 0, 0);
    return 0;
}


/****************************************************************************
**
*F  AssGVar(<gvar>,<val>) . . . . . . . . . . . . assign to a global variable
**
**  'AssGVar' assigns the value <val> to the global variable <gvar>.
*/


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'.
static void 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
    else 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 = ErrorMustEvalToFuncFunc;
        }
    }

    // if this was an unbind, assign the other error function
    else if ( 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);
        }
    }

    AssGVarInternal(gvar, val, info.hasExprCopiesFopies, TRUE);
}

// 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);
    }

    AssGVarInternal(gvar, val, info.hasExprCopiesFopies, FALSE);
}


/****************************************************************************
**
*F  ValAutoGVar(<gvar>) . . . . . . . . value of an automatic global variable
**
**  'ValAutoGVar' returns the value of the global variable <gvar>.  This will
**  be 0 if  <gvar> has  no assigned value.    It will also cause a  function
**  call, if <gvar> is automatic.
*/

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);
        }

    }

    // return the value
    return val;
}

/****************************************************************************
**
*F  ValGVarTL(<gvar>) . . . . . . . . value of a global/thread-local variable
**
**  'ValGVarTL' returns the value of the global or thread-local variable
**  <gvar>.
*/

#ifdef HPCGAP
Obj             ValGVarTL (
    UInt                gvar )
{
    Obj                 expr;
    Obj                 val;

    val = ValGVar(gvar);
    // is this a thread-local variable?
    if ( val == 0 && (expr = ExprGVar(gvar)) != 0 ) {

        if (IS_INTOBJ(expr)) {
          // thread-local variable
          return GetTLRecordField(TLVars, INT_INTOBJ(expr));
        }
    }

    // return the value
    return val;
}

static Obj FuncIsThreadLocalGVar(Obj self, Obj name)
{
    RequireStringRep(SELF_NAME, name);

  UInt gvar = GVarName(CONST_CSTR_STRING(name));
  return (VAL_GVAR_INTERN(gvar) == 0 && IS_INTOBJ(ExprGVar(gvar))) ?
    TrueFalse;
}
#endif


#ifdef USE_GVAR_BUCKETS
static Obj NewGVarBucket(void)
{
    Obj result = NEW_PLIST(T_PLIST, GVAR_BUCKET_SIZE);
    SET_LEN_PLIST(result, GVAR_BUCKET_SIZE);
#ifdef HPCGAP
    MakeBagPublic(result);
#endif
    return result;
}
#endif

Obj NameGVar ( UInt gvar )
{
    return ELM_GVAR_LIST( NameGVars, gvar );
}

Obj ExprGVar ( UInt gvar )
{
    return ELM_GVAR_LIST( ExprGVars, gvar );
}

#define NSCHAR '@'

static Obj FuncSET_NAMESPACE(Obj self, Obj str)
{
    STATE(CurrNamespace) = str;
    return 0;
}

static Obj FuncGET_NAMESPACE(Obj self)
{
    return STATE(CurrNamespace);
}

/****************************************************************************
**
*F  GVarName(<name>)  . . . . . . . . . . . . . .  global variable for a name
**
**  'GVarName' returns the global variable with the name <name>.
*/

UInt GVarName(const Char * name)
{
    Char         gvarbuf[1024];    // temporary copy for namespace
    const Char * 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;
        }
    }

    return LookupSymbol(&GVarSymbolTable, name);
}

void NewGVarCallback(SymbolTable * symtab, UInt numGVars, Obj string)
{
#ifdef USE_GVAR_BUCKETS
    UInt gvar_bucket = GVAR_BUCKET(numGVars);
    if (!ValGVars[gvar_bucket]) {
        ValGVars[gvar_bucket] = NewGVarBucket();
        PtrGVars[gvar_bucket] = ADDR_OBJ(ValGVars[gvar_bucket]) + 1;
        NameGVars[gvar_bucket] = NewGVarBucket();
        FlagsGVars[gvar_bucket] = NewGVarBucket();
        ExprGVars[gvar_bucket] = NewGVarBucket();
        CopiesGVars[gvar_bucket] = NewGVarBucket();
        FopiesGVars[gvar_bucket] = NewGVarBucket();
    }
#else
    GROW_PLIST(ValGVars, numGVars);
    SET_LEN_PLIST(ValGVars, numGVars);
    GROW_PLIST(NameGVars, numGVars);
    SET_LEN_PLIST(NameGVars, numGVars);
    GROW_PLIST(FlagsGVars, numGVars);
    SET_LEN_PLIST(FlagsGVars, numGVars);
    GROW_PLIST(ExprGVars, numGVars);
    SET_LEN_PLIST(ExprGVars, numGVars);
    GROW_PLIST(CopiesGVars, numGVars);
    SET_LEN_PLIST(CopiesGVars, numGVars);
    GROW_PLIST(FopiesGVars, numGVars);
    SET_LEN_PLIST(FopiesGVars, numGVars);
    PtrGVars = ADDR_OBJ(ValGVars);
#endif
    SET_ELM_GVAR_LIST(ValGVars, numGVars, 0);
    SET_ELM_GVAR_LIST(NameGVars, numGVars, string);
    CHANGED_GVAR_LIST(NameGVars, numGVars);
    InitGVarFlagInfo(numGVars);
    SET_ELM_GVAR_LIST(ExprGVars, numGVars, 0);
    SET_ELM_GVAR_LIST(CopiesGVars, numGVars, 0);
    SET_ELM_GVAR_LIST(FopiesGVars, numGVars, 0);
}


/****************************************************************************
**
*F  MakeReadOnlyGVar( <gvar> )  . . . . . .  make a global variable read only
*/

void MakeReadOnlyGVar (
    UInt                gvar )
{
    if (IsConstantGVar(gvar)) {
        ErrorMayQuit("Variable: '%g' is constant", (Int)NameGVar(gvar), 0);
    }
    SetGVarWriteState(gvar, GVarReadOnly);
}

/****************************************************************************
**
*F  MakeConstantGVar( <gvar> )  . . . . . .  make a global variable constant
*/

void MakeConstantGVar(UInt gvar)
{
    SetGVarWriteState(gvar, GVarConstant);
}


/****************************************************************************
**
*F  MakeThreadLocalVar( <gvar> )  . . . . . .  make a variable thread-local
*/

#ifdef HPCGAP
void MakeThreadLocalVar (
    UInt                gvar,
    UInt                rnam )
{
    Obj value = ValGVar(gvar);
    VAL_GVAR_INTERN(gvar) = (Obj) 0;
    if (IS_INTOBJ(ExprGVar(gvar)))
       value = (Obj) 0;
    SET_ELM_GVAR_LIST( ExprGVars, gvar, INTOBJ_INT(rnam) );
    SetHasExprCopiesFopies(gvar, 1);
    CHANGED_GVAR_LIST( ExprGVars, gvar );
    if (value && TLVars)
        SetTLDefault(TLVars, rnam, value);
}
#endif


/****************************************************************************
**
*F  FuncDeclareGlobalName(<self>,<name>)
*/

Obj FuncDeclareGlobalName(Obj self, Obj name)
{
    RequireStringRep("DeclareGlobalName", name);
    SetIsDeclaredName(GVarName(CONST_CSTR_STRING(name)), 1);
    return 0;
}


/****************************************************************************
**
*F  FuncMakeReadOnlyGVar(<self>,<name>)   make a global variable read only
**
**  'FuncMakeReadOnlyGVar' implements the function 'MakeReadOnlyGVar'.
**
**  'MakeReadOnlyGVar( <name> )'
**
**  'MakeReadOnlyGVar' make the global  variable with the name <name>  (which
**  must be a GAP string) read only.
*/

static Obj FuncMakeReadOnlyGVar(Obj self, Obj name)
{
    RequireStringRep(SELF_NAME, name);
    MakeReadOnlyGVar(GVarName(CONST_CSTR_STRING(name)));
    return 0;
}

/****************************************************************************
**
*F  FuncMakeConstantGVar(<self>,<name>)   make a global variable constant
**
**  'FuncMakeConstantGVar' implements the function 'MakeConstantGVar'.
**
**  'MakeConstantGVar( <name> )'
**
**  'MakeConstantGVar' make the global  variable with the name <name>  (which
**  must be a GAP string) constant.
*/

static Obj FuncMakeConstantGVar(Obj self, Obj name)
{
    RequireStringRep(SELF_NAME, name);
    MakeConstantGVar(GVarName(CONST_CSTR_STRING(name)));
    return 0;
}

/****************************************************************************
**
*F  MakeReadWriteGVar( <gvar> ) . . . . . . make a global variable read write
*/

void MakeReadWriteGVar (
    UInt                gvar )
{
    if (IsConstantGVar(gvar)) {
        ErrorMayQuit("Variable: '%g' is constant", (Int)NameGVar(gvar), 0);
    }
    SetGVarWriteState(gvar, GVarAssignable);
}


/****************************************************************************
**
*F  FuncMakeReadWriteGVar(<self>,<name>) make a global variable read write
**
**  'FuncMakeReadWriteGVar' implements the function 'MakeReadWriteGVar'.
**
**  'MakeReadWriteGVar( <name> )'
**
**  'MakeReadWriteGVar' make the global  variable with the name <name>  (which
**  must be a GAP string) read and writable.
*/

static Obj FuncMakeReadWriteGVar(Obj self, Obj name)
{
    RequireStringRep(SELF_NAME, name);
    MakeReadWriteGVar(GVarName(CONST_CSTR_STRING(name)));
    return 0;
}

/****************************************************************************
**
*F  IsReadOnlyGVar( <gvar> ) . . . . . . return status of a global variable
*/

BOOL IsReadOnlyGVar(UInt gvar)
{
    return GetGVarFlagInfo(gvar).gvarWriteFlag == GVarReadOnly;
}

/****************************************************************************
**
*F  FuncIsReadOnlyGVar( <name> ) . . .handler for GAP function
**
*/


static Obj FuncIsReadOnlyGVar (
    Obj                 self,
    Obj                 name )
{
    RequireStringRep(SELF_NAME, name);
    return IsReadOnlyGVar(GVarName(CONST_CSTR_STRING(name))) ? True : False;
}

/****************************************************************************
**
*F  IsConstantGVar( <gvar> ) . . . . . . return if a variable is a constant
*/

BOOL IsConstantGVar(UInt gvar)
{
    return GetGVarFlagInfo(gvar).gvarWriteFlag == GVarConstant;
}

/****************************************************************************
**
*F  FuncIsConstantGVar( <name> ) . . .handler for GAP function
**
*/


static Obj FuncIsConstantGVar(Obj self, Obj name)
{
    RequireStringRep(SELF_NAME, name);
    return IsConstantGVar(GVarName(CONST_CSTR_STRING(name))) ? True : False;
}


/****************************************************************************
**
*F  FuncAUTO() . . . . . . . . . . . . .   make automatic global variables
**
**  'FuncAUTO' implements the internal function 'AUTO'.
**
**  'AUTO( <func>, <arg>, <name1>, ... )'
**
**  'AUTO' makes   the global variables,  whose  names are given  the strings
**  <name1>, <name2>, ..., automatic.  That means  that when the value of one
**  of  those global  variables  is requested,  then  the function  <func> is
**  called and the  argument <arg>  is passed.   This function  call  should,
**  cause the execution  of an assignment to  that global variable, otherwise
**  an error is signalled.
*/

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 );
    }

    return 0;
}


/****************************************************************************
**
*F  iscomplete( <name>, <len> ) . . . . . . . .  find the completions of name
*F  completion( <name>, <len> ) . . . . . . . .  find the completions of name
*/

BOOL iscomplete_gvar(Char * name, UInt len)
{
    const Char *        curr;
    UInt                i, k;
    UInt                numGVars;

    numGVars = LengthSymbolTable(&GVarSymbolTable);
    for ( i = 1; i <= numGVars; i++ ) {
        curr = CONST_CSTR_STRING( NameGVar( i ) );
        for ( k = 0; name[k] != 0 && curr[k] == name[k]; k++ ) ;
        if (k == len && curr[k] == '\0')
            return TRUE;
    }
    return FALSE;
}

UInt            completion_gvar (
    Char *              name,
    UInt                len )
{
    const Char *        curr;
    const Char *        next;
    UInt                i, k;
    UInt                numGVars;

    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';
    }

    return next != 0;
}


/****************************************************************************
**
*F  FuncIDENTS_GVAR( <self> ) . . . . . . . . . .  idents of global variables
*/

static Obj FuncIDENTS_GVAR(Obj self)
{
    Obj                 copy;
    UInt                i;
    UInt                numGVars;
    Obj                 strcopy;

    numGVars = LengthSymbolTable(&GVarSymbolTable);

    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;
}

static Obj FuncIDENTS_BOUND_GVARS(Obj self)
{
    Obj                 copy;
    UInt                i, j;
    UInt                numGVars;
    Obj                 strcopy;

    numGVars = LengthSymbolTable(&GVarSymbolTable);

    copy = NEW_PLIST_IMM( T_PLIST, numGVars );
    for ( i = 1, j = 1;  i <= numGVars;  i++ ) {
        if ( VAL_GVAR_INTERN( i ) || ELM_GVAR_LIST( ExprGVars, 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, j, strcopy );
           CHANGED_BAG( copy );
           j++;
        }
    }
    SET_LEN_PLIST( copy, j - 1 );
    return copy;
}

/****************************************************************************
**
*F  FuncASS_GVAR( <self>, <gvar>, <val> ) . . . . assign to a global variable
*/

static Obj FuncASS_GVAR(Obj self, Obj gvar, Obj val)
{
    RequireStringRep(SELF_NAME, gvar);
    AssGVar( GVarName( CONST_CSTR_STRING(gvar) ), val );
    return 0;
}


/****************************************************************************
**
*F  FuncISB_GVAR( <self>, <gvar> )  . . check assignment of a global variable
*/

static Obj FuncISB_GVAR(Obj self, Obj gvar)
{
    RequireStringRep(SELF_NAME, gvar);

    UInt gv = GVarName( CONST_CSTR_STRING(gvar) );
    if (VAL_GVAR_INTERN(gv))
      return True;
    Obj expr = ExprGVar(gv);
#ifdef HPCGAP
    if (expr && !IS_INTOBJ(expr)) // auto gvar
      return True;
    if (!expr || !TLVars)
      return False;
    return GetTLRecordField(TLVars, INT_INTOBJ(expr)) ? True : False;
#else
    return expr ? True : False;
#endif
}

/****************************************************************************
**
*F  FuncIS_AUTO_GVAR( <self>, <gvar> ) . . check if a global variable is auto
*/


static Obj FuncIS_AUTO_GVAR(Obj self, Obj gvar)
{
    RequireStringRep(SELF_NAME, gvar);
    Obj expr = ExprGVar(GVarName( CONST_CSTR_STRING(gvar) ) );
    return (expr && !IS_INTOBJ(expr)) ? True : False;
}


/****************************************************************************
**
*F  FuncVAL_GVAR( <self>, <gvar> )  . . contents of a global variable
*/


static Obj FuncVAL_GVAR(Obj self, Obj gvar)
{
    Obj val;

    RequireStringRep(SELF_NAME, gvar);

    val = ValAutoGVar( GVarName( CONST_CSTR_STRING(gvar) ) );

    if (val == 0)
        ErrorMayQuit("VAL_GVAR: No value bound to %g", (Int)gvar, 0);
    return val;
}

/****************************************************************************
**
*F  FuncUNB_GVAR( <self>, <gvar> )  . . unbind a global variable
*/


static Obj FuncUNB_GVAR(Obj self, Obj gvar)
{
    RequireStringRep(SELF_NAME, gvar);
    AssGVar( GVarName( CONST_CSTR_STRING(gvar) ), (Obj)0 );
    return 0;
}



/****************************************************************************
**
*F * * * * * * * * * * * * * copies and fopies  * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*V  CopyAndFopyGVars  . . . . . .  kernel table of kernel copies and "fopies"
**
**  This needs to be kept inside the kernel so that the copies can be updated
**  after loading a workspace.
*/

typedef struct  {
    Obj *               copy;
    UInt                isFopy;
    const Char *        name;
} StructCopyGVar;

enum {
    MAX_COPY_AND_FOPY_GVARS = 30000
};

static StructCopyGVar CopyAndFopyGVars[MAX_COPY_AND_FOPY_GVARS];
static Int NCopyAndFopyGVars = 0;


/****************************************************************************
**
*F  InitCopyGVar( <name>, <copy> )  . .  declare C variable as copy of global
**
**  'InitCopyGVar' makes  the C variable <cvar>  at address  <copy> a copy of
**  the global variable named <name> (which must be a kernel string).
**
**  The function only registers the  information in <CopyAndFopyGVars>.  At a
**  latter stage one  has to call  'UpdateCopyFopyInfo' to actually enter the
**  information stored in <CopyAndFopyGVars> into a plain list.
**
**  This is OK for garbage collection, but  a real problem  for saving in any
**  event, this information  does not really want to  be saved  because it is
**  kernel centred rather than workspace centred.
*/

void InitCopyGVar (
    const Char *        name ,
    Obj *               copy )
{
    // make a record in the kernel for saving and loading
#ifdef HPCGAP
    LockSymbolTableForWriting(&GVarSymbolTable);
#endif
    if ( NCopyAndFopyGVars >= MAX_COPY_AND_FOPY_GVARS ) {
#ifdef HPCGAP
        UnlockSymbolTable(&GVarSymbolTable);
#endif
        Panic("no room to record CopyGVar");
    }
    CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy;
    CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 0;
    CopyAndFopyGVars[NCopyAndFopyGVars].name = name;
    NCopyAndFopyGVars++;
#ifdef HPCGAP
    UnlockSymbolTable(&GVarSymbolTable);
#endif
}


/****************************************************************************
**
*F  InitFopyGVar( <name>, <copy> )  . .  declare C variable as copy of global
**
**  'InitFopyGVar' makes the C variable <cvar> at address <copy> a (function)
**  copy  of the  global variable <gvar>,  whose name  is <name>.  That means
**  that whenever   the value  of   <gvar> is a    function, then <cvar> will
**  reference the same value (i.e., will hold the same bag identifier).  When
**  the value  of <gvar>  is not a   function, then  <cvar> will  reference a
**  function  that signals  the error ``<func>  must be  a function''.   When
**  <gvar> has no assigned value, then <cvar> will  reference a function that
**  signals the error ``<gvar> must have an assigned value''.
*/

void InitFopyGVar (
    const Char *        name,
    Obj *               copy )
{
    // make a record in the kernel for saving and loading
#ifdef HPCGAP
    LockSymbolTableForWriting(&GVarSymbolTable);
#endif
    if ( NCopyAndFopyGVars >= MAX_COPY_AND_FOPY_GVARS ) {
#ifdef HPCGAP
        UnlockSymbolTable(&GVarSymbolTable);
#endif
        Panic("no room to record FopyGVar");
    }
    CopyAndFopyGVars[NCopyAndFopyGVars].copy = copy;
    CopyAndFopyGVars[NCopyAndFopyGVars].isFopy = 1;
    CopyAndFopyGVars[NCopyAndFopyGVars].name = name;
    NCopyAndFopyGVars++;
#ifdef HPCGAP
    UnlockSymbolTable(&GVarSymbolTable);
#endif
}


/****************************************************************************
**
*F  UpdateCopyFopyInfo()  . . . . . . . . . .  convert kernel info into plist
*/

static Int NCopyAndFopyDone = 0;

#ifdef HPCGAP
static void DeclareAllGVars( void );
#endif

void UpdateCopyFopyInfo ( void )
{
    Obj                 cops;           // copies list
    UInt                gvar;
    const Char *        name;           // name of the variable
    Obj *               copy;           // address of the copy

#ifdef HPCGAP
    LockSymbolTableForWriting(&GVarSymbolTable);
#endif
    // loop over new copies and fopies
    for ( ; NCopyAndFopyDone < NCopyAndFopyGVars; NCopyAndFopyDone++ ) {
        name = CopyAndFopyGVars[NCopyAndFopyDone].name;
        copy = CopyAndFopyGVars[NCopyAndFopyDone].copy;
        gvar = GVarName(name);

        // get the copies list and its length
        if ( CopyAndFopyGVars[NCopyAndFopyDone].isFopy ) {
            cops = ELM_GVAR_LIST( FopiesGVars, gvar );
            if ( cops == 0 ) {
                cops = NEW_PLIST( T_PLIST, 0 );
#ifdef HPCGAP
                MakeBagPublic(cops);
#endif
                SET_ELM_GVAR_LIST( FopiesGVars, gvar, cops );
                SetHasExprCopiesFopies(gvar, 1);
                CHANGED_GVAR_LIST( FopiesGVars, gvar );
            }
        }
        else {
            cops = ELM_GVAR_LIST( CopiesGVars, gvar );
            if ( cops == 0 ) {
                cops = NEW_PLIST( T_PLIST, 0 );
#ifdef HPCGAP
                MakeBagPublic(cops);
#endif
                SET_ELM_GVAR_LIST( CopiesGVars, gvar, cops );
                SetHasExprCopiesFopies(gvar, 1);
                CHANGED_GVAR_LIST( CopiesGVars, gvar );
            }
        }

        // 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;
            }
            else if ( val != 0 ) {
                *copy = ErrorMustEvalToFuncFunc;
            }
            else {
                *copy = ErrorMustHaveAssObjFunc;
            }
        }
        else {
            *copy = val;
        }
    }
#ifdef HPCGAP
    DeclareAllGVars();
    UnlockSymbolTable(&GVarSymbolTable);
#endif
}


/****************************************************************************
**
*F  RemoveCopyFopyInfo()  . . . remove the info about copies of gvars from ws
*/

static void RemoveCopyFopyInfo( void )
{
#ifdef HPCGAP
    LockSymbolTableForWriting(&GVarSymbolTable);
#endif

#ifdef USE_GVAR_BUCKETS
    UInt        i, k, l;

    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

    NCopyAndFopyDone = 0;

#ifdef HPCGAP
    UnlockSymbolTable(&GVarSymbolTable);
#endif
}


/****************************************************************************
**
*/

static void GVarsAfterCollectBags(void)
{
#ifdef USE_GVAR_BUCKETS
  for (int i = 0; i < GVAR_BUCKETS; i++) {
    if (ValGVars[i])
      PtrGVars[i] = ADDR_OBJ( ValGVars[i] ) + 1;
    else
      break;
  }
#else
  if (ValGVars)
    PtrGVars = ADDR_OBJ( ValGVars );
#endif
}


#ifdef HPCGAP

static GVarDescriptor * FirstDeclaredGVar;
static GVarDescriptor * LastDeclaredGVar;

/****************************************************************************
**
*F  DeclareGVar(<gvar>, <name>) . . . . . .  declare global variable by name
*F  GVarValue(<gvar>) . . . . . . . . . return value of <gvar>, 0 if unbound
*F  GVarObj(<gvar>) . . . . . . . . return value of <gvar>, error if unbound
*F  GVarFunction(<gvar>) . . return value of <gvar>, error if not a function
*F  GVarOptFunction(<gvar>) return value of <gvar>, 0 if unbound/no function
*F  SetGVar(<gvar>, <obj>) . . . . . . . . . . . . .  assign <obj> to <gvar>
*/


void DeclareGVar(GVarDescriptor *gvar, const char *name)
{
  gvar->ref = NULL;
  gvar->name = name;
  gvar->next = NULL;
  if (LastDeclaredGVar) {
    LastDeclaredGVar->next = gvar;
    LastDeclaredGVar = gvar;
  } else {
    FirstDeclaredGVar = gvar;
    LastDeclaredGVar = gvar;
  }
}

static void DeclareAllGVars( void )
{
  GVarDescriptor *gvar;
  for (gvar = FirstDeclaredGVar; gvar; gvar = gvar->next) {
    UInt index = GVarName(gvar->name);
    gvar->ref = &(VAL_GVAR_INTERN(index));
  }
  FirstDeclaredGVar = LastDeclaredGVar = 0;
}

Obj GVarValue(GVarDescriptor *gvar)
{
  Obj result = *(gvar->ref);
  MEMBAR_READ();
  return result;
}

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;
}

void SetGVar(GVarDescriptor *gvar, Obj obj)
{
  MEMBAR_WRITE();
  *(gvar->ref) = obj;
}

#endif


/****************************************************************************
**
*F * * * * * * * * * * * * * initialize module * * * * * * * * * * * * * * *
*/



/****************************************************************************
**
*V  GVarFuncs . . . . . . . . . . . . . . . . . . list of functions to export
*/

static StructGVarFunc GVarFuncs[] = {

    GVAR_FUNC_1ARGS(MakeReadOnlyGVar, name),
    GVAR_FUNC_1ARGS(MakeReadWriteGVar, name),
    GVAR_FUNC_1ARGS(MakeConstantGVar, name),
    GVAR_FUNC_1ARGS(IsReadOnlyGVar, name),
    GVAR_FUNC_1ARGS(IsConstantGVar, name),
    GVAR_FUNC_XARGS(AUTO, -3, "func, arg, names"),

    GVAR_FUNC_1ARGS(DeclareGlobalName, name),

    GVAR_FUNC_0ARGS(IDENTS_GVAR),
    GVAR_FUNC_0ARGS(IDENTS_BOUND_GVARS),
    GVAR_FUNC_1ARGS(ISB_GVAR, gvar),
    GVAR_FUNC_1ARGS(IS_AUTO_GVAR, gvar),
    GVAR_FUNC_2ARGS(ASS_GVAR, gvar, value),
    GVAR_FUNC_1ARGS(VAL_GVAR, gvar),
    GVAR_FUNC_1ARGS(UNB_GVAR, gvar),
    GVAR_FUNC_1ARGS(SET_NAMESPACE, str),
    GVAR_FUNC_0ARGS(GET_NAMESPACE),
#ifdef HPCGAP
    GVAR_FUNC_1ARGS(IsThreadLocalGVar, name),
#endif

    { 0, 0, 0, 0, 0 }

};


/****************************************************************************
**
*F  InitKernel( <module> )  . . . . . . . . initialise kernel data structures
*/

static Int InitKernel (
    StructInitInfo *    module )
{
    // init global bags and handler
    InitGlobalBag( &ErrorMustEvalToFuncFunc,
                   "src/gvars.c:ErrorMustEvalToFuncFunc" );
    InitGlobalBag( &ErrorMustHaveAssObjFunc,
                   "src/gvars.c:ErrorMustHaveAssObjFunc" );
#ifdef USE_GVAR_BUCKETS
    int i;
    static char cookies[6][GVAR_BUCKETS][10];

    for (i=0; i<GVAR_BUCKETS; i++) {
      sprintf((cookies[0][i]), "Vgv%d", i);
      sprintf((cookies[1][i]), "Ngv%d", i);
      sprintf((cookies[2][i]), "Wgv%d", i);
      sprintf((cookies[3][i]), "Egv%d", i);
      sprintf((cookies[4][i]), "Cgv%d", i);
      sprintf((cookies[5][i]), "Fgv%d", i);
      InitGlobalBag( ValGVars+i, (cookies[0][i]) );
      InitGlobalBag( NameGVars+i, (cookies[1][i]) );
      InitGlobalBag(FlagsGVars + i, (cookies[2][i]));
      InitGlobalBag( ExprGVars+i, (cookies[3][i]) );
      InitGlobalBag( CopiesGVars+i, (cookies[4][i]) );
      InitGlobalBag( FopiesGVars+i, (cookies[5][i])  );
    }
#else
    InitGlobalBag( &ValGVars,
                   "src/gvars.c:ValGVars" );
    InitGlobalBag( &NameGVars,
                   "src/gvars.c:NameGVars" );
    InitGlobalBag(&FlagsGVars, "src/gvars.c:FlagsGVars");
    InitGlobalBag( &ExprGVars,
                   "src/gvars.c:ExprGVars" );
    InitGlobalBag( &CopiesGVars,
                   "src/gvars.c:CopiesGVars" );
    InitGlobalBag( &FopiesGVars,
                   "src/gvars.c:FopiesGVars"  );
#endif

    InitGlobalBag( &STATE(CurrNamespace),
                   "src/gvars.c:CurrNamespace" );

    InitSymbolTableKernel(&GVarSymbolTable, "src/gvars.c:GVarSymbolCount",
                          "src/gvars.c:GVarSymbolTable", NameGVar,
                          NewGVarCallback);

    InitHandlerFunc( ErrorMustEvalToFuncHandler,
                     "src/gvars.c:ErrorMustEvalToFuncHandler" );
    InitHandlerFunc( ErrorMustHaveAssObjHandler,
                     "src/gvars.c:ErrorMustHaveAssObjHandler" );

#ifdef USE_GASMAN
    // install post-GC callback
    RegisterAfterCollectFuncBags(GVarsAfterCollectBags);
#endif

    // init filters and functions
    InitHdlrFuncsFromTable( GVarFuncs );

#ifdef HPCGAP
    // For thread-local variables
    InitCopyGVar("ThreadVar", &TLVars);
#endif

    // Get a copy of REREADING
    ImportGVarFromLibrary("REREADING", &REREADING);


    return 0;
}


/****************************************************************************
**
*F  PostRestore( <module> ) . . . . . . . . . . . . . after restore workspace
*/


static Int PostRestore (
    StructInitInfo *    module )
{
    // restore PtrGVars
    GVarsAfterCollectBags();

    // update fopies and copies
    UpdateCopyFopyInfo();

    return 0;
}

/****************************************************************************
**
*F  PreSave( <module> ) . . . . . . . . . . . . . before save workspace
*/

static Int PreSave (
    StructInitInfo *    module )
{
  RemoveCopyFopyInfo();
  return 0;
}

/****************************************************************************
**
*F  PostSave( <module> ) . . . . . . . . . . . . . after save workspace
*/

static Int PostSave (
    StructInitInfo *    module )
{
  UpdateCopyFopyInfo();
  return 0;
}


/****************************************************************************
**
*F  InitLibrary( <module> ) . . . . . . .  initialise library data structures
*/

static Int InitLibrary (
    StructInitInfo *    module )
{
    InitSymbolTableLibrary(&GVarSymbolTable, 28069);

    // make the error functions for 'AssGVar'
    ErrorMustEvalToFuncFunc = NewFunctionC(
        "ErrorMustEvalToFunc", -1, "args", ErrorMustEvalToFuncHandler);

    ErrorMustHaveAssObjFunc = NewFunctionC(
        "ErrorMustHaveAssObj", -1, "args", ErrorMustHaveAssObjHandler);

#if !defined(USE_GVAR_BUCKETS)
    // make the lists for global variables
    ValGVars = NEW_PLIST( T_PLIST, 0 );
    NameGVars = NEW_PLIST( T_PLIST, 0 );
    FlagsGVars = NEW_PLIST(T_PLIST, 0);
    ExprGVars = NEW_PLIST( T_PLIST, 0 );
    CopiesGVars = NEW_PLIST( T_PLIST, 0 );
    FopiesGVars = NEW_PLIST( T_PLIST, 0 );
#endif

    // fix C vars
    PostRestore( module );

    // init filters and functions
    InitGVarFuncsFromTable( GVarFuncs );

    return 0;
}


/****************************************************************************
**
*F  CheckInit( <module> ) . . . . . . . . . . . . . . .  check initialisation
*/

static Int CheckInit (
    StructInitInfo *    module )
{
    Int                 success = 1;

    if ( NCopyAndFopyGVars != NCopyAndFopyDone ) {
        success = 0;
        Pr("#W failed to updated copies and fopies\n", 0, 0);
    }

    return ! success;
}


static Int InitModuleState(void)
{
    // Create the current namespace:
    STATE(CurrNamespace) = NEW_STRING(0);
    SET_LEN_STRING(STATE(CurrNamespace), 0);

    return 0;
}


/****************************************************************************
**
*F  InitInfoGVars() . . . . . . . . . . . . . . . . . table of init functions
*/

static StructInitInfo module = {
    // init struct using C99 designated initializers; for a full list of
    // fields, please refer to the definition of StructInitInfo
    .type = MODULE_BUILTIN,
    .name = "gvars",
    .initKernel = InitKernel,
    .initLibrary = InitLibrary,
    .checkInit = CheckInit,
    .preSave = PreSave,
    .postSave = PostSave,
    .postRestore = PostRestore,
    .initModuleState = InitModuleState,
};

StructInitInfo * InitInfoGVars ( void )
{
    return &module;
}

87%


¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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 ist noch experimentell.