/**************************************************************************** ** ** 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 GAP interface for thread primitives.
*/
/** Object sets and maps -------------------- * * Object sets and maps are hash tables where identity is determined * according to the IsIdenticalObj() relation. They are primarily intended * for code that needs to traverse object structures in order to remember if * an object has already been seen by the traversal algorithm. They can also * be used as sparse lists with integer keys and as proper sets and maps for * short integers and small finite field elements. * * Object sets and object maps consist of four header words describing the * map layout, followed by a list of entries containing the actual set/map * data. The size of that list is always a power of 2. * * The first header word contains the size of the data list, the second * header word contains the base 2 logarithm of that size, the third word * contains the number of entries actually in use, and the fourth word * contains the number of deleted but not reused entries. * * Entries in the data list comprise either a single GAP object for sets or a * (key, value) pair of GAP objects for maps. * * Unused entries contain a null pointer; deleted entries for sets and the * keys of deleted entries for sets contain the special boolean value * `Undefined`. Values of deleted entries contain a null pointer.
*/
/** * Functions to print object maps and sets * ---------------------------------------
*/
staticvoid PrintObjSet(Obj set)
{
UInt i, size = CONST_ADDR_WORD(set)[OBJSET_SIZE]; Int comma = 0;
Pr("OBJ_SET([ ", 0, 0); for (i=0; i < size; i++) {
Obj obj = READ_SLOT(set, i); if (obj && obj != Undefined) { if (comma) {
Pr(", ", 0, 0);
} else {
comma = 1;
}
PrintObj(obj);
}
}
Pr(" ])", 0, 0);
}
staticvoid PrintObjMap(Obj map)
{
UInt i, size = CONST_ADDR_WORD(map)[OBJSET_SIZE]; Int comma = 0;
Pr("OBJ_MAP([ ", 0, 0); for (i=0; i < size; i++) {
Obj obj = READ_SLOT(map, i * 2); if (obj && obj != Undefined) { if (comma) {
Pr(", ", 0, 0);
} else {
comma = 1;
}
PrintObj(obj);
Pr(", ", 0, 0);
PrintObj(READ_SLOT(map, i * 2 + 1));
}
}
Pr(" ])", 0, 0);
}
/** * Garbage collector support for object maps and sets * -------------------------------------------------- * * These functions are not yet implemented.
*/
/** * `CheckObjSetForCleanUp()` * ------------------------- * * Determine if there is an excess number of deleted entries in `set` and * compact the set if necessary. The additional parameter `expand` can be * set to a non-zero value to reserve space for that many additional entries * that will be inserted right after compaction.
*/
/** * `FindObjSet()` * -------------- * * Locate `obj` within `set`. Return -1 if `obj` was not found, otherwise * return the position within the data, starting with zero for the first * entry.
*/
Int FindObjSet(Obj set, Obj obj) {
GAP_ASSERT(IS_OBJSET(set));
UInt size = CONST_ADDR_WORD(set)[OBJSET_SIZE];
UInt hash = ObjHash(set, obj);
GAP_ASSERT(hash < size); for (;;) {
Obj current;
current = READ_SLOT(set, hash); if (!current) return -1; if (current == obj) return (Int) hash;
hash++; if (hash >= size)
hash = 0;
}
}
/** * `AddObjSetNew()` * ---------------- * * Add `obj` to `set`. * * Precondition: `set` must not already contain `obj`. * * This function does not call CHANGED_BAG, so the caller * should do so, unless loading a workspace.
*/
/** * `ObjSetValues()` * --------------- * * This function returns the elements of the set as a list.
*/
Obj ObjSetValues(Obj set) {
GAP_ASSERT(IS_OBJSET(set));
UInt len = CONST_ADDR_WORD(set)[OBJSET_USED];
UInt size = CONST_ADDR_WORD(set)[OBJSET_SIZE];
UInt p, i;
Obj result = NEW_PLIST(T_PLIST, len);
SET_LEN_PLIST(result, len); for (i=0, p=1; i < size; i++) {
Obj el = READ_SLOT(set, i); if (el && el != Undefined) {
SET_ELM_PLIST(result, p, el);
p++;
}
}
GAP_ASSERT(p == len + 1);
CHANGED_BAG(result); return result;
}
/** * `ResizeObjSet()` * ---------------- * * This function resizes `set` to have room for `2^bits` entries. * * Precondition: the number of entries in `set` must be less than * `2^bits`. There must be at least one free entry remaining.
*/
/** * `CheckObjMapForCleanUp()` * ------------------------- * * Determine if there is an excess number of deleted entries in `map` and * compact the map if necessary. The additional parameter `expand` can be * set to a non-zero value to reserve space for that many additional entries * that will be inserted right after compaction.
*/
/** * `FindObjMap()` * -------------- * * Locate the data entry with key `obj` within `map`. Return -1 if such an * entry was not found, otherwise return the position within the data, * starting with zero for the first entry.
*/
Int FindObjMap(Obj map, Obj obj) {
GAP_ASSERT(IS_OBJMAP(map));
UInt size = CONST_ADDR_WORD(map)[OBJSET_SIZE];
UInt hash = ObjHash(map, obj); for (;;) {
Obj current = READ_SLOT(map, hash*2); if (!current) return -1; if (current == obj) return (Int) hash;
hash++; if (hash >= size)
hash = 0;
}
}
/** * `LookupObjMap()` * ---------------- * * Locate the data entry with key `obj` within `map`. Return a null pointer * if such an entry was not found, otherwise return the corresponding value.
*/
Obj LookupObjMap(Obj map, Obj obj) { Int index = FindObjMap(map, obj); if (index < 0) return (Obj) 0; return READ_SLOT(map, index*2+1);
}
/** * `AddObjMapNew()` * ---------------- * * Add an entry `(key, value)` to `map`. * * Precondition: No other entry with key `key` exists within `map`. * * This function does not call CHANGED_BAG, so the caller * should do so, unless loading a workspace.
*/
/** * `AddObjMap()` * ------------- * * Add a data entry `(key, value)` to `map`. If `map` already contains an * entry with that key, its value will be replaced.
*/
/** * `ObjMapValues()` * --------------- * * This function returns all values from the map.
*/
Obj ObjMapValues(Obj map)
{
GAP_ASSERT(IS_OBJMAP(map));
UInt len = CONST_ADDR_WORD(map)[OBJSET_USED];
UInt size = CONST_ADDR_WORD(map)[OBJSET_SIZE];
UInt p, i;
Obj result = NEW_PLIST(T_PLIST, len);
SET_LEN_PLIST(result, len); for (i=0, p=1; i < size; i++) {
Obj el = READ_SLOT(map, 2*i+1); if (el && el != Undefined) {
SET_ELM_PLIST(result, p, el);
p++;
}
}
GAP_ASSERT(p == len + 1);
CHANGED_BAG(result); return result;
}
/** * `ObjMapKeys()` * --------------- * * This function returns all keys from the map.
*/
Obj ObjMapKeys(Obj map)
{
GAP_ASSERT(IS_OBJMAP(map));
UInt len = CONST_ADDR_WORD(map)[OBJSET_USED];
UInt size = CONST_ADDR_WORD(map)[OBJSET_SIZE];
UInt p, i;
Obj result = NEW_PLIST(T_PLIST, len);
SET_LEN_PLIST(result, len); for (i=0, p=1; i < size; i++) {
Obj el = READ_SLOT(map, 2*i); if (el && el != Undefined) {
SET_ELM_PLIST(result, p, el);
p++;
}
}
GAP_ASSERT(p == len + 1);
CHANGED_BAG(result); return result;
}
/** * `ResizeObjMap()` * ---------------- * * Resizes `map` so that it contains `2^bits` entries. * * Precondition: The number of entries in `map` must be less than `2^bits`.
*/
for (UInt i = 1; i <= used; i++) {
Obj key = LoadSubObj();
Obj val = LoadSubObj();
AddObjMapNew(map, key, val); // No CHANGED_BAG required while loading a workspace
}
} #endif
#ifdef USE_THREADSAFE_COPYING #ifndef WARD_ENABLED staticvoid TraverseObjMap(TraversalState * traversal, Obj obj)
{
UInt i, len = CONST_ADDR_WORD(obj)[OBJSET_SIZE]; for (i = 0; i < len; i++) {
Obj key = READ_SLOT(obj, 2 * i);
Obj val = READ_SLOT(obj, 2 * i + 1); if (key && key != Undefined) {
QueueForTraversal(traversal, key);
QueueForTraversal(traversal, val);
}
}
}
staticvoid CopyObjMap(TraversalState * traversal, Obj copy, Obj original)
{
UInt i, len = CONST_ADDR_WORD(original)[OBJSET_SIZE]; for (i = 0; i < len; i++) {
Obj key = READ_SLOT(original, 2 * i);
Obj val = READ_SLOT(original, 2 * i + 1);
WRITE_SLOT(copy, 2 * i, ReplaceByCopy(traversal, key));
WRITE_SLOT(copy, 2 * i + 1, ReplaceByCopy(traversal, val));
}
} #endif #endif
/** * `FuncOBJ_SET()` * --------------- * * GAP function to create a new object set. * * It takes an optional argument that must be a list containing the elements * of the new set. If no argument is provided, an empty set is created.
*/
static Obj FuncOBJ_SET(Obj self, Obj arg)
{
Obj result;
Obj list;
UInt i, len; switch (LEN_PLIST(arg)) { case 0: return NewObjSet(); case 1:
list = ELM_PLIST(arg, 1); if (!IS_LIST(list))
ErrorQuit("OBJ_SET: Argument must be a list", 0, 0);
result = NewObjSet();
len = LEN_LIST(list); for (i = 1; i <= len; i++) {
Obj obj = ELM_LIST(list, i); if (obj)
AddObjSet(result, obj);
}
CHANGED_BAG(result); return result; default:
ErrorQuit("OBJ_SET: Too many arguments", 0, 0); return (Obj) 0; // flow control hint
}
}
/** * `FuncADD_OBJ_SET()` * ------------------- * * GAP function to add `obj` to `set`.
*/
static Obj FuncADD_OBJ_SET(Obj self, Obj set, Obj obj)
{
RequireArgumentCondition(SELF_NAME, set, TNUM_OBJ(set) == T_OBJSET, "must be a mutable object set");
AddObjSet(set, obj); return 0;
}
/** * `FuncREMOVE_OBJ_SET()` * ---------------------- * * GAP function to remove `obj` from `set`.
*/
static Obj FuncREMOVE_OBJ_SET(Obj self, Obj set, Obj obj)
{
RequireArgumentCondition(SELF_NAME, set, TNUM_OBJ(set) == T_OBJSET, "must be a mutable object set");
RemoveObjSet(set, obj); return 0;
}
/** * `FuncFIND_OBJ_SET()` * ---------------------- * * GAP function to test if `obj` is contained in `set`. Returns `true` or * `false`.
*/
static Obj FuncFIND_OBJ_SET(Obj self, Obj set, Obj obj)
{
RequireArgumentCondition(SELF_NAME, set, IS_OBJSET(set), "must be an object set");
/** * `FuncCLEAR_OBJ_SET()` * --------------------- * * GAP function to remove all objects from `set`.
*/
static Obj FuncCLEAR_OBJ_SET(Obj self, Obj set)
{
RequireArgumentCondition(SELF_NAME, set, TNUM_OBJ(set) == T_OBJSET, "must be a mutable object set");
ClearObjSet(set); return 0;
}
/** * `FuncOBJ_SET_VALUES()` * --------------------- * * GAP function to return values in set as a list.
*/
static Obj FuncOBJ_SET_VALUES(Obj self, Obj set)
{
RequireArgumentCondition(SELF_NAME, set, IS_OBJSET(set), "must be an object set");
return ObjSetValues(set);
}
/** * `FuncOBJ_MAP()` * --------------- * * GAP function to create a new object map. * * It takes an optional argument that must be a list containing the * keys and values for the new map. Keys and values must alternate and * there must be an equal number of keys and values. If no argument is * provided, an empty map is created.
*/
static Obj FuncOBJ_MAP(Obj self, Obj arg)
{
Obj result;
Obj list;
UInt i, len; switch (LEN_PLIST(arg)) { case 0: return NewObjMap(); case 1:
list = ELM_PLIST(arg, 1); if (!IS_LIST(list) || LEN_LIST(list) % 2 != 0)
ErrorQuit("OBJ_MAP: Argument must be a list with even length", 0, 0);
result = NewObjMap();
len = LEN_LIST(list); for (i = 1; i <= len; i += 2) {
Obj key = ELM_LIST(list, i);
Obj value = ELM_LIST(list, i+1); if (key && value)
AddObjMap(result, key, value);
} return result; default:
ErrorQuit("OBJ_MAP: Too many arguments", 0, 0); return (Obj) 0; // flow control hint
}
}
/** * `FuncADD_OBJ_MAP()` * ------------------- * * GAP function to add a (key, value) pair to an object map.
*/
/** * `FuncFIND_OBJ_MAP()` * -------------------- * * GAP function to locate an entry with key `key` within `map`. The * function returns the corresponding value if found and `defvalue` * otherwise.
*/
static Obj FuncFIND_OBJ_MAP(Obj self, Obj map, Obj key, Obj defvalue)
{
RequireArgumentCondition(SELF_NAME, map, IS_OBJMAP(map), "must be an object map");
Int pos = FindObjMap(map, key); if (pos < 0) return defvalue; return READ_SLOT(map, 2 * pos + 1);
}
/** * `FuncCONTAINS_OBJ_MAP()` * ------------------------ * * GAP function to locate an entry with key `key` within `map`. The * function returns true if such an entry exists, false otherwise.
*/
static Obj FuncCONTAINS_OBJ_MAP(Obj self, Obj map, Obj key)
{
RequireArgumentCondition(SELF_NAME, map, IS_OBJMAP(map), "must be an object map");
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.