xref: /netbsd-src/external/bsd/jemalloc.old/include/jemalloc/internal/ph.h (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
1*8e33eff8Schristos /*
2*8e33eff8Schristos  * A Pairing Heap implementation.
3*8e33eff8Schristos  *
4*8e33eff8Schristos  * "The Pairing Heap: A New Form of Self-Adjusting Heap"
5*8e33eff8Schristos  * https://www.cs.cmu.edu/~sleator/papers/pairing-heaps.pdf
6*8e33eff8Schristos  *
7*8e33eff8Schristos  * With auxiliary twopass list, described in a follow on paper.
8*8e33eff8Schristos  *
9*8e33eff8Schristos  * "Pairing Heaps: Experiments and Analysis"
10*8e33eff8Schristos  * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.106.2988&rep=rep1&type=pdf
11*8e33eff8Schristos  *
12*8e33eff8Schristos  *******************************************************************************
13*8e33eff8Schristos  */
14*8e33eff8Schristos 
15*8e33eff8Schristos #ifndef PH_H_
16*8e33eff8Schristos #define PH_H_
17*8e33eff8Schristos 
18*8e33eff8Schristos /* Node structure. */
19*8e33eff8Schristos #define phn(a_type)							\
20*8e33eff8Schristos struct {								\
21*8e33eff8Schristos 	a_type	*phn_prev;						\
22*8e33eff8Schristos 	a_type	*phn_next;						\
23*8e33eff8Schristos 	a_type	*phn_lchild;						\
24*8e33eff8Schristos }
25*8e33eff8Schristos 
26*8e33eff8Schristos /* Root structure. */
27*8e33eff8Schristos #define ph(a_type)							\
28*8e33eff8Schristos struct {								\
29*8e33eff8Schristos 	a_type	*ph_root;						\
30*8e33eff8Schristos }
31*8e33eff8Schristos 
32*8e33eff8Schristos /* Internal utility macros. */
33*8e33eff8Schristos #define phn_lchild_get(a_type, a_field, a_phn)				\
34*8e33eff8Schristos 	(a_phn->a_field.phn_lchild)
35*8e33eff8Schristos #define phn_lchild_set(a_type, a_field, a_phn, a_lchild) do {		\
36*8e33eff8Schristos 	a_phn->a_field.phn_lchild = a_lchild;				\
37*8e33eff8Schristos } while (0)
38*8e33eff8Schristos 
39*8e33eff8Schristos #define phn_next_get(a_type, a_field, a_phn)				\
40*8e33eff8Schristos 	(a_phn->a_field.phn_next)
41*8e33eff8Schristos #define phn_prev_set(a_type, a_field, a_phn, a_prev) do {		\
42*8e33eff8Schristos 	a_phn->a_field.phn_prev = a_prev;				\
43*8e33eff8Schristos } while (0)
44*8e33eff8Schristos 
45*8e33eff8Schristos #define phn_prev_get(a_type, a_field, a_phn)				\
46*8e33eff8Schristos 	(a_phn->a_field.phn_prev)
47*8e33eff8Schristos #define phn_next_set(a_type, a_field, a_phn, a_next) do {		\
48*8e33eff8Schristos 	a_phn->a_field.phn_next = a_next;				\
49*8e33eff8Schristos } while (0)
50*8e33eff8Schristos 
51*8e33eff8Schristos #define phn_merge_ordered(a_type, a_field, a_phn0, a_phn1, a_cmp) do {	\
52*8e33eff8Schristos 	a_type *phn0child;						\
53*8e33eff8Schristos 									\
54*8e33eff8Schristos 	assert(a_phn0 != NULL);						\
55*8e33eff8Schristos 	assert(a_phn1 != NULL);						\
56*8e33eff8Schristos 	assert(a_cmp(a_phn0, a_phn1) <= 0);				\
57*8e33eff8Schristos 									\
58*8e33eff8Schristos 	phn_prev_set(a_type, a_field, a_phn1, a_phn0);			\
59*8e33eff8Schristos 	phn0child = phn_lchild_get(a_type, a_field, a_phn0);		\
60*8e33eff8Schristos 	phn_next_set(a_type, a_field, a_phn1, phn0child);		\
61*8e33eff8Schristos 	if (phn0child != NULL) {					\
62*8e33eff8Schristos 		phn_prev_set(a_type, a_field, phn0child, a_phn1);	\
63*8e33eff8Schristos 	}								\
64*8e33eff8Schristos 	phn_lchild_set(a_type, a_field, a_phn0, a_phn1);		\
65*8e33eff8Schristos } while (0)
66*8e33eff8Schristos 
67*8e33eff8Schristos #define phn_merge(a_type, a_field, a_phn0, a_phn1, a_cmp, r_phn) do {	\
68*8e33eff8Schristos 	if (a_phn0 == NULL) {						\
69*8e33eff8Schristos 		r_phn = a_phn1;						\
70*8e33eff8Schristos 	} else if (a_phn1 == NULL) {					\
71*8e33eff8Schristos 		r_phn = a_phn0;						\
72*8e33eff8Schristos 	} else if (a_cmp(a_phn0, a_phn1) < 0) {				\
73*8e33eff8Schristos 		phn_merge_ordered(a_type, a_field, a_phn0, a_phn1,	\
74*8e33eff8Schristos 		    a_cmp);						\
75*8e33eff8Schristos 		r_phn = a_phn0;						\
76*8e33eff8Schristos 	} else {							\
77*8e33eff8Schristos 		phn_merge_ordered(a_type, a_field, a_phn1, a_phn0,	\
78*8e33eff8Schristos 		    a_cmp);						\
79*8e33eff8Schristos 		r_phn = a_phn1;						\
80*8e33eff8Schristos 	}								\
81*8e33eff8Schristos } while (0)
82*8e33eff8Schristos 
83*8e33eff8Schristos #define ph_merge_siblings(a_type, a_field, a_phn, a_cmp, r_phn) do {	\
84*8e33eff8Schristos 	a_type *head = NULL;						\
85*8e33eff8Schristos 	a_type *tail = NULL;						\
86*8e33eff8Schristos 	a_type *phn0 = a_phn;						\
87*8e33eff8Schristos 	a_type *phn1 = phn_next_get(a_type, a_field, phn0);		\
88*8e33eff8Schristos 									\
89*8e33eff8Schristos 	/*								\
90*8e33eff8Schristos 	 * Multipass merge, wherein the first two elements of a FIFO	\
91*8e33eff8Schristos 	 * are repeatedly merged, and each result is appended to the	\
92*8e33eff8Schristos 	 * singly linked FIFO, until the FIFO contains only a single	\
93*8e33eff8Schristos 	 * element.  We start with a sibling list but no reference to	\
94*8e33eff8Schristos 	 * its tail, so we do a single pass over the sibling list to	\
95*8e33eff8Schristos 	 * populate the FIFO.						\
96*8e33eff8Schristos 	 */								\
97*8e33eff8Schristos 	if (phn1 != NULL) {						\
98*8e33eff8Schristos 		a_type *phnrest = phn_next_get(a_type, a_field, phn1);	\
99*8e33eff8Schristos 		if (phnrest != NULL) {					\
100*8e33eff8Schristos 			phn_prev_set(a_type, a_field, phnrest, NULL);	\
101*8e33eff8Schristos 		}							\
102*8e33eff8Schristos 		phn_prev_set(a_type, a_field, phn0, NULL);		\
103*8e33eff8Schristos 		phn_next_set(a_type, a_field, phn0, NULL);		\
104*8e33eff8Schristos 		phn_prev_set(a_type, a_field, phn1, NULL);		\
105*8e33eff8Schristos 		phn_next_set(a_type, a_field, phn1, NULL);		\
106*8e33eff8Schristos 		phn_merge(a_type, a_field, phn0, phn1, a_cmp, phn0);	\
107*8e33eff8Schristos 		head = tail = phn0;					\
108*8e33eff8Schristos 		phn0 = phnrest;						\
109*8e33eff8Schristos 		while (phn0 != NULL) {					\
110*8e33eff8Schristos 			phn1 = phn_next_get(a_type, a_field, phn0);	\
111*8e33eff8Schristos 			if (phn1 != NULL) {				\
112*8e33eff8Schristos 				phnrest = phn_next_get(a_type, a_field,	\
113*8e33eff8Schristos 				    phn1);				\
114*8e33eff8Schristos 				if (phnrest != NULL) {			\
115*8e33eff8Schristos 					phn_prev_set(a_type, a_field,	\
116*8e33eff8Schristos 					    phnrest, NULL);		\
117*8e33eff8Schristos 				}					\
118*8e33eff8Schristos 				phn_prev_set(a_type, a_field, phn0,	\
119*8e33eff8Schristos 				    NULL);				\
120*8e33eff8Schristos 				phn_next_set(a_type, a_field, phn0,	\
121*8e33eff8Schristos 				    NULL);				\
122*8e33eff8Schristos 				phn_prev_set(a_type, a_field, phn1,	\
123*8e33eff8Schristos 				    NULL);				\
124*8e33eff8Schristos 				phn_next_set(a_type, a_field, phn1,	\
125*8e33eff8Schristos 				    NULL);				\
126*8e33eff8Schristos 				phn_merge(a_type, a_field, phn0, phn1,	\
127*8e33eff8Schristos 				    a_cmp, phn0);			\
128*8e33eff8Schristos 				phn_next_set(a_type, a_field, tail,	\
129*8e33eff8Schristos 				    phn0);				\
130*8e33eff8Schristos 				tail = phn0;				\
131*8e33eff8Schristos 				phn0 = phnrest;				\
132*8e33eff8Schristos 			} else {					\
133*8e33eff8Schristos 				phn_next_set(a_type, a_field, tail,	\
134*8e33eff8Schristos 				    phn0);				\
135*8e33eff8Schristos 				tail = phn0;				\
136*8e33eff8Schristos 				phn0 = NULL;				\
137*8e33eff8Schristos 			}						\
138*8e33eff8Schristos 		}							\
139*8e33eff8Schristos 		phn0 = head;						\
140*8e33eff8Schristos 		phn1 = phn_next_get(a_type, a_field, phn0);		\
141*8e33eff8Schristos 		if (phn1 != NULL) {					\
142*8e33eff8Schristos 			while (true) {					\
143*8e33eff8Schristos 				head = phn_next_get(a_type, a_field,	\
144*8e33eff8Schristos 				    phn1);				\
145*8e33eff8Schristos 				assert(phn_prev_get(a_type, a_field,	\
146*8e33eff8Schristos 				    phn0) == NULL);			\
147*8e33eff8Schristos 				phn_next_set(a_type, a_field, phn0,	\
148*8e33eff8Schristos 				    NULL);				\
149*8e33eff8Schristos 				assert(phn_prev_get(a_type, a_field,	\
150*8e33eff8Schristos 				    phn1) == NULL);			\
151*8e33eff8Schristos 				phn_next_set(a_type, a_field, phn1,	\
152*8e33eff8Schristos 				    NULL);				\
153*8e33eff8Schristos 				phn_merge(a_type, a_field, phn0, phn1,	\
154*8e33eff8Schristos 				    a_cmp, phn0);			\
155*8e33eff8Schristos 				if (head == NULL) {			\
156*8e33eff8Schristos 					break;				\
157*8e33eff8Schristos 				}					\
158*8e33eff8Schristos 				phn_next_set(a_type, a_field, tail,	\
159*8e33eff8Schristos 				    phn0);				\
160*8e33eff8Schristos 				tail = phn0;				\
161*8e33eff8Schristos 				phn0 = head;				\
162*8e33eff8Schristos 				phn1 = phn_next_get(a_type, a_field,	\
163*8e33eff8Schristos 				    phn0);				\
164*8e33eff8Schristos 			}						\
165*8e33eff8Schristos 		}							\
166*8e33eff8Schristos 	}								\
167*8e33eff8Schristos 	r_phn = phn0;							\
168*8e33eff8Schristos } while (0)
169*8e33eff8Schristos 
170*8e33eff8Schristos #define ph_merge_aux(a_type, a_field, a_ph, a_cmp) do {			\
171*8e33eff8Schristos 	a_type *_phn = phn_next_get(a_type, a_field, a_ph->ph_root);	\
172*8e33eff8Schristos 	if (_phn != NULL) {						\
173*8e33eff8Schristos 		phn_prev_set(a_type, a_field, a_ph->ph_root, NULL);	\
174*8e33eff8Schristos 		phn_next_set(a_type, a_field, a_ph->ph_root, NULL);	\
175*8e33eff8Schristos 		phn_prev_set(a_type, a_field, _phn, NULL);		\
176*8e33eff8Schristos 		ph_merge_siblings(a_type, a_field, _phn, a_cmp, _phn);	\
177*8e33eff8Schristos 		assert(phn_next_get(a_type, a_field, _phn) == NULL);	\
178*8e33eff8Schristos 		phn_merge(a_type, a_field, a_ph->ph_root, _phn, a_cmp,	\
179*8e33eff8Schristos 		    a_ph->ph_root);					\
180*8e33eff8Schristos 	}								\
181*8e33eff8Schristos } while (0)
182*8e33eff8Schristos 
183*8e33eff8Schristos #define ph_merge_children(a_type, a_field, a_phn, a_cmp, r_phn) do {	\
184*8e33eff8Schristos 	a_type *lchild = phn_lchild_get(a_type, a_field, a_phn);	\
185*8e33eff8Schristos 	if (lchild == NULL) {						\
186*8e33eff8Schristos 		r_phn = NULL;						\
187*8e33eff8Schristos 	} else {							\
188*8e33eff8Schristos 		ph_merge_siblings(a_type, a_field, lchild, a_cmp,	\
189*8e33eff8Schristos 		    r_phn);						\
190*8e33eff8Schristos 	}								\
191*8e33eff8Schristos } while (0)
192*8e33eff8Schristos 
193*8e33eff8Schristos /*
194*8e33eff8Schristos  * The ph_proto() macro generates function prototypes that correspond to the
195*8e33eff8Schristos  * functions generated by an equivalently parameterized call to ph_gen().
196*8e33eff8Schristos  */
197*8e33eff8Schristos #define ph_proto(a_attr, a_prefix, a_ph_type, a_type)			\
198*8e33eff8Schristos a_attr void	a_prefix##new(a_ph_type *ph);				\
199*8e33eff8Schristos a_attr bool	a_prefix##empty(a_ph_type *ph);				\
200*8e33eff8Schristos a_attr a_type	*a_prefix##first(a_ph_type *ph);			\
201*8e33eff8Schristos a_attr a_type	*a_prefix##any(a_ph_type *ph);				\
202*8e33eff8Schristos a_attr void	a_prefix##insert(a_ph_type *ph, a_type *phn);		\
203*8e33eff8Schristos a_attr a_type	*a_prefix##remove_first(a_ph_type *ph);			\
204*8e33eff8Schristos a_attr a_type	*a_prefix##remove_any(a_ph_type *ph);			\
205*8e33eff8Schristos a_attr void	a_prefix##remove(a_ph_type *ph, a_type *phn);
206*8e33eff8Schristos 
207*8e33eff8Schristos /*
208*8e33eff8Schristos  * The ph_gen() macro generates a type-specific pairing heap implementation,
209*8e33eff8Schristos  * based on the above cpp macros.
210*8e33eff8Schristos  */
211*8e33eff8Schristos #define ph_gen(a_attr, a_prefix, a_ph_type, a_type, a_field, a_cmp)	\
212*8e33eff8Schristos a_attr void								\
213*8e33eff8Schristos a_prefix##new(a_ph_type *ph) {						\
214*8e33eff8Schristos 	memset(ph, 0, sizeof(ph(a_type)));				\
215*8e33eff8Schristos }									\
216*8e33eff8Schristos a_attr bool								\
217*8e33eff8Schristos a_prefix##empty(a_ph_type *ph) {					\
218*8e33eff8Schristos 	return (ph->ph_root == NULL);					\
219*8e33eff8Schristos }									\
220*8e33eff8Schristos a_attr a_type *								\
221*8e33eff8Schristos a_prefix##first(a_ph_type *ph) {					\
222*8e33eff8Schristos 	if (ph->ph_root == NULL) {					\
223*8e33eff8Schristos 		return NULL;						\
224*8e33eff8Schristos 	}								\
225*8e33eff8Schristos 	ph_merge_aux(a_type, a_field, ph, a_cmp);			\
226*8e33eff8Schristos 	return ph->ph_root;						\
227*8e33eff8Schristos }									\
228*8e33eff8Schristos a_attr a_type *								\
229*8e33eff8Schristos a_prefix##any(a_ph_type *ph) {						\
230*8e33eff8Schristos 	if (ph->ph_root == NULL) {					\
231*8e33eff8Schristos 		return NULL;						\
232*8e33eff8Schristos 	}								\
233*8e33eff8Schristos 	a_type *aux = phn_next_get(a_type, a_field, ph->ph_root);	\
234*8e33eff8Schristos 	if (aux != NULL) {						\
235*8e33eff8Schristos 		return aux;						\
236*8e33eff8Schristos 	}								\
237*8e33eff8Schristos 	return ph->ph_root;						\
238*8e33eff8Schristos }									\
239*8e33eff8Schristos a_attr void								\
240*8e33eff8Schristos a_prefix##insert(a_ph_type *ph, a_type *phn) {				\
241*8e33eff8Schristos 	memset(&phn->a_field, 0, sizeof(phn(a_type)));			\
242*8e33eff8Schristos 									\
243*8e33eff8Schristos 	/*								\
244*8e33eff8Schristos 	 * Treat the root as an aux list during insertion, and lazily	\
245*8e33eff8Schristos 	 * merge during a_prefix##remove_first().  For elements that	\
246*8e33eff8Schristos 	 * are inserted, then removed via a_prefix##remove() before the	\
247*8e33eff8Schristos 	 * aux list is ever processed, this makes insert/remove		\
248*8e33eff8Schristos 	 * constant-time, whereas eager merging would make insert	\
249*8e33eff8Schristos 	 * O(log n).							\
250*8e33eff8Schristos 	 */								\
251*8e33eff8Schristos 	if (ph->ph_root == NULL) {					\
252*8e33eff8Schristos 		ph->ph_root = phn;					\
253*8e33eff8Schristos 	} else {							\
254*8e33eff8Schristos 		phn_next_set(a_type, a_field, phn, phn_next_get(a_type,	\
255*8e33eff8Schristos 		    a_field, ph->ph_root));				\
256*8e33eff8Schristos 		if (phn_next_get(a_type, a_field, ph->ph_root) !=	\
257*8e33eff8Schristos 		    NULL) {						\
258*8e33eff8Schristos 			phn_prev_set(a_type, a_field,			\
259*8e33eff8Schristos 			    phn_next_get(a_type, a_field, ph->ph_root),	\
260*8e33eff8Schristos 			    phn);					\
261*8e33eff8Schristos 		}							\
262*8e33eff8Schristos 		phn_prev_set(a_type, a_field, phn, ph->ph_root);	\
263*8e33eff8Schristos 		phn_next_set(a_type, a_field, ph->ph_root, phn);	\
264*8e33eff8Schristos 	}								\
265*8e33eff8Schristos }									\
266*8e33eff8Schristos a_attr a_type *								\
267*8e33eff8Schristos a_prefix##remove_first(a_ph_type *ph) {					\
268*8e33eff8Schristos 	a_type *ret;							\
269*8e33eff8Schristos 									\
270*8e33eff8Schristos 	if (ph->ph_root == NULL) {					\
271*8e33eff8Schristos 		return NULL;						\
272*8e33eff8Schristos 	}								\
273*8e33eff8Schristos 	ph_merge_aux(a_type, a_field, ph, a_cmp);			\
274*8e33eff8Schristos 									\
275*8e33eff8Schristos 	ret = ph->ph_root;						\
276*8e33eff8Schristos 									\
277*8e33eff8Schristos 	ph_merge_children(a_type, a_field, ph->ph_root, a_cmp,		\
278*8e33eff8Schristos 	    ph->ph_root);						\
279*8e33eff8Schristos 									\
280*8e33eff8Schristos 	return ret;							\
281*8e33eff8Schristos }									\
282*8e33eff8Schristos a_attr a_type *								\
283*8e33eff8Schristos a_prefix##remove_any(a_ph_type *ph) {					\
284*8e33eff8Schristos 	/*								\
285*8e33eff8Schristos 	 * Remove the most recently inserted aux list element, or the	\
286*8e33eff8Schristos 	 * root if the aux list is empty.  This has the effect of	\
287*8e33eff8Schristos 	 * behaving as a LIFO (and insertion/removal is therefore	\
288*8e33eff8Schristos 	 * constant-time) if a_prefix##[remove_]first() are never	\
289*8e33eff8Schristos 	 * called.							\
290*8e33eff8Schristos 	 */								\
291*8e33eff8Schristos 	if (ph->ph_root == NULL) {					\
292*8e33eff8Schristos 		return NULL;						\
293*8e33eff8Schristos 	}								\
294*8e33eff8Schristos 	a_type *ret = phn_next_get(a_type, a_field, ph->ph_root);	\
295*8e33eff8Schristos 	if (ret != NULL) {						\
296*8e33eff8Schristos 		a_type *aux = phn_next_get(a_type, a_field, ret);	\
297*8e33eff8Schristos 		phn_next_set(a_type, a_field, ph->ph_root, aux);	\
298*8e33eff8Schristos 		if (aux != NULL) {					\
299*8e33eff8Schristos 			phn_prev_set(a_type, a_field, aux,		\
300*8e33eff8Schristos 			    ph->ph_root);				\
301*8e33eff8Schristos 		}							\
302*8e33eff8Schristos 		return ret;						\
303*8e33eff8Schristos 	}								\
304*8e33eff8Schristos 	ret = ph->ph_root;						\
305*8e33eff8Schristos 	ph_merge_children(a_type, a_field, ph->ph_root, a_cmp,		\
306*8e33eff8Schristos 	    ph->ph_root);						\
307*8e33eff8Schristos 	return ret;							\
308*8e33eff8Schristos }									\
309*8e33eff8Schristos a_attr void								\
310*8e33eff8Schristos a_prefix##remove(a_ph_type *ph, a_type *phn) {				\
311*8e33eff8Schristos 	a_type *replace, *parent;					\
312*8e33eff8Schristos 									\
313*8e33eff8Schristos 	if (ph->ph_root == phn) {					\
314*8e33eff8Schristos 		/*							\
315*8e33eff8Schristos 		 * We can delete from aux list without merging it, but	\
316*8e33eff8Schristos 		 * we need to merge if we are dealing with the root	\
317*8e33eff8Schristos 		 * node and it has children.				\
318*8e33eff8Schristos 		 */							\
319*8e33eff8Schristos 		if (phn_lchild_get(a_type, a_field, phn) == NULL) {	\
320*8e33eff8Schristos 			ph->ph_root = phn_next_get(a_type, a_field,	\
321*8e33eff8Schristos 			    phn);					\
322*8e33eff8Schristos 			if (ph->ph_root != NULL) {			\
323*8e33eff8Schristos 				phn_prev_set(a_type, a_field,		\
324*8e33eff8Schristos 				    ph->ph_root, NULL);			\
325*8e33eff8Schristos 			}						\
326*8e33eff8Schristos 			return;						\
327*8e33eff8Schristos 		}							\
328*8e33eff8Schristos 		ph_merge_aux(a_type, a_field, ph, a_cmp);		\
329*8e33eff8Schristos 		if (ph->ph_root == phn) {				\
330*8e33eff8Schristos 			ph_merge_children(a_type, a_field, ph->ph_root,	\
331*8e33eff8Schristos 			    a_cmp, ph->ph_root);			\
332*8e33eff8Schristos 			return;						\
333*8e33eff8Schristos 		}							\
334*8e33eff8Schristos 	}								\
335*8e33eff8Schristos 									\
336*8e33eff8Schristos 	/* Get parent (if phn is leftmost child) before mutating. */	\
337*8e33eff8Schristos 	if ((parent = phn_prev_get(a_type, a_field, phn)) != NULL) {	\
338*8e33eff8Schristos 		if (phn_lchild_get(a_type, a_field, parent) != phn) {	\
339*8e33eff8Schristos 			parent = NULL;					\
340*8e33eff8Schristos 		}							\
341*8e33eff8Schristos 	}								\
342*8e33eff8Schristos 	/* Find a possible replacement node, and link to parent. */	\
343*8e33eff8Schristos 	ph_merge_children(a_type, a_field, phn, a_cmp, replace);	\
344*8e33eff8Schristos 	/* Set next/prev for sibling linked list. */			\
345*8e33eff8Schristos 	if (replace != NULL) {						\
346*8e33eff8Schristos 		if (parent != NULL) {					\
347*8e33eff8Schristos 			phn_prev_set(a_type, a_field, replace, parent);	\
348*8e33eff8Schristos 			phn_lchild_set(a_type, a_field, parent,		\
349*8e33eff8Schristos 			    replace);					\
350*8e33eff8Schristos 		} else {						\
351*8e33eff8Schristos 			phn_prev_set(a_type, a_field, replace,		\
352*8e33eff8Schristos 			    phn_prev_get(a_type, a_field, phn));	\
353*8e33eff8Schristos 			if (phn_prev_get(a_type, a_field, phn) !=	\
354*8e33eff8Schristos 			    NULL) {					\
355*8e33eff8Schristos 				phn_next_set(a_type, a_field,		\
356*8e33eff8Schristos 				    phn_prev_get(a_type, a_field, phn),	\
357*8e33eff8Schristos 				    replace);				\
358*8e33eff8Schristos 			}						\
359*8e33eff8Schristos 		}							\
360*8e33eff8Schristos 		phn_next_set(a_type, a_field, replace,			\
361*8e33eff8Schristos 		    phn_next_get(a_type, a_field, phn));		\
362*8e33eff8Schristos 		if (phn_next_get(a_type, a_field, phn) != NULL) {	\
363*8e33eff8Schristos 			phn_prev_set(a_type, a_field,			\
364*8e33eff8Schristos 			    phn_next_get(a_type, a_field, phn),		\
365*8e33eff8Schristos 			    replace);					\
366*8e33eff8Schristos 		}							\
367*8e33eff8Schristos 	} else {							\
368*8e33eff8Schristos 		if (parent != NULL) {					\
369*8e33eff8Schristos 			a_type *next = phn_next_get(a_type, a_field,	\
370*8e33eff8Schristos 			    phn);					\
371*8e33eff8Schristos 			phn_lchild_set(a_type, a_field, parent, next);	\
372*8e33eff8Schristos 			if (next != NULL) {				\
373*8e33eff8Schristos 				phn_prev_set(a_type, a_field, next,	\
374*8e33eff8Schristos 				    parent);				\
375*8e33eff8Schristos 			}						\
376*8e33eff8Schristos 		} else {						\
377*8e33eff8Schristos 			assert(phn_prev_get(a_type, a_field, phn) !=	\
378*8e33eff8Schristos 			    NULL);					\
379*8e33eff8Schristos 			phn_next_set(a_type, a_field,			\
380*8e33eff8Schristos 			    phn_prev_get(a_type, a_field, phn),		\
381*8e33eff8Schristos 			    phn_next_get(a_type, a_field, phn));	\
382*8e33eff8Schristos 		}							\
383*8e33eff8Schristos 		if (phn_next_get(a_type, a_field, phn) != NULL) {	\
384*8e33eff8Schristos 			phn_prev_set(a_type, a_field,			\
385*8e33eff8Schristos 			    phn_next_get(a_type, a_field, phn),		\
386*8e33eff8Schristos 			    phn_prev_get(a_type, a_field, phn));	\
387*8e33eff8Schristos 		}							\
388*8e33eff8Schristos 	}								\
389*8e33eff8Schristos }
390*8e33eff8Schristos 
391*8e33eff8Schristos #endif /* PH_H_ */
392