summary refs log tree commit diff stats
path: root/lib/filter.cpp
diff options
context:
space:
mode:
authorKelly Rauchenberger <fefferburbia@gmail.com>2017-01-16 18:02:50 -0500
committerKelly Rauchenberger <fefferburbia@gmail.com>2017-01-16 18:02:50 -0500
commit6746da6edd7d9d50efe374eabbb79a3cac882d81 (patch)
treeff20917e08b08d36b9541c1371106596e7bec442 /lib/filter.cpp
parent4af7e55733098ca42f75a4ffaca1b0f6bab4dd36 (diff)
downloadverbly-6746da6edd7d9d50efe374eabbb79a3cac882d81.tar.gz
verbly-6746da6edd7d9d50efe374eabbb79a3cac882d81.tar.bz2
verbly-6746da6edd7d9d50efe374eabbb79a3cac882d81.zip
Started structural rewrite
The new object structure was designed to build on the existing WordNet
structure, while also adding in all of the data that we get from other sources.
More information about this can be found on the project wiki.

The generator has already been completely rewritten to generate a
datafile that uses the new structure. In addition, a number of indexes
are created, which does double the size of the datafile, but also allows
for much faster lookups. Finally, the new generator is written modularly
and is a lot more readable than the old one.

The verbly interface to the new object structure has mostly been
completed, but has not been tested fully. There is a completely new
search API which utilizes a lot of operator overloading; documentation
on how to use it should go up at some point.

Token processing and verb frames are currently unimplemented. Source for
these have been left in the repository for now.
Diffstat (limited to 'lib/filter.cpp')
-rw-r--r--lib/filter.cpp1365
1 files changed, 1365 insertions, 0 deletions
diff --git a/lib/filter.cpp b/lib/filter.cpp new file mode 100644 index 0000000..959fa05 --- /dev/null +++ b/lib/filter.cpp
@@ -0,0 +1,1365 @@
1#include "filter.h"
2#include <stdexcept>
3#include <map>
4#include "notion.h"
5#include "word.h"
6#include "group.h"
7#include "frame.h"
8#include "lemma.h"
9#include "form.h"
10#include "pronunciation.h"
11
12namespace verbly {
13
14 filter::filter(const filter& other)
15 {
16 type_ = other.type_;
17
18 switch (type_)
19 {
20 case type::empty:
21 {
22 break;
23 }
24
25 case type::singleton:
26 {
27 new(&singleton_.filterField) field(other.singleton_.filterField);
28 singleton_.filterType = other.singleton_.filterType;
29
30 switch (singleton_.filterType)
31 {
32 case comparison::int_equals:
33 case comparison::int_does_not_equal:
34 case comparison::int_is_at_least:
35 case comparison::int_is_greater_than:
36 case comparison::int_is_at_most:
37 case comparison::int_is_less_than:
38 {
39 singleton_.intValue = other.singleton_.intValue;
40
41 break;
42 }
43
44 case comparison::boolean_equals:
45 {
46 singleton_.boolValue = other.singleton_.boolValue;
47
48 break;
49 }
50
51 case comparison::string_equals:
52 case comparison::string_does_not_equal:
53 case comparison::string_is_like:
54 case comparison::string_is_not_like:
55 {
56 new(&singleton_.stringValue) std::string(other.singleton_.stringValue);
57
58 break;
59 }
60
61 case comparison::is_null:
62 case comparison::is_not_null:
63 {
64 break;
65 }
66
67 case comparison::matches:
68 case comparison::does_not_match:
69 case comparison::hierarchally_matches:
70 case comparison::does_not_hierarchally_match:
71 {
72 new(&singleton_.join) std::unique_ptr<filter>(new filter(*other.singleton_.join));
73
74 break;
75 }
76 }
77
78 break;
79 }
80
81 case type::group:
82 {
83 new(&group_.children) std::list<filter>(other.group_.children);
84 group_.orlogic = other.group_.orlogic;
85
86 break;
87 }
88 }
89 }
90
91 filter::filter(filter&& other) : filter()
92 {
93 swap(*this, other);
94 }
95
96 filter& filter::operator=(filter other)
97 {
98 swap(*this, other);
99
100 return *this;
101 }
102
103 void swap(filter& first, filter& second)
104 {
105 using type = filter::type;
106 using comparison = filter::comparison;
107
108 type tempType = first.type_;
109 field tempField;
110 comparison tempComparison;
111 std::unique_ptr<filter> tempJoin;
112 std::string tempStringValue;
113 int tempIntValue;
114 bool tempBoolValue;
115 std::list<filter> tempChildren;
116 bool tempOrlogic;
117
118 switch (tempType)
119 {
120 case type::empty:
121 {
122 break;
123 }
124
125 case type::singleton:
126 {
127 tempField = std::move(first.singleton_.filterField);
128 tempComparison = first.singleton_.filterType;
129
130 switch (tempComparison)
131 {
132 case comparison::int_equals:
133 case comparison::int_does_not_equal:
134 case comparison::int_is_at_least:
135 case comparison::int_is_greater_than:
136 case comparison::int_is_at_most:
137 case comparison::int_is_less_than:
138 {
139 tempIntValue = first.singleton_.intValue;
140
141 break;
142 }
143
144 case comparison::boolean_equals:
145 {
146 tempBoolValue = first.singleton_.boolValue;
147
148 break;
149 }
150
151 case comparison::string_equals:
152 case comparison::string_does_not_equal:
153 case comparison::string_is_like:
154 case comparison::string_is_not_like:
155 {
156 tempStringValue = std::move(first.singleton_.stringValue);
157
158 break;
159 }
160
161 case comparison::is_null:
162 case comparison::is_not_null:
163 {
164 break;
165 }
166
167 case comparison::matches:
168 case comparison::does_not_match:
169 case comparison::hierarchally_matches:
170 case comparison::does_not_hierarchally_match:
171 {
172 tempJoin = std::move(first.singleton_.join);
173
174 break;
175 }
176 }
177
178 break;
179 }
180
181 case type::group:
182 {
183 tempChildren = std::move(first.group_.children);
184 tempOrlogic = first.group_.orlogic;
185
186 break;
187 }
188 }
189
190 first.~filter();
191
192 first.type_ = second.type_;
193
194 switch (first.type_)
195 {
196 case type::empty:
197 {
198 break;
199 }
200
201 case type::singleton:
202 {
203 new(&first.singleton_.filterField) field(std::move(second.singleton_.filterField));
204 first.singleton_.filterType = second.singleton_.filterType;
205
206 switch (first.singleton_.filterType)
207 {
208 case comparison::int_equals:
209 case comparison::int_does_not_equal:
210 case comparison::int_is_at_least:
211 case comparison::int_is_greater_than:
212 case comparison::int_is_at_most:
213 case comparison::int_is_less_than:
214 {
215 first.singleton_.intValue = second.singleton_.intValue;
216
217 break;
218 }
219
220 case comparison::boolean_equals:
221 {
222 first.singleton_.boolValue = second.singleton_.boolValue;
223
224 break;
225 }
226
227 case comparison::string_equals:
228 case comparison::string_does_not_equal:
229 case comparison::string_is_like:
230 case comparison::string_is_not_like:
231 {
232 new(&first.singleton_.stringValue) std::string(std::move(second.singleton_.stringValue));
233
234 break;
235 }
236
237 case comparison::is_null:
238 case comparison::is_not_null:
239 {
240 break;
241 }
242
243 case comparison::matches:
244 case comparison::does_not_match:
245 case comparison::hierarchally_matches:
246 case comparison::does_not_hierarchally_match:
247 {
248 new(&first.singleton_.join) std::unique_ptr<filter>(std::move(second.singleton_.join));
249
250 break;
251 }
252 }
253
254 break;
255 }
256
257 case type::group:
258 {
259 new(&first.group_.children) std::list<filter>(std::move(second.group_.children));
260 first.group_.orlogic = second.group_.orlogic;
261
262 break;
263 }
264 }
265
266 second.~filter();
267
268 second.type_ = tempType;
269
270 switch (second.type_)
271 {
272 case type::empty:
273 {
274 break;
275 }
276
277 case type::singleton:
278 {
279 new(&second.singleton_.filterField) field(std::move(tempField));
280 second.singleton_.filterType = tempComparison;
281
282 switch (second.singleton_.filterType)
283 {
284 case comparison::int_equals:
285 case comparison::int_does_not_equal:
286 case comparison::int_is_at_least:
287 case comparison::int_is_greater_than:
288 case comparison::int_is_at_most:
289 case comparison::int_is_less_than:
290 {
291 second.singleton_.intValue = tempIntValue;
292
293 break;
294 }
295
296 case comparison::boolean_equals:
297 {
298 second.singleton_.boolValue = tempBoolValue;
299
300 break;
301 }
302
303 case comparison::string_equals:
304 case comparison::string_does_not_equal:
305 case comparison::string_is_like:
306 case comparison::string_is_not_like:
307 {
308 new(&second.singleton_.stringValue) std::string(std::move(tempStringValue));
309
310 break;
311 }
312
313 case comparison::is_null:
314 case comparison::is_not_null:
315 {
316 break;
317 }
318
319 case comparison::matches:
320 case comparison::does_not_match:
321 case comparison::hierarchally_matches:
322 case comparison::does_not_hierarchally_match:
323 {
324 new(&second.singleton_.join) std::unique_ptr<filter>(std::move(tempJoin));
325
326 break;
327 }
328 }
329
330 break;
331 }
332
333 case type::group:
334 {
335 new(&second.group_.children) std::list<filter>(std::move(tempChildren));
336 second.group_.orlogic = tempOrlogic;
337
338 break;
339 }
340 }
341 }
342
343 filter::~filter()
344 {
345 switch (type_)
346 {
347 case type::empty:
348 {
349 break;
350 }
351
352 case type::singleton:
353 {
354 singleton_.filterField.~field();
355
356 switch (singleton_.filterType)
357 {
358 case comparison::int_equals:
359 case comparison::int_does_not_equal:
360 case comparison::int_is_at_least:
361 case comparison::int_is_greater_than:
362 case comparison::int_is_at_most:
363 case comparison::int_is_less_than:
364 case comparison::boolean_equals:
365 case comparison::is_null:
366 case comparison::is_not_null:
367 {
368 break;
369 }
370
371 case comparison::string_equals:
372 case comparison::string_does_not_equal:
373 case comparison::string_is_like:
374 case comparison::string_is_not_like:
375 {
376 using string_type = std::string;
377
378 singleton_.stringValue.~string_type();
379
380 break;
381 }
382
383 case comparison::matches:
384 case comparison::does_not_match:
385 case comparison::hierarchally_matches:
386 case comparison::does_not_hierarchally_match:
387 {
388 using ptr_type = std::unique_ptr<filter>;
389
390 singleton_.join.~ptr_type();
391
392 break;
393 }
394 }
395
396 break;
397 }
398
399 case type::group:
400 {
401 using list_type = std::list<filter>;
402
403 group_.children.~list_type();
404
405 break;
406 }
407 }
408 }
409
410 filter::filter()
411 {
412 }
413
414 filter::filter(
415 field filterField,
416 comparison filterType,
417 int filterValue) :
418 type_(type::singleton)
419 {
420 if (filterField.getType() == field::type::integer)
421 {
422 switch (filterType)
423 {
424 case comparison::int_equals:
425 case comparison::int_does_not_equal:
426 case comparison::int_is_at_least:
427 case comparison::int_is_greater_than:
428 case comparison::int_is_at_most:
429 case comparison::int_is_less_than:
430 {
431 new(&singleton_.filterField) field(std::move(filterField));
432 singleton_.filterType = filterType;
433 singleton_.intValue = filterValue;
434
435 break;
436 }
437
438 case comparison::boolean_equals:
439 case comparison::string_equals:
440 case comparison::string_does_not_equal:
441 case comparison::string_is_like:
442 case comparison::string_is_not_like:
443 case comparison::is_null:
444 case comparison::is_not_null:
445 case comparison::matches:
446 case comparison::does_not_match:
447 case comparison::hierarchally_matches:
448 case comparison::does_not_hierarchally_match:
449 {
450 throw std::invalid_argument("Invalid comparison for integer field");
451 }
452 }
453 } else {
454 throw std::domain_error("Cannot match a non-integer field against an integer value");
455 }
456 }
457
458 filter::filter(
459 field filterField,
460 comparison filterType,
461 std::string filterValue) :
462 type_(type::singleton)
463 {
464 if (filterField.getType() == field::type::string)
465 {
466 switch (filterType)
467 {
468 case comparison::string_equals:
469 case comparison::string_does_not_equal:
470 case comparison::string_is_like:
471 case comparison::string_is_not_like:
472 {
473 new(&singleton_.filterField) field(std::move(filterField));
474 singleton_.filterType = filterType;
475 new(&singleton_.stringValue) std::string(std::move(filterValue));
476
477 break;
478 }
479
480 case comparison::int_equals:
481 case comparison::int_does_not_equal:
482 case comparison::int_is_at_least:
483 case comparison::int_is_greater_than:
484 case comparison::int_is_at_most:
485 case comparison::int_is_less_than:
486 case comparison::boolean_equals:
487 case comparison::is_null:
488 case comparison::is_not_null:
489 case comparison::matches:
490 case comparison::does_not_match:
491 case comparison::hierarchally_matches:
492 case comparison::does_not_hierarchally_match:
493 {
494 throw std::invalid_argument("Invalid comparison for string field");
495 }
496 }
497 } else {
498 throw std::domain_error("Cannot match a non-string field against an string value");
499 }
500 }
501
502 filter::filter(
503 field filterField,
504 comparison filterType,
505 bool filterValue) :
506 type_(type::singleton)
507 {
508 if (filterField.getType() == field::type::boolean)
509 {
510 switch (filterType)
511 {
512 case comparison::boolean_equals:
513 {
514 new(&singleton_.filterField) field(std::move(filterField));
515 singleton_.filterType = filterType;
516 singleton_.boolValue = filterValue;
517
518 break;
519 }
520
521 case comparison::string_equals:
522 case comparison::string_does_not_equal:
523 case comparison::string_is_like:
524 case comparison::string_is_not_like:
525 case comparison::int_equals:
526 case comparison::int_does_not_equal:
527 case comparison::int_is_at_least:
528 case comparison::int_is_greater_than:
529 case comparison::int_is_at_most:
530 case comparison::int_is_less_than:
531 case comparison::is_null:
532 case comparison::is_not_null:
533 case comparison::matches:
534 case comparison::does_not_match:
535 case comparison::hierarchally_matches:
536 case comparison::does_not_hierarchally_match:
537 {
538 throw std::invalid_argument("Invalid comparison for boolean field");
539 }
540 }
541 } else {
542 throw std::domain_error("Cannot match a non-boolean field against a boolean value");
543 }
544 }
545
546 filter::filter(
547 field filterField,
548 comparison filterType) :
549 type_(type::singleton)
550 {
551 if (filterField.isNullable())
552 {
553 switch (filterType)
554 {
555 case comparison::is_null:
556 case comparison::is_not_null:
557 {
558 new(&singleton_.filterField) field(std::move(filterField));
559 singleton_.filterType = filterType;
560
561 break;
562 }
563
564 case comparison::string_equals:
565 case comparison::string_does_not_equal:
566 case comparison::string_is_like:
567 case comparison::string_is_not_like:
568 case comparison::int_equals:
569 case comparison::int_does_not_equal:
570 case comparison::int_is_at_least:
571 case comparison::int_is_greater_than:
572 case comparison::int_is_at_most:
573 case comparison::int_is_less_than:
574 case comparison::boolean_equals:
575 case comparison::matches:
576 case comparison::does_not_match:
577 case comparison::hierarchally_matches:
578 case comparison::does_not_hierarchally_match:
579 {
580 throw std::invalid_argument("Incorrect constructor for given comparison");
581 }
582 }
583 } else {
584 throw std::domain_error("Cannot check nullity/non-nullity of non-nullable field");
585 }
586 }
587
588 filter::filter(
589 field joinOn,
590 comparison filterType,
591 filter joinCondition) :
592 type_(type::singleton)
593 {
594 switch (joinOn.getType())
595 {
596 case field::type::join:
597 case field::type::join_through:
598 {
599 switch (filterType)
600 {
601 case comparison::matches:
602 case comparison::does_not_match:
603 {
604 new(&singleton_.filterField) field(std::move(joinOn));
605 singleton_.filterType = filterType;
606 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getJoinObject())));
607
608 break;
609 }
610
611 case comparison::int_equals:
612 case comparison::int_does_not_equal:
613 case comparison::int_is_at_least:
614 case comparison::int_is_greater_than:
615 case comparison::int_is_at_most:
616 case comparison::int_is_less_than:
617 case comparison::boolean_equals:
618 case comparison::string_equals:
619 case comparison::string_does_not_equal:
620 case comparison::string_is_like:
621 case comparison::string_is_not_like:
622 case comparison::is_null:
623 case comparison::is_not_null:
624 case comparison::hierarchally_matches:
625 case comparison::does_not_hierarchally_match:
626 {
627 throw std::invalid_argument("Incorrect constructor for given comparison");
628 }
629 }
630
631 break;
632 }
633
634 case field::type::hierarchal_join:
635 {
636 switch (filterType)
637 {
638 case comparison::hierarchally_matches:
639 case comparison::does_not_hierarchally_match:
640 {
641 new(&singleton_.filterField) field(std::move(joinOn));
642 singleton_.filterType = filterType;
643 new(&singleton_.join) std::unique_ptr<filter>(new filter(joinCondition.normalize(singleton_.filterField.getObject())));
644
645 break;
646 }
647
648 case comparison::int_equals:
649 case comparison::int_does_not_equal:
650 case comparison::int_is_at_least:
651 case comparison::int_is_greater_than:
652 case comparison::int_is_at_most:
653 case comparison::int_is_less_than:
654 case comparison::boolean_equals:
655 case comparison::string_equals:
656 case comparison::string_does_not_equal:
657 case comparison::string_is_like:
658 case comparison::string_is_not_like:
659 case comparison::is_null:
660 case comparison::is_not_null:
661 case comparison::matches:
662 case comparison::does_not_match:
663 {
664 throw std::invalid_argument("Incorrect constructor for given comparison");
665 }
666 }
667
668 break;
669 }
670
671 case field::type::undefined:
672 case field::type::string:
673 case field::type::integer:
674 case field::type::boolean:
675 {
676 throw std::domain_error("Matching field must be a join field");
677 }
678 }
679 }
680
681 field filter::getField() const
682 {
683 if (type_ == type::singleton)
684 {
685 return singleton_.filterField;
686 } else {
687 throw std::domain_error("This filter does not have a field");
688 }
689 }
690
691 filter::comparison filter::getComparison() const
692 {
693 if (type_ == type::singleton)
694 {
695 return singleton_.filterType;
696 } else {
697 throw std::domain_error("This filter does not have a comparison");
698 }
699 }
700
701 filter filter::getJoinCondition() const
702 {
703 if (type_ == type::singleton)
704 {
705 switch (singleton_.filterType)
706 {
707 case comparison::matches:
708 case comparison::does_not_match:
709 case comparison::hierarchally_matches:
710 case comparison::does_not_hierarchally_match:
711 {
712 return *singleton_.join;
713 }
714
715 case comparison::string_equals:
716 case comparison::string_does_not_equal:
717 case comparison::string_is_like:
718 case comparison::string_is_not_like:
719 case comparison::int_equals:
720 case comparison::int_does_not_equal:
721 case comparison::int_is_at_least:
722 case comparison::int_is_greater_than:
723 case comparison::int_is_at_most:
724 case comparison::int_is_less_than:
725 case comparison::boolean_equals:
726 case comparison::is_null:
727 case comparison::is_not_null:
728 {
729 throw std::domain_error("This filter does not have a join condition");
730 }
731 }
732 } else {
733 throw std::domain_error("This filter does not have a join condition");
734 }
735 }
736
737 std::string filter::getStringArgument() const
738 {
739 if (type_ == type::singleton)
740 {
741 switch (singleton_.filterType)
742 {
743 case comparison::string_equals:
744 case comparison::string_does_not_equal:
745 case comparison::string_is_like:
746 case comparison::string_is_not_like:
747 {
748 return singleton_.stringValue;
749 }
750
751 case comparison::int_equals:
752 case comparison::int_does_not_equal:
753 case comparison::int_is_at_least:
754 case comparison::int_is_greater_than:
755 case comparison::int_is_at_most:
756 case comparison::int_is_less_than:
757 case comparison::boolean_equals:
758 case comparison::is_null:
759 case comparison::is_not_null:
760 case comparison::matches:
761 case comparison::does_not_match:
762 case comparison::hierarchally_matches:
763 case comparison::does_not_hierarchally_match:
764 {
765 throw std::domain_error("This filter does not have a string argument");
766 }
767 }
768 } else {
769 throw std::domain_error("This filter does not have a string argument");
770 }
771 }
772
773 int filter::getIntegerArgument() const
774 {
775 if (type_ == type::singleton)
776 {
777 switch (singleton_.filterType)
778 {
779 case comparison::int_equals:
780 case comparison::int_does_not_equal:
781 case comparison::int_is_at_least:
782 case comparison::int_is_greater_than:
783 case comparison::int_is_at_most:
784 case comparison::int_is_less_than:
785 {
786 return singleton_.intValue;
787 }
788
789 case comparison::string_equals:
790 case comparison::string_does_not_equal:
791 case comparison::string_is_like:
792 case comparison::string_is_not_like:
793 case comparison::boolean_equals:
794 case comparison::is_null:
795 case comparison::is_not_null:
796 case comparison::matches:
797 case comparison::does_not_match:
798 case comparison::hierarchally_matches:
799 case comparison::does_not_hierarchally_match:
800 {
801 throw std::domain_error("This filter does not have an integer argument");
802 }
803 }
804 } else {
805 throw std::domain_error("This filter does not have an integer argument");
806 }
807 }
808
809 bool filter::getBooleanArgument() const
810 {
811 if ((type_ == type::singleton) && (singleton_.filterType == comparison::boolean_equals))
812 {
813 return singleton_.boolValue;
814 } else {
815 throw std::domain_error("This filter does not have a boolean argument");
816 }
817 }
818
819 filter::filter(bool orlogic) : type_(type::group)
820 {
821 new(&group_.children) std::list<filter>();
822 group_.orlogic = orlogic;
823 }
824
825 bool filter::getOrlogic() const
826 {
827 if (type_ == type::group)
828 {
829 return group_.orlogic;
830 } else {
831 throw std::domain_error("This filter is not a group filter");
832 }
833 }
834
835 filter filter::operator+(filter condition) const
836 {
837 filter result(*this);
838 result += std::move(condition);
839
840 return result;
841 }
842
843 filter& filter::operator+=(filter condition)
844 {
845 if (type_ == type::group)
846 {
847 group_.children.push_back(std::move(condition));
848
849 return *this;
850 } else {
851 throw std::domain_error("Children can only be added to group filters");
852 }
853 }
854
855 filter::const_iterator filter::begin() const
856 {
857 if (type_ == type::group)
858 {
859 return std::begin(group_.children);
860 } else {
861 throw std::domain_error("This filter has no children");
862 }
863 }
864
865 filter::const_iterator filter::end() const
866 {
867 if (type_ == type::group)
868 {
869 return std::end(group_.children);
870 } else {
871 throw std::domain_error("This filter has no children");
872 }
873 }
874
875 filter filter::operator!() const
876 {
877 switch (type_)
878 {
879 case type::empty:
880 {
881 return {};
882 }
883
884 case type::singleton:
885 {
886 switch (singleton_.filterType)
887 {
888 case comparison::int_equals:
889 {
890 return filter(singleton_.filterField, comparison::int_does_not_equal, singleton_.intValue);
891 }
892
893 case comparison::int_does_not_equal:
894 {
895 return filter(singleton_.filterField, comparison::int_equals, singleton_.intValue);
896 }
897
898 case comparison::int_is_at_least:
899 {
900 return filter(singleton_.filterField, comparison::int_is_less_than, singleton_.intValue);
901 }
902
903 case comparison::int_is_greater_than:
904 {
905 return filter(singleton_.filterField, comparison::int_is_at_most, singleton_.intValue);
906 }
907
908 case comparison::int_is_at_most:
909 {
910 return filter(singleton_.filterField, comparison::int_is_greater_than, singleton_.intValue);
911 }
912
913 case comparison::int_is_less_than:
914 {
915 return filter(singleton_.filterField, comparison::int_is_at_least, singleton_.intValue);
916 }
917
918 case comparison::boolean_equals:
919 {
920 return filter(singleton_.filterField, comparison::boolean_equals, !singleton_.boolValue);
921 }
922
923 case comparison::string_equals:
924 {
925 return filter(singleton_.filterField, comparison::string_does_not_equal, singleton_.stringValue);
926 }
927
928 case comparison::string_does_not_equal:
929 {
930 return filter(singleton_.filterField, comparison::string_equals, singleton_.stringValue);
931 }
932
933 case comparison::string_is_like:
934 {
935 return filter(singleton_.filterField, comparison::string_is_not_like, singleton_.stringValue);
936 }
937
938 case comparison::string_is_not_like:
939 {
940 return filter(singleton_.filterField, comparison::string_is_like, singleton_.stringValue);
941 }
942
943 case comparison::is_null:
944 {
945 return filter(singleton_.filterField, comparison::is_not_null);
946 }
947
948 case comparison::is_not_null:
949 {
950 return filter(singleton_.filterField, comparison::is_null);
951 }
952
953 case comparison::matches:
954 {
955 return filter(singleton_.filterField, comparison::does_not_match, *singleton_.join);
956 }
957
958 case comparison::does_not_match:
959 {
960 return filter(singleton_.filterField, comparison::matches, *singleton_.join);
961 }
962
963 case comparison::hierarchally_matches:
964 {
965 return filter(singleton_.filterField, comparison::does_not_hierarchally_match, *singleton_.join);
966 }
967
968 case comparison::does_not_hierarchally_match:
969 {
970 return filter(singleton_.filterField, comparison::hierarchally_matches, *singleton_.join);
971 }
972 }
973 }
974
975 case type::group:
976 {
977 filter result(!group_.orlogic);
978
979 for (const filter& child : group_.children)
980 {
981 result += !child;
982 }
983
984 return result;
985 }
986 }
987 }
988
989 filter& filter::operator&=(filter condition)
990 {
991 return (*this = (*this && std::move(condition)));
992 }
993
994 filter& filter::operator|=(filter condition)
995 {
996 return (*this = (*this || std::move(condition)));
997 }
998
999 filter filter::operator&&(filter condition) const
1000 {
1001 switch (type_)
1002 {
1003 case type::empty:
1004 {
1005 return condition;
1006 }
1007
1008 case type::singleton:
1009 {
1010 filter result(false);
1011 result.group_.children.push_back(*this);
1012 result.group_.children.push_back(std::move(condition));
1013
1014 return result;
1015 }
1016
1017 case type::group:
1018 {
1019 if (group_.orlogic)
1020 {
1021 filter result(false);
1022 result.group_.children.push_back(*this);
1023 result.group_.children.push_back(std::move(condition));
1024
1025 return result;
1026 } else {
1027 filter result(*this);
1028 result.group_.children.push_back(std::move(condition));
1029
1030 return result;
1031 }
1032 }
1033 }
1034 }
1035
1036 filter filter::operator||(filter condition) const
1037 {
1038 switch (type_)
1039 {
1040 case type::empty:
1041 {
1042 return condition;
1043 }
1044
1045 case type::singleton:
1046 {
1047 filter result(true);
1048 result.group_.children.push_back(*this);
1049 result.group_.children.push_back(std::move(condition));
1050
1051 return result;
1052 }
1053
1054 case type::group:
1055 {
1056 if (!group_.orlogic)
1057 {
1058 filter result(true);
1059 result.group_.children.push_back(*this);
1060 result.group_.children.push_back(std::move(condition));
1061
1062 return result;
1063 } else {
1064 filter result(*this);
1065 result.group_.children.push_back(std::move(condition));
1066
1067 return result;
1068 }
1069 }
1070 }
1071 }
1072
1073 filter filter::normalize(object context) const
1074 {
1075 {
1076 switch (type_)
1077 {
1078 case type::empty:
1079 {
1080 return *this;
1081 }
1082
1083 case type::singleton:
1084 {
1085 // First, switch on the normalized context, and then switch on the
1086 // current context. We recursively recontextualize by using the
1087 // current filter as a subquery for a join such that the context of
1088 // the subquery is one step closer to the context of the current
1089 // filter, and then letting the filter constructor normalize the
1090 // subquery.
1091 switch (context)
1092 {
1093 case object::undefined:
1094 {
1095 // An undefined object indicates no participation in
1096 // recontexualization.
1097 return *this;
1098 }
1099
1100 case object::notion:
1101 {
1102 switch (singleton_.filterField.getObject())
1103 {
1104 case object::undefined:
1105 case object::notion:
1106 {
1107 return *this;
1108 }
1109
1110 case object::word:
1111 case object::group:
1112 case object::frame:
1113 case object::lemma:
1114 case object::form:
1115 case object::pronunciation:
1116 {
1117 return (verbly::notion::word %= *this);
1118 }
1119 }
1120 }
1121
1122 case object::word:
1123 {
1124 switch (singleton_.filterField.getObject())
1125 {
1126 case object::notion:
1127 {
1128 return (verbly::word::notion %= *this);
1129 }
1130
1131 case object::undefined:
1132 case object::word:
1133 {
1134 return *this;
1135 }
1136
1137 case object::group:
1138 case object::frame:
1139 {
1140 return (verbly::word::group %= *this);
1141 }
1142
1143 case object::lemma:
1144 case object::form:
1145 case object::pronunciation:
1146 {
1147 return (verbly::word::lemma %= *this);
1148 }
1149 }
1150
1151 case object::group:
1152 {
1153 switch (singleton_.filterField.getObject())
1154 {
1155 case object::undefined:
1156 case object::group:
1157 {
1158 return *this;
1159 }
1160
1161 case object::notion:
1162 case object::word:
1163 case object::lemma:
1164 case object::form:
1165 case object::pronunciation:
1166 {
1167 return (verbly::group::word %= *this);
1168 }
1169
1170 case object::frame:
1171 {
1172 return (verbly::group::frame %= *this);
1173 }
1174 }
1175 }
1176
1177 case object::frame:
1178 {
1179 switch (singleton_.filterField.getObject())
1180 {
1181 case object::undefined:
1182 case object::frame:
1183 {
1184 return *this;
1185 }
1186
1187 case object::notion:
1188 case object::word:
1189 case object::group:
1190 case object::lemma:
1191 case object::form:
1192 case object::pronunciation:
1193 {
1194 return (verbly::frame::group %= *this);
1195 }
1196 }
1197 }
1198
1199 case object::lemma:
1200 {
1201 switch (singleton_.filterField.getObject())
1202 {
1203 case object::notion:
1204 case object::word:
1205 case object::group:
1206 case object::frame:
1207 {
1208 return verbly::lemma::word %= *this;
1209 }
1210
1211 case object::undefined:
1212 case object::lemma:
1213 {
1214 return *this;
1215 }
1216
1217 case object::form:
1218 case object::pronunciation:
1219 {
1220 return (verbly::lemma::form(inflection::base) %= *this);
1221 }
1222 }
1223 }
1224
1225 case object::form:
1226 {
1227 switch (singleton_.filterField.getObject())
1228 {
1229 case object::notion:
1230 case object::word:
1231 case object::group:
1232 case object::frame:
1233 case object::lemma:
1234 {
1235 return verbly::form::lemma(inflection::base) %= *this;
1236 }
1237
1238 case object::undefined:
1239 case object::form:
1240 {
1241 return *this;
1242 }
1243
1244 case object::pronunciation:
1245 {
1246 return (verbly::form::pronunciation %= *this);
1247 }
1248 }
1249 }
1250
1251 case object::pronunciation:
1252 {
1253 switch (singleton_.filterField.getObject())
1254 {
1255 case object::notion:
1256 case object::word:
1257 case object::group:
1258 case object::frame:
1259 case object::lemma:
1260 case object::form:
1261 {
1262 return verbly::pronunciation::form %= *this;
1263 }
1264
1265 case object::undefined:
1266 case object::pronunciation:
1267 {
1268 return *this;
1269 }
1270 }
1271 }
1272 }
1273 }
1274 }
1275
1276 case type::group:
1277 {
1278 filter result(group_.orlogic);
1279 std::map<field, filter> joins;
1280
1281 for (const filter& child : group_.children)
1282 {
1283 filter normalized = child.normalize(context);
1284
1285 // Notably, this does not attempt to merge hierarchal matches.
1286 switch (normalized.getType())
1287 {
1288 case type::singleton:
1289 {
1290 switch (normalized.getComparison())
1291 {
1292 case comparison::matches:
1293 {
1294 if (!joins.count(normalized.singleton_.filterField))
1295 {
1296 joins[normalized.getField()] = filter(group_.orlogic);
1297 }
1298
1299 joins.at(normalized.getField()) += std::move(*normalized.singleton_.join);
1300
1301 break;
1302 }
1303
1304 case comparison::does_not_match:
1305 {
1306 if (!joins.count(normalized.singleton_.filterField))
1307 {
1308 joins[normalized.getField()] = filter(group_.orlogic);
1309 }
1310
1311 joins.at(normalized.getField()) += !*normalized.singleton_.join;
1312
1313 break;
1314 }
1315
1316 case comparison::int_equals:
1317 case comparison::int_does_not_equal:
1318 case comparison::int_is_at_least:
1319 case comparison::int_is_greater_than:
1320 case comparison::int_is_at_most:
1321 case comparison::int_is_less_than:
1322 case comparison::boolean_equals:
1323 case comparison::string_equals:
1324 case comparison::string_does_not_equal:
1325 case comparison::string_is_like:
1326 case comparison::string_is_not_like:
1327 case comparison::is_null:
1328 case comparison::is_not_null:
1329 case comparison::hierarchally_matches:
1330 case comparison::does_not_hierarchally_match:
1331 {
1332 result += std::move(normalized);
1333
1334 break;
1335 }
1336 }
1337
1338 break;
1339 }
1340
1341 case type::group:
1342 case type::empty:
1343 {
1344 result += std::move(normalized);
1345
1346 break;
1347 }
1348 }
1349 }
1350
1351 for (auto& mapping : joins)
1352 {
1353 const field& joinOn = mapping.first;
1354 filter& joinCondition = mapping.second;
1355
1356 result += (joinOn %= joinCondition.normalize(joinOn.getJoinObject()));
1357 }
1358
1359 return result;
1360 }
1361 }
1362 }
1363 }
1364
1365};