Commit 0543606d for xz

commit 0543606d156c3bd3bb5b1c08b848b4cbb794c094
Author: Lasse Collin <lasse.collin@tukaani.org>
Date:   Sat Aug 15 19:42:55 2026 +0300

    liblzma: index.c 2/4: Make index_tree_append support prepending too

diff --git a/src/liblzma/common/index.c b/src/liblzma/common/index.c
index ceaa9222..09ee2fed 100644
--- a/src/liblzma/common/index.c
+++ b/src/liblzma/common/index.c
@@ -57,13 +57,10 @@ typedef struct {
 	/// Root node
 	index_tree_node *root;

-	/// Leftmost node. Since the tree will be filled sequentially,
-	/// this won't change after the first node has been added to
-	/// the tree.
+	/// Leftmost (first) node
 	index_tree_node *leftmost;

-	/// The rightmost node in the tree. Since the tree is filled
-	/// sequentially, this is always the node where to add the new data.
+	/// Rightmost (last) node
 	index_tree_node *rightmost;

 	/// Number of nodes in the tree
@@ -246,10 +243,13 @@ index_tree_end(index_tree *tree, const lzma_allocator *allocator,

 /// Add a new node to the tree. node->uncompressed_base and
 /// node->compressed_base must have been set by the caller already.
+///
+/// The tree is always filled sequentially: index_streams are prepended
+/// and index_groups are appended.
 static void
-index_tree_append(index_tree *tree, index_tree_node *node)
+index_tree_append(index_tree *tree, index_tree_node *node, bool prepend)
 {
-	node->parent = tree->rightmost;
+	node->parent = prepend ? tree->leftmost : tree->rightmost;
 	node->left = NULL;
 	node->right = NULL;

@@ -263,14 +263,22 @@ index_tree_append(index_tree *tree, index_tree_node *node)
 		return;
 	}

-	// The tree is always filled sequentially.
-	assert(tree->rightmost->uncompressed_base <= node->uncompressed_base);
-	assert(tree->rightmost->compressed_base < node->compressed_base);
-
-	// Add the new node after the rightmost node. It's the correct
-	// place due to the reason above.
-	tree->rightmost->right = node;
-	tree->rightmost = node;
+	// Add the new node before the leftmost or after the rightmost node.
+	if (prepend) {
+		assert(tree->leftmost->uncompressed_base
+				>= node->uncompressed_base);
+		assert(tree->leftmost->compressed_base
+				> node->compressed_base);
+		tree->leftmost->left = node;
+		tree->leftmost = node;
+	} else {
+		assert(tree->rightmost->uncompressed_base
+				<= node->uncompressed_base);
+		assert(tree->rightmost->compressed_base
+				< node->compressed_base);
+		tree->rightmost->right = node;
+		tree->rightmost = node;
+	}

 	// Balance the AVL-tree if needed. We don't need to keep the balance
 	// factors in nodes, because we always fill the tree sequentially,
@@ -285,11 +293,14 @@ index_tree_append(index_tree *tree, index_tree_node *node)
 			node = node->parent;
 		} while (--up > 0);

-		// Rotate left using node as the rotation root.
-		index_tree_node *pivot = node->right;
+		// Rotate right/left using node as the rotation root.
+		index_tree_node *pivot = prepend ? node->left : node->right;

 		if (node->parent == NULL) {
 			tree->root = pivot;
+		} else if (prepend) {
+			assert(node->parent->left == node);
+			node->parent->left = pivot;
 		} else {
 			assert(node->parent->right == node);
 			node->parent->right = pivot;
@@ -297,11 +308,20 @@ index_tree_append(index_tree *tree, index_tree_node *node)

 		pivot->parent = node->parent;

-		node->right = pivot->left;
-		if (node->right != NULL)
-			node->right->parent = node;
+		if (prepend) {
+			node->left = pivot->right;
+			if (node->left != NULL)
+				node->left->parent = node;
+
+			pivot->right = node;
+		} else {
+			node->right = pivot->left;
+			if (node->right != NULL)
+				node->right->parent = node;
+
+			pivot->left = node;
+		}

-		pivot->left = node;
 		node->parent = pivot;
 	}

@@ -429,7 +449,7 @@ lzma_index_init(const lzma_allocator *allocator)
 		return NULL;
 	}

-	index_tree_append(&i->streams, &s->node);
+	index_tree_append(&i->streams, &s->node, false);

 	return i;
 }
@@ -745,7 +765,7 @@ lzma_index_append(lzma_index *i, const lzma_allocator *allocator,
 		g->number_base = s->record_count + 1;

 		// Add the new group to the Stream.
-		index_tree_append(&s->groups, &g->node);
+		index_tree_append(&s->groups, &g->node, false);
 	}

 	// Add the new Record to the group.
@@ -805,7 +825,7 @@ index_cat_helper(const index_cat_info *info, index_stream *this)
 	this->node.compressed_base += info->file_size;
 	this->number += info->stream_number_add;
 	this->block_number_base += info->block_number_add;
-	index_tree_append(info->streams, &this->node);
+	index_tree_append(info->streams, &this->node, false);

 	if (right != NULL)
 		index_cat_helper(info, right);
@@ -980,7 +1000,7 @@ index_dup_stream(const index_stream *src, const lzma_allocator *allocator)
 	assert(i == destg->allocated);

 	// Add the group to the new Stream.
-	index_tree_append(&dest->groups, &destg->node);
+	index_tree_append(&dest->groups, &destg->node, false);

 	return dest;
 }
@@ -1015,7 +1035,7 @@ lzma_index_dup(const lzma_index *src, const lzma_allocator *allocator)
 			return NULL;
 		}

-		index_tree_append(&dest->streams, &deststream->node);
+		index_tree_append(&dest->streams, &deststream->node, false);

 		srcstream = index_tree_next(&srcstream->node);
 	} while (srcstream != NULL);