[libc-commits] [libc] [libc][tsearch] use weak AVL tree for tsearch implementation (PR #172411)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Mon Dec 15 20:05:52 PST 2025
https://github.com/SchrodingerZhu created https://github.com/llvm/llvm-project/pull/172411
- **[libc][tsearch] scaffold WAVL header**
- **stage**
- **stage**
- **stage the work**
- **stage the work**
>From 1588de4b6f0da428155f4175f23043c292fb6575 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Mon, 15 Dec 2025 03:09:11 -0500
Subject: [PATCH 1/5] [libc][tsearch] scaffold WAVL header
---
libc/src/__support/CMakeLists.txt | 9 +++++++++
libc/src/__support/weak_avl.h | 19 +++++++++++++++++++
2 files changed, 28 insertions(+)
create mode 100644 libc/src/__support/weak_avl.h
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index c7f127d6934a0..99a1641d629f3 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -391,6 +391,15 @@ add_header_library(
libc.src.__support.macros.attributes
)
+add_header_library(
+ weak_avl
+ HDRS
+ weak_avl.h
+ DEPENDS
+ libc.src.__support.CPP.new
+ libc.src.__support.macros.config
+)
+
add_subdirectory(FPUtil)
add_subdirectory(OSUtil)
add_subdirectory(StringUtil)
diff --git a/libc/src/__support/weak_avl.h b/libc/src/__support/weak_avl.h
new file mode 100644
index 0000000000000..817146e8b9ab9
--- /dev/null
+++ b/libc/src/__support/weak_avl.h
@@ -0,0 +1,19 @@
+//===-- 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 "src/__support/CPP/new.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_WEAK_AVL_H
>From c58c5373397e2c3353e934edbe8a51d0ee5c80be Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Mon, 15 Dec 2025 16:42:22 -0500
Subject: [PATCH 2/5] stage
---
libc/src/__support/weak_avl.h | 97 +++++++++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/libc/src/__support/weak_avl.h b/libc/src/__support/weak_avl.h
index 817146e8b9ab9..552f6bf4e47be 100644
--- a/libc/src/__support/weak_avl.h
+++ b/libc/src/__support/weak_avl.h
@@ -5,15 +5,112 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+// Weak AVL tree implementation based on the algorithm described in:
+// 1. https://maskray.me/blog/2025-12-14-weak-avl-tree
+// 2. https://reviews.freebsd.org/D25480
+//===----------------------------------------------------------------------===//
#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/macros/attributes.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
+namespace wavl {
+struct WeakAVLDefaultCompare {
+ template <typename T>
+ LIBC_INLINE bool operator()(const T &a, const T &b) const {
+ return a < b;
+ }
+};
+
+template <typename T, typename Compare = WeakAVLDefaultCompare>
+class WeakAVLNode {
+ // Data
+ T data;
+
+ // Packs the parent pointer with 2 flag bits in the low bits. Bit 0 indicates
+ // whether the left child has rank difference 2; bit 1 indicates whether the
+ // right child has rank difference 2. A cleared bit means rank difference 1.
+ uintptr_t parent_and_flags;
+
+ // Children pointers
+ WeakAVLNode *children[2];
+
+ // Constants
+ static LIBC_INLINE_VAR constexpr uintptr_t FLAGS_MASK = 0b11;
+ static LIBC_INLINE_VAR constexpr uintptr_t LEFT_FLAG_BIT = 0b01;
+ static LIBC_INLINE_VAR constexpr uintptr_t RIGHT_FLAG_BIT = 0b10;
+ static_assert(alignof(WeakAVLNode) >= 4,
+ "WeakAVLNode alignment must be at least 4 to store flags.");
+
+ // Auxiliary methods for accessing fields
+ LIBC_INLINE WeakAVLNode *parent() const {
+ return cpp::bit_cast<WeakAVLNode *>(parent_and_flags & ~FLAGS_MASK);
+ }
+ LIBC_INLINE uintptr_t flags() const { return parent_and_flags & FLAGS_MASK; }
+ LIBC_INLINE void set_parent(WeakAVLNode *p) {
+ parent_and_flags = cpp::bit_cast<uintptr_t>(p) | flags();
+ }
+ LIBC_INLINE bool has_rank_diff_2(bool is_right) const {
+ return flags() & (is_right ? RIGHT_FLAG_BIT : LEFT_FLAG_BIT);
+ }
+ LIBC_INLINE void toggle_rank_diff_2(bool is_right) {
+ parent_and_flags ^= (is_right ? RIGHT_FLAG_BIT : LEFT_FLAG_BIT);
+ }
+ LIBC_INLINE void clear_flags() { parent_and_flags &= ~FLAGS_MASK; }
+ LIBC_INLINE bool operator<(const WeakAVLNode &other) const {
+ return Compare{}(data, other.data);
+ }
+
+ LIBC_INLINE WeakAVLNode(T data)
+ : data(cpp::move(data)), parent_and_flags(0), children{nullptr, nullptr} {
+ }
+
+public:
+ LIBC_INLINE static WeakAVLNode *create(T value) {
+ AllocChecker ac;
+ WeakAVLNode *res = ::new (ac) WeakAVLNode(value);
+ if (ac)
+ return res;
+ return nullptr;
+ }
+ LIBC_INLINE static void destroy(WeakAVLNode *node) {
+ if (!node)
+ return;
+ destroy(node->children[0]);
+ destroy(node->children[1]);
+ ::delete node;
+ }
+ LIBC_INLINE static WeakAVLNode *rotate(WeakAVLNode *&root, WeakAVLNode *node,
+ bool is_right) {
+ WeakAVLNode *pivot = node->children[is_right];
+ // Handover pivot's child
+ WeakAVLNode *grandchild = pivot->children[!is_right];
+ node->children[is_right] = grandchild;
+ if (grandchild)
+ grandchild->set_parent(node);
+ pivot->set_parent(node->parent());
+ // Pivot becomes the new root of the subtree
+ if (!node->parent())
+ root = pivot;
+ else {
+ bool node_is_right = node->parent()->children[1] == node;
+ node->parent()->children[node_is_right] = pivot;
+ }
+ pivot->children[!is_right] = node;
+ node->set_parent(pivot);
+ return pivot;
+ }
+};
+} // namespace wavl
+
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_WEAK_AVL_H
>From 1b6a1d6f689144c41d915dbd8ec874f4adc9300c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Mon, 15 Dec 2025 17:01:06 -0500
Subject: [PATCH 3/5] stage
---
libc/src/__support/weak_avl.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/libc/src/__support/weak_avl.h b/libc/src/__support/weak_avl.h
index 552f6bf4e47be..965dc69e4c530 100644
--- a/libc/src/__support/weak_avl.h
+++ b/libc/src/__support/weak_avl.h
@@ -108,6 +108,9 @@ class WeakAVLNode {
node->set_parent(pivot);
return pivot;
}
+ LIBC_INLINE static void insert(WeakAVLNode*& root, WeakAVLNode* node) {
+
+ }
};
} // namespace wavl
>From e3b68949d5dfbf18b3097cbe78421f16b73e23eb Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Mon, 15 Dec 2025 22:52:14 -0500
Subject: [PATCH 4/5] stage the work
---
libc/src/__support/CMakeLists.txt | 5 +
libc/src/__support/weak_avl.h | 172 +++++++++++++++++++---
libc/test/src/__support/CMakeLists.txt | 10 ++
libc/test/src/__support/weak_avl_test.cpp | 128 ++++++++++++++++
4 files changed, 296 insertions(+), 19 deletions(-)
create mode 100644 libc/test/src/__support/weak_avl_test.cpp
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index 99a1641d629f3..bde12abaa291e 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -396,7 +396,12 @@ add_header_library(
HDRS
weak_avl.h
DEPENDS
+ libc.hdr.stdint_proxy
+ libc.src.__support.CPP.bit
libc.src.__support.CPP.new
+ libc.src.__support.CPP.utility
+ libc.src.__support.libc_assert
+ libc.src.__support.macros.attributes
libc.src.__support.macros.config
)
diff --git a/libc/src/__support/weak_avl.h b/libc/src/__support/weak_avl.h
index 965dc69e4c530..aa38199cc1bfa 100644
--- a/libc/src/__support/weak_avl.h
+++ b/libc/src/__support/weak_avl.h
@@ -17,27 +17,20 @@
#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 {
-namespace wavl {
-struct WeakAVLDefaultCompare {
- template <typename T>
- LIBC_INLINE bool operator()(const T &a, const T &b) const {
- return a < b;
- }
-};
-
-template <typename T, typename Compare = WeakAVLDefaultCompare>
-class WeakAVLNode {
+template <typename T> class WeakAVLNode {
// Data
T data;
// Packs the parent pointer with 2 flag bits in the low bits. Bit 0 indicates
// whether the left child has rank difference 2; bit 1 indicates whether the
// right child has rank difference 2. A cleared bit means rank difference 1.
+ // All rank differences are 1 or 2, and every leaf has rank 0.
uintptr_t parent_and_flags;
// Children pointers
@@ -47,8 +40,6 @@ class WeakAVLNode {
static LIBC_INLINE_VAR constexpr uintptr_t FLAGS_MASK = 0b11;
static LIBC_INLINE_VAR constexpr uintptr_t LEFT_FLAG_BIT = 0b01;
static LIBC_INLINE_VAR constexpr uintptr_t RIGHT_FLAG_BIT = 0b10;
- static_assert(alignof(WeakAVLNode) >= 4,
- "WeakAVLNode alignment must be at least 4 to store flags.");
// Auxiliary methods for accessing fields
LIBC_INLINE WeakAVLNode *parent() const {
@@ -65,15 +56,13 @@ class WeakAVLNode {
parent_and_flags ^= (is_right ? RIGHT_FLAG_BIT : LEFT_FLAG_BIT);
}
LIBC_INLINE void clear_flags() { parent_and_flags &= ~FLAGS_MASK; }
- LIBC_INLINE bool operator<(const WeakAVLNode &other) const {
- return Compare{}(data, other.data);
+ LIBC_INLINE void set_flags(uintptr_t flags) {
+ parent_and_flags |= (FLAGS_MASK & flags);
}
-
LIBC_INLINE WeakAVLNode(T data)
: data(cpp::move(data)), parent_and_flags(0), children{nullptr, nullptr} {
}
-public:
LIBC_INLINE static WeakAVLNode *create(T value) {
AllocChecker ac;
WeakAVLNode *res = ::new (ac) WeakAVLNode(value);
@@ -81,6 +70,16 @@ class WeakAVLNode {
return res;
return nullptr;
}
+
+public:
+ LIBC_INLINE const WeakAVLNode *get_left() const { return children[0]; }
+ LIBC_INLINE const WeakAVLNode *get_right() const { return children[1]; }
+ LIBC_INLINE const T &get_data() const { return data; }
+ LIBC_INLINE bool is_rank_diff_2(bool is_right) const {
+ return has_rank_diff_2(is_right);
+ }
+
+ // Destroy the subtree rooted at node
LIBC_INLINE static void destroy(WeakAVLNode *node) {
if (!node)
return;
@@ -88,6 +87,16 @@ class WeakAVLNode {
destroy(node->children[1]);
::delete node;
}
+ // Rotate the subtree rooted at node in the given direction.
+ //
+ // Illustration for is_right = true (Left Rotation):
+ //
+ // (Node) (Pivot)
+ // / \ / \
+ // A (Pivot) => (Node) C
+ // / \ / \
+ // B C A B
+ //
LIBC_INLINE static WeakAVLNode *rotate(WeakAVLNode *&root, WeakAVLNode *node,
bool is_right) {
WeakAVLNode *pivot = node->children[is_right];
@@ -108,11 +117,136 @@ class WeakAVLNode {
node->set_parent(pivot);
return pivot;
}
- LIBC_INLINE static void insert(WeakAVLNode*& root, WeakAVLNode* node) {
-
+ // Insert data into the subtree rooted at root.
+ // Returns the node if insertion is successful or the node exists in
+ // the tree.
+ // Returns nullptr if memory allocation fails.
+ // `Compare` returns integer values for ternary comparison.
+ template <typename Compare>
+ LIBC_INLINE static WeakAVLNode *find_or_insert(WeakAVLNode *&root, T data,
+ Compare &&comp) {
+ WeakAVLNode *parent = nullptr, *cursor = root;
+ bool is_right = false;
+ while (cursor != nullptr) {
+ parent = cursor;
+ int comp_result = comp(parent->data, data);
+ if (comp_result == 0)
+ return parent; // Node already exists
+ is_right = comp_result < 0;
+ cursor = cursor->children[is_right];
+ }
+ WeakAVLNode *allocated = create(cpp::move(data));
+ if (!allocated)
+ return nullptr;
+ WeakAVLNode *node = allocated;
+ node->set_parent(parent);
+
+ // Case 0: inserting into an empty tree
+ if (!parent) {
+ root = node; // Tree was empty
+ return node;
+ }
+
+ parent->children[is_right] = node;
+ // Rebalance process
+ while (parent) {
+ // Case 1: parent does not need to be promoted as node is lowering
+ // than the parent by 2 ranks.
+ // (P) (P)
+ // / \ / \
+ // 2 1 => 1 1
+ // / \ / \
+ // (N) (*) (N) (*)
+ if (parent->has_rank_diff_2(is_right)) {
+ parent->toggle_rank_diff_2(is_right);
+ break;
+ }
+
+ bool sibling_has_rank_diff_2 = parent->has_rank_diff_2(!is_right);
+ // Case 2: node's sibling has rank-difference 1.
+ // Promoting parent will fix the conflict of the trinodes but we may need
+ // to continue on parent.
+ //
+ // (GP) (GP)
+ // | Promote | x - 1
+ // | x -----> (P)
+ // 0 | / 1 / \
+ // (N) --- (P) ---- (N) \ 2
+ // \ 1 \
+ // (S) (S)
+ if (!sibling_has_rank_diff_2) {
+ parent->toggle_rank_diff_2(!is_right);
+ node = parent;
+ parent = node->parent();
+ continue;
+ }
+
+ LIBC_ASSERT((node->flags() != 0b11) &&
+ "there should be no 2-2 nodes in a weak AVL tree");
+
+ LIBC_ASSERT((node == allocated || node->flags() != 0) &&
+ "Internal node must have a child with rank-difference 2, "
+ "otherwise it should have already been handled.");
+
+ bool node_is_right = (node == parent->children[1]);
+ // Case 3: node's sibling has rank-difference 2. And node has a 1-node
+ // along the same direction. We can do a single rotation to fix the
+ // trinode.
+ // (GP) (GP)
+ // 0 | X Rotate |
+ // (N) ----- (P) => (N)
+ // 1 / \ 2 \ 2 1 / \ 1
+ // (C1) \ \ (C1) (P)
+ // (C2) (S) 1 / \ 1
+ // (C2) (S)
+ if (node->has_rank_diff_2(!node_is_right)) {
+ WeakAVLNode *new_subroot = rotate(root, parent, node_is_right);
+ new_subroot->clear_flags();
+ parent->clear_flags();
+ break;
+ }
+ // Case 4: node's sibling has rank-difference 2. And node has a 1-node
+ // along the opposite direction. We need a double rotation to fix the
+ // trinode.
+ // (GP) (GP)
+ // 0 | X Zig-Zag | X
+ // (N) ----- (P) => (C1)
+ // 2 / \ 1 \ 2 1 / \ 1
+ // / (C1) \ (N) (P)
+ // (C2) L / \ R (S) 1 / \ L R / \ 1
+ // (A) (B) (C2) (A)(B) (S)
+ // (mirrored)
+ // (GP) (GP)
+ // X | 0 Zig-Zag | X
+ // (P) ----- (N) => (C1)
+ // 2 / 1 / \ 2 1 / \ 1
+ // / (C1) \ (P) (N)
+ // (S) L / \ R (C2) 1 / \ L R / \ 1
+ // (A) (B) (S)(A) (B)(C2)
+ WeakAVLNode *subroot1 =
+ rotate(root, node, !node_is_right); // First rotation
+ [[maybe_unused]] WeakAVLNode *subroot2 =
+ rotate(root, parent, node_is_right); // Second rotation
+ LIBC_ASSERT(subroot1 == subroot2 &&
+ "Subroots after double rotation should be the same");
+ uintptr_t flags = subroot1->flags();
+ node->clear_flags();
+ parent->clear_flags();
+ subroot1->clear_flags();
+ // Select destinations
+ WeakAVLNode *dst_left = node_is_right ? parent : node;
+ WeakAVLNode *dst_right = node_is_right ? node : parent;
+ // Masked toggles
+ if (flags & LEFT_FLAG_BIT)
+ dst_left->toggle_rank_diff_2(true);
+
+ if (flags & RIGHT_FLAG_BIT)
+ dst_right->toggle_rank_diff_2(false);
+ break;
+ }
+ return allocated;
}
};
-} // namespace wavl
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/__support/CMakeLists.txt b/libc/test/src/__support/CMakeLists.txt
index 138866b4cc869..97ee42347c9f3 100644
--- a/libc/test/src/__support/CMakeLists.txt
+++ b/libc/test/src/__support/CMakeLists.txt
@@ -280,6 +280,16 @@ add_libc_test(
libc.src.__support.CPP.bit
)
+add_libc_test(
+ weak_avl_test
+ SUITE
+ libc-support-tests
+ SRCS
+ weak_avl_test.cpp
+ DEPENDS
+ libc.src.__support.weak_avl
+)
+
add_subdirectory(CPP)
add_subdirectory(File)
add_subdirectory(RPC)
diff --git a/libc/test/src/__support/weak_avl_test.cpp b/libc/test/src/__support/weak_avl_test.cpp
new file mode 100644
index 0000000000000..daddc047ab9f0
--- /dev/null
+++ b/libc/test/src/__support/weak_avl_test.cpp
@@ -0,0 +1,128 @@
+//===-- Unittests for WeakAVL ---------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/weak_avl.h"
+#include "test/UnitTest/Test.h"
+
+using Node = LIBC_NAMESPACE::WeakAVLNode<int>;
+
+namespace {
+
+// Validate weak-AVL rank-difference invariant:
+// no node may have rank-difference 2 on both sides.
+bool validate(const Node *node) {
+ if (!node)
+ return true;
+ bool left_2 = node->is_rank_diff_2(false);
+ bool right_2 = node->is_rank_diff_2(true);
+ return (!left_2 || !right_2) && validate(node->get_left()) &&
+ validate(node->get_right());
+}
+
+// Insert according to pattern `next(i)`
+using NextFn = int (*)(int);
+
+static Node *build_tree(NextFn next, int N, int (*compare)(int, int)) {
+ Node *root = nullptr;
+ for (int i = 0; i < N; ++i)
+ Node::find_or_insert(root, next(i), compare);
+ return root;
+}
+
+// Insertion patterns
+
+static int seq(int i) { return i; }
+
+static int rev(int i) {
+ constexpr int N = 1000;
+ return N - 1 - i;
+}
+
+// Coprime stride permutation: i -> (i * X) % N
+static int stride(int i) {
+ constexpr int N = 1000;
+ constexpr int X = 7919; // gcd(X, N) = 1
+ return (i * X) % N;
+}
+
+} // namespace
+
+TEST(LlvmLibcWeakAVLTest, SimpleInsertion) {
+ Node *root = nullptr;
+ auto compare = [](int a, int b) { return a - b; };
+
+ Node *node10 = Node::find_or_insert(root, 10, compare);
+ ASSERT_TRUE(node10 != nullptr);
+ ASSERT_EQ(root, node10);
+ ASSERT_TRUE(validate(root));
+
+ Node *node5 = Node::find_or_insert(root, 5, compare);
+ ASSERT_TRUE(node5 != nullptr);
+ ASSERT_TRUE(validate(root));
+
+ Node *node15 = Node::find_or_insert(root, 15, compare);
+ ASSERT_TRUE(node15 != nullptr);
+ ASSERT_TRUE(validate(root));
+
+ Node *node10_again = Node::find_or_insert(root, 10, compare);
+ ASSERT_EQ(node10, node10_again);
+ ASSERT_TRUE(validate(root));
+
+ Node::destroy(root);
+}
+
+TEST(LlvmLibcWeakAVLTest, SequentialInsertion) {
+ auto compare = [](int a, int b) { return a - b; };
+ constexpr int N = 1000;
+
+ Node *root = build_tree(seq, N, compare);
+ ASSERT_TRUE(validate(root));
+
+ for (int i = 0; i < N; ++i) {
+ Node *node = Node::find_or_insert(root, i, compare);
+ ASSERT_TRUE(node != nullptr);
+ ASSERT_EQ(node->get_data(), i);
+ }
+
+ ASSERT_TRUE(validate(root));
+ Node::destroy(root);
+}
+
+TEST(LlvmLibcWeakAVLTest, ReversedInsertion) {
+ auto compare = [](int a, int b) { return a - b; };
+ constexpr int N = 1000;
+
+ Node *root = build_tree(rev, N, compare);
+ ASSERT_TRUE(validate(root));
+
+ for (int i = 0; i < N; ++i) {
+ Node *node = Node::find_or_insert(root, i, compare);
+ ASSERT_TRUE(node != nullptr);
+ ASSERT_EQ(node->get_data(), i);
+ }
+
+ ASSERT_TRUE(validate(root));
+ Node::destroy(root);
+}
+
+TEST(LlvmLibcWeakAVLTest, StridedInsertion) {
+ auto compare = [](int a, int b) { return a - b; };
+ constexpr int N = 1000;
+
+ Node *root = build_tree(stride, N, compare);
+ ASSERT_TRUE(validate(root));
+
+ for (int i = 0; i < N; ++i) {
+ Node *node = Node::find_or_insert(root, i, compare);
+ ASSERT_TRUE(node != nullptr);
+ ASSERT_EQ(node->get_data(), i);
+ }
+
+ ASSERT_TRUE(validate(root));
+ Node::destroy(root);
+}
>From 5640d0fb67d07611a2ef98eb3413c794e9b6a35a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Mon, 15 Dec 2025 23:04:49 -0500
Subject: [PATCH 5/5] stage the work
---
libc/src/__support/weak_avl.h | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/libc/src/__support/weak_avl.h b/libc/src/__support/weak_avl.h
index aa38199cc1bfa..492e8df0e32d9 100644
--- a/libc/src/__support/weak_avl.h
+++ b/libc/src/__support/weak_avl.h
@@ -150,6 +150,7 @@ template <typename T> class WeakAVLNode {
parent->children[is_right] = node;
// Rebalance process
while (parent) {
+ is_right = (parent->children[1] == node);
// Case 1: parent does not need to be promoted as node is lowering
// than the parent by 2 ranks.
// (P) (P)
@@ -188,7 +189,6 @@ template <typename T> class WeakAVLNode {
"Internal node must have a child with rank-difference 2, "
"otherwise it should have already been handled.");
- bool node_is_right = (node == parent->children[1]);
// Case 3: node's sibling has rank-difference 2. And node has a 1-node
// along the same direction. We can do a single rotation to fix the
// trinode.
@@ -199,8 +199,8 @@ template <typename T> class WeakAVLNode {
// (C1) \ \ (C1) (P)
// (C2) (S) 1 / \ 1
// (C2) (S)
- if (node->has_rank_diff_2(!node_is_right)) {
- WeakAVLNode *new_subroot = rotate(root, parent, node_is_right);
+ if (node->has_rank_diff_2(!is_right)) {
+ WeakAVLNode *new_subroot = rotate(root, parent, is_right);
new_subroot->clear_flags();
parent->clear_flags();
break;
@@ -223,10 +223,9 @@ template <typename T> class WeakAVLNode {
// / (C1) \ (P) (N)
// (S) L / \ R (C2) 1 / \ L R / \ 1
// (A) (B) (S)(A) (B)(C2)
- WeakAVLNode *subroot1 =
- rotate(root, node, !node_is_right); // First rotation
+ WeakAVLNode *subroot1 = rotate(root, node, !is_right); // First rotation
[[maybe_unused]] WeakAVLNode *subroot2 =
- rotate(root, parent, node_is_right); // Second rotation
+ rotate(root, parent, is_right); // Second rotation
LIBC_ASSERT(subroot1 == subroot2 &&
"Subroots after double rotation should be the same");
uintptr_t flags = subroot1->flags();
@@ -234,8 +233,8 @@ template <typename T> class WeakAVLNode {
parent->clear_flags();
subroot1->clear_flags();
// Select destinations
- WeakAVLNode *dst_left = node_is_right ? parent : node;
- WeakAVLNode *dst_right = node_is_right ? node : parent;
+ WeakAVLNode *dst_left = is_right ? parent : node;
+ WeakAVLNode *dst_right = is_right ? node : parent;
// Masked toggles
if (flags & LEFT_FLAG_BIT)
dst_left->toggle_rank_diff_2(true);
More information about the libc-commits
mailing list