Browse Source

faux.list: List can be sorted/unsorted, unique/non-unique

Serj Kalichev 3 months ago
parent
commit
eb0c999b9c
6 changed files with 134 additions and 55 deletions
  1. 1 0
      .gitignore
  2. 1 1
      faux/ini/ini.c
  3. 11 9
      faux/list.h
  4. 101 39
      faux/list/list.c
  5. 5 2
      faux/list/private.h
  6. 15 4
      testc/testc.c

+ 1 - 0
.gitignore

@@ -40,6 +40,7 @@
 /bin/konf
 /bin/konfd
 /bin/sigexec
+/testc/testc
 
 # Docs
 /doc/*.html

+ 1 - 1
faux/ini/ini.c

@@ -30,7 +30,7 @@ faux_ini_t *faux_ini_new(void) {
 		return NULL;
 
 	// Init
-	ini->list = faux_list_new(faux_pair_compare, faux_pair_free);
+	ini->list = faux_list_new(BOOL_TRUE, BOOL_TRUE, faux_pair_compare, NULL, faux_pair_free);
 
 	return ini;
 }

+ 11 - 9
faux/list.h

@@ -12,9 +12,9 @@
 typedef struct faux_list_node_s faux_list_node_t;
 typedef struct faux_list_s faux_list_t;
 
-typedef int faux_list_compare_fn(const void *first, const void *second);
-typedef void faux_list_free_fn(void *data);
-typedef int faux_list_match_fn(const void *key, const void *data);
+typedef int (*faux_list_cmp_fn)(const void *new_item, const void *list_item);
+typedef int (*faux_list_kcmp_fn)(const void *key, const void *list_item);
+typedef void (*faux_list_free_fn)(void *list_item);
 
 C_DECL_BEGIN
 
@@ -23,10 +23,13 @@ faux_list_node_t *faux_list_prev_node(const faux_list_node_t *node);
 faux_list_node_t *faux_list_next_node(const faux_list_node_t *node);
 void *faux_list_data(const faux_list_node_t *node);
 faux_list_node_t *faux_list_each_node(faux_list_node_t **iter);
+faux_list_node_t *faux_list_eachr_node(faux_list_node_t **iter);
 void *faux_list_each(faux_list_node_t **iter);
+void *faux_list_eachr(faux_list_node_t **iter);
 
 // list_t methods
-faux_list_t *faux_list_new(faux_list_compare_fn compareFn,
+faux_list_t *faux_list_new(bool_t sorted, bool_t unique,
+	faux_list_cmp_fn cmpFn, faux_list_kcmp_fn kcmpFn,
 	faux_list_free_fn freeFn);
 void faux_list_free(faux_list_t *list);
 
@@ -35,21 +38,20 @@ faux_list_node_t *faux_list_tail(const faux_list_t *list);
 size_t faux_list_len(const faux_list_t *list);
 
 faux_list_node_t *faux_list_add(faux_list_t *list, void *data);
-faux_list_node_t *faux_list_add_uniq(faux_list_t *list, void *data);
 faux_list_node_t *faux_list_add_find(faux_list_t *list, void *data);
 void *faux_list_takeaway(faux_list_t *list, faux_list_node_t *node);
 int faux_list_del(faux_list_t *list, faux_list_node_t *node);
 
 faux_list_node_t *faux_list_match_node(const faux_list_t *list,
-	faux_list_match_fn matchFn, const void *userkey,
+	faux_list_kcmp_fn matchFn, const void *userkey,
 	faux_list_node_t **saveptr);
 void *faux_list_match(const faux_list_t *list,
-	faux_list_match_fn matchFn, const void *userkey,
+	faux_list_kcmp_fn matchFn, const void *userkey,
 	faux_list_node_t **saveptr);
 faux_list_node_t *faux_list_find_node(const faux_list_t *list,
-	faux_list_match_fn matchFn, const void *userkey);
+	faux_list_kcmp_fn matchFn, const void *userkey);
 void *faux_list_find(const faux_list_t *list,
-	faux_list_match_fn matchFn, const void *userkey);
+	faux_list_kcmp_fn matchFn, const void *userkey);
 
 C_DECL_END
 

+ 101 - 39
faux/list/list.c

@@ -119,6 +119,27 @@ faux_list_node_t *faux_list_each_node(faux_list_node_t **iter) {
 }
 
 
+/** @brief Iterate through each list node. Reverse order.
+ *
+ * On each call to this function the iterator will change its value.
+ * Before function using the iterator must be initialised by list tail node.
+ *
+ * @param [in,out] iter List node ptr used as an iterator.
+ * @return List node or NULL if list elements are over.
+ */
+faux_list_node_t *faux_list_eachr_node(faux_list_node_t **iter) {
+
+	faux_list_node_t *current_node = *iter;
+
+	// No assert() on current_node. NULL iterator is normal
+	if (!current_node)
+		return NULL;
+	*iter = faux_list_prev_node(current_node);
+
+	return current_node;
+}
+
+
 /** @brief Iterate through each list node and returns user data.
  *
  * On each call to this function the iterator will change its value.
@@ -140,24 +161,56 @@ void *faux_list_each(faux_list_node_t **iter) {
 }
 
 
+/** @brief Iterate (reverse order) through each list node and returns user data.
+ *
+ * On each call to this function the iterator will change its value.
+ * Before function using the iterator must be initialised by list head node.
+ *
+ * @param [in,out] iter List node ptr used as an iterator.
+ * @return User data or NULL if list elements are over.
+ */
+void *faux_list_eachr(faux_list_node_t **iter) {
+
+	faux_list_node_t *current_node = NULL;
+
+	// No assert() on current_node. NULL iterator is normal
+	if (!*iter)
+		return NULL;
+	current_node = faux_list_eachr_node(iter);
+
+	return faux_list_data(current_node);
+}
+
+
 /** @brief Allocate and initialize bidirectional list.
  *
  * Prototypes for callback functions:
  * @code
- * int faux_list_compare_fn(const void *first, const void *second);
+ * int faux_list_cmp_fn(const void *new_item, const void *list_item);
  * void faux_list_free_fn(void *data);
  * @endcode
  *
+ * @param [in] sorted If list is sorted - BOOL_TRUE, unsorted - BOOL_FALSE.
+ * @param [in] unique If list entry is unique - BOOL_TRUE, else - BOOL_FALSE.
  * @param [in] compareFn Callback function to compare two user data instances
  * to sort list.
  * @param [in] freeFn Callback function to free user data.
  * @return Newly created bidirectional list or NULL on error.
  */
-faux_list_t *faux_list_new(
-	faux_list_compare_fn compareFn, faux_list_free_fn freeFn) {
+faux_list_t *faux_list_new(bool_t sorted, bool_t unique,
+	faux_list_cmp_fn cmpFn, faux_list_kcmp_fn kcmpFn,
+	faux_list_free_fn freeFn) {
 
 	faux_list_t *list = NULL;
 
+	// Sorted list must have cmpFn
+	if (sorted && !cmpFn)
+		return NULL;
+
+	// Unique list must have cmpFn
+	if (unique && !cmpFn)
+		return NULL;
+
 	list = faux_zmalloc(sizeof(*list));
 	assert(list);
 	if (!list)
@@ -166,7 +219,10 @@ faux_list_t *faux_list_new(
 	// Initialize
 	list->head = NULL;
 	list->tail = NULL;
-	list->compareFn = compareFn;
+	list->sorted = sorted;
+	list->unique = unique;
+	list->cmpFn = cmpFn;
+	list->kcmpFn = kcmpFn;
 	list->freeFn = freeFn;
 	list->len = 0;
 
@@ -187,7 +243,6 @@ void faux_list_free(faux_list_t *list) {
 
 	faux_list_node_t *iter = NULL;
 
-	assert(list);
 	if (!list)
 		return;
 
@@ -247,14 +302,13 @@ size_t faux_list_len(const faux_list_t *list) {
  *
  * @param [in] list List to add node to.
  * @param [in] data User data for new list node.
- * @param [in] uniq - true/false Don't add entry with identical order
- * key (when the compareFn() returns 0)
+ * key (when the cmpFn() returns 0)
  * @param [in] find - true/false Function returns list node if there is
  * identical entry. Or NULL if find is false.
  * @return Newly added list node.
  */
 static faux_list_node_t *faux_list_add_generic(
-	faux_list_t *list, void *data, bool_t uniq, bool_t find) {
+	faux_list_t *list, void *data, bool_t find) {
 
 	faux_list_node_t *node = NULL;
 	faux_list_node_t *iter = NULL;
@@ -268,7 +322,7 @@ static faux_list_node_t *faux_list_add_generic(
 	if (!node)
 		return NULL;
 
-	// Empty list.
+	// Empty list
 	if (!list->head) {
 		list->head = node;
 		list->tail = node;
@@ -276,8 +330,21 @@ static faux_list_node_t *faux_list_add_generic(
 		return node;
 	}
 
-	// Not sorted list. Add to the tail.
-	if (!list->compareFn) {
+	// Non-sorted: Insert to tail
+	if (!list->sorted) {
+		// Unique: Search through whole list
+		if (list->unique) {
+			iter = list->tail;
+			while (iter) {
+				int res = list->cmpFn(node->data, iter->data);
+				if (0 == res) { // Already in list
+					faux_list_free_node(node);
+					return (find ? iter : NULL);
+				}
+				iter = iter->prev;
+			}
+		}
+		// Add entry to the tail
 		node->prev = list->tail;
 		node->next = NULL;
 		list->tail->next = node;
@@ -286,15 +353,16 @@ static faux_list_node_t *faux_list_add_generic(
 		return node;
 	}
 
-	// Sorted list.
+	// Sorted: Insert from tail
 	iter = list->tail;
 	while (iter) {
-		int res = list->compareFn(node->data, iter->data);
-
-		if (uniq && (0 == res)) {
+		int res = list->cmpFn(node->data, iter->data);
+		// Unique: Already exists
+		if (list->unique && (0 == res)) {
 			faux_list_free_node(node);
 			return (find ? iter : NULL);
 		}
+		// Non-unique: Entry will be inserted after existent one
 		if (res >= 0) {
 			node->next = iter->next;
 			node->prev = iter;
@@ -320,7 +388,7 @@ static faux_list_node_t *faux_list_add_generic(
 }
 
 
-/** @brief Adds user data (not unique) to the list.
+/** @brief Adds user data to the list.
  *
  * The user data is not unique. It means that two equal user data instances
  * can be added to the list.
@@ -331,23 +399,7 @@ static faux_list_node_t *faux_list_add_generic(
  */
 faux_list_node_t *faux_list_add(faux_list_t *list, void *data) {
 
-	return faux_list_add_generic(list, data, BOOL_FALSE, BOOL_FALSE);
-}
-
-
-/** @brief Adds user data (unique) to the list.
- *
- * The user data must be unique. It means that two equal user data instances
- * can not be added to the list. Function will return NULL if equal user
- * data is already in the list.
- *
- * @param [in] list List to add entry to.
- * @param [in] data User data.
- * @return Newly created list node or NULL on error.
- */
-faux_list_node_t *faux_list_add_uniq(faux_list_t *list, void *data) {
-
-	return faux_list_add_generic(list, data, BOOL_TRUE, BOOL_FALSE);
+	return faux_list_add_generic(list, data, BOOL_FALSE);
 }
 
 
@@ -363,7 +415,17 @@ faux_list_node_t *faux_list_add_uniq(faux_list_t *list, void *data) {
  */
 faux_list_node_t *faux_list_add_find(faux_list_t *list, void *data) {
 
-	return faux_list_add_generic(list, data, BOOL_TRUE, BOOL_TRUE);
+	assert(list);
+	if (!list)
+		return NULL;
+
+	// Function add_find has no meaning for non-unique list. What is the
+	// function behaviour? It found entry. Must it return existent entry or
+	// add new non-unique entry?
+	if (!list->unique)
+		return NULL;
+
+	return faux_list_add_generic(list, data, BOOL_TRUE);
 }
 
 
@@ -444,7 +506,7 @@ int faux_list_del(faux_list_t *list, faux_list_node_t *node) {
  *
  * Prototype for matchFn callback function:
  * @code
- * int faux_list_match_fn(const void *key, const void *data);
+ * int faux_list_kcmp_fn(const void *key, const void *list_item);
  * @endcode
  *
  * @param [in] list List.
@@ -454,7 +516,7 @@ int faux_list_del(faux_list_t *list, faux_list_node_t *node) {
  * @return Matched list node.
  */
 faux_list_node_t *faux_list_match_node(const faux_list_t *list,
-	faux_list_match_fn matchFn, const void *userkey,
+	faux_list_kcmp_fn matchFn, const void *userkey,
 	faux_list_node_t **saveptr) {
 
 	faux_list_node_t *iter = NULL;
@@ -491,7 +553,7 @@ faux_list_node_t *faux_list_match_node(const faux_list_t *list,
  *
  * @sa faux_list_match_node()
  */
-void *faux_list_match(const faux_list_t *list, faux_list_match_fn matchFn,
+void *faux_list_match(const faux_list_t *list, faux_list_kcmp_fn matchFn,
 	const void *userkey, faux_list_node_t **saveptr) {
 
 	faux_list_node_t *res =
@@ -511,7 +573,7 @@ void *faux_list_match(const faux_list_t *list, faux_list_match_fn matchFn,
  * @sa faux_list_match_node()
  */
 faux_list_node_t *faux_list_find_node(const faux_list_t *list,
-	faux_list_match_fn matchFn, const void *userkey) {
+	faux_list_kcmp_fn matchFn, const void *userkey) {
 
 	return faux_list_match_node(list, matchFn, userkey, NULL);
 }
@@ -524,7 +586,7 @@ faux_list_node_t *faux_list_find_node(const faux_list_t *list,
  *
  * @sa faux_list_match_node()
  */
-void *faux_list_find(const faux_list_t *list, faux_list_match_fn matchFn,
+void *faux_list_find(const faux_list_t *list, faux_list_kcmp_fn matchFn,
 	const void *userkey) {
 
 	return faux_list_match(list, matchFn, userkey, NULL);

+ 5 - 2
faux/list/private.h

@@ -9,7 +9,10 @@ struct faux_list_node_s {
 struct faux_list_s {
 	faux_list_node_t *head;
 	faux_list_node_t *tail;
-	faux_list_compare_fn *compareFn; // Function to compare two list elements
-	faux_list_free_fn *freeFn; // Function to properly free data field
+	bool_t sorted;
+	bool_t unique;
+	faux_list_cmp_fn cmpFn; // Function to compare two list elements
+	faux_list_kcmp_fn kcmpFn; // Function to compare key and list element
+	faux_list_free_fn freeFn; // Function to properly free data field
 	size_t len;
 };

+ 15 - 4
testc/testc.c

@@ -48,18 +48,28 @@ static void help(int status, const char *argv0);
 int main(int argc, char *argv[]) {
 
 	opts_t *opts = NULL;
+	faux_list_node_t *iter = NULL;
+	char *so = NULL;
 
 #if HAVE_LOCALE_H
 	// Set current locale
 	setlocale(LC_ALL, "");
 #endif
 
+	// Parse command line options
 	opts = opts_parse(argc, argv);
 	if (!opts) {
 		fprintf(stderr, "Error: Can't parse command line options\n");
 		return -1;
 	}
 
+	iter = faux_list_head(opts->so_list);
+	while ((so = faux_list_each(&iter))) {
+		printf("%s\n", so);
+	}
+	
+
+
 	opts_free(opts);
 
 	return 0;
@@ -89,7 +99,8 @@ static opts_t *opts_new(void) {
 	opts->debug = BOOL_FALSE;
 
 	// Members of list are static strings from argv so don't free() it
-	opts->so_list = faux_list_new(NULL, NULL);
+	opts->so_list = faux_list_new(BOOL_FALSE, BOOL_TRUE,
+		(faux_list_cmp_fn)strcmp, NULL, NULL);
 	if (!opts->so_list) {
 		opts_free(opts);
 		return NULL;
@@ -147,9 +158,9 @@ static opts_t *opts_parse(int argc, char *argv[]) {
 	}
 
 	if (optind < argc) {
-		int i;
-		for (i = argc - 1; i >= optind; i--)
-			faux_list_add_uniq(opts->so_list, argv[i]);
+		int i = 0;
+		for (i = optind; i < argc; i++)
+			faux_list_add(opts->so_list, argv[i]);
 	} else {
 		help(-1, argv[0]);
 		exit(-1);