Add more structure constructor tests.
[piglit/hramrach.git] / tests / glean / dsfilt.cpp
blob015aa64b8a838a4c528b4fb09e9d86944703e3d7
1 // BEGIN_COPYRIGHT
2 //
3 // Copyright (C) 1999 Allen Akin All Rights Reserved.
4 //
5 // multisample changes: Copyright (c) 2008 VMware, Inc. All rights reserved.
6 //
7 // Permission is hereby granted, free of charge, to any person
8 // obtaining a copy of this software and associated documentation
9 // files (the "Software"), to deal in the Software without
10 // restriction, including without limitation the rights to use,
11 // copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following
14 // conditions:
15 //
16 // The above copyright notice and this permission notice shall be
17 // included in all copies or substantial portions of the
18 // Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
21 // KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
22 // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
23 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ALLEN AKIN BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
25 // AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
26 // OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 // DEALINGS IN THE SOFTWARE.
28 //
29 // END_COPYRIGHT
34 // dsfilt.cpp: Implementation of drawing surface configuration filtering
36 #include <iostream>
37 #include <ctype.h>
38 #include <stdlib.h>
39 #include <algorithm>
40 #include "dsfilt.h"
41 #include "dsconfig.h"
43 namespace GLEAN {
46 ///////////////////////////////////////////////////////////////////////////////
47 // Constructor:
48 ///////////////////////////////////////////////////////////////////////////////
49 DrawingSurfaceFilter::DrawingSurfaceFilter(const string& s):
50 lex(s.c_str(), true) {
52 if (!varTableInitialized)
53 InitVarTable();
55 try {
56 GetSymbol();
57 if (!ParseCriteria())
58 throw Syntax("no criteria found", lex.position());
60 catch (Lex::Lexical e) {
61 throw Syntax(e.err, e.position);
64 // Make the final sort in order of increasing ID number:
65 EmitKey(MIN);
66 EmitKey(VAR_ID);
67 # if defined(GLX_VERSION_1_3)
68 EmitKey(MIN);
69 EmitKey(VAR_FBCID);
70 # endif
71 } // DrawingSurfaceFilter::DrawingSurfaceFilter
73 ///////////////////////////////////////////////////////////////////////////////
74 // matches - determine if a drawing surface config matches the specified
75 // criteria
76 ///////////////////////////////////////////////////////////////////////////////
77 bool
78 DrawingSurfaceFilter::matches(DrawingSurfaceConfig& c) {
79 // Process the RPN expression in ``condition'', using the supplied
80 // drawing surface configuration to determine values of variables.
82 vector<int> stack;
84 for (vector<int>::const_iterator p = condition.begin();
85 p < condition.end(); ++p) {
86 int right;
88 switch (*p) {
89 case ADD:
90 right = stack.back(); stack.pop_back();
91 stack.back() += right;
92 break;
93 case AND:
94 right = stack.back(); stack.pop_back();
95 stack.back() = stack.back() && right;
96 break;
97 case DIV:
98 right = stack.back(); stack.pop_back();
99 stack.back() = (right == 0)? 0: stack.back() / right;
100 break;
101 case EQ:
102 right = stack.back(); stack.pop_back();
103 stack.back() = stack.back() == right;
104 break;
105 case GE:
106 right = stack.back(); stack.pop_back();
107 stack.back() = stack.back() >= right;
108 break;
109 case GT:
110 right = stack.back(); stack.pop_back();
111 stack.back() = stack.back() > right;
112 break;
113 case LE:
114 right = stack.back(); stack.pop_back();
115 stack.back() = stack.back() <= right;
116 break;
117 case LT:
118 right = stack.back(); stack.pop_back();
119 stack.back() = stack.back() < right;
120 break;
121 case MOD:
122 right = stack.back(); stack.pop_back();
123 stack.back() = (right == 0)? 0: stack.back() % right;
124 break;
125 case MUL:
126 right = stack.back(); stack.pop_back();
127 stack.back() *= right;
128 break;
129 case NE:
130 right = stack.back(); stack.pop_back();
131 stack.back() = stack.back() != right;
132 break;
133 case NEGATE:
134 stack.back() = -stack.back();
135 break;
136 case NOT:
137 stack.back() = !stack.back();
138 break;
139 case OR:
140 right = stack.back(); stack.pop_back();
141 stack.back() = stack.back() || right;
142 break;
143 case SUB:
144 right = stack.back(); stack.pop_back();
145 stack.back() -= right;
146 break;
147 case CONSTANT:
148 stack.push_back(*++p);
149 break;
150 default:
151 // Must be a variable.
152 stack.push_back(FetchVariable(c,
153 static_cast<Token>(*p)));
154 break;
158 return stack.back();
159 } // DrawingSurfaceFilter::matches
161 ///////////////////////////////////////////////////////////////////////////////
162 // filter - find and sort all matching drawing surface configurations
163 ///////////////////////////////////////////////////////////////////////////////
164 vector<DrawingSurfaceConfig*>
165 DrawingSurfaceFilter::filter(vector<DrawingSurfaceConfig*>& v) {
166 return filter(v, ~0u);
167 } // DrawingSurfaceFilter::filter
169 ///////////////////////////////////////////////////////////////////////////////
170 // filter - filter as above, but limit number of results
171 ///////////////////////////////////////////////////////////////////////////////
172 vector<DrawingSurfaceConfig*>
173 DrawingSurfaceFilter::filter(vector<DrawingSurfaceConfig*>& v,
174 unsigned int maxConfigs) {
175 vector<DrawingSurfaceConfig*> result;
176 unsigned count = 0;
177 for (vector<DrawingSurfaceConfig*>::const_iterator p = v.begin();
178 p < v.end() && count < maxConfigs; ++p) {
179 if (matches(**p)) {
180 result.push_back(*p);
181 count++;
185 sort(result.begin(), result.end(), ConfigSort(sortKeys));
186 return result;
187 } // DrawingSurfaceFilter::filter
189 ///////////////////////////////////////////////////////////////////////////////
190 // ConfigSort operator() - sort comparison for final ordering of configurations
191 ///////////////////////////////////////////////////////////////////////////////
192 bool
193 DrawingSurfaceFilter::ConfigSort::operator()
194 (const DrawingSurfaceConfig* c1, const DrawingSurfaceConfig* c2) {
195 for (vector<Token>::const_iterator p=keys.begin(); p<keys.end(); ++p) {
196 Token dir = *p++;
197 int d = FetchVariable(*c1, *p) - FetchVariable(*c2, *p);
198 if (dir == MAX) // sort largest first?
199 d = -d;
200 if (d < 0)
201 return true; // c1 goes before c2
202 if (d > 0)
203 return false; // c1 goes after c2
205 return false; // order doesn't matter
208 ///////////////////////////////////////////////////////////////////////////////
209 // InitVarTable - initialize the table mapping variable names to token values
210 ///////////////////////////////////////////////////////////////////////////////
212 map<string,DrawingSurfaceFilter::Token> DrawingSurfaceFilter::varTable;
213 bool DrawingSurfaceFilter::varTableInitialized;
215 void
216 DrawingSurfaceFilter::InitVarTable() {
217 varTable["r"] = VAR_R;
218 varTable["g"] = VAR_G;
219 varTable["b"] = VAR_B;
220 varTable["a"] = VAR_A;
221 varTable["rgb"] = VAR_RGB;
222 varTable["rgba"] = VAR_RGBA;
223 varTable["ci"] = VAR_CI;
224 varTable["accumr"] = VAR_ACCUM_R;
225 varTable["accumg"] = VAR_ACCUM_G;
226 varTable["accumb"] = VAR_ACCUM_B;
227 varTable["accuma"] = VAR_ACCUM_A;
228 varTable["accumrgb"] = VAR_ACCUM_RGB;
229 varTable["accumrgba"] = VAR_ACCUM_RGBA;
230 varTable["samples"] = VAR_SAMPLES;
231 varTable["aux"] = VAR_AUX;
232 varTable["db"] = VAR_DB;
233 varTable["sb"] = VAR_SB;
234 varTable["id"] = VAR_ID;
235 varTable["fbcid"] = VAR_FBCID;
236 varTable["level"] = VAR_LEVEL;
237 varTable["main"] = VAR_MAIN;
238 varTable["overlay"] = VAR_OVERLAY;
239 varTable["underlay"] = VAR_UNDERLAY;
240 varTable["mono"] = VAR_MONO;
241 varTable["stereo"] = VAR_STEREO;
242 varTable["ms"] = VAR_MS;
243 varTable["s"] = VAR_S;
244 varTable["z"] = VAR_Z;
245 varTable["fast"] = VAR_FAST;
246 varTable["conformant"] = VAR_CONFORMANT;
247 varTable["transparent"] = VAR_TRANSPARENT;
248 varTable["transr"] = VAR_TRANS_R;
249 varTable["transg"] = VAR_TRANS_G;
250 varTable["transb"] = VAR_TRANS_B;
251 varTable["transa"] = VAR_TRANS_A;
252 varTable["transci"] = VAR_TRANS_CI;
253 varTable["window"] = VAR_WINDOW;
254 varTable["pbuffer"] = VAR_PBUFFER;
255 varTable["pixmap"] = VAR_PIXMAP;
256 varTable["glonly"] = VAR_GL_ONLY;
257 varTable["max"] = MAX;
258 varTable["min"] = MIN;
260 varTableInitialized = true;
261 } // DrawingSurfaceFilter::InitVarTable
263 ///////////////////////////////////////////////////////////////////////////////
264 // FetchVariable - fetch the value of a variable from a
265 // DrawingSurfaceConfig
266 ///////////////////////////////////////////////////////////////////////////////
269 DrawingSurfaceFilter::FetchVariable(const DrawingSurfaceConfig& c, Token v) {
270 switch (v) {
271 case VAR_R:
272 return c.r;
273 case VAR_G:
274 return c.g;
275 case VAR_B:
276 return c.b;
277 case VAR_A:
278 return c.a;
279 case VAR_RGB:
280 return min(c.r, min(c.g, c.b));
281 case VAR_RGBA:
282 return min(c.r, min(c.g, min(c.b, c.a)));
284 case VAR_CI:
285 return c.canCI? c.bufSize: 0;
287 case VAR_ACCUM_R:
288 return c.accR;
289 case VAR_ACCUM_G:
290 return c.accG;
291 case VAR_ACCUM_B:
292 return c.accB;
293 case VAR_ACCUM_A:
294 return c.accA;
295 case VAR_ACCUM_RGB:
296 return min(c.accR, min(c.accG, c.accB));
297 case VAR_ACCUM_RGBA:
298 return min(c.accR, min(c.accG, min(c.accB, c.accA)));
300 case VAR_SAMPLES:
301 return c.samples;
303 case VAR_AUX:
304 return c.aux;
306 case VAR_DB:
307 return c.db;
308 case VAR_SB:
309 return !c.db;
311 case VAR_ID:
312 # if defined(__X11__)
313 return c.visID;
314 # elif defined(__WIN__)
315 return c.pfdID;
316 # endif
317 case VAR_FBCID:
318 # if defined(GLX_VERSION_1_3)
319 return c.fbcID;
320 # else
321 return 0;
322 # endif
324 case VAR_LEVEL:
325 return c.level;
326 case VAR_MAIN:
327 return c.level == 0;
328 case VAR_OVERLAY:
329 return c.level > 0;
330 case VAR_UNDERLAY:
331 return c.level < 0;
333 case VAR_MONO:
334 return !c.stereo;
335 break;
336 case VAR_STEREO:
337 return c.stereo;
339 case VAR_MS:
340 // XXX Can't support this at the moment; have no way to
341 // compile or test.
342 return 0;
344 case VAR_S:
345 return c.s;
347 case VAR_Z:
348 return c.z;
350 case VAR_FAST:
351 return c.fast;
352 case VAR_CONFORMANT:
353 return c.conformant;
355 case VAR_TRANSPARENT:
356 return c.transparent;
357 case VAR_TRANS_R:
358 return c.transR;
359 case VAR_TRANS_G:
360 return c.transG;
361 case VAR_TRANS_B:
362 return c.transB;
363 case VAR_TRANS_A:
364 return c.transA;
365 case VAR_TRANS_CI:
366 return c.transI;
368 case VAR_WINDOW:
369 return c.canWindow;
370 case VAR_PBUFFER:
371 # if defined(GLX_VERSION_1_3)
372 return c.canPBuffer;
373 # else
374 return 0;
375 # endif
376 case VAR_PIXMAP:
377 # if defined(__X11__)
378 return c.canPixmap;
379 # else
380 return 0;
381 # endif
383 case VAR_GL_ONLY:
384 return !c.canWinSysRender;
386 default:
387 throw InternalError();
391 ///////////////////////////////////////////////////////////////////////////////
392 // GetSymbol - Fetch next symbol from the input string
393 ///////////////////////////////////////////////////////////////////////////////
394 void
395 DrawingSurfaceFilter::GetSymbol() {
396 lex.next();
397 switch(lex.token) {
398 case Lex::ID:
399 Symbol = varTable[lex.id];
400 // Note: Because ERROR has value zero in the
401 // Token enumeration, if the user provides a
402 // variable that is not in varTable, then Symbol
403 // will be set to ERROR.
404 if (Symbol == ERROR)
405 throw Syntax("unrecognized variable", lex.position());
406 break;
407 case Lex::ICONST:
408 Value = lex.iValue;
409 Symbol = CONSTANT;
410 break;
411 case Lex::OR_OR:
412 Symbol = OR;
413 break;
414 case Lex::AND_AND:
415 Symbol = AND;
416 break;
417 case Lex::LE:
418 Symbol = LE;
419 break;
420 case Lex::LT:
421 Symbol = LT;
422 break;
423 case Lex::GE:
424 Symbol = GE;
425 break;
426 case Lex::GT:
427 Symbol = GT;
428 break;
429 case Lex::EQ:
430 Symbol = EQ;
431 break;
432 case Lex::NE:
433 Symbol = NE;
434 break;
435 case Lex::BANG:
436 Symbol = NOT;
437 break;
438 case Lex::PLUS:
439 Symbol = ADD;
440 break;
441 case Lex::MINUS:
442 Symbol = SUB;
443 break;
444 case Lex::STAR:
445 Symbol = MUL;
446 break;
447 case Lex::SLASH:
448 Symbol = DIV;
449 break;
450 case Lex::PERCENT:
451 Symbol = MOD;
452 break;
453 case Lex::COMMA:
454 Symbol = SEPARATOR;
455 break;
456 case Lex::LPAREN:
457 Symbol = LPAREN;
458 break;
459 case Lex::RPAREN:
460 Symbol = RPAREN;
461 break;
462 case Lex::END:
463 Symbol = END;
464 break;
465 default:
466 throw Syntax("unrecognized symbol", lex.position());
469 return;
470 } // DrawingSurfaceFilter::GetSymbol
472 ///////////////////////////////////////////////////////////////////////////////
473 // ParseArithExpr
474 // Syntax: arithExpr -> arithTerm {('+'|'-') arithTerm}
475 ///////////////////////////////////////////////////////////////////////////////
476 bool
477 DrawingSurfaceFilter::ParseArithExpr() {
478 if (!ParseArithTerm())
479 return false;
481 for (;;) {
482 if (Symbol == ADD || Symbol == SUB) {
483 Token op = Symbol;
484 GetSymbol();
485 if (!ParseArithTerm())
486 throw Syntax("missing operand of + or -",
487 lex.position());
488 Emit(op);
489 } else
490 return true;
494 ///////////////////////////////////////////////////////////////////////////////
495 // ParseArithFactor
496 // Syntax: arithFactor -> ['+'|'-'|'!'] arithPrimary
497 ///////////////////////////////////////////////////////////////////////////////
498 bool
499 DrawingSurfaceFilter::ParseArithFactor() {
500 if (Symbol == ADD || Symbol == SUB || Symbol == NOT) {
501 Token op = Symbol;
502 GetSymbol();
503 if (!ParseArithPrimary())
504 throw Syntax("missing operand of unary +, -, or !",
505 lex.position());
506 if (op == SUB)
507 Emit(NEGATE);
508 else if (op == NOT)
509 Emit(NOT);
510 return true;
513 return ParseArithPrimary();
516 ///////////////////////////////////////////////////////////////////////////////
517 // ParseArithPrimary
518 // Syntax: arithPrimary -> variable | constant | '(' expression ')'
519 ///////////////////////////////////////////////////////////////////////////////
520 bool
521 DrawingSurfaceFilter::ParseArithPrimary() {
522 if (FIRST_VAR < Symbol && Symbol < LAST_VAR) {
523 Emit(Symbol);
524 GetSymbol();
525 return true;
528 if (Symbol == CONSTANT) {
529 Emit(CONSTANT);
530 Emit(Value);
531 GetSymbol();
532 return true;
535 if (Symbol == LPAREN) {
536 GetSymbol();
537 if (!ParseExpression())
538 throw Syntax("missing expression after (",
539 lex.position());
540 if (Symbol == RPAREN) {
541 GetSymbol();
542 return true;
543 } else
544 throw Syntax("missing )", lex.position());
547 return false;
550 ///////////////////////////////////////////////////////////////////////////////
551 // ParseArithTerm
552 // Syntax: arithTerm -> arithFactor {('*'|'/'|'%') arithFactor}
553 ///////////////////////////////////////////////////////////////////////////////
554 bool
555 DrawingSurfaceFilter::ParseArithTerm() {
556 if (!ParseArithFactor())
557 return false;
559 for (;;) {
560 if (Symbol == MUL
561 || Symbol == DIV
562 || Symbol == MOD) {
563 Token op = Symbol;
564 GetSymbol();
565 if (!ParseArithFactor())
566 throw Syntax("missing operand of *, /, or %",
567 lex.position());
568 Emit(op);
569 } else
570 return true;
574 ///////////////////////////////////////////////////////////////////////////////
575 // ParseBoolFactor
576 // Syntax: boolFactor -> arithExpr [('<'|'>'|'<='|'>='|'=='|'!=') arithExpr]
577 ///////////////////////////////////////////////////////////////////////////////
578 bool
579 DrawingSurfaceFilter::ParseBoolFactor() {
580 if (!ParseArithExpr())
581 return false;
583 if (Symbol == LT
584 || Symbol == GT
585 || Symbol == LE
586 || Symbol == GE
587 || Symbol == EQ
588 || Symbol == NE) {
589 Token op = Symbol;
590 GetSymbol();
591 if (!ParseArithExpr())
592 throw Syntax("missing operand of comparison",
593 lex.position());
594 Emit(op);
597 return true;
600 ///////////////////////////////////////////////////////////////////////////////
601 // ParseBoolTerm
602 // Syntax: boolTerm -> boolFactor {'&&' boolFactor}
603 ///////////////////////////////////////////////////////////////////////////////
604 bool
605 DrawingSurfaceFilter::ParseBoolTerm() {
606 if (!ParseBoolFactor())
607 return false;
609 for (;;) {
610 if (Symbol == AND) {
611 GetSymbol();
612 if (!ParseBoolFactor())
613 throw Syntax("missing operand of &&",
614 lex.position());
615 Emit(AND);
616 } else
617 return true;
621 ///////////////////////////////////////////////////////////////////////////////
622 // ParseCriteria
623 // Syntax: criteria -> criterion {',' criterion}
624 ///////////////////////////////////////////////////////////////////////////////
625 bool
626 DrawingSurfaceFilter::ParseCriteria() {
627 /* Process all the user-specified conditions and sort keys: */
628 if (!ParseCriterion())
629 return false;
631 for (;;) {
632 if (Symbol == SEPARATOR) {
633 GetSymbol();
634 if (!ParseCriterion())
635 throw Syntax("missing criterion after comma",
636 lex.position());
637 Emit(AND);
638 } else if (Symbol == END)
639 return true;
640 else
641 throw Syntax("expected comma or end of criteria",
642 lex.position());
646 ///////////////////////////////////////////////////////////////////////////////
647 // ParseCriterion
648 // Syntax: criterion -> sortKey | expression
649 ///////////////////////////////////////////////////////////////////////////////
650 bool
651 DrawingSurfaceFilter::ParseCriterion() {
652 if (ParseSortKey())
653 return true;
654 return ParseExpression();
657 ///////////////////////////////////////////////////////////////////////////////
658 // ParseExpression
659 // Syntax: expression -> boolTerm {'||' boolTerm}
660 ///////////////////////////////////////////////////////////////////////////////
661 bool
662 DrawingSurfaceFilter::ParseExpression() {
663 if (!ParseBoolTerm())
664 return false;
666 for (;;) {
667 if (Symbol == OR) {
668 GetSymbol();
669 if (!ParseBoolTerm())
670 throw Syntax("missing operand of ||",
671 lex.position());
672 Emit(OR);
673 } else
674 return true;
678 ///////////////////////////////////////////////////////////////////////////////
679 // ParseSortKey
680 // Syntax: sortKey -> ('max'|'min') variable
681 ///////////////////////////////////////////////////////////////////////////////
682 bool
683 DrawingSurfaceFilter::ParseSortKey() {
684 if (Symbol == MAX || Symbol == MIN) {
685 EmitKey(Symbol);
686 GetSymbol();
687 if (FIRST_VAR < Symbol && Symbol < LAST_VAR) {
688 EmitKey(Symbol);
690 // When sorting, eliminate visuals with a zero value
691 // for the key. This is hard to justify on grounds
692 // of orthogonality, but it seems to yield the right
693 // behavior (especially for ``min'').
695 Emit(Symbol);
696 GetSymbol();
697 return true;
698 } else
699 throw Syntax("missing variable name after sort key",
700 lex.position());
703 return false;
704 } // DrawingSurfaceFilter::ParseSortKey
707 } // namespace GLEAN