@@ -59,115 +59,196 @@ static void load_subtree(struct leaf_node *subtree, struct int_node *node,
59
59
unsigned int n );
60
60
61
61
/*
62
- * To find a leaf_node :
62
+ * Search the tree until the appropriate location for the given key is found :
63
63
* 1. Start at the root node, with n = 0
64
- * 2. Use the nth nibble of the key as an index into a:
65
- * - If a[n] is an int_node, recurse into that node and increment n
66
- * - If a leaf_node with matching key, return leaf_node (assert note entry)
64
+ * 2. If a[0] at the current level is a matching subtree entry, unpack that
65
+ * subtree entry and remove it; restart search at the current level.
66
+ * 3. Use the nth nibble of the key as an index into a:
67
+ * - If a[n] is an int_node, recurse from #2 into that node and increment n
67
68
* - If a matching subtree entry, unpack that subtree entry (and remove it);
68
69
* restart search at the current level.
69
- * - Otherwise, we end up at a NULL pointer, or a non-matching leaf_node.
70
- * Backtrack out of the recursion, one level at a time and check a[0]:
71
- * - If a[0] at the current level is a matching subtree entry, unpack that
72
- * subtree entry (and remove it); restart search at the current level.
70
+ * - Otherwise, we have found one of the following:
71
+ * - a subtree entry which does not match the key
72
+ * - a note entry which may or may not match the key
73
+ * - an unused leaf node (NULL)
74
+ * In any case, set *tree and *n, and return pointer to the tree location.
73
75
*/
74
- static struct leaf_node * note_tree_find (struct int_node * tree , unsigned char n ,
75
- const unsigned char * key_sha1 )
76
+ static void * * note_tree_search (struct int_node * * tree ,
77
+ unsigned char * n , const unsigned char * key_sha1 )
76
78
{
77
79
struct leaf_node * l ;
78
- unsigned char i = GET_NIBBLE ( n , key_sha1 ) ;
79
- void * p = tree -> a [i ];
80
+ unsigned char i ;
81
+ void * p = ( * tree ) -> a [0 ];
80
82
83
+ if (GET_PTR_TYPE (p ) == PTR_TYPE_SUBTREE ) {
84
+ l = (struct leaf_node * ) CLR_PTR_TYPE (p );
85
+ if (!SUBTREE_SHA1_PREFIXCMP (key_sha1 , l -> key_sha1 )) {
86
+ /* unpack tree and resume search */
87
+ (* tree )-> a [0 ] = NULL ;
88
+ load_subtree (l , * tree , * n );
89
+ free (l );
90
+ return note_tree_search (tree , n , key_sha1 );
91
+ }
92
+ }
93
+
94
+ i = GET_NIBBLE (* n , key_sha1 );
95
+ p = (* tree )-> a [i ];
81
96
switch (GET_PTR_TYPE (p )) {
82
97
case PTR_TYPE_INTERNAL :
83
- l = note_tree_find (CLR_PTR_TYPE (p ), n + 1 , key_sha1 );
84
- if (l )
85
- return l ;
86
- break ;
87
- case PTR_TYPE_NOTE :
88
- l = (struct leaf_node * ) CLR_PTR_TYPE (p );
89
- if (!hashcmp (key_sha1 , l -> key_sha1 ))
90
- return l ; /* return note object matching given key */
91
- break ;
98
+ * tree = CLR_PTR_TYPE (p );
99
+ (* n )++ ;
100
+ return note_tree_search (tree , n , key_sha1 );
92
101
case PTR_TYPE_SUBTREE :
93
102
l = (struct leaf_node * ) CLR_PTR_TYPE (p );
94
103
if (!SUBTREE_SHA1_PREFIXCMP (key_sha1 , l -> key_sha1 )) {
95
104
/* unpack tree and resume search */
96
- tree -> a [i ] = NULL ;
97
- load_subtree (l , tree , n );
105
+ ( * tree ) -> a [i ] = NULL ;
106
+ load_subtree (l , * tree , * n );
98
107
free (l );
99
- return note_tree_find (tree , n , key_sha1 );
108
+ return note_tree_search (tree , n , key_sha1 );
100
109
}
101
- break ;
102
- case PTR_TYPE_NULL :
110
+ /* fall through */
103
111
default :
104
- assert (!p );
105
- break ;
112
+ return & ((* tree )-> a [i ]);
106
113
}
114
+ }
107
115
108
- /*
109
- * Did not find key at this (or any lower) level.
110
- * Check if there's a matching subtree entry in tree->a[0].
111
- * If so, unpack tree and resume search.
112
- */
113
- p = tree -> a [0 ];
114
- if (GET_PTR_TYPE (p ) != PTR_TYPE_SUBTREE )
115
- return NULL ;
116
- l = (struct leaf_node * ) CLR_PTR_TYPE (p );
117
- if (!SUBTREE_SHA1_PREFIXCMP (key_sha1 , l -> key_sha1 )) {
118
- /* unpack tree and resume search */
119
- tree -> a [0 ] = NULL ;
120
- load_subtree (l , tree , n );
121
- free (l );
122
- return note_tree_find (tree , n , key_sha1 );
116
+ /*
117
+ * To find a leaf_node:
118
+ * Search to the tree location appropriate for the given key:
119
+ * If a note entry with matching key, return the note entry, else return NULL.
120
+ */
121
+ static struct leaf_node * note_tree_find (struct int_node * tree , unsigned char n ,
122
+ const unsigned char * key_sha1 )
123
+ {
124
+ void * * p = note_tree_search (& tree , & n , key_sha1 );
125
+ if (GET_PTR_TYPE (* p ) == PTR_TYPE_NOTE ) {
126
+ struct leaf_node * l = (struct leaf_node * ) CLR_PTR_TYPE (* p );
127
+ if (!hashcmp (key_sha1 , l -> key_sha1 ))
128
+ return l ;
123
129
}
124
130
return NULL ;
125
131
}
126
132
133
+ /* Create a new blob object by concatenating the two given blob objects */
134
+ static int concatenate_notes (unsigned char * cur_sha1 ,
135
+ const unsigned char * new_sha1 )
136
+ {
137
+ char * cur_msg , * new_msg , * buf ;
138
+ unsigned long cur_len , new_len , buf_len ;
139
+ enum object_type cur_type , new_type ;
140
+ int ret ;
141
+
142
+ /* read in both note blob objects */
143
+ new_msg = read_sha1_file (new_sha1 , & new_type , & new_len );
144
+ if (!new_msg || !new_len || new_type != OBJ_BLOB ) {
145
+ free (new_msg );
146
+ return 0 ;
147
+ }
148
+ cur_msg = read_sha1_file (cur_sha1 , & cur_type , & cur_len );
149
+ if (!cur_msg || !cur_len || cur_type != OBJ_BLOB ) {
150
+ free (cur_msg );
151
+ free (new_msg );
152
+ hashcpy (cur_sha1 , new_sha1 );
153
+ return 0 ;
154
+ }
155
+
156
+ /* we will separate the notes by a newline anyway */
157
+ if (cur_msg [cur_len - 1 ] == '\n' )
158
+ cur_len -- ;
159
+
160
+ /* concatenate cur_msg and new_msg into buf */
161
+ buf_len = cur_len + 1 + new_len ;
162
+ buf = (char * ) xmalloc (buf_len );
163
+ memcpy (buf , cur_msg , cur_len );
164
+ buf [cur_len ] = '\n' ;
165
+ memcpy (buf + cur_len + 1 , new_msg , new_len );
166
+
167
+ free (cur_msg );
168
+ free (new_msg );
169
+
170
+ /* create a new blob object from buf */
171
+ ret = write_sha1_file (buf , buf_len , "blob" , cur_sha1 );
172
+ free (buf );
173
+ return ret ;
174
+ }
175
+
127
176
/*
128
177
* To insert a leaf_node:
129
- * 1. Start at the root node, with n = 0
130
- * 2. Use the nth nibble of the key as an index into a:
131
- * - If a[n] is NULL, store the tweaked pointer directly into a[n]
132
- * - If a[n] is an int_node, recurse into that node and increment n
133
- * - If a[n] is a leaf_node:
134
- * 1. Check if they're equal, and handle that (abort? overwrite?)
135
- * 2. Create a new int_node, and store both leaf_nodes there
136
- * 3. Store the new int_node into a[n].
178
+ * Search to the tree location appropriate for the given leaf_node's key:
179
+ * - If location is unused (NULL), store the tweaked pointer directly there
180
+ * - If location holds a note entry that matches the note-to-be-inserted, then
181
+ * concatenate the two notes.
182
+ * - If location holds a note entry that matches the subtree-to-be-inserted,
183
+ * then unpack the subtree-to-be-inserted into the location.
184
+ * - If location holds a matching subtree entry, unpack the subtree at that
185
+ * location, and restart the insert operation from that level.
186
+ * - Else, create a new int_node, holding both the node-at-location and the
187
+ * node-to-be-inserted, and store the new int_node into the location.
137
188
*/
138
- static int note_tree_insert (struct int_node * tree , unsigned char n ,
139
- const struct leaf_node * entry , unsigned char type )
189
+ static void note_tree_insert (struct int_node * tree , unsigned char n ,
190
+ struct leaf_node * entry , unsigned char type )
140
191
{
141
192
struct int_node * new_node ;
142
- const struct leaf_node * l ;
143
- int ret ;
144
- unsigned char i = GET_NIBBLE ( n , entry -> key_sha1 );
145
- void * p = tree -> a [ i ];
146
- assert ( GET_PTR_TYPE ( entry ) == PTR_TYPE_NULL );
147
- switch (GET_PTR_TYPE (p )) {
193
+ struct leaf_node * l ;
194
+ void * * p = note_tree_search ( & tree , & n , entry -> key_sha1 ) ;
195
+
196
+ assert ( GET_PTR_TYPE ( entry ) == 0 ); /* no type bits set */
197
+ l = ( struct leaf_node * ) CLR_PTR_TYPE ( * p );
198
+ switch (GET_PTR_TYPE (* p )) {
148
199
case PTR_TYPE_NULL :
149
- assert (!p );
150
- tree -> a [i ] = SET_PTR_TYPE (entry , type );
151
- return 0 ;
152
- case PTR_TYPE_INTERNAL :
153
- return note_tree_insert (CLR_PTR_TYPE (p ), n + 1 , entry , type );
154
- default :
155
- assert (GET_PTR_TYPE (p ) == PTR_TYPE_NOTE ||
156
- GET_PTR_TYPE (p ) == PTR_TYPE_SUBTREE );
157
- l = (const struct leaf_node * ) CLR_PTR_TYPE (p );
158
- if (!hashcmp (entry -> key_sha1 , l -> key_sha1 ))
159
- return -1 ; /* abort insert on matching key */
160
- new_node = (struct int_node * )
161
- xcalloc (sizeof (struct int_node ), 1 );
162
- ret = note_tree_insert (new_node , n + 1 ,
163
- CLR_PTR_TYPE (p ), GET_PTR_TYPE (p ));
164
- if (ret ) {
165
- free (new_node );
166
- return -1 ;
200
+ assert (!* p );
201
+ * p = SET_PTR_TYPE (entry , type );
202
+ return ;
203
+ case PTR_TYPE_NOTE :
204
+ switch (type ) {
205
+ case PTR_TYPE_NOTE :
206
+ if (!hashcmp (l -> key_sha1 , entry -> key_sha1 )) {
207
+ /* skip concatenation if l == entry */
208
+ if (!hashcmp (l -> val_sha1 , entry -> val_sha1 ))
209
+ return ;
210
+
211
+ if (concatenate_notes (l -> val_sha1 ,
212
+ entry -> val_sha1 ))
213
+ die ("failed to concatenate note %s "
214
+ "into note %s for commit %s" ,
215
+ sha1_to_hex (entry -> val_sha1 ),
216
+ sha1_to_hex (l -> val_sha1 ),
217
+ sha1_to_hex (l -> key_sha1 ));
218
+ free (entry );
219
+ return ;
220
+ }
221
+ break ;
222
+ case PTR_TYPE_SUBTREE :
223
+ if (!SUBTREE_SHA1_PREFIXCMP (l -> key_sha1 ,
224
+ entry -> key_sha1 )) {
225
+ /* unpack 'entry' */
226
+ load_subtree (entry , tree , n );
227
+ free (entry );
228
+ return ;
229
+ }
230
+ break ;
231
+ }
232
+ break ;
233
+ case PTR_TYPE_SUBTREE :
234
+ if (!SUBTREE_SHA1_PREFIXCMP (entry -> key_sha1 , l -> key_sha1 )) {
235
+ /* unpack 'l' and restart insert */
236
+ * p = NULL ;
237
+ load_subtree (l , tree , n );
238
+ free (l );
239
+ note_tree_insert (tree , n , entry , type );
240
+ return ;
167
241
}
168
- tree -> a [i ] = SET_PTR_TYPE (new_node , PTR_TYPE_INTERNAL );
169
- return note_tree_insert (new_node , n + 1 , entry , type );
242
+ break ;
170
243
}
244
+
245
+ /* non-matching leaf_node */
246
+ assert (GET_PTR_TYPE (* p ) == PTR_TYPE_NOTE ||
247
+ GET_PTR_TYPE (* p ) == PTR_TYPE_SUBTREE );
248
+ new_node = (struct int_node * ) xcalloc (sizeof (struct int_node ), 1 );
249
+ note_tree_insert (new_node , n + 1 , l , GET_PTR_TYPE (* p ));
250
+ * p = SET_PTR_TYPE (new_node , PTR_TYPE_INTERNAL );
251
+ note_tree_insert (new_node , n + 1 , entry , type );
171
252
}
172
253
173
254
/* Free the entire notes data contained in the given tree */
@@ -220,7 +301,6 @@ static void load_subtree(struct leaf_node *subtree, struct int_node *node,
220
301
{
221
302
unsigned char commit_sha1 [20 ];
222
303
unsigned int prefix_len ;
223
- int status ;
224
304
void * buf ;
225
305
struct tree_desc desc ;
226
306
struct name_entry entry ;
@@ -254,8 +334,7 @@ static void load_subtree(struct leaf_node *subtree, struct int_node *node,
254
334
l -> key_sha1 [19 ] = (unsigned char ) len ;
255
335
type = PTR_TYPE_SUBTREE ;
256
336
}
257
- status = note_tree_insert (node , n , l , type );
258
- assert (!status );
337
+ note_tree_insert (node , n , l , type );
259
338
}
260
339
}
261
340
free (buf );
0 commit comments