Set
A small collection of unique void * values. Membership is linear in the size of the set. Use the set functions to preserve uniqueness. For hashed membership, see hashset.
Usage#
Initialize the set with an equality callback and an optional payload destructor. The equality callback returns 0 for equal values. This example passes NULL for the destructor because its payloads are stack allocated.
int int_match(const void *a, const void *b) {
return *(const int *)a == *(const int *)b ? 0 : 1;
}
Set set;
if (set_init(&set, int_match, NULL) == 0) {
int value = 1;
int duplicate = 1;
set_insert(&set, &value);
set_insert(&set, &duplicate); /* Keeps value if the first insert succeeded. */
set_destroy(&set);
}
set_destroy frees the nodes and calls the destructor on remaining payloads. It does not free the Set handle. Keep values unchanged in ways that affect equality while stored.
Structs#
Set#
typedef struct {
List impl;
} Set;
match is required at set_init. It returns 0 if two elements are equal (the same convention as strcmp). Compare with ==, not subtraction, so signed overflow is not an issue.
Functions#
set_init#
Initializes the set. The user owns the Set handle. match is required; destroy is optional and is called on members only by set_destroy. Returns 0 on success, -1 if set or match is NULL.
int set_init(Set *set, int (*match)(const void *a, const void *b),
void (*destroy)(void *data));
/* Usage */
int int_match(const void *a, const void *b) {
return *(const int *)a == *(const int *)b ? 0 : 1;
}
Set set;
set_init(&set, int_match, NULL);set_destroy#
Destroys the nodes inside a Set and calls the deallocation function on the data if one was provided. Does not destroy the set itself, that is left up to the user.
void set_destroy(Set *set);
/* Usage */
set_destroy(&set);set_insert#
Inserts data into the set. If data is already a member (determined by the match function), the insertion is skipped and 1 is returned. Returns 0 on successful insertion, -1 on error. Duplicate and failed inserts leave the payload with the caller.
int set_insert(Set *set, const void *data);
/* Usage */
int a = 1;
int b = 1;
set_insert(&set, &a); /* returns 0, inserted */
set_insert(&set, &b); /* returns 1, duplicate skipped */set_remove#
Removes the element matching *data from the set. data is updated to point to the removed element's data so the user can manage its memory. The destructor is not called. Returns 0 on success, -1 if the element is not found or if data is NULL.
int set_remove(Set *set, void **data);
/* Usage */
int key = 1;
void *removed = &key;
set_remove(&set, &removed);Algebra (borrowed)#
set_union, set_intersection, and set_difference write into a destination you initialize. The destination must be empty, use the same match as a and b, and have destroy == NULL. Result members alias the payloads in a and b. Do not destroy a or b while the result is in use. dest cannot be a or b. Returns 0 on success, -1 on error. Allocation failure leaves the destination empty and initialized.
int set_union(Set *dest, const Set *a, const Set *b);
int set_intersection(Set *dest, const Set *a, const Set *b);
int set_difference(Set *dest, const Set *a, const Set *b);
/* Usage */
Set result;
set_init(&result, int_match, NULL);
set_union(&result, &set1, &set2);
/* use result, then: */
set_destroy(&result); /* nodes only; payloads still owned by set1/set2 */
Union contains every element from a or b. Intersection contains elements present in both. Difference is elements in a that are not in b.
set_is_member#
Returns 1 if data is a member of the set, 0 otherwise.
int set_is_member(const Set *set, const void *data);set_is_subset#
Returns 1 if a is a subset of b (every element in a is also in b), 0 otherwise.
int set_is_subset(const Set *a, const Set *b);set_is_equal#
Returns 1 if sets a and b contain the same elements, 0 otherwise.
int set_is_equal(const Set *a, const Set *b);Macros#
set_size#
Returns the number of elements in the set.
#define set_size(s) ((s)->impl.size)