1 /* $NetBSD: graph3.c,v 1.4 2011/10/21 23:47:11 joerg Exp $ */
3 * Copyright (c) 2009 The NetBSD Foundation, Inc.
6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Joerg Sonnenberger.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #if HAVE_NBTOOL_CONFIG_H
35 #include "nbtool_config.h"
38 #include <sys/cdefs.h>
39 __RCSID("$NetBSD: graph3.c,v 1.4 2011/10/21 23:47:11 joerg Exp $");
50 static const uint32_t unused
= 0xffffffffU
;
53 graph3_setup(struct graph3
*graph
, uint32_t v
, uint32_t e
)
58 graph
->verts
= calloc(sizeof(struct vertex3
), v
);
59 graph
->edges
= calloc(sizeof(struct edge3
), e
);
60 graph
->output_order
= calloc(sizeof(uint32_t), e
);
62 if (graph
->verts
== NULL
|| graph
->edges
== NULL
||
63 graph
->output_order
== NULL
)
64 err(1, "malloc failed");
68 graph3_free(struct graph3
*graph
)
72 free(graph
->output_order
);
76 graph
->output_order
= NULL
;
80 graph3_check_duplicates(struct nbperf
*nbperf
, struct graph3
*graph
)
86 for (i
= 0; i
< graph
->e
; ++i
) {
88 v
= &graph
->verts
[e
->left
];
90 e2
= &graph
->edges
[j
];
92 if (i
< j
&& e
->middle
== e2
->middle
&&
93 e
->right
== e2
->right
&&
94 nbperf
->keylens
[i
] == nbperf
->keylens
[j
] &&
95 memcmp(nbperf
->keys
[i
], nbperf
->keys
[j
],
96 nbperf
->keylens
[i
]) == 0) {
97 nbperf
->has_duplicates
= 1;
100 if (e2
->l_next
== unused
)
103 e2
= &graph
->edges
[j
];
110 graph3_hash(struct nbperf
*nbperf
, struct graph3
*graph
)
113 uint32_t hashes
[NBPERF_MAX_HASH_SIZE
];
116 for (i
= 0; i
< graph
->e
; ++i
) {
117 (*nbperf
->compute_hash
)(nbperf
,
118 nbperf
->keys
[i
], nbperf
->keylens
[i
], hashes
);
119 graph
->edges
[i
].left
= hashes
[0] % graph
->v
;
120 graph
->edges
[i
].middle
= hashes
[1] % graph
->v
;
121 graph
->edges
[i
].right
= hashes
[2] % graph
->v
;
122 if (graph
->edges
[i
].left
== graph
->edges
[i
].middle
)
124 if (graph
->edges
[i
].left
== graph
->edges
[i
].right
)
126 if (graph
->edges
[i
].middle
== graph
->edges
[i
].right
)
130 for (i
= 0; i
< graph
->v
; ++i
) {
131 graph
->verts
[i
].l_edge
= unused
;
132 graph
->verts
[i
].m_edge
= unused
;
133 graph
->verts
[i
].r_edge
= unused
;
136 for (i
= 0; i
< graph
->e
; ++i
) {
137 v
= &graph
->verts
[graph
->edges
[i
].left
];
138 if (v
->l_edge
!= unused
)
139 graph
->edges
[v
->l_edge
].l_prev
= i
;
140 graph
->edges
[i
].l_next
= v
->l_edge
;
141 graph
->edges
[i
].l_prev
= unused
;
144 v
= &graph
->verts
[graph
->edges
[i
].middle
];
145 if (v
->m_edge
!= unused
)
146 graph
->edges
[v
->m_edge
].m_prev
= i
;
147 graph
->edges
[i
].m_next
= v
->m_edge
;
148 graph
->edges
[i
].m_prev
= unused
;
151 v
= &graph
->verts
[graph
->edges
[i
].right
];
152 if (v
->r_edge
!= unused
)
153 graph
->edges
[v
->r_edge
].r_prev
= i
;
154 graph
->edges
[i
].r_next
= v
->r_edge
;
155 graph
->edges
[i
].r_prev
= unused
;
159 if (nbperf
->first_round
) {
160 nbperf
->first_round
= 0;
161 return graph3_check_duplicates(nbperf
, graph
);
168 graph3_remove_vertex(struct graph3
*graph
, struct vertex3
*v
)
171 struct vertex3
*vl
, *vm
, *vr
;
173 if (v
->l_edge
!= unused
&& v
->m_edge
!= unused
)
175 if (v
->l_edge
!= unused
&& v
->r_edge
!= unused
)
177 if (v
->m_edge
!= unused
&& v
->r_edge
!= unused
)
179 if (v
->l_edge
== unused
&& v
->m_edge
== unused
&& v
->r_edge
== unused
)
182 if (v
->l_edge
!= unused
) {
183 e
= &graph
->edges
[v
->l_edge
];
184 if (e
->l_next
!= unused
)
186 } else if (v
->m_edge
!= unused
) {
187 e
= &graph
->edges
[v
->m_edge
];
188 if (e
->m_next
!= unused
)
191 if (v
->r_edge
== unused
)
193 e
= &graph
->edges
[v
->r_edge
];
194 if (e
->r_next
!= unused
)
198 graph
->output_order
[--graph
->output_index
] = e
- graph
->edges
;
200 vl
= &graph
->verts
[e
->left
];
201 vm
= &graph
->verts
[e
->middle
];
202 vr
= &graph
->verts
[e
->right
];
204 if (e
->l_prev
== unused
)
205 vl
->l_edge
= e
->l_next
;
207 graph
->edges
[e
->l_prev
].l_next
= e
->l_next
;
208 if (e
->l_next
!= unused
)
209 graph
->edges
[e
->l_next
].l_prev
= e
->l_prev
;
211 if (e
->m_prev
== unused
)
212 vm
->m_edge
= e
->m_next
;
214 graph
->edges
[e
->m_prev
].m_next
= e
->m_next
;
215 if (e
->m_next
!= unused
)
216 graph
->edges
[e
->m_next
].m_prev
= e
->m_prev
;
218 if (e
->r_prev
== unused
)
219 vr
->r_edge
= e
->r_next
;
221 graph
->edges
[e
->r_prev
].r_next
= e
->r_next
;
222 if (e
->r_next
!= unused
)
223 graph
->edges
[e
->r_next
].r_prev
= e
->r_prev
;
227 graph3_output_order(struct graph3
*graph
)
232 graph
->output_index
= graph
->e
;
234 for (i
= 0; i
< graph
->v
; ++i
)
235 graph3_remove_vertex(graph
, &graph
->verts
[i
]);
237 for (i
= graph
->e
; i
> 0 && i
> graph
->output_index
;) {
239 e
= &graph
->edges
[graph
->output_order
[i
]];
241 graph3_remove_vertex(graph
, &graph
->verts
[e
->left
]);
242 graph3_remove_vertex(graph
, &graph
->verts
[e
->middle
]);
243 graph3_remove_vertex(graph
, &graph
->verts
[e
->right
]);
246 if (graph
->output_index
!= 0)