[libc-commits] [libc] [libc][tsearch] add weak AVL tree for tsearch implementation (PR #172411)
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Wed Dec 17 11:02:34 PST 2025
================
@@ -0,0 +1,574 @@
+//===-- Implementation header for weak AVL tree -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_WEAK_AVL_H
+#define LLVM_LIBC_SRC___SUPPORT_WEAK_AVL_H
+
+#include "hdr/stdint_proxy.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/CPP/utility/move.h"
+#include "src/__support/libc_assert.h"
+#include "src/__support/macros/attributes.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// A general self-balancing binary search tree where the node pointer can
+// be used as stable handles to the stored values.
+//
+// The self-balancing strategy is the Weak AVL (WAVL) tree, based on the
+// following foundational references:
+// 1. https://maskray.me/blog/2025-12-14-weak-avl-tree
+// 2. https://reviews.freebsd.org/D25480
+// 3. https://ics.uci.edu/~goodrich/teach/cs165/notes/WeakAVLTrees.pdf
+// 4. https://dl.acm.org/doi/10.1145/2689412 (Rank-Balanced Trees)
+//
+// WAVL trees belong to the rank-balanced binary search tree framework
+// (reference 4), alongside AVL and Red-Black trees.
+//
+// Key Properties of WAVL Trees:
+// 1. Relationship to Red-Black Trees: A WAVL tree can always be colored as a
+// Red-Black tree.
+// 2. Relationship to AVL Trees: An AVL tree meets all the requirements of a
+// WAVL tree. Insertion-only WAVL trees maintain the same structure as AVL
+// trees.
+//
+// Rank-Based Balancing:
+// In rank-balanced trees, each node is assigned a rank (conceptually similar
+// to height). The rank difference between a parent and its child is
+// strictly enforced to be either **1** or **2**.
+//
+// - **AVL Trees:** Rank is equivalent to height. The strict condition is that
+// there are no 2-2 nodes (a parent with rank difference 2 to both children).
+// - **WAVL Trees:** The no 2-2 node rule is relaxed for internal nodes during
+// the deletion fixup process, making WAVL trees less strictly balanced than
+// AVL trees but easier to maintain than Red-Black trees.
+//
+// Balancing Mechanics (Promotion/Demotion):
+// - **Null nodes** are considered to have rank -1.
+// - **External/leaf nodes** have rank 0.
+// - **Insertion:** Inserting a node may create a situation where a parent and
+// child
+// have the same rank (difference 0). This is fixed by **promoting** the rank
+// of the parent and propagating the fix upwards using at most two rotations
+// (trinode fixup).
+// - **Deletion:** Deleting a node may result in a parent being 3 ranks higher
+// than a child (difference 3). This is fixed by **demoting** the parent's
+// rank and propagating the fix upwards.
+//
+// Implementation Detail:
+// The rank is **implicitly** maintained. We never store the full rank. Instead,
+// a 2-bit tag is used on each node to record the rank difference to each child:
+// - Bit cleared (0) -> Rank difference is **1**.
+// - Bit set (1) -> Rank difference is **2**.
+template <typename T> class WeakAVLNode {
+ // Data
+ T data;
+
+ // Parent pointer
+ WeakAVLNode *parent;
+
+ // Children pointers
+ WeakAVLNode *children[2];
+
+ // Flags
+ unsigned char left_rank_diff_2 : 1;
+ unsigned char right_rank_diff_2 : 1;
+
+ LIBC_INLINE bool is_leaf() {
+ return (children[0] == nullptr) && (children[1] == nullptr);
+ }
+
+ LIBC_INLINE void toggle_rank_diff_2(bool is_right) {
+ if (is_right)
+ right_rank_diff_2 ^= 1;
+ else
+ left_rank_diff_2 ^= 1;
+ }
+
+ LIBC_INLINE bool both_flags_set() const {
+ return left_rank_diff_2 && right_rank_diff_2;
+ }
+
+ LIBC_INLINE bool any_flag_set() const {
+ return left_rank_diff_2 || right_rank_diff_2;
+ }
+
+ LIBC_INLINE void clear_flags() {
+ left_rank_diff_2 = 0;
+ right_rank_diff_2 = 0;
+ }
+
+ LIBC_INLINE void set_both_flags() {
+ left_rank_diff_2 = 1;
+ right_rank_diff_2 = 1;
+ }
+
+ LIBC_INLINE WeakAVLNode(T data)
+ : data(cpp::move(data)), parent(nullptr), children{nullptr, nullptr},
+ left_rank_diff_2(0), right_rank_diff_2(0) {}
+
+ LIBC_INLINE static WeakAVLNode *create(T value) {
+ AllocChecker ac;
+ WeakAVLNode *res = ::new (ac) WeakAVLNode(value);
----------------
michaelrj-google wrote:
nit:
```suggestion
WeakAVLNode *res = new (ac) WeakAVLNode(value);
```
https://github.com/llvm/llvm-project/pull/172411
More information about the libc-commits
mailing list