2 /******************************************************************************
3 * MODULE : ip_observer.cpp
4 * DESCRIPTION: Persistently attach inverse paths to trees
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * An inverse path observer maintains the inverse path of the position
8 * of the corresponding tree with respect to the global meta-tree.
9 *******************************************************************************
10 * This software falls under the GNU general public license version 3 or later.
11 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
12 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
13 ******************************************************************************/
15 #include "modification.hpp"
20 /******************************************************************************
21 * Definition of the ip_observer_rep class
22 ******************************************************************************/
24 class ip_observer_rep
: public observer_rep
{
27 ip_observer_rep (path ip2
): ip (ip2
) {}
28 int get_type () { return OBSERVER_IP
; }
29 tm_ostream
& print (tm_ostream
& out
) { return out
<< " " << ip
; }
31 void announce (tree
& ref
, modification mod
);
32 void done (tree
& ref
, modification mod
);
34 void notify_assign (tree
& ref
, tree t
);
35 void notify_insert (tree
& ref
, int pos
, int nr
);
36 void notify_remove (tree
& ref
, int pos
, int nr
);
37 void notify_split (tree
& ref
, int pos
, tree prev
);
38 void notify_var_split (tree
& ref
, tree t1
, tree t2
);
39 void notify_join (tree
& ref
, int pos
, tree next
);
40 void notify_var_join (tree
& ref
, tree t
, int offset
);
41 void notify_assign_node (tree
& ref
, tree_label op
);
42 void notify_insert_node (tree
& ref
, int pos
);
43 void notify_remove_node (tree
& ref
, int pos
);
44 void notify_detach (tree
& ref
, tree closest
, bool right
);
46 bool get_ip (path
& ip
);
47 bool set_ip (path ip
);
50 /******************************************************************************
51 * Call back routines for announcements
52 ******************************************************************************/
55 has_parent (path ip
) {
56 return !is_nil (ip
) && last_item (ip
) != DETACHED
;
60 ip_observer_rep::announce (tree
& ref
, modification mod
) {
62 //cout << "Announce " << ip << ", " << p << "\n";
63 if (!has_parent (ip
)) return;
64 tree
& parent (subtree (the_et
, reverse (ip
->next
)));
65 parent
->obs
->announce (parent
, ip
->item
* mod
);
69 ip_observer_rep::done (tree
& ref
, modification mod
) {
71 //cout << "Done " << ip << ", " << p << "\n";
72 if (!has_parent (ip
)) return;
73 tree
& parent (subtree (the_et
, reverse (ip
->next
)));
74 parent
->obs
->done (parent
, ip
->item
* mod
);
77 /******************************************************************************
78 * Call back routines for modifications
79 ******************************************************************************/
82 ip_observer_rep::notify_assign (tree
& ref
, tree t
) {
83 // cout << "Notify assign " << ref << ", " << t << "\n";
84 path temp_ip
= obtain_ip (ref
);
85 temp_ip
= path (temp_ip
->item
, temp_ip
->next
); // prevents overriding temp_ip
87 attach_ip (t
, temp_ip
);
91 ip_observer_rep::notify_insert (tree
& ref
, int pos
, int nr
) {
92 // cout << "Notify insert " << ref << ", " << pos << ", " << nr << "\n";
94 if (is_compound (ref
)) {
97 attach_ip (ref
[i
], path (i
, ip
));
102 ip_observer_rep::notify_remove (tree
& ref
, int pos
, int nr
) {
103 // cout << "Notify remove " << ref << ", " << pos << ", " << nr << "\n";
105 if (is_compound (ref
)) {
107 for (i
=pos
; i
<(pos
+nr
); i
++)
110 attach_ip (ref
[i
], path (i
-nr
, ip
));
115 ip_observer_rep::notify_split (tree
& ref
, int pos
, tree prev
) {
116 // cout << "Notify split " << ref << ", " << pos << ", " << prev << "\n";
119 for (i
=pos
; i
<n
; i
++)
120 attach_ip (ref
[i
], path (i
, ip
));
124 ip_observer_rep::notify_var_split (tree
& ref
, tree t1
, tree t2
) {
125 (void) ref
; (void) t1
; (void) t2
;
129 ip_observer_rep::notify_join (tree
& ref
, int pos
, tree next
) {
130 // cout << "Notify join " << ref << ", " << pos << ", " << next << "\n";
132 detach_ip (ref
[pos
]);
133 detach_ip (ref
[pos
+1]);
134 for (i
=pos
+2; i
<n
; i
++)
135 attach_ip (ref
[i
], path (i
-1, ip
));
136 attach_ip (next
, path (pos
, ip
));
140 ip_observer_rep::notify_var_join (tree
& ref
, tree t
, int offset
) {
141 (void) ref
; (void) t
; (void) offset
;
145 ip_observer_rep::notify_assign_node (tree
& ref
, tree_label op
) {
146 // cout << "Notify assign node " << ref << ", " << as_string (op) << "\n";
147 (void) ref
; (void) op
;
151 ip_observer_rep::notify_insert_node (tree
& ref
, int pos
) {
152 // cout << "Notify insert node " << ref << ", " << pos << "\n";
154 attach_ip (ref
[pos
], ip
); // updates children's ips
155 attach_ip (ref
, ip
->next
);
159 ip_observer_rep::notify_remove_node (tree
& ref
, int pos
) {
160 // cout << "Notify remove node " << ref << ", " << pos << "\n";
161 for (int i
=0; i
<N(ref
); i
++)
164 if ((!is_nil (ip
)) && (ip
->item
>=0)) attach_ip (ref
[pos
], ip
);
165 else detach_ip (ref
[pos
]);
166 ip
= DETACHED
; // detach_ip (ref);
170 ip_observer_rep::notify_detach (tree
& ref
, tree closest
, bool right
) {
171 (void) ref
; (void) closest
; (void) right
;
174 /******************************************************************************
175 * Setting and getting inverse paths
176 ******************************************************************************/
179 ip_observer_rep::get_ip (path
& ip2
) {
185 ip_observer_rep::set_ip (path ip2
) {
186 if (is_nil (ip
) || is_nil (ip2
))
187 FAILED ("cannot alter global root");
194 attach_ip (tree
& ref
, path ip
) {
195 // cout << "Set ip of " << ref << " to " << ip << "\n";
196 if (is_nil (ref
->obs
) || !ref
->obs
->set_ip (ip
)) {
197 // cout << "Create ip observer " << ip << " for " << ref << "\n";
198 ref
->obs
= list_observer (ip_observer (ip
), ref
->obs
);
200 if (is_compound (ref
)) {
202 for (i
=0; i
<n
; i
++) {
203 path old_ip
= obtain_ip (ref
[i
]);
204 if ((old_ip
->item
!= i
) || (!strong_equal (old_ip
->next
, ip
))) {
205 attach_ip (ref
[i
], path (i
, ip
));
212 detach_ip (tree
& ref
) {
213 // cout << "Detach ip of " << ref << "\n";
214 if (!is_nil (ref
->obs
))
215 (void) ref
->obs
->set_ip (DETACHED
);
219 obtain_ip (tree
& ref
) {
221 if (is_nil (ref
->obs
)) return DETACHED
;
222 if (!ref
->obs
->get_ip (ip
)) return DETACHED
;
227 ip_attached (path ip
) {
228 return is_nil (ip
) || last_item (ip
) != DETACHED
;
231 /******************************************************************************
232 * Setting and getting inverse paths
233 ******************************************************************************/
236 ip_observer (path ip
) {
237 return tm_new
<ip_observer_rep
> (ip
);