18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Based on strlist.c by:
48c2ecf20Sopenharmony_ci * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <errno.h>
88c2ecf20Sopenharmony_ci#include <stdio.h>
98c2ecf20Sopenharmony_ci#include <stdlib.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "rblist.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ciint rblist__add_node(struct rblist *rblist, const void *new_entry)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct rb_node **p = &rblist->entries.rb_root.rb_node;
168c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL, *new_node;
178c2ecf20Sopenharmony_ci	bool leftmost = true;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	while (*p != NULL) {
208c2ecf20Sopenharmony_ci		int rc;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci		parent = *p;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci		rc = rblist->node_cmp(parent, new_entry);
258c2ecf20Sopenharmony_ci		if (rc > 0)
268c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
278c2ecf20Sopenharmony_ci		else if (rc < 0) {
288c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
298c2ecf20Sopenharmony_ci			leftmost = false;
308c2ecf20Sopenharmony_ci		}
318c2ecf20Sopenharmony_ci		else
328c2ecf20Sopenharmony_ci			return -EEXIST;
338c2ecf20Sopenharmony_ci	}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	new_node = rblist->node_new(rblist, new_entry);
368c2ecf20Sopenharmony_ci	if (new_node == NULL)
378c2ecf20Sopenharmony_ci		return -ENOMEM;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	rb_link_node(new_node, parent, p);
408c2ecf20Sopenharmony_ci	rb_insert_color_cached(new_node, &rblist->entries, leftmost);
418c2ecf20Sopenharmony_ci	++rblist->nr_entries;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	return 0;
448c2ecf20Sopenharmony_ci}
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_civoid rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	rb_erase_cached(rb_node, &rblist->entries);
498c2ecf20Sopenharmony_ci	--rblist->nr_entries;
508c2ecf20Sopenharmony_ci	rblist->node_delete(rblist, rb_node);
518c2ecf20Sopenharmony_ci}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic struct rb_node *__rblist__findnew(struct rblist *rblist,
548c2ecf20Sopenharmony_ci					 const void *entry,
558c2ecf20Sopenharmony_ci					 bool create)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	struct rb_node **p = &rblist->entries.rb_root.rb_node;
588c2ecf20Sopenharmony_ci	struct rb_node *parent = NULL, *new_node = NULL;
598c2ecf20Sopenharmony_ci	bool leftmost = true;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	while (*p != NULL) {
628c2ecf20Sopenharmony_ci		int rc;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		parent = *p;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci		rc = rblist->node_cmp(parent, entry);
678c2ecf20Sopenharmony_ci		if (rc > 0)
688c2ecf20Sopenharmony_ci			p = &(*p)->rb_left;
698c2ecf20Sopenharmony_ci		else if (rc < 0) {
708c2ecf20Sopenharmony_ci			p = &(*p)->rb_right;
718c2ecf20Sopenharmony_ci			leftmost = false;
728c2ecf20Sopenharmony_ci		}
738c2ecf20Sopenharmony_ci		else
748c2ecf20Sopenharmony_ci			return parent;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (create) {
788c2ecf20Sopenharmony_ci		new_node = rblist->node_new(rblist, entry);
798c2ecf20Sopenharmony_ci		if (new_node) {
808c2ecf20Sopenharmony_ci			rb_link_node(new_node, parent, p);
818c2ecf20Sopenharmony_ci			rb_insert_color_cached(new_node,
828c2ecf20Sopenharmony_ci					       &rblist->entries, leftmost);
838c2ecf20Sopenharmony_ci			++rblist->nr_entries;
848c2ecf20Sopenharmony_ci		}
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return new_node;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistruct rb_node *rblist__find(struct rblist *rblist, const void *entry)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return __rblist__findnew(rblist, entry, false);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistruct rb_node *rblist__findnew(struct rblist *rblist, const void *entry)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	return __rblist__findnew(rblist, entry, true);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_civoid rblist__init(struct rblist *rblist)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	if (rblist != NULL) {
1038c2ecf20Sopenharmony_ci		rblist->entries	 = RB_ROOT_CACHED;
1048c2ecf20Sopenharmony_ci		rblist->nr_entries = 0;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_civoid rblist__exit(struct rblist *rblist)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct rb_node *pos, *next = rb_first_cached(&rblist->entries);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	while (next) {
1158c2ecf20Sopenharmony_ci		pos = next;
1168c2ecf20Sopenharmony_ci		next = rb_next(pos);
1178c2ecf20Sopenharmony_ci		rblist__remove_node(rblist, pos);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_civoid rblist__delete(struct rblist *rblist)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	if (rblist != NULL) {
1248c2ecf20Sopenharmony_ci		rblist__exit(rblist);
1258c2ecf20Sopenharmony_ci		free(rblist);
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistruct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	struct rb_node *node;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	for (node = rb_first_cached(&rblist->entries); node;
1348c2ecf20Sopenharmony_ci	     node = rb_next(node)) {
1358c2ecf20Sopenharmony_ci		if (!idx--)
1368c2ecf20Sopenharmony_ci			return node;
1378c2ecf20Sopenharmony_ci	}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	return NULL;
1408c2ecf20Sopenharmony_ci}
141