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 65 kB image not shown  

Quelle  objects.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 objects package.
*/


#include "objects.h"

#include "bool.h"
#include "calls.h"
#include "error.h"
#include "gapstate.h"
#include "gvars.h"
#include "io.h"
#include "lists.h"
#include "modules.h"
#include "opers.h"
#include "plist.h"
#include "precord.h"
#include "records.h"
#include "saveload.h"
#include "stringobj.h"

#ifdef HPCGAP
#include "hpc/aobjects.h"
#include "hpc/guards.h"
#include "hpc/thread.h"
#include "hpc/traverse.h"
#include <stdio.h>      // for sprintf
#include <stdlib.h>     // for getenv
#endif

#if defined(USE_THREADSAFE_COPYING)
#include "hpc/traverse.h"
#endif

enum {
    MAXPRINTDEPTH = 64,
};

static ModuleStateOffset ObjectsStateOffset = -1;

typedef struct {
    UInt  PrintObjDepth;
    Obj   PrintObjThiss[MAXPRINTDEPTH];
    Int   PrintObjIndices[MAXPRINTDEPTH];

    // This variable is used to allow a ViewObj method to call PrintObj on the
    // same object without triggering use of '~'. It contains one of the
    // values 0, 1 and 2 according to whether ...
    // 0: there is no enclosing call to PrintObj or ViewObj still open, or
    // 1: the innermost such is PrintObj, or
    // 2: the innermost such is ViewObj.
    UInt LastPV;

} ObjectsModuleState;


static Int lastFreePackageTNUM = FIRST_PACKAGE_TNUM;


static Obj TYPE_KERNEL_OBJECT;


/****************************************************************************
**
*V  NameOfType[<type>] . . . . . . . . . . . . . . . . . . . . names of types
**
**  'NameOfType[<type>]' is the name of the type <type>.
*/

static const char * NameOfType[NUM_TYPES];


/****************************************************************************
**
*F  RegisterPackageTNUM( <name>, <typeObjFunc> )
**
**  Allocates a TNUM for use by a package. The parameters <name> and
**  <typeObjFunc> are used to initialize the relevant entries in the
**  InfoBags and TypeObjFuncs arrays.
**
**  If allocation fails (e.g. because no more TNUMs are available),
**  a negative value is returned.
*/

Int RegisterPackageTNUM( const char *name, Obj (*typeObjFunc)(Obj obj) )
{
#ifdef HPCGAP
    HashLock(0);
#endif

    if (lastFreePackageTNUM > LAST_PACKAGE_TNUM)
        return -1;

    Int tnum = lastFreePackageTNUM++;
#ifdef HPCGAP
    HashUnlock(0);
#endif

    SET_TNAM_TNUM(tnum, name);
    TypeObjFuncs[tnum] = typeObjFunc;

    return tnum;
}

const Char * TNAM_TNUM(UInt tnum)
{
    return NameOfType[tnum];
}

void SET_TNAM_TNUM(UInt tnum, const Char *name)
{
    GAP_ASSERT(NameOfType[tnum] == 0);
    NameOfType[tnum] = name;
}


/****************************************************************************
**
*F  FuncFAMILY_TYPE( <self>, <type> ) . . . . . . handler for 'FAMILY_TYPE'
*/

static Obj FuncFAMILY_TYPE(Obj self, Obj type)
{
    return FAMILY_TYPE( type );
}


/****************************************************************************
**
*F  FuncFAMILY_OBJ( <self>, <obj> ) . . . . . . .  handler for 'FAMILY_OBJ'
*/

static Obj FuncFAMILY_OBJ(Obj self, Obj obj)
{
    return FAMILY_OBJ( obj );
}


/****************************************************************************
**
*F  TYPE_OBJ( <obj> ) . . . . . . . . . . . . . . . . . . . type of an object
**
**  'TYPE_OBJ' returns the type of the object <obj>.
**
**  'TYPE_OBJ' is defined in the declaration part of this package.
*/

Obj (*TypeObjFuncs[LAST_REAL_TNUM+1]) ( Obj obj );

static Obj TypeObjError(Obj obj)
{
    ErrorQuit("Panic: basic object of type '%s' is unkind",
              (Int)TNAM_OBJ(obj), 0);
    return 0;
}

/****************************************************************************
**
*F  SET_TYPE_OBJ( <obj>, <type> ) . . . . . . . . . . . set type of an object
**
**  'SET_TYPE_OBJ' sets the type of the object <obj> to <type>; if <obj>
**  is not a posobj/comobj/datobj, attempts to first convert it to one; if
**  that fails, an error is raised.
*/

void SET_TYPE_OBJ(Obj obj, Obj type)
{
    switch (TNUM_OBJ(obj)) {
#ifdef HPCGAP
    case T_ALIST:
    case T_FIXALIST:
        HashLock(obj);
        ADDR_OBJ(obj)[1] = type;
        CHANGED_BAG(obj);
        RetypeBag(obj, T_APOSOBJ);
        HashUnlock(obj);
        MEMBAR_WRITE();
        break;
    case T_APOSOBJ:
        HashLock(obj);
        ADDR_OBJ(obj)[1] = type;
        CHANGED_BAG(obj);
        HashUnlock(obj);
        MEMBAR_WRITE();
        break;
    case T_AREC:
    case T_ACOMOBJ:
        ADDR_OBJ(obj)[0] = type;
        CHANGED_BAG(obj);
        RetypeBag(obj, T_ACOMOBJ);
        MEMBAR_WRITE();
        break;
#endif
    case T_PREC:
#ifdef HPCGAP
        MEMBAR_WRITE();
#endif
        RetypeBag(obj, T_COMOBJ);
        SET_TYPE_COMOBJ(obj, type);
        CHANGED_BAG(obj);
        break;
    case T_COMOBJ:
#ifdef HPCGAP
        ReadGuard(obj);
        MEMBAR_WRITE();
#endif
        SET_TYPE_COMOBJ(obj, type);
        CHANGED_BAG(obj);
        break;
    case T_POSOBJ:
#ifdef HPCGAP
        ReadGuard(obj);
        MEMBAR_WRITE();
#endif
        SET_TYPE_POSOBJ(obj, type);
        CHANGED_BAG(obj);
        break;
    case T_DATOBJ:
        SetTypeDatObj(obj, type);
        break;

    default:
        if (!IS_PLIST(obj)) {
            ErrorMayQuit("cannot change type of a %s", (Int)TNAM_OBJ(obj), 0);
        }
        // TODO: we should also reject immutable plists, but that risks
        // breaking existing code
#ifdef HPCGAP
        MEMBAR_WRITE();
#endif
        RetypeBag(obj, T_POSOBJ);
        SET_TYPE_POSOBJ(obj, type);
        CHANGED_BAG(obj);
        break;
    }
}


/****************************************************************************
**
*F  FuncTYPE_OBJ( <self>, <obj> ) . . . . . . . . .  handler for 'TYPE_OBJ'
*/

#ifndef WARD_ENABLED
static Obj FuncTYPE_OBJ(Obj self, Obj obj)
{
    return TYPE_OBJ( obj );
}
#endif

/****************************************************************************
**
*F  FuncSET_TYPE_OBJ( <self>, <obj>, <type> ) . . handler for 'SET_TYPE_OBJ'
*/

static Obj FuncSET_TYPE_OBJ(Obj self, Obj obj, Obj type)
{
    SET_TYPE_OBJ( obj, type );
    return (Obj) 0;
}



/****************************************************************************
**
*F  IS_MUTABLE_OBJ( <obj> ) . . . . . . . . . . . . . .  is an object mutable
**
**  'IS_MUTABLE_OBJ' returns   1 if the object  <obj> is mutable   (i.e., can
**  change due to assignments), and 0 otherwise.
**
**  'IS_MUTABLE_OBJ' is defined in the declaration part of this package.
*/

BOOL (*IsMutableObjFuncs[LAST_REAL_TNUM + 1])(Obj obj);

static Obj IsMutableObjFilt;

static BOOL IsMutableObjError(Obj obj)
{
    ErrorQuit("Panic: tried to test mutability of unsupported type '%s'",
              (Int)TNAM_OBJ(obj), 0);
    return FALSE;
}

static BOOL IsMutableObjObject(Obj obj)
{
#ifdef HPCGAP
    if (RegionBag(obj) == ReadOnlyRegion)
        return FALSE;
#endif
    return (DoFilter( IsMutableObjFilt, obj ) == True);
}


/****************************************************************************
**
*F  FiltIS_MUTABLE_OBJ( <self>, <obj> )  . . .  handler for 'IS_MUTABLE_OBJ'
*/

static Obj FiltIS_MUTABLE_OBJ(Obj self, Obj obj)
{
    return (IS_MUTABLE_OBJ( obj ) ? True : False);
}

/****************************************************************************
**
*F  FiltIS_INTERNALLY_MUTABLE_OBJ(<self>, <obj>)
*/


#ifdef HPCGAP

static Obj IsInternallyMutableObjFilt;

static Obj FiltIS_INTERNALLY_MUTABLE_OBJ(Obj self, Obj obj)
{
    return (TNUM_OBJ(obj) == T_DATOBJ &&
      RegionBag(obj) != ReadOnlyRegion &&
      DoFilter( IsInternallyMutableObjFilt, obj) == True) ? True : False;
}

BOOL IsInternallyMutableObj(Obj obj)
{
    return TNUM_OBJ(obj) == T_DATOBJ &&
      RegionBag(obj) != ReadOnlyRegion &&
      DoFilter( IsInternallyMutableObjFilt, obj) == True;
}

#endif


/****************************************************************************
**
*F  IS_COPYABLE_OBJ(<obj>)  . . . . . . . . . . . . . . is an object copyable
**
**  'IS_COPYABLE_OBJ' returns 1 if the object <obj> is copyable (i.e., can be
**  copied into a mutable object), and 0 otherwise.
**
**  'IS_COPYABLE_OBJ' is defined in the declaration part of this package.
*/

BOOL (*IsCopyableObjFuncs[LAST_REAL_TNUM + 1])(Obj obj);

static Obj IsCopyableObjFilt;

static BOOL IsCopyableObjError(Obj obj)
{
    ErrorQuit("Panic: tried to test copyability of unsupported type '%s'",
              (Int)TNAM_OBJ(obj), 0);
    return FALSE;
}

static BOOL IsCopyableObjObject(Obj obj)
{
    return (DoFilter( IsCopyableObjFilt, obj ) == True);
}


/****************************************************************************
**
*F  FiltIS_COPYABLE_OBJ( <self>, <obj> ) . . . handler for 'IS_COPYABLE_OBJ'
*/

static Obj FiltIS_COPYABLE_OBJ(Obj self, Obj obj)
{
    return (IS_COPYABLE_OBJ( obj ) ? True : False);
}


/****************************************************************************
**
*V  ShallowCopyObjFuncs[<type>] . . . . . . . . . .  shallow copier functions
*/

Obj (*ShallowCopyObjFuncs[LAST_REAL_TNUM+1]) ( Obj obj );

static Obj ShallowCopyObjOper;


/****************************************************************************
**
*F  ShallowCopyObjError( <obj> )  . . . . . . . . . . . . . . .  unknown type
*/

static Obj ShallowCopyObjError(Obj obj)
{
    ErrorQuit("Panic: tried to shallow copy object of unsupported type '%s'",
              (Int)TNAM_OBJ(obj), 0);
    return (Obj)0;
}


/****************************************************************************
**
*F  ShallowCopyObjConstant( <obj> ) . . . . . . . . . . . . . . .  do nothing
*/

static Obj ShallowCopyObjConstant(Obj obj)
{
    return obj;
}


/****************************************************************************
**
*F  ShallowCopyObjObject( <obj> ) . . . . . . . . . . . . . . . . call method
*/

static Obj ShallowCopyObjObject(Obj obj)
{
    return DoOperation1Args( ShallowCopyObjOper, obj );
}


/****************************************************************************
**
*F  ShallowCopyObjDefault( <obj> )  . . . . . . . . . .  default shallow copy
*/

static Obj ShallowCopyObjDefault(Obj obj)
{
    Obj                 new;
    const Obj *         o;
    Obj *               n;

    // make the new object and copy the contents
    new = NewBag( MUTABLE_TNUM(TNUM_OBJ(obj)), SIZE_OBJ(obj) );
    o = CONST_ADDR_OBJ(obj);
    n = ADDR_OBJ( new );
    memcpy(n, o, SIZE_OBJ(obj) );

    // 'CHANGED_BAG(new);' not needed, <new> is newest object
    return new;
}


/****************************************************************************
**
*F  FuncSHALLOW_COPY_OBJ( <self>, <obj> ) . .  handler for 'SHALLOW_COPY_OBJ'
*/

static Obj FuncSHALLOW_COPY_OBJ(Obj self, Obj obj)
{
    return SHALLOW_COPY_OBJ( obj );
}


/****************************************************************************
**
*F  CopyObj( <obj>, <mut> ) . . . . . . . make a structural copy of an object
**
**  'CopyObj' only calls 'COPY_OBJ' and then 'CLEAN_OBJ'.
*/

Obj CopyObj (
    Obj                 obj,
    Int                 mut )
{
#ifdef USE_THREADSAFE_COPYING
    return CopyReachableObjectsFrom(obj, 0, 0, !mut);
#else
    Obj                 new;            // copy of <obj>

    // make a copy
    new = COPY_OBJ( obj, mut );

    // clean up the marks
    CLEAN_OBJ( obj );

    // return the copy
    return new;
#endif
}


#if !defined(USE_THREADSAFE_COPYING)

/****************************************************************************
**
*V  CopyObjFuncs[<type>]  . . . . . . . . . . . .  table of copying functions
*/

Obj (*CopyObjFuncs[ LAST_REAL_TNUM+1 ]) ( Obj obj, Int mut );


/****************************************************************************
**
*V  CleanObjFuncs[<type>] . . . . . . . . . . . . table of cleaning functions
*/

void (*CleanObjFuncs[ LAST_REAL_TNUM+1 ]) ( Obj obj );


/****************************************************************************
**
*F  PrepareCopy(<obj>,<copy>) . . .  helper for use in CopyObjFuncs functions
**
*/

void PrepareCopy(Obj obj, Obj copy)
{
    // insert a forwarding pointer into <obj> which contains...
    // - the value overwritten by this forwarding pointer,
    // - a pointer to <copy>,
    // - the TNUM of <obj>.
    // Note that we cannot simply restore the overwritten value by copying
    // the corresponding value from <copy>, as they may actually differ
    // between original and copy (e.g. for objects, they point to the type;
    // if making an immutable copy of a mutable object, the types will
    // differ).
    // Likewise, the TNUM of the copy and the original can and will differ;
    // e.g. for a weak pointer list, the copy can be a plist.
    Obj tmp = NEW_PLIST(T_PLIST, 3);
    SET_LEN_PLIST(tmp, 3);
    SET_ELM_PLIST(tmp, 1, CONST_ADDR_OBJ(obj)[0]);
    SET_ELM_PLIST(tmp, 2, copy);
    SET_ELM_PLIST(tmp, 3, INTOBJ_INT(TNUM_OBJ(obj)));

    // insert the forwarding pointer
    GAP_ASSERT(SIZE_OBJ(obj) >= sizeof(Obj));
    ADDR_OBJ(obj)[0] = tmp;
    CHANGED_BAG(obj);

    // update the TNUM to indicate the object is being copied
    RetypeBag(obj, T_COPYING);
}


/****************************************************************************
**
*F  COPY_OBJ(<obj>) . . . . . . . . . . . make a structural copy of an object
**
**  'COPY_OBJ'  implements  the first pass  of  'CopyObj', i.e., it makes the
**  structural copy of <obj> and marks <obj> as already copied.
*/

Obj COPY_OBJ(Obj obj, Int mut)
{
    UInt tnum = TNUM_OBJ(obj);
    Obj copy;

    if (tnum == T_COPYING) {
        // get the plist reference by the forwarding pointer
        Obj fpl = CONST_ADDR_OBJ(obj)[0];

        // return pointer to the copy
        copy = ELM_PLIST(fpl, 2);
    }
    else if (!IS_MUTABLE_OBJ(obj)) {
        copy = obj;
    }
    else {
        copy = (*CopyObjFuncs[tnum])(obj, mut);
    }
    return copy;
}


/****************************************************************************
**
*F  CLEAN_OBJ(<obj>)  . . . . . . . . . . . . . clean up object after copying
**
**  'CLEAN_OBJ' implements the second pass of 'CopyObj', i.e., it removes the
**  mark from <obj>.
*/

void CLEAN_OBJ(Obj obj)
{
    if (TNUM_OBJ(obj) != T_COPYING)
        return;

    // get the plist reference by the forwarding pointer
    Obj fpl = CONST_ADDR_OBJ(obj)[0];

    // remove the forwarding pointer
    ADDR_OBJ(obj)[0] = ELM_PLIST(fpl, 1);
    CHANGED_BAG(obj);

    // restore the tnum
    UInt tnum = INT_INTOBJ(ELM_PLIST(fpl, 3));
    RetypeBag(obj, tnum);

    // invoke type specific cleanup, if any
    if (CleanObjFuncs[tnum])
        CleanObjFuncs[tnum](obj);
}

#if !defined(USE_THREADSAFE_COPYING) && !defined(USE_BOEHM_GC)

static void MarkCopyingSubBags(Obj obj, void * ref)
{
    Obj fpl = CONST_ADDR_OBJ(obj)[0];

    // mark the forwarding pointer
    MarkBag(fpl, ref);

    // mark the rest as in the non-copied case
    UInt tnum = INT_INTOBJ(ELM_PLIST(fpl, 3));
    TabMarkFuncBags[tnum](obj, ref);
}

#endif


/****************************************************************************
**
*F  CopyObjError( <obj> ) . . . . . . . . . . . . . . . . . . .  unknown type
*/

static Obj CopyObjError(Obj obj, Int mut)
{
    ErrorQuit("Panic: tried to copy object of unsupported type '%s'",
              (Int)TNAM_OBJ(obj), 0);
    return (Obj)0;
}


/****************************************************************************
**
*F  CleanObjError( <obj> )  . . . . . . . . . . . . . . . . . .  unknown type
*/

static void CleanObjError(Obj obj)
{
    ErrorQuit("Panic: tried to clean object of unsupported type '%s'",
              (Int)TNAM_OBJ(obj), 0);
}


/****************************************************************************
**
*F  CopyObjConstant( <obj> )  . . . . . . . . . . . .  copy a constant object
*/

static Obj CopyObjConstant(Obj obj, Int mut)
{
    return obj;
}


/****************************************************************************
**
*F  CopyObjPosObj( <obj>, <mut> ) . . . . . . . . .  copy a positional object
*/

static Obj CopyObjPosObj(Obj obj, Int mut)
{
    Obj                 copy;           // copy, result
    Obj                 tmp;            // temporary variable
    UInt                i;              // loop variable

    // immutable input is handled by COPY_OBJ
    GAP_ASSERT(IS_MUTABLE_OBJ(obj));

    // if the object is not copyable return
    if ( ! IS_COPYABLE_OBJ(obj) ) {
        ErrorQuit("Panic: encountered mutable, non-copyable object", 0, 0);
    }

    // make a copy
    copy = NewBag( TNUM_OBJ(obj), SIZE_OBJ(obj) );
    ADDR_OBJ(copy)[0] = CONST_ADDR_OBJ(obj)[0];
    if ( !mut ) {
        CALL_2ARGS( RESET_FILTER_OBJ, copy, IsMutableObjFilt );
    }

    // leave a forwarding pointer
    PrepareCopy(obj, copy);

    // copy the subvalues
    for ( i = 1; i < SIZE_OBJ(obj)/sizeof(Obj); i++ ) {
        if (CONST_ADDR_OBJ(obj)[i] != 0) {
            tmp = COPY_OBJ(CONST_ADDR_OBJ(obj)[i], mut);
            ADDR_OBJ(copy)[i] = tmp;
            CHANGED_BAG( copy );
        }
    }

    // return the copy
    return copy;
}


/****************************************************************************
**
*F  CleanObjPosObj( <obj> ) . . . . . . . . . . . . . . . . . .  clean posobj
*/

static void CleanObjPosObj(Obj obj)
{
    UInt                i;              // loop variable

    // clean the subvalues
    for ( i = 1; i < SIZE_OBJ(obj)/sizeof(Obj); i++ ) {
        if (CONST_ADDR_OBJ(obj)[i] != 0)
            CLEAN_OBJ(CONST_ADDR_OBJ(obj)[i]);
    }

}


/****************************************************************************
**
*F  CopyObjComObj( <obj>, <mut> ) . . . . . . . . . . . . . . . copy a comobj
*/

static Obj CopyObjComObj(Obj obj, Int mut)
{
    Obj                 copy;           // copy, result
    Obj                 tmp;            // temporary variable

    // immutable input is handled by COPY_OBJ
    GAP_ASSERT(IS_MUTABLE_OBJ(obj));

    // if the object is not copyable return
    if ( ! IS_COPYABLE_OBJ(obj) ) {
        ErrorQuit("Panic: encountered mutable, non-copyable object", 0, 0);
    }

    // make a copy
    copy = NewBag( TNUM_OBJ(obj), SIZE_OBJ(obj) );
    memcpy(ADDR_OBJ(copy), CONST_ADDR_OBJ(obj), SIZE_OBJ(obj));
    if ( !mut ) {
        CALL_2ARGS( RESET_FILTER_OBJ, copy, IsMutableObjFilt );
    }

    // leave a forwarding pointer
    PrepareCopy(obj, copy);

    // copy the subvalues; since we used memcpy above, we don't need to worry
    // about copying the length or RNAMs; and by working solely inside the
    // copy, we avoid triggering tnum assertions in GET_ELM_PREC and
    // SET_ELM_PREC
    const UInt len = LEN_PREC(copy);
    for (UInt i = 1; i <= len; i++) {
        tmp = COPY_OBJ(GET_ELM_PREC(copy, i), mut);
        SET_ELM_PREC(copy, i, tmp);
        CHANGED_BAG(copy);
    }

    // return the copy
    return copy;
}


/****************************************************************************
**
*F  CleanObjComObj( <obj> ) . . . . . . . . . . . . . . . . .  clean a comobj
*/

static void CleanObjComObj(Obj obj)
{
    UInt                i;              // loop variable

    // clean the subvalues
    for ( i = 1; i <= LEN_PREC(obj); i++ ) {
        CLEAN_OBJ( GET_ELM_PREC(obj,i) );
    }

}


/****************************************************************************
**
*F  CopyObjDatObj( <obj>, <mut> ) . . . . . . . . . . . . . . . copy a datobj
*/

static Obj CopyObjDatObj(Obj obj, Int mut)
{
    Obj                 copy;           // copy, result

    // immutable input is handled by COPY_OBJ
    GAP_ASSERT(IS_MUTABLE_OBJ(obj));

    // if the object is not copyable return
    if ( ! IS_COPYABLE_OBJ(obj) ) {
        ErrorQuit("Panic: encountered mutable, non-copyable object", 0, 0);
    }

    // make a copy
    copy = NewBag( TNUM_OBJ(obj), SIZE_OBJ(obj) );
    memcpy(ADDR_OBJ(copy), CONST_ADDR_OBJ(obj), SIZE_OBJ(obj));
    if ( !mut ) {
        CALL_2ARGS( RESET_FILTER_OBJ, copy, IsMutableObjFilt );
    }

    // leave a forwarding pointer
    PrepareCopy(obj, copy);

    // return the copy
    return copy;
}


/****************************************************************************
**
*F  CleanObjDatObj( <obj> ) . . . . . . . . . . . . . . . . .  clean a datobj
*/

static void CleanObjDatObj(Obj obj)
{
}

#endif // !defined(USE_THREADSAFE_COPYING)

/****************************************************************************
**
*F  FuncIMMUTABLE_COPY_OBJ( <self>, <obj> )  . . . . immutable copy of <obj>
*/

static Obj FuncIMMUTABLE_COPY_OBJ(Obj self, Obj obj)
{
    return CopyObj( obj, 0 );
}


/****************************************************************************
**
*F  FuncDEEP_COPY_OBJ( <self>, <obj> )  . . . . . . mutable copy of <obj>
*/

static Obj FuncDEEP_COPY_OBJ(Obj self, Obj obj)
{
    return CopyObj( obj, 1 );
}

/****************************************************************************
**
*F  MakeImmutable( <obj> . . . . . . . . . . make an object immutable inplace
**
**  Mark an object and all subobjects immutable in-place.
**  May cause confusion if there are shared subobjects
**
*/


static Obj PostMakeImmutableOp = 0;

void (*MakeImmutableObjFuncs[LAST_REAL_TNUM+1])( Obj );


void MakeImmutable( Obj obj )
{
  if (IS_MUTABLE_OBJ( obj ))
    {
      (*(MakeImmutableObjFuncs[TNUM_OBJ(obj)]))(obj);
    }
}

#ifdef HPCGAP
void CheckedMakeImmutable( Obj obj )
{
  if (!PreMakeImmutableCheck(obj))
    ErrorMayQuit("MakeImmutable: Argument has inaccessible subobjects", 0, 0);
  MakeImmutable(obj);
}
#endif

static void MakeImmutableError(Obj obj)
{
  ErrorQuit("No make immutable function installed for a %s",
            (Int)TNAM_OBJ(obj), 0);
}


static void MakeImmutableComObj(Obj obj)
{
  CALL_2ARGS( RESET_FILTER_OBJ, obj, IsMutableObjFilt );
  CALL_1ARGS( PostMakeImmutableOp, obj);
}

static void MakeImmutablePosObj(Obj obj)
{
  CALL_2ARGS( RESET_FILTER_OBJ, obj, IsMutableObjFilt );
  CALL_1ARGS( PostMakeImmutableOp, obj);

}

#ifdef HPCGAP
// HPCGAP-HACK:
// There is a considerable amount of library code that currently
// relies on being able to modify immutable data objects; in order
// to not break all of that, MakeImmutableDatObj() makes immutable
// data objects public, not read-only if they are not internally
// mutable. Note that this is potentially unsafe if these objects
// are shared between threads and then modified by kernel code.
//
// By setting the environment variable GAP_READONLY_DATOBJS, one
// can restore the old behavior in order to find and debug the
// offending code.
static int ReadOnlyDatObjs = 0;
#endif

static void MakeImmutableDatObj(Obj obj)
{
  CALL_2ARGS( RESET_FILTER_OBJ, obj, IsMutableObjFilt );
#ifdef HPCGAP
  if (!IsInternallyMutableObj(obj)) {
    if (ReadOnlyDatObjs)
      MakeBagReadOnly(obj);
    else
      MakeBagPublic(obj);
  }
#endif
}

static Obj FuncMakeImmutable(Obj self, Obj obj)
{
#ifdef HPCGAP
  CheckedMakeImmutable(obj);
#else
  MakeImmutable(obj);
#endif
  return obj;
}

static Obj FuncGET_TNAM_FROM_TNUM(Obj self, Obj obj)
{
    UInt         tnum = GetBoundedInt(SELF_NAME, obj, 0, NUM_TYPES - 1);
    const char * name = TNAM_TNUM(tnum);
    return MakeImmString(name ? name : "");
}


// This function is used to keep track of which objects are already
// being printed or viewed to trigger the use of ~ when needed.
static inline BOOL IS_ON_PRINT_STACK(const ObjectsModuleState * os, Obj obj)
{
    if (!(FIRST_RECORD_TNUM <= TNUM_OBJ(obj) &&
          TNUM_OBJ(obj) <= LAST_LIST_TNUM))
        return FALSE;
    for (UInt i = 0; i < os->PrintObjDepth; i++)
        if (os->PrintObjThiss[i] == obj)
            return TRUE;
    return FALSE;
}

#ifdef HPCGAP
static void PrintInaccessibleObject(Obj obj)
{
  Char buffer[20];
  Char *name;
  Region *region;
  Obj nameobj;

  region = REGION(obj);
  if (!region)
    nameobj = PublicRegionName; // this should not happen, but let's be safe
  else
    nameobj = GetRegionName(region);
  if (nameobj) {
    name = CSTR_STRING(nameobj);
  } else {
    sprintf(buffer, "%p", (void *)region);
    name = buffer;
    Pr("", (Int) name, (Int) obj);
    return;
  }
  Pr("", (Int) name, (Int) obj);
}
#endif

static void PRINT_PATH(Obj obj, Int idx)
{
    UInt tnum = TNUM_OBJ(obj);
    if (IS_PREC(obj)) {
        Pr(".%I", (Int)NAME_RNAM(idx), 0);
    }
    else if (FIRST_LIST_TNUM <= tnum && tnum <= LAST_LIST_TNUM) {
        Pr("[%d]", idx, 0);
    }
    else {
        ErrorQuit("Panic: tried to print a path of unsupported type '%s'",
                  (Int)tnum, 0);
    }
}

/****************************************************************************
**
*F  PrintObj( <obj> ) . . . . . . . . . . . . . . . . . . . . print an object
**
**  'PrintObj' prints the object <obj>.
*/

void PrintObj(Obj obj)
{
#if defined(HPCGAP) && !defined(WARD_ENABLED)
    if (IS_BAG_REF(obj) && !CheckReadAccess(obj)) {
        PrintInaccessibleObject(obj);
        return;
    }
#endif

    ObjectsModuleState * os = &MODULE_STATE(Objects);

    // First check if <obj> is actually the current object being viewed, since
    // ViewObj(<obj>) may result in a call to PrintObj(<obj>); in that case,
    // we should not put <obj> on the print stack
    if ((os->PrintObjDepth > 0) && (os->LastPV == 2) &&
        (obj == os->PrintObjThiss[os->PrintObjDepth - 1])) {
        os->LastPV = 1;
        PRINT_OBJ(obj);
        os->LastPV = 2;
    }

    // print the path if <obj> is on the stack
    else if (IS_ON_PRINT_STACK(os, obj)) {
        Pr("~", 0, 0);
        for (int i = 0; obj != os->PrintObjThiss[i]; i++) {
            PRINT_PATH(os->PrintObjThiss[i], os->PrintObjIndices[i]);
        }
    }

    // dispatch to the appropriate printing function
    else if (os->PrintObjDepth < MAXPRINTDEPTH) {

        Obj oldThis = os->PrintObjThiss[os->PrintObjDepth];
        Int oldIndx = os->PrintObjIndices[os->PrintObjDepth];

        // push obj on the stack
        os->PrintObjThiss[os->PrintObjDepth] = obj;
        os->PrintObjIndices[os->PrintObjDepth] = 0;
        os->PrintObjDepth++;

        UInt lastPV = os->LastPV;
        os->LastPV = 1;
        PRINT_OBJ(obj);
        os->LastPV = lastPV;

        // pop <obj> from the stack
        os->PrintObjDepth--;
        os->PrintObjThiss[os->PrintObjDepth] = oldThis;
        os->PrintObjIndices[os->PrintObjDepth] = oldIndx;
    }
    else {
        Pr("\nprinting stopped, too many recursion levels!\n", 0, 0);
    }
}


/****************************************************************************
**
*V  PrintObjFuncs[<type>] . . . . . . . .  printer for objects of type <type>
**
**  'PrintObjFuncs' is  the dispatch  table that  contains  for every type of
**  objects a pointer to the printer for objects of this  type.  The  printer
**  is the function '<func>(<obj>)' that should be called to print the object
**  <obj> of this type.
*/

void (* PrintObjFuncs [ LAST_REAL_TNUM  +1 ])( Obj obj );


/****************************************************************************
**
*F  PrintObjObject( <obj> ) . . . . . . . . . . . . . . . . . print an object
*/

Obj PrintObjOper;

static void PrintObjObject(Obj obj)
{
    DoOperation1Args( PrintObjOper, obj );
}


/****************************************************************************
**
*F  FuncPRINT_OBJ( <self>, <obj> ) . . . . . . . . . . handler for 'PrintObj'
*/

static Obj FuncPRINT_OBJ(Obj self, Obj obj)
{
    PrintObj( obj );
    return 0;
}

UInt SetPrintObjState(UInt state)
{
    UInt oldDepth = MODULE_STATE(Objects).PrintObjDepth;
    UInt oldLastPV = MODULE_STATE(Objects).LastPV;
    MODULE_STATE(Objects).PrintObjDepth = state >> 2;
    MODULE_STATE(Objects).LastPV = state & 3;
    return (oldDepth << 2) | oldLastPV;
}

void SetPrintObjIndex(Int index)
{
    UInt depth = MODULE_STATE(Objects).PrintObjDepth;
    if (depth == 0)
        ErrorQuit("SetPrintObjIndex: bad state, PrintObjDepth is 0", 0, 0);
    MODULE_STATE(Objects).PrintObjIndices[depth - 1] = index;
}

static Obj FuncSET_PRINT_OBJ_INDEX(Obj self, Obj index)
{
    SetPrintObjIndex(GetSmallInt(SELF_NAME, index));
    return 0;
}


/****************************************************************************
**
*F  ViewObj( <obj> ) . . . . . . . . . . . . . . . . . . . . . view an object
**
**  'ViewObj' views the object <obj>.
**
**  ViewObj shares all the associated variables with PrintObj, so that
**  recursion works nicely.
*/


static Obj ViewObjOper;

void ViewObj(Obj obj)
{
#if defined(HPCGAP) && !defined(WARD_ENABLED)
    if (IS_BAG_REF(obj) && !CheckReadAccess(obj)) {
        PrintInaccessibleObject(obj);
        return;
    }
#endif

    ObjectsModuleState * os = &MODULE_STATE(Objects);

    // print the path if <obj> is on the stack
    if (IS_ON_PRINT_STACK(os, obj)) {
        Pr("~", 0, 0);
        for (int i = 0; obj != os->PrintObjThiss[i]; i++) {
            PRINT_PATH(os->PrintObjThiss[i], os->PrintObjIndices[i]);
        }
    }

    // dispatch to the appropriate viewing function
    else if (os->PrintObjDepth < MAXPRINTDEPTH) {

        Obj oldThis = os->PrintObjThiss[os->PrintObjDepth];
        Int oldIndx = os->PrintObjIndices[os->PrintObjDepth];

        // push obj on the stack
        os->PrintObjThiss[os->PrintObjDepth] = obj;
        os->PrintObjIndices[os->PrintObjDepth] = 0;
        os->PrintObjDepth++;

        UInt lastPV = os->LastPV;
        os->LastPV = 2;
        DoOperation1Args(ViewObjOper, obj);
        os->LastPV = lastPV;

        // pop <obj> from the stack
        os->PrintObjDepth--;
        os->PrintObjThiss[os->PrintObjDepth] = oldThis;
        os->PrintObjIndices[os->PrintObjDepth] = oldIndx;
    }
    else {
        Pr("\nviewing stopped, too many recursion levels!\n", 0, 0);
    }
}


/****************************************************************************
**
*F  FuncVIEW_OBJ( <self>, <obj> ) . . . . . . . . . . . handler for 'ViewObj'
*/

static Obj FuncVIEW_OBJ(Obj self, Obj obj)
{
    ViewObj( obj );
    return 0;
}


/****************************************************************************
**
*F  TypeComObj( <obj> ) . . . . . . . . . . function version of 'TYPE_COMOBJ'
*/

#ifndef WARD_ENABLED
static Obj TypeComObj(Obj obj)
{
    Obj result = TYPE_COMOBJ( obj );
#ifdef HPCGAP
    MEMBAR_READ();
#endif
    return result;
}

#endif


/*****************************************************************************
**
*F  FuncIS_COMOBJ( <self>, <obj> ) . . . . . . . . handler for 'IS_COMOBJ'
*/

static Obj FuncIS_COMOBJ(Obj self, Obj obj)
{
#ifdef HPCGAP
    switch (TNUM_OBJ(obj)) {
      case T_COMOBJ:
      case T_ACOMOBJ:
        return True;
      default:
        return False;
    }
#else
    return (TNUM_OBJ(obj) == T_COMOBJ ? True : False);
#endif
}


/****************************************************************************
**
*F  FuncSET_TYPE_COMOBJ( <self>, <obj>, <type> ) . . .  'SET_TYPE_COMOBJ'
*/

static Obj FuncSET_TYPE_COMOBJ(Obj self, Obj obj, Obj type)
{
    switch (TNUM_OBJ(obj)) {
    case T_PREC:
    case T_COMOBJ:
#ifdef HPCGAP
    case T_AREC:
    case T_ACOMOBJ:
#endif
        SET_TYPE_OBJ(obj, type);
        break;
    default:
        ErrorMayQuit("You can't make a component object from a %s",
                     (Int)TNAM_OBJ(obj), 0);
    }
    return obj;
}


/****************************************************************************
**
*F  AssComObj( <obj>, <rnam>, <val> )
*F  UnbComObj( <obj>, <rnam> )
*F  ElmComObj( <obj>, <rnam> )
*F  IsbComObj( <obj>, <rnam> )
*/

void AssComObj(Obj obj, UInt rnam, Obj val)
{
    switch (TNUM_OBJ(obj)) {
    case T_COMOBJ:
        AssPRec(obj, rnam, val);
        break;
#ifdef HPCGAP
    case T_ACOMOBJ:
        SetARecordField(obj, rnam, val);
        break;
#endif
    default:
        ASS_REC(obj, rnam, val);
        break;
    }
}

void UnbComObj(Obj obj, UInt rnam)
{
    switch (TNUM_OBJ(obj)) {
    case T_COMOBJ:
        UnbPRec(obj, rnam);
        break;
#ifdef HPCGAP
    case T_ACOMOBJ:
        UnbARecord(obj, rnam);
        break;
#endif
    default:
        UNB_REC(obj, rnam);
        break;
    }
}

Obj ElmComObj(Obj obj, UInt rnam)
{
    switch (TNUM_OBJ(obj)) {
    case T_COMOBJ:
        return ElmPRec(obj, rnam);
#ifdef HPCGAP
    case T_ACOMOBJ:
        return ElmARecord(obj, rnam);
#endif
    default:
        return ELM_REC(obj, rnam);
    }
}

BOOL IsbComObj(Obj obj, UInt rnam)
{
    switch (TNUM_OBJ(obj)) {
    case T_COMOBJ:
        return IsbPRec(obj, rnam);
#ifdef HPCGAP
    case T_ACOMOBJ:
        return IsbARecord(obj, rnam);
#endif
    default:
        return ISB_REC(obj, rnam);
    }
}


/****************************************************************************
**
*F  TypePosObj( <obj> ) . . . . . . . . . . function version of 'TYPE_POSOBJ'
*/

#ifndef WARD_ENABLED
static Obj TypePosObj(Obj obj)
{
    Obj result = TYPE_POSOBJ( obj );
#ifdef HPCGAP
    MEMBAR_READ();
#endif
    return result;
}
#endif


/****************************************************************************
**
*F  FuncIS_POSOBJ( <self>, <obj> )  . . . . . . . handler for 'IS_POSOBJ'
*/

static Obj FuncIS_POSOBJ(Obj self, Obj obj)
{
   switch (TNUM_OBJ(obj)) {
      case T_POSOBJ:
#ifdef HPCGAP
      case T_APOSOBJ:
#endif
        return True;
      default:
        return False;
    }
}


/****************************************************************************
**
*F  FuncSET_TYPE_POSOBJ( <self>, <obj>, <type> )  . . .  'SET_TYPE_POSOB'
*/

static Obj FuncSET_TYPE_POSOBJ(Obj self, Obj obj, Obj type)
{
    switch (TNUM_OBJ(obj)) {
#ifdef HPCGAP
    case T_APOSOBJ:
    case T_ALIST:
    case T_FIXALIST:
#endif
    case T_POSOBJ:
        break;
    default:
        if (!IS_PLIST(obj)) {
            ErrorMayQuit("You can't make a positional object from a %s",
                         (Int)TNAM_OBJ(obj), 0);
        }
        // TODO: we should also reject immutable plists, but that risks
        // breaking existing code
        break;
    }
    SET_TYPE_OBJ(obj, type);
    return obj;
}


/****************************************************************************
**
*F  FuncLEN_POSOBJ( <self>, <obj> ) . . . . . .  handler for 'LEN_POSOBJ'
*/

static Obj FuncLEN_POSOBJ(Obj self, Obj obj)
{
#ifdef HPCGAP
    switch (TNUM_OBJ(obj)) {
    case T_APOSOBJ:
    case T_ALIST:
    case T_FIXALIST:
      return LengthAList( obj );
    }
#endif
    return INTOBJ_INT( SIZE_OBJ(obj) / sizeof(Obj) - 1 );
}


/****************************************************************************
**
*F  AssPosbj( <obj>, <rnam>, <val> )
*F  UnbPosbj( <obj>, <rnam> )
*F  ElmPosbj( <obj>, <rnam> )
*F  IsbPosbj( <obj>, <rnam> )
*/

void AssPosObj(Obj obj, Int idx, Obj val)
{
    if (TNUM_OBJ(obj) == T_POSOBJ) {
#ifdef HPCGAP
        // Because BindOnce() functions can reallocate the list even if they
        // only have read-only access, we have to be careful when accessing
        // positional objects. Hence the explicit WriteGuard().
        WriteGuard(obj);
#endif
        if (SIZE_OBJ(obj) / sizeof(Obj) - 1 < idx) {
            ResizeBag(obj, (idx + 1) * sizeof(Obj));
        }
        SET_ELM_PLIST(obj, idx, val);
        CHANGED_BAG(obj);
    }
#ifdef HPCGAP
    else if (TNUM_OBJ(obj) == T_APOSOBJ) {
        AssListFuncs[T_FIXALIST](obj, idx, val);
    }
#endif
    else {
        ASS_LIST(obj, idx, val);
    }
}

void UnbPosObj(Obj obj, Int idx)
{
    if (TNUM_OBJ(obj) == T_POSOBJ) {
#ifdef HPCGAP
        // Because BindOnce() functions can reallocate the list even if they
        // only have read-only access, we have to be careful when accessing
        // positional objects. Hence the explicit WriteGuard().
        WriteGuard(obj);
#endif
        if (idx <= SIZE_OBJ(obj) / sizeof(Obj) - 1) {
            SET_ELM_PLIST(obj, idx, 0);
        }
    }
#ifdef HPCGAP
    else if (TNUM_OBJ(obj) == T_APOSOBJ) {
        UnbListFuncs[T_FIXALIST](obj, idx);
    }
#endif
    else {
        UNB_LIST(obj, idx);
    }
}

Obj ElmPosObj(Obj obj, Int idx)
{
    Obj elm;
    if (TNUM_OBJ(obj) == T_POSOBJ) {
#ifdef HPCGAP
        // Because BindOnce() functions can reallocate the list even if they
        // only have read-only access, we have to be careful when accessing
        // positional objects.
        const Bag * contents = CONST_PTR_BAG(obj);
        MEMBAR_READ(); // essential memory barrier
        if (SIZE_BAG_CONTENTS(contents) / sizeof(Obj) - 1 < idx) {
            ErrorMayQuit(
                "PosObj Element: ![%d] must have an assigned value",
                (Int)idx, 0);
        }
        elm = contents[idx];
#else
        if (SIZE_OBJ(obj) / sizeof(Obj) - 1 < idx) {
            ErrorMayQuit(
                "PosObj Element: ![%d] must have an assigned value",
                (Int)idx, 0);
        }
        elm = ELM_PLIST(obj, idx);
#endif
        if (elm == 0) {
            ErrorMayQuit(
                "PosObj Element: ![%d] must have an assigned value",
                (Int)idx, 0);
        }
    }
#ifdef HPCGAP
    else if (TNUM_OBJ(obj) == T_APOSOBJ) {
        elm = ElmListFuncs[T_FIXALIST](obj, idx);
    }
#endif
    else {
        elm = ELM_LIST(obj, idx);
    }
    return elm;
}

BOOL IsbPosObj(Obj obj, Int idx)
{
    BOOL isb;
    if (TNUM_OBJ(obj) == T_POSOBJ) {
#ifdef HPCGAP
        // Because BindOnce() functions can reallocate the list even if they
        // only have read-only access, we have to be careful when accessing
        // positional objects.
        const Bag * contents = CONST_PTR_BAG(obj);
        if (idx > SIZE_BAG_CONTENTS(contents) / sizeof(Obj) - 1)
            isb = FALSE;
        else
            isb = contents[idx] != 0;
#else
        isb = (idx <= SIZE_OBJ(obj) / sizeof(Obj) - 1 &&
               ELM_PLIST(obj, idx) != 0);
#endif
    }
#ifdef HPCGAP
    else if (TNUM_OBJ(obj) == T_APOSOBJ) {
        isb = IsbListFuncs[T_FIXALIST](obj, idx);
    }
#endif
    else {
        isb = ISB_LIST(obj, idx);
    }
    return isb;
}


/****************************************************************************
**
*F  TypeDatObj( <obj> ) . . . . . . . . . . function version of 'TYPE_DATOBJ'
*/

static Obj TypeDatObj(Obj obj)
{
    Obj type = TYPE_DATOBJ( obj );
    return type ? type : TYPE_KERNEL_OBJECT;
}

void SetTypeDatObj( Obj obj, Obj type)
{
    SET_TYPE_DATOBJ(obj, type);
#ifdef HPCGAP
    if (TNUM_OBJ(obj) == T_DATOBJ &&
        !IsMutableObjObject(obj) && !IsInternallyMutableObj(obj)) {
      if (ReadOnlyDatObjs)
        MakeBagReadOnly(obj);
      else
        MakeBagPublic(obj);
    }
#endif
    CHANGED_BAG(obj);
}


/*****************************************************************************
**
*F  FuncIS_DATOBJ( <self>, <obj> ) . . . . . . . . handler for 'IS_DATOBJ'
*/

static Obj FuncIS_DATOBJ(Obj self, Obj obj)
{
    return (TNUM_OBJ(obj) == T_DATOBJ ? True : False);
}


/****************************************************************************
**
*F  FuncSET_TYPE_DATOBJ( <self>, <obj>, <type> ) . . .  'SET_TYPE_DATOBJ'
*/

static Obj FuncSET_TYPE_DATOBJ(Obj self, Obj obj, Obj type)
{
#ifndef WARD_ENABLED
#ifdef HPCGAP
    ReadGuard( obj );
#endif
    SET_TYPE_DATOBJ(obj, type);
    RetypeBag( obj, T_DATOBJ );
    CHANGED_BAG( obj );
    return obj;
#endif
}


/****************************************************************************
**
*F  NewKernelBuffer( <size> )  . . . . . . . . . . return a new kernel buffer
*/

Obj NewKernelBuffer(UInt size)
{
    Obj obj = NewBag(T_DATOBJ, size);
    SET_TYPE_DATOBJ(obj, TYPE_KERNEL_OBJECT);
    return obj;
}


/****************************************************************************
**
*F  FuncIS_IDENTICAL_OBJ( <self>, <obj1>, <obj2> )  . . . . .  handler for '=='
**
**  'FuncIS_IDENTICAL_OBJ' implements 'IsIdentical'
*/

static Obj FuncIS_IDENTICAL_OBJ(Obj self, Obj obj1, Obj obj2)
{
    return (obj1 == obj2 ? True : False);
}

/****************************************************************************
**
*V  SaveObjFuncs (<type>) . . . . . . . . . . . . . functions to save objects
**
** 'SaveObjFuncs' is the dispatch table that  contains, for every type
**  of  objects, a pointer to the saving function for objects of that type
**  These should not handle the file directly, but should work via the
**  functions 'SaveSubObj', 'SaveUInt<n>' (<n> = 1,2,4 or 8), and others
**  to be determined. Their role is to identify the C types of the various
**  parts of the bag, and perhaps to leave out some information that does
**  not need to be saved. By the time this function is called, the bag
**  size and type have already been saved
**  No saving function may allocate any bag
*/

#ifdef GAP_ENABLE_SAVELOAD
void (*SaveObjFuncs[LAST_REAL_TNUM+1]) ( Obj obj );

void SaveObjError( Obj obj )
{
    ErrorQuit("Panic: tried to save an object of unsupported type '%s'",
              (Int)TNAM_OBJ(obj), 0);
}
#endif


/****************************************************************************
**
*V  LoadObjFuncs (<type>) . . . . . . . . . . . . . functions to load objects
**
** 'LoadObjFuncs' is the dispatch table that  contains, for every type
**  of  objects, a pointer to the loading function for objects of that type
**  These should not handle the file directly, but should work via the
**  functions 'LoadObjRef', 'LoadUInt<n>' (<n> = 1,2,4 or 8), and others
**  to be determined. Their role is to reinstall the information in the bag
**  and reconstruct anything that was left out. By the time this function is
**  called, the bag size and type have already been loaded and the bag argument
**  contains the bag in question
**  No loading function may allocate any bag
*/

#ifdef GAP_ENABLE_SAVELOAD
void (*LoadObjFuncs[LAST_REAL_TNUM+1]) ( Obj obj );

void LoadObjError( Obj obj )
{
    ErrorQuit("Panic: tried to load an object of unsupported type '%s'",
              (Int)TNAM_OBJ(obj), 0);
}
#endif


/****************************************************************************
**
*F  SaveComObj( Obj comobj)
**
*/

#ifdef GAP_ENABLE_SAVELOAD
static void SaveComObj(Obj comobj)
{
  UInt len,i;
  SaveSubObj(TYPE_COMOBJ( comobj ));
  len = LEN_PREC(comobj);
  SaveUInt(len);
  for (i = 1; i <= len; i++)
    {
      SaveUInt(GET_RNAM_PREC(comobj, i));
      SaveSubObj(GET_ELM_PREC(comobj, i));
    }
}
#endif

/****************************************************************************
**
*F  SavePosObj( Obj posobj)
**
*/

#ifdef GAP_ENABLE_SAVELOAD
static void SavePosObj(Obj posobj)
{
  UInt len,i;
  SaveSubObj(TYPE_POSOBJ( posobj ));
  len = (SIZE_OBJ(posobj)/sizeof(Obj) - 1);
  for (i = 1; i <= len; i++)
    {
      SaveSubObj(CONST_ADDR_OBJ(posobj)[i]);
    }
}
#endif

/****************************************************************************
**
*F  SaveDatObj( Obj datobj)
**
**  Here we lose endianness protection, because we don't know if this is really
**  UInts, or if it might be smaller data
*/

#ifdef GAP_ENABLE_SAVELOAD
static void SaveDatObj(Obj datobj)
{
  UInt len,i;
  const UInt * ptr;
  SaveSubObj(TYPE_DATOBJ( datobj ));
  len = ((SIZE_OBJ(datobj)+sizeof(UInt)-1)/sizeof(UInt) - 1);
  ptr = (const UInt *)CONST_ADDR_OBJ(datobj) + 1;
  for (i = 1; i <= len; i++)
    {
      SaveUInt(*ptr++);
    }
}
#endif

/****************************************************************************
**
*F  LoadComObj( Obj comobj)
**
*/

#ifdef GAP_ENABLE_SAVELOAD
static void LoadComObj(Obj comobj)
{
  UInt len,i;
  SET_TYPE_COMOBJ(comobj, LoadSubObj());
  len = LoadUInt();
  SET_LEN_PREC(comobj,len);
  for (i = 1; i <= len; i++)
    {
      SET_RNAM_PREC(comobj, i, LoadUInt());
      SET_ELM_PREC(comobj, i, LoadSubObj());
    }
}
#endif

/****************************************************************************
**
*F  LoadPosObj( Obj posobj)
**
*/

#ifdef GAP_ENABLE_SAVELOAD
static void LoadPosObj(Obj posobj)
{
  UInt len,i;
  SET_TYPE_POSOBJ(posobj, LoadSubObj());
  len = (SIZE_OBJ(posobj)/sizeof(Obj) - 1);
  for (i = 1; i <= len; i++)
    {
      ADDR_OBJ(posobj)[i] = LoadSubObj();
    }
}
#endif

/****************************************************************************
**
*F  LoadDatObj( Obj datobj)
**
**  Here we lose endianness protection, because we don't know if this is really
**  UInts, or if it might be smaller data
*/

#ifdef GAP_ENABLE_SAVELOAD
static void LoadDatObj(Obj datobj)
{
  UInt len,i;
  UInt *ptr;
  SET_TYPE_DATOBJ(datobj, LoadSubObj());
  len = ((SIZE_OBJ(datobj)+sizeof(UInt)-1)/sizeof(UInt) - 1);
  ptr = (UInt *)ADDR_OBJ(datobj)+1;
  for (i = 1; i <= len; i++)
    {
      *ptr ++ = LoadUInt();
    }
}
#endif


/****************************************************************************
**
*F * * * * * * * *  GAP functions for "to be defined" objects * * * * * * * *
*/



/****************************************************************************
**
*F  FuncCLONE_OBJ( <self>, <dst>, <src> ) . . . . . . .  clone <src> to <dst>
**
**  `CLONE_OBJ' clones  the source  <src> into  <dst>.  It  is not allowed to
**  clone small integers or finite field elements.
**
**  If <src> is a constant, than a "shallow" copy, that is to say, a bit-copy
**  of the bag of <src>  is created.  If <src>  is mutable than a "structural
**  copy is created, which is then in turn "shallow" cloned into <dst>.
**
**  WARNING: at the moment the functions breaks on cloning `[1,~]'.  This can
**  be fixed if necessary.
*/

static Obj IsToBeDefinedObj;

static Obj REREADING;

static Obj FuncCLONE_OBJ(Obj self, Obj dst, Obj src)
{
    const Obj *     psrc;
    Obj *           pdst;

    // check <src>
    if ( IS_INTOBJ(src) ) {
        ErrorMayQuit("small integers cannot be cloned", 0, 0);
    }
    if ( IS_FFE(src) ) {
        ErrorMayQuit("finite field elements cannot be cloned", 0, 0);
    }
    if ( TNUM_OBJ(src) == T_BOOL ) {
        ErrorMayQuit("booleans cannot be cloned", 0, 0);
    }

#ifdef HPCGAP
    switch (TNUM_OBJ(src)) {
        case T_AREC:
        case T_ACOMOBJ:
        case T_TLREC:
            ErrorMayQuit("cannot clone %ss", (Int)TNAM_OBJ(src), 0);
    }
    if (!REGION(dst)) {
        ErrorMayQuit("CLONE_OBJ() cannot overwrite public objects", 0, 0);
    }
    if (REGION(src) != REGION(dst) && REGION(src)) {
        ErrorMayQuit("objects can only be cloned to replace objects within"
                     "the same region or if the object is public",
                     0, 0);
    }
#endif

    // if object is mutable, produce a structural copy
    if ( IS_MUTABLE_OBJ(src) ) {
        src = CopyObj( src, 1 );
    }

    // now shallow clone the object
#ifdef HPCGAP
    Obj tmp = NewBag(TNUM_OBJ(src), SIZE_OBJ(src));
    pdst = ADDR_OBJ(tmp);
#else
    ResizeBag( dst, SIZE_OBJ(src) );
    RetypeBag( dst, TNUM_OBJ(src) );
    pdst = ADDR_OBJ(dst);
#endif
    psrc = CONST_ADDR_OBJ(src);
    memcpy(pdst, psrc, SIZE_OBJ(src));
    CHANGED_BAG(dst);
#ifdef HPCGAP
    SET_REGION(dst, REGION(src));
    MEMBAR_WRITE();
    // The following is a no-op unless the region is public
    SET_PTR_BAG(dst, PTR_BAG(tmp));
#endif

    return 0;
}

/****************************************************************************
**
*F  FuncSWITCH_OBJ( <self>, <obj1>, <obj2> ) . . .  switch <obj1> and <obj2>
**
**  `SWITCH_OBJ' exchanges the objects referenced by its two arguments.  It
**   is not allowed to switch clone small integers or finite field elements.
**
**   This is inspired by the Smalltalk 'become:' operation.
*/


static Obj FuncSWITCH_OBJ(Obj self, Obj obj1, Obj obj2)
{
    if ( IS_INTOBJ(obj1) || IS_INTOBJ(obj2) ) {
        ErrorMayQuit("small integer objects cannot be switched", 0, 0);
    }
    if ( IS_FFE(obj1) || IS_FFE(obj2) ) {
        ErrorMayQuit("finite field elements cannot be switched", 0, 0);
    }
#ifdef HPCGAP
    Region * ds1 = REGION(obj1);
    Region * ds2 = REGION(obj2);
    if (!ds1 || ds1->owner != GetTLS())
        ErrorQuit("SWITCH_OBJ: Cannot write to first object's region.", 0, 0);
    if (!ds2 || ds2->owner != GetTLS())
        ErrorQuit("SWITCH_OBJ: Cannot write to second object's region.", 0, 0);
    SET_REGION(obj2, ds1);
    SET_REGION(obj1, ds2);
#endif
    SwapMasterPoint(obj1, obj2);
    return 0;
}


/****************************************************************************
**
*F  FuncFORCE_SWITCH_OBJ( <self>, <obj1>, <obj2> ) .  switch <obj1> and <obj2>
**
**  `FORCE_SWITCH_OBJ' exchanges the objects referenced by its two arguments.
**  It is not allowed to switch clone small integers or finite field
**  elements.
**
**  In GAP, FORCE_SWITCH_OBJ does the same thing as SWITCH_OBJ. In HPC_GAP
**  it allows public objects to be exchanged.
*/


static Obj FuncFORCE_SWITCH_OBJ(Obj self, Obj obj1, Obj obj2)
{
    if ( IS_INTOBJ(obj1) || IS_INTOBJ(obj2) ) {
        ErrorMayQuit("small integer objects cannot be switched", 0, 0);
    }
    if ( IS_FFE(obj1) || IS_FFE(obj2) ) {
        ErrorMayQuit("finite field elements cannot be switched", 0, 0);
    }
#ifdef HPCGAP
    Region * ds1 = REGION(obj1);
    Region * ds2 = REGION(obj2);
    if (ds1 && ds1->owner != GetTLS())
        ErrorQuit("FORCE_SWITCH_OBJ: Cannot write to first object's region.", 0, 0);
    if (ds2 && ds2->owner != GetTLS())
        ErrorQuit("FORCE_SWITCH_OBJ: Cannot write to second object's region.", 0, 0);
    SET_REGION(obj2, ds1);
    SET_REGION(obj1, ds2);
#endif
    SwapMasterPoint(obj1, obj2);
    return 0;
}


/****************************************************************************
**
*F  FuncDEBUG_TNUM_NAMES
**
**  Print all defined TNUM values and names
*/

#define START_SYMBOLIC_TNUM(name)                                            \
    if (k == name) {                                                         \
        Pr("%3d: %s", k, (Int)indentStr);                                    \
        Pr("%s" #name "\n", (Int)indentStr, 0);                              \
        assert(indentLvl + 1 < sizeof(indentStr));                           \
        indentStr[indentLvl++] = ' ';                                        \
        indentStr[indentLvl] = 0;                                            \
    }

#define STOP_SYMBOLIC_TNUM(name)                                             \
    if (k == name) {                                                         \
        assert(indentLvl > 0);                                               \
        indentStr[--indentLvl] = 0;                                          \
        Pr("%3d: %s", k, (Int)indentStr);                                    \
        Pr("%s" #name "\n", (Int)indentStr, 0);                              \
    }

static Obj FuncDEBUG_TNUM_NAMES(Obj self)
{
    UInt indentLvl = 0;
    Char indentStr[20] = "";
    for (UInt k = 0; k < NUM_TYPES; k++) {
        START_SYMBOLIC_TNUM(FIRST_REAL_TNUM);
        START_SYMBOLIC_TNUM(FIRST_CONSTANT_TNUM);
        START_SYMBOLIC_TNUM(FIRST_MULT_TNUM);
        START_SYMBOLIC_TNUM(FIRST_IMM_MUT_TNUM);
        START_SYMBOLIC_TNUM(FIRST_RECORD_TNUM);
        START_SYMBOLIC_TNUM(FIRST_LIST_TNUM);
        START_SYMBOLIC_TNUM(FIRST_PLIST_TNUM);
        START_SYMBOLIC_TNUM(FIRST_OBJSET_TNUM);
#ifdef HPCGAP
        START_SYMBOLIC_TNUM(FIRST_SHARED_TNUM);
        START_SYMBOLIC_TNUM(FIRST_ATOMIC_TNUM);
        START_SYMBOLIC_TNUM(FIRST_ATOMIC_LIST_TNUM);
        START_SYMBOLIC_TNUM(FIRST_ATOMIC_RECORD_TNUM);
#endif
        START_SYMBOLIC_TNUM(FIRST_EXTERNAL_TNUM);
        START_SYMBOLIC_TNUM(FIRST_PACKAGE_TNUM);
        const char *name = TNAM_TNUM(k);
        Pr("%3d: %s", k, (Int)indentStr);
        Pr("%s%s\n", (Int)indentStr, (Int)(name ? name : "."));
        if (name == 0 && k >= FIRST_PACKAGE_TNUM) {
            // scan ahead and skip over all unused package slots
            int i = k + 1;
            while (i <= LAST_PACKAGE_TNUM && TNAM_TNUM(i) == 0)
                i++;
            i--;
            if (i > k + 1)
                Pr("... %s%s.\n", (Int)indentStr, (Int)indentStr);
            if (i > k) {
                Pr("%3d: %s", i, (Int)indentStr);
                Pr("%s.\n", (Int)indentStr, 0);
            }
            k = i;
        }

        STOP_SYMBOLIC_TNUM(LAST_MULT_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_CONSTANT_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_RECORD_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_PLIST_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_LIST_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_OBJSET_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_IMM_MUT_TNUM);
#ifdef HPCGAP
        STOP_SYMBOLIC_TNUM(LAST_SHARED_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_ATOMIC_RECORD_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_ATOMIC_LIST_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_ATOMIC_TNUM);
#endif
        STOP_SYMBOLIC_TNUM(LAST_PACKAGE_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_EXTERNAL_TNUM);
        STOP_SYMBOLIC_TNUM(LAST_REAL_TNUM);
    }
    return 0;
}
#undef START_SYMBOLIC_TNUM
#undef STOP_SYMBOLIC_TNUM


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



/****************************************************************************
**
*V  BagNames  . . . . . . . . . . . . . . . . . . . . . . . list of bag names
*/

static StructBagNames BagNames[] = {
  { T_COMOBJ,                         "component object"               },
  { T_POSOBJ,                         "positional object"              },
  { T_DATOBJ,                         "data object"                    },
#if !defined(USE_THREADSAFE_COPYING)
  { T_COPYING,                        "copy in progress"               },
#endif
  { -1,                               ""                               }
};


/****************************************************************************
**
*V  GVarFilts . . . . . . . . . . . . . . . . . . . list of filters to export
*/

static StructGVarFilt GVarFilts [] = {

    GVAR_FILT(IS_MUTABLE_OBJ, "obj", &IsMutableObjFilt),
    GVAR_FILT(IS_COPYABLE_OBJ, "obj", &IsCopyableObjFilt),
#ifdef HPCGAP
    GVAR_FILT(IS_INTERNALLY_MUTABLE_OBJ, "obj", &IsInternallyMutableObjFilt),
#endif
    { 0, 0, 0, 0, 0 }

};


/****************************************************************************
**
*V  GVarOpers . . . . . . . . . . . . . . . . .  list of operations to export
*/

static StructGVarOper GVarOpers [] = {

    GVAR_OPER_1ARGS(SHALLOW_COPY_OBJ, obj, &ShallowCopyObjOper),
    GVAR_OPER_1ARGS(PRINT_OBJ, obj, &PrintObjOper),
    GVAR_OPER_1ARGS(VIEW_OBJ, obj, &ViewObjOper),

    { 0, 0, 0, 0, 0, 0 }

};


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

static StructGVarFunc GVarFuncs[] = {

    GVAR_FUNC_1ARGS(FAMILY_TYPE, type),
    GVAR_FUNC_1ARGS(TYPE_OBJ, obj),
    GVAR_FUNC_2ARGS(SET_TYPE_OBJ, obj, type),
    GVAR_FUNC_1ARGS(FAMILY_OBJ, obj),
    GVAR_FUNC_1ARGS(IMMUTABLE_COPY_OBJ, obj),
    GVAR_FUNC_1ARGS(DEEP_COPY_OBJ, obj),
    GVAR_FUNC_2ARGS(IS_IDENTICAL_OBJ, obj1, obj2),
    GVAR_FUNC_1ARGS(IS_COMOBJ, obj),
    GVAR_FUNC_2ARGS(SET_TYPE_COMOBJ, obj, type),
    GVAR_FUNC_1ARGS(IS_POSOBJ, obj),
    GVAR_FUNC_2ARGS(SET_TYPE_POSOBJ, obj, type),
    GVAR_FUNC_1ARGS(LEN_POSOBJ, obj),
    GVAR_FUNC_1ARGS(IS_DATOBJ, obj),
    GVAR_FUNC_2ARGS(SET_TYPE_DATOBJ, obj, type),
    GVAR_FUNC_2ARGS(CLONE_OBJ, dst, src),
    GVAR_FUNC_2ARGS(SWITCH_OBJ, obj1, obj2),
    GVAR_FUNC_2ARGS(FORCE_SWITCH_OBJ, obj1, obj2),
    GVAR_FUNC_1ARGS(SET_PRINT_OBJ_INDEX, index),
    GVAR_FUNC_1ARGS(MakeImmutable, obj),
    GVAR_FUNC_1ARGS(GET_TNAM_FROM_TNUM, obj),
    GVAR_FUNC_0ARGS(DEBUG_TNUM_NAMES),

    { 0, 0, 0, 0, 0 }

};


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

static Int InitKernel (
    StructInitInfo *    module )
{
    Int                 t;              // loop variable

    // set the bag type names (for error messages and debugging)
    InitBagNamesFromTable( BagNames );

    // install the marking methods
    InitMarkFuncBags( T_COMOBJ          , MarkPRecSubBags );
    InitMarkFuncBags( T_POSOBJ          , MarkAllSubBags  );
    InitMarkFuncBags( T_DATOBJ          , MarkOneSubBags  );
#if !defined(USE_THREADSAFE_COPYING) && !defined(USE_BOEHM_GC)
    InitMarkFuncBags(T_COPYING, MarkCopyingSubBags);
#endif

    for ( t = FIRST_REAL_TNUM; t <= LAST_REAL_TNUM; t++ ) {
        assert(TypeObjFuncs[ t ] == 0);
        TypeObjFuncs[ t ] = TypeObjError;
    }

    TypeObjFuncs[ T_COMOBJ ] = TypeComObj;
    TypeObjFuncs[ T_POSOBJ ] = TypePosObj;
    TypeObjFuncs[ T_DATOBJ ] = TypeDatObj;

    // functions for 'to-be-defined' objects
    ImportFuncFromLibrary( "IsToBeDefinedObj", &IsToBeDefinedObj );
    ImportFuncFromLibrary( "PostMakeImmutable", &PostMakeImmutableOp );
    ImportGVarFromLibrary( "REREADING", &REREADING );
    ImportGVarFromLibrary( "TYPE_KERNEL_OBJECT", &TYPE_KERNEL_OBJECT );

    // init filters and functions
    InitHdlrFiltsFromTable( GVarFilts );
    InitHdlrOpersFromTable( GVarOpers );
    InitHdlrFuncsFromTable( GVarFuncs );

    // make and install the 'IS_MUTABLE_OBJ' filter
    for ( t = FIRST_REAL_TNUM; t <= LAST_REAL_TNUM; t++ ) {
        assert(IsMutableObjFuncs[ t ] == 0);
        IsMutableObjFuncs[ t ] = IsMutableObjError;
    }
    for ( t = FIRST_CONSTANT_TNUM; t <= LAST_CONSTANT_TNUM; t++ )
        IsMutableObjFuncs[ t ] = AlwaysNo;
    for ( t = FIRST_EXTERNAL_TNUM; t <= LAST_EXTERNAL_TNUM; t++ )
        IsMutableObjFuncs[ t ] = IsMutableObjObject;

    // make and install the 'IS_COPYABLE_OBJ' filter
    for ( t = FIRST_REAL_TNUM; t <= LAST_REAL_TNUM; t++ ) {
        assert(IsCopyableObjFuncs[ t ] == 0);
        IsCopyableObjFuncs[ t ] = IsCopyableObjError;
    }
    for ( t = FIRST_CONSTANT_TNUM; t <= LAST_CONSTANT_TNUM; t++ )
        IsCopyableObjFuncs[ t ] = AlwaysNo;
    for ( t = FIRST_EXTERNAL_TNUM; t <= LAST_EXTERNAL_TNUM; t++ )
        IsCopyableObjFuncs[ t ] = IsCopyableObjObject;

    // make and install the 'SHALLOW_COPY_OBJ' operation
    for ( t = FIRST_REAL_TNUM; t <= LAST_REAL_TNUM; t++ ) {
        assert(ShallowCopyObjFuncs[ t ] == 0);
        ShallowCopyObjFuncs[ t ] = ShallowCopyObjError;
    }
    for ( t = FIRST_CONSTANT_TNUM; t <= LAST_CONSTANT_TNUM; t++ )
        ShallowCopyObjFuncs[ t ] = ShallowCopyObjConstant;
    for ( t = FIRST_RECORD_TNUM; t <= LAST_RECORD_TNUM; t++ )
        ShallowCopyObjFuncs[ t ] = ShallowCopyObjDefault;
    for ( t = FIRST_LIST_TNUM; t <= LAST_LIST_TNUM; t++ )
        ShallowCopyObjFuncs[ t ] = ShallowCopyObjDefault;
    for ( t = FIRST_EXTERNAL_TNUM; t <= LAST_EXTERNAL_TNUM; t++ )
        ShallowCopyObjFuncs[ t ] = ShallowCopyObjObject;

#ifdef USE_THREADSAFE_COPYING
    SetTraversalMethod(T_POSOBJ, TRAVERSE_ALL_BUT_FIRST, 0, 0);
    SetTraversalMethod(T_COMOBJ, TRAVERSE_BY_FUNCTION, TraversePRecord, CopyPRecord);
    SetTraversalMethod(T_DATOBJ, TRAVERSE_NONE, 0, 0);
#else
    // make and install the 'COPY_OBJ' function
    for ( t = FIRST_REAL_TNUM; t <= LAST_REAL_TNUM; t++ ) {
        assert(CopyObjFuncs [ t ] == 0);
        CopyObjFuncs [ t ] = CopyObjError;
        assert(CleanObjFuncs[ t ] == 0);
        CleanObjFuncs[ t ] = CleanObjError;
    }
    for ( t = FIRST_CONSTANT_TNUM; t <= LAST_CONSTANT_TNUM; t++ ) {
        CopyObjFuncs [ t ] = CopyObjConstant;
        CleanObjFuncs[ t ] = 0;
    }
    CopyObjFuncs[  T_POSOBJ           ] = CopyObjPosObj;
    CleanObjFuncs[ T_POSOBJ           ] = CleanObjPosObj;
    CopyObjFuncs[  T_COMOBJ           ] = CopyObjComObj;
    CleanObjFuncs[ T_COMOBJ           ] = CleanObjComObj;
    CopyObjFuncs[  T_DATOBJ           ] = CopyObjDatObj;
    CleanObjFuncs[ T_DATOBJ           ] = CleanObjDatObj;
#endif

    // make and install the 'PRINT_OBJ' operation
    for ( t = FIRST_REAL_TNUM; t <= LAST_REAL_TNUM; t++ ) {
        assert(PrintObjFuncs[ t ] == 0);
        PrintObjFuncs[ t ] = PrintObjObject;
    }

#ifdef GAP_ENABLE_SAVELOAD
    // enter 'SaveObjError' and 'LoadObjError' for all types initially
    for ( t = FIRST_REAL_TNUM;  t <= LAST_REAL_TNUM;  t++ ) {
        assert(SaveObjFuncs[ t ] == 0);
        SaveObjFuncs[ t ] = SaveObjError;
        assert(LoadObjFuncs[ t ] == 0);
        LoadObjFuncs[ t ] = LoadObjError;
    }

    // install the saving functions
    SaveObjFuncs[ T_COMOBJ ] = SaveComObj;
    SaveObjFuncs[ T_POSOBJ ] = SavePosObj;
    SaveObjFuncs[ T_DATOBJ ] = SaveDatObj;

    // install the loading functions
    LoadObjFuncs[ T_COMOBJ ] = LoadComObj;
    LoadObjFuncs[ T_POSOBJ ] = LoadPosObj;
    LoadObjFuncs[ T_DATOBJ ] = LoadDatObj;
#endif

    for (t = FIRST_REAL_TNUM; t <= LAST_REAL_TNUM; t++ ) {
        assert(MakeImmutableObjFuncs[ t ] == 0);
        MakeImmutableObjFuncs[t] = MakeImmutableError;
    }

    // install the makeimmutableing functions
    MakeImmutableObjFuncs[ T_COMOBJ ] = MakeImmutableComObj;
    MakeImmutableObjFuncs[ T_POSOBJ ] = MakeImmutablePosObj;
    MakeImmutableObjFuncs[ T_DATOBJ ] = MakeImmutableDatObj;

#ifdef HPCGAP
    ReadOnlyDatObjs = (getenv("GAP_READONLY_DATOBJS") != 0);
#endif

    return 0;
}


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

static Int InitLibrary (
    StructInitInfo *    module )
{
    // init filters and functions
    InitGVarFiltsFromTable( GVarFilts );
    InitGVarOpersFromTable( GVarOpers );
    InitGVarFuncsFromTable( GVarFuncs );

    // export certain TNUM values as global variable
    ExportAsConstantGVar(FIRST_REAL_TNUM);
    ExportAsConstantGVar(LAST_REAL_TNUM);

    ExportAsConstantGVar(FIRST_CONSTANT_TNUM);
    ExportAsConstantGVar(LAST_CONSTANT_TNUM);

    ExportAsConstantGVar(FIRST_MULT_TNUM);
    ExportAsConstantGVar(LAST_MULT_TNUM);

    ExportAsConstantGVar(FIRST_IMM_MUT_TNUM);
    ExportAsConstantGVar(LAST_IMM_MUT_TNUM);

    ExportAsConstantGVar(FIRST_RECORD_TNUM);
    ExportAsConstantGVar(LAST_RECORD_TNUM);

    ExportAsConstantGVar(FIRST_LIST_TNUM);
    ExportAsConstantGVar(LAST_LIST_TNUM);

    ExportAsConstantGVar(FIRST_PLIST_TNUM);
    ExportAsConstantGVar(LAST_PLIST_TNUM);

    ExportAsConstantGVar(FIRST_OBJSET_TNUM);
    ExportAsConstantGVar(LAST_OBJSET_TNUM);

    ExportAsConstantGVar(FIRST_EXTERNAL_TNUM);
    ExportAsConstantGVar(LAST_EXTERNAL_TNUM);

    ExportAsConstantGVar(FIRST_PACKAGE_TNUM);
    ExportAsConstantGVar(LAST_PACKAGE_TNUM);

#ifdef HPCGAP
    ExportAsConstantGVar(FIRST_SHARED_TNUM);
    ExportAsConstantGVar(LAST_SHARED_TNUM);
#endif

    ExportAsConstantGVar(T_INT);
    ExportAsConstantGVar(T_INTPOS);
    ExportAsConstantGVar(T_INTNEG);
    ExportAsConstantGVar(T_RAT);
    ExportAsConstantGVar(T_CYC);
    ExportAsConstantGVar(T_FFE);
    ExportAsConstantGVar(T_PERM2);
    ExportAsConstantGVar(T_PERM4);
    ExportAsConstantGVar(T_TRANS2);
    ExportAsConstantGVar(T_TRANS4);
    ExportAsConstantGVar(T_PPERM2);
    ExportAsConstantGVar(T_PPERM4);
    ExportAsConstantGVar(T_BOOL);
    ExportAsConstantGVar(T_CHAR);
    ExportAsConstantGVar(T_FUNCTION);
    ExportAsConstantGVar(T_BODY);
    ExportAsConstantGVar(T_FLAGS);
    ExportAsConstantGVar(T_MACFLOAT);
    ExportAsConstantGVar(T_LVARS);
    ExportAsConstantGVar(T_HVARS);

    ExportAsConstantGVar(T_PREC);

    ExportAsConstantGVar(T_PLIST);
    ExportAsConstantGVar(T_PLIST_NDENSE);
    ExportAsConstantGVar(T_PLIST_DENSE);
    ExportAsConstantGVar(T_PLIST_DENSE_NHOM);
    ExportAsConstantGVar(T_PLIST_DENSE_NHOM_SSORT);
    ExportAsConstantGVar(T_PLIST_DENSE_NHOM_NSORT);
    ExportAsConstantGVar(T_PLIST_EMPTY);
    ExportAsConstantGVar(T_PLIST_HOM);
    ExportAsConstantGVar(T_PLIST_HOM_NSORT);
    ExportAsConstantGVar(T_PLIST_HOM_SSORT);
    ExportAsConstantGVar(T_PLIST_TAB);
    ExportAsConstantGVar(T_PLIST_TAB_NSORT);
    ExportAsConstantGVar(T_PLIST_TAB_SSORT);
    ExportAsConstantGVar(T_PLIST_TAB_RECT);
    ExportAsConstantGVar(T_PLIST_TAB_RECT_NSORT);
    ExportAsConstantGVar(T_PLIST_TAB_RECT_SSORT);
    ExportAsConstantGVar(T_PLIST_CYC);
    ExportAsConstantGVar(T_PLIST_CYC_NSORT);
    ExportAsConstantGVar(T_PLIST_CYC_SSORT);
    ExportAsConstantGVar(T_PLIST_FFE);

    ExportAsConstantGVar(T_RANGE_NSORT);
    ExportAsConstantGVar(T_RANGE_SSORT);
    ExportAsConstantGVar(T_BLIST);
    ExportAsConstantGVar(T_BLIST_NSORT);
    ExportAsConstantGVar(T_BLIST_SSORT);
    ExportAsConstantGVar(T_STRING);
    ExportAsConstantGVar(T_STRING_NSORT);
    ExportAsConstantGVar(T_STRING_SSORT);

    ExportAsConstantGVar(T_OBJSET);
    ExportAsConstantGVar(T_OBJMAP);

    ExportAsConstantGVar(T_COMOBJ);
    ExportAsConstantGVar(T_POSOBJ);
    ExportAsConstantGVar(T_DATOBJ);
    ExportAsConstantGVar(T_WPOBJ);
#ifdef HPCGAP
    ExportAsConstantGVar(T_APOSOBJ);
    ExportAsConstantGVar(T_ACOMOBJ);

    ExportAsConstantGVar(T_THREAD);
    ExportAsConstantGVar(T_MONITOR);
    ExportAsConstantGVar(T_REGION);
    ExportAsConstantGVar(T_SEMAPHORE);
    ExportAsConstantGVar(T_CHANNEL);
    ExportAsConstantGVar(T_BARRIER);
    ExportAsConstantGVar(T_SYNCVAR);
    ExportAsConstantGVar(T_FIXALIST);
    ExportAsConstantGVar(T_ALIST);
    ExportAsConstantGVar(T_AREC);
    ExportAsConstantGVar(T_AREC_INNER);
    ExportAsConstantGVar(T_TLREC);
    ExportAsConstantGVar(T_TLREC_INNER);
#endif

#if !defined(USE_THREADSAFE_COPYING)
    ExportAsConstantGVar(T_COPYING);
--> --------------------

--> maximum size reached

--> --------------------

93%


¤ Dauer der Verarbeitung: 0.26 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.