2 * A judge comparing shuffled sequences of tokens
4 * (c) 2007 Martin Mares <mj@ucw.cz>
15 static int ignore_nl, ignore_empty, ignore_case;
16 static int shuffle_lines, shuffle_words;
18 typedef unsigned int uns;
20 /*** Token buffer ***/
30 struct tokpage *first_page, *last_page;
31 uns num_tokens, num_lines;
33 struct tokpage *this_page;
37 #define TOKBUF_PAGE 65536
39 static void init_tokbuf(struct tokbuf *tb)
41 memset(tb, 0, sizeof(*tb));
44 static void add_token(struct tokbuf *tb, char *token, int l)
47 struct tokpage *pg = tb->last_page;
48 if (!pg || pg->end - pg->pos < l)
52 int size = TOKBUF_PAGE - sizeof(struct tokbuf);
55 pg = xmalloc(sizeof(struct tokbuf) + size);
57 tb->last_page->next = pg;
63 pg->end = pg->buf + size;
65 memcpy(pg->pos, token, l);
72 static void close_tokens(struct tokbuf *tb)
75 tb->last_page->end = tb->last_page->pos;
78 static char *get_next(struct tokbuf *tb)
80 struct tokpage *pg = tb->this_page;
81 tb->read_pos += strlen(tb->read_pos) + 1;
82 if (tb->read_pos >= pg->end)
84 tb->this_page = pg = pg->next;
87 tb->read_pos = pg->buf;
92 static char *get_first(struct tokbuf *tb)
94 struct tokpage *pg = tb->first_page;
98 tb->read_pos = pg->buf;
102 /*** Reading and shuffling ***/
118 struct tok *tok_array;
119 struct line *line_array;
123 static void read_input(struct tokenizer *t, struct tokbuf *tb)
129 while (tok = get_token(t))
135 for (char *c=tok; *c; c++)
136 if (*c >= 'a' && *c <= 'z')
145 add_token(tb, tok, t->toksize);
148 add_token(tb, "", 0);
152 static inline uns string_hash(unsigned char *x)
156 h = (h * 0x6011) + *x++;
160 static inline uns line_hash(struct tok *t, uns cnt)
164 h = (h * 0x6011) + (t++)->hash;
168 static int compare_toks(struct tok *x, struct tok *y)
170 if (x->hash < y->hash)
172 if (x->hash > y->hash)
174 return strcmp(x->token, y->token);
177 static int compare_lines(struct line *x, struct line *y)
179 if (x->hash < y->hash)
181 if (x->hash > y->hash)
189 for (uns i=0; i < x->len; i++)
191 int c = compare_toks(&x->toks[i], &y->toks[i]);
198 static void slurp(struct tokenizer *t, struct shouffle *s)
200 read_input(t, &s->tb);
201 s->tok_array = xmalloc(sizeof(struct tok) * s->tb.num_tokens);
202 s->line_array = xmalloc(sizeof(struct line) * (s->tb.num_lines+1));
205 struct tok *tok = s->tok_array;
206 struct line *line = s->line_array;
208 for (char *x = get_first(&s->tb); x; x = get_next(&s->tb))
212 tok->hash = string_hash(x);
217 line->len = tok - line->toks;
219 qsort(line->toks, line->len, sizeof(struct tok), (int(*)(const void *, const void *)) compare_toks);
220 line->hash = line_hash(line->toks, line->len);
221 line->orig_line = ++s->num_lines;
223 for (struct tok *t=line->toks; t<tok; t++)
224 printf("<%08x|%s>", t->hash, t->token);
225 printf(" -> %08x (%d)\n", line->hash, line->orig_line);
230 if (line->toks != tok)
231 die("Bug #41: unterminated line");
232 if (s->num_lines != s->tb.num_lines)
233 die("Bug #42: got %d lines, expected %d", s->num_lines, s->tb.num_lines);
236 qsort(s->line_array, s->num_lines, sizeof(struct line), (int(*)(const void *, const void *)) compare_lines);
239 static void compare(struct shouffle *s1, struct shouffle *s2)
241 if (s1->num_lines != s2->num_lines)
243 printf("Output has %d lines, expecting %d\n", s1->num_lines, s2->num_lines);
248 for (uns i=0; i<s1->num_lines; i++)
250 struct line *l1 = &s1->line_array[i], *l2 = &s2->line_array[i];
251 if (compare_lines(l1, l2))
253 printf("Line %d does not match\n", l1->orig_line);
254 printf(" %08x(%d) vs. %08x(%d)\n", l1->hash, l1->orig_line, l2->hash, l2->orig_line);
264 static void usage(void)
266 fprintf(stderr, "Usage: judge-shuff [<options>] <output> <correct>\n\
269 -n\t\tIgnore newlines and match the whole input as a single line\n\
270 -e\t\tIgnore empty lines\n\
271 -l\t\tShuffle lines (i.e., ignore their order)\n\
272 -w\t\tShuffle words in each line\n\
278 int main(int argc, char **argv)
280 struct tokenizer t1, t2;
283 while ((opt = getopt(argc, argv, "nelwi")) >= 0)
304 if (optind + 2 != argc)
307 tok_init(&t1, sopen_read(argv[optind]));
308 tok_init(&t2, sopen_read(argv[optind+1]));
310 t1.flags = t2.flags = TF_REPORT_LINES;
312 struct shouffle s1, s2;