1 /* Copyright (C) 2021 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 51 Franklin Street - Fifth Floor, Boston,
19 MA 02110-1301, USA. */
21 // The Persistent Red-Black Tree
23 // Implementation is based on an algorithm described in
24 // Sarnak, N., Tarjan, R., "Planar point location using
25 // persistent search trees", in Communications of the ACM,
26 // 1986, Vol.29, Number 7.
38 #define IS_BLACK(x) ((x)==NULL || (x)->color == Black)
39 #define IS_RED(x) ((x)!=NULL && (x)->color == Red)
40 #define SET_BLACK(x) if(x) x->color = Black
41 #define SET_RED(x) (x)->color = Red
43 #define D_OPPOSITE(x) (((x)==Left) ? Right : Left )
45 PRBTree::LMap::LMap (Key_t _key
, void *_item
)
51 for (int i
= 0; i
< NPTRS
; i
++)
59 PRBTree::LMap::LMap (const LMap
& lm
)
65 for (int i
= 0; i
< NPTRS
; i
++)
75 roots
= new Vector
<LMap
*>;
77 times
= new Vector
<Time_t
>;
102 vals
= new Vector
<void*>;
103 for (LMap
*lm
= mlist
; lm
; lm
= lm
->next
)
104 vals
->append (lm
->item
);
110 PRBTree::rb_new_node (Key_t key
, void *item
)
112 LMap
*lm
= new LMap (key
, item
);
119 PRBTree::rb_new_node (LMap
*lm
)
121 LMap
*lmnew
= new LMap (*lm
);
128 PRBTree::rb_child (LMap
*lm
, Direction d
, Time_t ts
)
132 for (int i
= 0; i
< NPTRS
; i
++)
134 if (lm
->time
[i
] > ts
)
138 else if (lm
->dir
[i
] == None
)
145 PRBTree::rb_which_chld (LMap
*lm
)
147 LMap
*prnt
= lm
->parent
;
150 for (int i
= 0; i
< NPTRS
; i
++)
152 if (prnt
->dir
[i
] == None
)
154 if (prnt
->chld
[i
] == lm
)
155 return (Direction
) prnt
->dir
[i
];
161 PRBTree::rb_neighbor (LMap
*lm
, Time_t ts
)
163 ASSERT (lm
->dir
[0] != None
);
164 Direction d
= D_OPPOSITE (lm
->dir
[0]);
166 LMap
*next
= lm
->chld
[0];
170 next
= rb_child (y
, d
, ts
);
176 PRBTree::rb_copy_node (LMap
*lm
, Direction d
)
178 LMap
*nlm
= rb_new_node (lm
);
179 rb_fix_chld (lm
->parent
, nlm
, rb_which_chld (lm
));
183 rb_fix_chld (nlm
, rb_child (lm
, d
, curts
), d
);
186 // copy the other child
187 Direction dd
= D_OPPOSITE (d
);
188 rb_fix_chld (nlm
, rb_child (lm
, dd
, curts
), dd
);
193 PRBTree::rb_fix_chld (LMap
*prnt
, LMap
*lm
, Direction d
)
204 roots
->append (root
);
205 times
->append (rtts
);
214 // If we already have a d-pointer at time curts, reuse it
215 for (int i
= 0; prnt
->time
[i
] == curts
; i
++)
217 if (prnt
->dir
[i
] == d
)
226 if (prnt
->dir
[NPTRS
- 1] != None
)
227 prnt
= rb_copy_node (prnt
, d
);
228 ASSERT (prnt
->dir
[NPTRS
- 1] == None
);
230 for (int i
= NPTRS
- 1; i
> 0; i
--)
232 prnt
->dir
[i
] = prnt
->dir
[i
- 1];
233 prnt
->chld
[i
] = prnt
->chld
[i
- 1];
234 prnt
->time
[i
] = prnt
->time
[i
- 1];
238 prnt
->time
[0] = curts
;
245 PRBTree::rb_rotate (LMap
*x
, Direction d
)
247 Direction dd
= D_OPPOSITE (d
);
248 LMap
*y
= rb_child (x
, dd
, curts
);
249 x
= rb_fix_chld (x
, rb_child (y
, d
, curts
), dd
);
250 rb_fix_chld (x
->parent
, y
, rb_which_chld (x
));
251 rb_fix_chld (y
, x
, d
);
256 PRBTree::rb_remove_fixup (LMap
*x
, LMap
*prnt
, Direction d0
)
259 while (IS_BLACK (x
) && (x
!= root
))
261 Direction d
= (x
== NULL
) ? d0
: rb_which_chld (x
);
262 Direction dd
= D_OPPOSITE (d
);
263 LMap
*y
= rb_child (prnt
, dd
, curts
);
268 prnt
= rb_rotate (prnt
, d
);
269 y
= rb_child (prnt
, dd
, curts
);
271 LMap
*y_d
= rb_child (y
, d
, curts
);
272 LMap
*y_dd
= rb_child (y
, dd
, curts
);
273 if (IS_BLACK (y_d
) && IS_BLACK (y_dd
))
285 y
= rb_rotate (y
, dd
);
286 prnt
= y
->parent
->parent
;
287 y
= rb_child (prnt
, dd
, curts
);
288 y_dd
= rb_child (y
, dd
, curts
);
290 y
->color
= prnt
->color
;
293 prnt
= rb_rotate (prnt
, d
);
301 PRBTree::rb_locate (Key_t key
, Time_t ts
, bool low
)
306 int tsz
= times
->size ();
312 // exponential search
313 for (i
= 1; i
<= tsz
; i
= i
* 2)
314 if (times
->fetch (tsz
- i
) <= ts
)
320 rt
= tsz
- i
/ 2 - 1;
329 int md
= (lt
+ rt
) / 2;
330 if (times
->fetch (md
) <= ts
)
337 lm
= roots
->fetch (rt
);
340 LMap
*last_lo
= NULL
;
341 LMap
*last_hi
= NULL
;
354 lm
= rb_child (lm
, d
, ts
);
356 return low
? last_lo
: last_hi
;
359 //==================================================== Public interface
362 PRBTree::insert (Key_t key
, Time_t ts
, void *item
)
369 return false; // can only update the current tree
371 // Insert in the tree in the usual way
374 for (LMap
*next
= root
; next
;)
379 // copy the node with both children
380 lm
= rb_copy_node (y
, None
);
381 // but use the new item
385 d
= (key
< y
->key
) ? Left
: Right
;
386 next
= rb_child (y
, d
, curts
);
388 lm
= rb_new_node (key
, item
);
389 rb_fix_chld (y
, lm
, d
);
391 // Rebalance the tree
392 while (IS_RED (lm
->parent
))
394 d
= rb_which_chld (lm
->parent
);
397 y
= rb_child (lm
->parent
->parent
, dd
, curts
);
400 SET_BLACK (lm
->parent
);
402 SET_RED (lm
->parent
->parent
);
403 lm
= lm
->parent
->parent
;
407 if (rb_which_chld (lm
) == dd
)
410 lm
= rb_rotate (lm
, d
);
412 SET_BLACK (lm
->parent
);
413 SET_RED (lm
->parent
->parent
);
414 rb_rotate (lm
->parent
->parent
, dd
);
418 // Color the root Black
424 PRBTree::remove (Key_t key
, Time_t ts
)
426 LMap
*lm
, *x
, *y
, *prnt
;
430 return false; // can only update the current tree
432 lm
= rb_locate (key
, curts
, true);
433 if (lm
== NULL
|| lm
->key
!= key
)
436 if (rb_child (lm
, Left
, curts
) && rb_child (lm
, Right
, curts
))
437 y
= rb_neighbor (lm
, curts
);
441 x
= rb_child (y
, Left
, curts
);
443 x
= rb_child (y
, Right
, curts
);
447 lm
= rb_copy_node (lm
, None
); // copied with children
452 Direction d
= rb_which_chld (y
);
453 prnt
= rb_fix_chld (y
->parent
, x
, d
);
455 rb_remove_fixup (x
, prnt
, d
);
460 PRBTree::locate (Key_t key
, Time_t ts
)
462 LMap
*lm
= rb_locate (key
, ts
, true);
463 return lm
? lm
->item
: NULL
;
467 PRBTree::locate_up (Key_t key
, Time_t ts
)
469 LMap
*lm
= rb_locate (key
, ts
, false);
470 return lm
? lm
->item
: NULL
;
474 PRBTree::locate_exact_match (Key_t key
, Time_t ts
)
476 LMap
*lm
= rb_locate (key
, ts
, true);
477 if (lm
&& key
== lm
->key
)