162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Based on strlist.c by:
462306a36Sopenharmony_ci * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <errno.h>
862306a36Sopenharmony_ci#include <stdio.h>
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "rblist.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ciint rblist__add_node(struct rblist *rblist, const void *new_entry)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	struct rb_node **p = &rblist->entries.rb_root.rb_node;
1662306a36Sopenharmony_ci	struct rb_node *parent = NULL, *new_node;
1762306a36Sopenharmony_ci	bool leftmost = true;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	while (*p != NULL) {
2062306a36Sopenharmony_ci		int rc;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci		parent = *p;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci		rc = rblist->node_cmp(parent, new_entry);
2562306a36Sopenharmony_ci		if (rc > 0)
2662306a36Sopenharmony_ci			p = &(*p)->rb_left;
2762306a36Sopenharmony_ci		else if (rc < 0) {
2862306a36Sopenharmony_ci			p = &(*p)->rb_right;
2962306a36Sopenharmony_ci			leftmost = false;
3062306a36Sopenharmony_ci		}
3162306a36Sopenharmony_ci		else
3262306a36Sopenharmony_ci			return -EEXIST;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	new_node = rblist->node_new(rblist, new_entry);
3662306a36Sopenharmony_ci	if (new_node == NULL)
3762306a36Sopenharmony_ci		return -ENOMEM;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	rb_link_node(new_node, parent, p);
4062306a36Sopenharmony_ci	rb_insert_color_cached(new_node, &rblist->entries, leftmost);
4162306a36Sopenharmony_ci	++rblist->nr_entries;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	return 0;
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_civoid rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
4762306a36Sopenharmony_ci{
4862306a36Sopenharmony_ci	rb_erase_cached(rb_node, &rblist->entries);
4962306a36Sopenharmony_ci	--rblist->nr_entries;
5062306a36Sopenharmony_ci	rblist->node_delete(rblist, rb_node);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic struct rb_node *__rblist__findnew(struct rblist *rblist,
5462306a36Sopenharmony_ci					 const void *entry,
5562306a36Sopenharmony_ci					 bool create)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct rb_node **p = &rblist->entries.rb_root.rb_node;
5862306a36Sopenharmony_ci	struct rb_node *parent = NULL, *new_node = NULL;
5962306a36Sopenharmony_ci	bool leftmost = true;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	while (*p != NULL) {
6262306a36Sopenharmony_ci		int rc;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		parent = *p;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci		rc = rblist->node_cmp(parent, entry);
6762306a36Sopenharmony_ci		if (rc > 0)
6862306a36Sopenharmony_ci			p = &(*p)->rb_left;
6962306a36Sopenharmony_ci		else if (rc < 0) {
7062306a36Sopenharmony_ci			p = &(*p)->rb_right;
7162306a36Sopenharmony_ci			leftmost = false;
7262306a36Sopenharmony_ci		}
7362306a36Sopenharmony_ci		else
7462306a36Sopenharmony_ci			return parent;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (create) {
7862306a36Sopenharmony_ci		new_node = rblist->node_new(rblist, entry);
7962306a36Sopenharmony_ci		if (new_node) {
8062306a36Sopenharmony_ci			rb_link_node(new_node, parent, p);
8162306a36Sopenharmony_ci			rb_insert_color_cached(new_node,
8262306a36Sopenharmony_ci					       &rblist->entries, leftmost);
8362306a36Sopenharmony_ci			++rblist->nr_entries;
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci	}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	return new_node;
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistruct rb_node *rblist__find(struct rblist *rblist, const void *entry)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	return __rblist__findnew(rblist, entry, false);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistruct rb_node *rblist__findnew(struct rblist *rblist, const void *entry)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	return __rblist__findnew(rblist, entry, true);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_civoid rblist__init(struct rblist *rblist)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (rblist != NULL) {
10362306a36Sopenharmony_ci		rblist->entries	 = RB_ROOT_CACHED;
10462306a36Sopenharmony_ci		rblist->nr_entries = 0;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	return;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_civoid rblist__exit(struct rblist *rblist)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct rb_node *pos, *next = rb_first_cached(&rblist->entries);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	while (next) {
11562306a36Sopenharmony_ci		pos = next;
11662306a36Sopenharmony_ci		next = rb_next(pos);
11762306a36Sopenharmony_ci		rblist__remove_node(rblist, pos);
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_civoid rblist__delete(struct rblist *rblist)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	if (rblist != NULL) {
12462306a36Sopenharmony_ci		rblist__exit(rblist);
12562306a36Sopenharmony_ci		free(rblist);
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistruct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct rb_node *node;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	for (node = rb_first_cached(&rblist->entries); node;
13462306a36Sopenharmony_ci	     node = rb_next(node)) {
13562306a36Sopenharmony_ci		if (!idx--)
13662306a36Sopenharmony_ci			return node;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	return NULL;
14062306a36Sopenharmony_ci}
141