diff options
Diffstat (limited to 'tcllib/modules/struct/sets/m.c')
-rw-r--r-- | tcllib/modules/struct/sets/m.c | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/tcllib/modules/struct/sets/m.c b/tcllib/modules/struct/sets/m.c new file mode 100644 index 0000000..820435e --- /dev/null +++ b/tcllib/modules/struct/sets/m.c @@ -0,0 +1,772 @@ +/* struct::set - critcl - layer 3 definitions. + * + * -> Set functions. + * Implementations for all set commands. + */ + +#include "s.h" +#include "m.h" + +/* .................................................. */ + +/* + *--------------------------------------------------------------------------- + * + * sm_ADD -- + * + * Copies the argument tree over into this tree object. Uses direct + * access to internal data structures for matching tree objects, and + * goes through a serialize/deserialize combination otherwise. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Only internal, memory allocation changes ... + * + *--------------------------------------------------------------------------- + */ + +int +sm_ADD (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set add SETVAR SET + * [0] [1] [2] [3] + */ + + SPtr vs, s; + Tcl_Obj* val; + int new = 0; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "Avar B"); + return TCL_ERROR; + } + + if (s_get (interp, objv[3], &s) != TCL_OK) { + return TCL_ERROR; + } + + val = Tcl_ObjGetVar2(interp, objv[2], NULL, 0); + if (val == NULL) { + /* Create missing variable */ + + vs = s_dup (NULL); + val = s_new (vs); + (void) Tcl_ObjSetVar2 (interp, objv[2], NULL, val, 0); + + } else if (s_get (interp, val, &vs) != TCL_OK) { + return TCL_ERROR; + } + + if (s->el.numEntries) { + int new, nx = 0; + Tcl_HashSearch hs; + Tcl_HashEntry* he; + CONST char* key; + + for(he = Tcl_FirstHashEntry(&s->el, &hs); + he != NULL; + he = Tcl_NextHashEntry(&hs)) { + key = Tcl_GetHashKey (&s->el, he); + if (Tcl_FindHashEntry (&vs->el, key) != NULL) continue; + /* Key not known to vs, to be added */ + + /* _Now_ unshare the object, if required */ + + if (Tcl_IsShared (val)) { + val = Tcl_DuplicateObj (val); + (void) Tcl_ObjSetVar2 (interp, objv[2], NULL, val, 0); + s_get (interp, val, &vs); + } + + (void*) Tcl_CreateHashEntry(&vs->el, key, &new); + nx = 1; + } + if (nx) { + Tcl_InvalidateStringRep(val); + } + } + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_CONTAINS -- + * + * Copies this tree over into the argument tree. Uses direct access to + * internal data structures for matching tree objects, and goes through a + * serialize/deserialize combination otherwise. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Only internal, memory allocation changes ... + * + *--------------------------------------------------------------------------- + */ + +int +sm_CONTAINS (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set contains SET ITEM + * [0] [1] [2] [3] + */ + + SPtr s; + CONST char* item; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "set item"); + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &s) != TCL_OK) { + return TCL_ERROR; + } + + item = Tcl_GetString (objv [3]); + + Tcl_SetObjResult (interp, + Tcl_NewIntObj (s_contains (s, item))); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_DIFFERENCE -- + * + * Returns a list containing the ancestors of the named node. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_DIFFERENCE (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set difference SETa SETb + * [0] [1] [2] [3] + */ + + SPtr sa, sb; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "A B"); + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &sa) != TCL_OK) { + return TCL_ERROR; + } + if (s_get (interp, objv[3], &sb) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_SetObjResult (interp, + s_new (s_difference (sa, sb))); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_EMPTY -- + * + * Appends a value to an attribute of the named node. + * May create the attribute. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_EMPTY (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set empty SET + * [0] [1] [2] + */ + + SPtr s; + + if (objc != 3) { + Tcl_WrongNumArgs (interp, 2, objv, "set"); + return TCL_ERROR; + } + + if (objv[2]->typePtr == s_ltype ()) { + int lc; + Tcl_Obj** lv; + Tcl_ListObjGetElements(interp, objv[2], &lc, &lv); + Tcl_SetObjResult (interp, Tcl_NewIntObj (lc == 0)); + return TCL_OK; + } + + if (s_get (interp, objv[2], &s) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_SetObjResult (interp, + Tcl_NewIntObj (s_empty (s))); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_EQUAL -- + * + * Returns a dictionary mapping from nodes to attribute values, for a + * named attribute. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_EQUAL (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set equal SETa SETb + * [0] [1] [2] [3] + */ + + SPtr sa, sb; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "A B"); + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &sa) != TCL_OK) { + return TCL_ERROR; + } + if (s_get (interp, objv[3], &sb) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_SetObjResult (interp, + Tcl_NewIntObj (s_equal (sa, sb))); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_EXCLUDE -- + * + * Returns a list of all direct or indirect descendants of the named + * node, possibly run through a Tcl command prefix for filtering. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. Per the filter command prefix, if + * one has been specified. + * + *--------------------------------------------------------------------------- + */ + +int +sm_EXCLUDE (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set exclude SETVAR ITEM + * [0] [1] [2] [3] + */ + + SPtr vs; + Tcl_Obj* val; + char* key; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "Avar element"); + return TCL_ERROR; + } + + val = Tcl_ObjGetVar2(interp, objv[2], NULL, TCL_LEAVE_ERR_MSG); + if (val == NULL) { + return TCL_ERROR; + } + if (s_get (interp, val, &vs) != TCL_OK) { + return TCL_ERROR; + } + + key = Tcl_GetString (objv[3]); + if (s_contains (vs, key)) { + if (Tcl_IsShared (val)) { + val = Tcl_DuplicateObj (val); + (void) Tcl_ObjSetVar2 (interp, objv[2], NULL, val, 0); + s_get (interp, val, &vs); + } + + s_subtract1 (vs, key); + Tcl_InvalidateStringRep(val); + } + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_INCLUDE -- + * + * Deletes the named nodes, but not its children. They are put into the + * place where the deleted node was. Complementary to sm_SPLICE. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_INCLUDE (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set include SETVAR ITEM + * [0] [1] [2] [3] + */ + + SPtr vs; + Tcl_Obj* val; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "Avar element"); + return TCL_ERROR; + } + + val = Tcl_ObjGetVar2(interp, objv[2], NULL, 0); + if (val == NULL) { + /* Create missing variable */ + + vs = s_dup (NULL); + s_add1 (vs, Tcl_GetString (objv[3])); + val = s_new (vs); + + (void) Tcl_ObjSetVar2 (interp, objv[2], NULL, val, 0); + } else { + /* Extend variable */ + char* key; + + if (s_get (interp, val, &vs) != TCL_OK) { + return TCL_ERROR; + } + + key = Tcl_GetString (objv[3]); + if (!s_contains (vs, key)) { + if (Tcl_IsShared (val)) { + val = Tcl_DuplicateObj (val); + (void) Tcl_ObjSetVar2 (interp, objv[2], NULL, val, 0); + s_get (interp, val, &vs); + } + + s_add1 (vs, key); + Tcl_InvalidateStringRep(val); + } + } + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_INTERSECT -- + * + * Deletes the named node and its children. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_INTERSECT (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set intersect ?SET...? + * [0] [1] [2] + */ + + SPtr sa, sb, next, acc; + int i; + + if (objc == 2) { + /* intersect nothing = nothing */ + Tcl_SetObjResult (interp, s_new (s_dup (NULL))); + return TCL_OK; + } + + for (i = 2; i < objc; i++) { + if (s_get (interp, objv[i], &sa) != TCL_OK) { + return TCL_ERROR; + } + } + + s_get (interp, objv[2], &sa); + + if (objc == 3) { + /* intersect with itself = unchanged */ + Tcl_SetObjResult (interp, s_new (s_dup (sa))); + return TCL_OK; + } + + acc = sa; + for (i = 3; i < objc; i++) { + s_get (interp, objv[i], &sb); + next = s_intersect (acc, sb); + if (acc != sa) s_free (acc); + acc = next; + if (s_empty (acc)) break; + } + + if (acc == sa) { + acc = s_dup (acc); + } + + Tcl_SetObjResult (interp, s_new (acc)); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_INTERSECT3 -- + * + * Returns a non-negative integer number describing the distance between + * the named node and the root of the tree. A depth of 0 implies that + * the node is the root node. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_INTERSECT3 (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set intersect3 SETa SETb + * [0] [1] [2] [3] + */ + + SPtr sa, sb; + Tcl_Obj* lv [3]; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "A B"); + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &sa) != TCL_OK) { + return TCL_ERROR; + } + if (s_get (interp, objv[3], &sb) != TCL_OK) { + return TCL_ERROR; + } + + lv [0] = s_new (s_intersect (sa, sb)); + lv [1] = s_new (s_difference (sa, sb)); + lv [2] = s_new (s_difference (sb, sa)); + + Tcl_SetObjResult (interp, Tcl_NewListObj (3, lv)); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_SIZE -- + * + * Returns a list of all descendants of the named node, possibly run + * through a Tcl command prefix for filtering. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. Per the filter command prefix, if + * one has been specified. + * + *--------------------------------------------------------------------------- + */ + +int +sm_SIZE (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set size SET + * [0] [1] [2] + */ + + SPtr s; + + if (objc != 3) { + Tcl_WrongNumArgs (interp, 2, objv, "set"); + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &s) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_SetObjResult (interp, + Tcl_NewIntObj (s_size (s))); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_SUBSETOF -- + * + * Parses a Tcl value containing a serialized tree and copies it over + * he existing tree. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_SUBSETOF (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set subsetof SETa SETb + * [0] [1] [2] [3] + */ + + SPtr sa, sb; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "A B"); + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &sa) != TCL_OK) { + return TCL_ERROR; + } + if (s_get (interp, objv[3], &sb) != TCL_OK) { + return TCL_ERROR; + } + + Tcl_SetObjResult (interp, + Tcl_NewIntObj (s_subsetof (sa, sb))); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_SUBTRACT -- + * + * Destroys the whole tree object. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * Releases memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_SUBTRACT (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set subtract SETVAR SET + * [0] [1] [2] [3] + */ + + SPtr vs, s; + Tcl_Obj* val; + int del; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "Avar B"); + return TCL_ERROR; + } + + val = Tcl_ObjGetVar2(interp, objv[2], NULL, TCL_LEAVE_ERR_MSG); + if (val == NULL) { + return TCL_ERROR; + } + if (s_get (interp, val, &vs) != TCL_OK) { + return TCL_ERROR; + } + if (s_get (interp, objv[3], &s) != TCL_OK) { + return TCL_ERROR; + } + + if (s->el.numEntries) { + int new, dx = 0; + Tcl_HashSearch hs; + Tcl_HashEntry* he; + CONST char* key; + + for(he = Tcl_FirstHashEntry(&s->el, &hs); + he != NULL; + he = Tcl_NextHashEntry(&hs)) { + key = Tcl_GetHashKey (&s->el, he); + if (Tcl_FindHashEntry (&vs->el, key) == NULL) continue; + /* Key known to vs, to be removed */ + + /* _Now_ unshare the object, if required */ + + if (Tcl_IsShared (val)) { + val = Tcl_DuplicateObj (val); + (void) Tcl_ObjSetVar2 (interp, objv[2], NULL, val, 0); + s_get (interp, val, &vs); + } + + Tcl_DeleteHashEntry (Tcl_FindHashEntry (&vs->el, key)); + dx = 1; + } + if (dx) { + Tcl_InvalidateStringRep(val); + } + } + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_SYMDIFF -- + * + * Returns a boolean value signaling whether the named node exists in + * the tree. True implies existence, and false non-existence. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_SYMDIFF (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set symdiff SETa SETb + * [0] [1] [2] [3] + */ + + SPtr sa, sb, xa, xb, u; + + if (objc != 4) { + Tcl_WrongNumArgs (interp, 2, objv, "A B"); + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &sa) != TCL_OK) { + return TCL_ERROR; + } + if (s_get (interp, objv[3], &sb) != TCL_OK) { + return TCL_ERROR; + } + + if (s_get (interp, objv[2], &sa) != TCL_OK) { + return TCL_ERROR; + } + if (s_get (interp, objv[3], &sb) != TCL_OK) { + return TCL_ERROR; + } + + xa = s_difference (sa, sb); + xb = s_difference (sb, sa); + u = s_union (xa, xb); + + s_free (xa); + s_free (xb); + + Tcl_SetObjResult (interp, s_new (u)); + return TCL_OK; +} + +/* + *--------------------------------------------------------------------------- + * + * sm_UNION -- + * + * Returns the value of the named attribute at the given node. + * + * Results: + * A standard Tcl result code. + * + * Side effects: + * May release and allocate memory. + * + *--------------------------------------------------------------------------- + */ + +int +sm_UNION (ClientData clientData, Tcl_Interp* interp, int objc, Tcl_Obj* CONST* objv) +{ + /* Syntax: set union ?SET...? + * [0] [1] [2] + */ + + SPtr sa, acc; + int i; + + if (objc == 2) { + /* union nothing = nothing */ + Tcl_SetObjResult (interp, s_new (s_dup (NULL))); + return TCL_OK; + } + + for (i = 2; i < objc; i++) { + if (s_get (interp, objv[i], &sa) != TCL_OK) { + return TCL_ERROR; + } + } + + acc = s_dup (NULL); + + for (i = 2; i < objc; i++) { + s_get (interp, objv[i], &sa); + s_add (acc, sa, NULL); + } + + Tcl_SetObjResult (interp, s_new (acc)); + return TCL_OK; +} + +/* .................................................. */ + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |