comparison lwlib/lw_expr.c @ 337:3b5a45c6ab92

Speed improvement to lw_expr Instead of using a singly linked list and doing the slow append algorithm when adding an operand to an expression (scan from the start to find the end), now maintain a tail pointer. Also maintain a previous pointer in each entry. Benchmarking suggests this yields a rougly 30% improvement in runtime. Also refactor some of the code in lw_expr.c to make it somewhat clearer to understand. For some values of clearer and understand.
author William Astle <lost@l-w.ca>
date Sat, 02 Aug 2014 10:08:01 -0600
parents 623b62ab774b
children 6138e304ab9a
comparison
equal deleted inserted replaced
336:30b2bad9b5eb 337:3b5a45c6ab92
103 { 103 {
104 lw_expr_t r; 104 lw_expr_t r;
105 105
106 r = lw_alloc(sizeof(struct lw_expr_priv)); 106 r = lw_alloc(sizeof(struct lw_expr_priv));
107 r -> operands = NULL; 107 r -> operands = NULL;
108 r -> operand_tail = NULL;
108 r -> value2 = NULL; 109 r -> value2 = NULL;
109 r -> type = lw_expr_type_int; 110 r -> type = lw_expr_type_int;
110 r -> value = 0; 111 r -> value = 0;
111 return r; 112 return r;
112 } 113 }
113 114
115 static lw_expr_t lw_expr_remove_operand(lw_expr_t E, struct lw_expr_opers *o)
116 {
117 lw_expr_t r;
118 if (E -> operands == o)
119 E -> operands = o -> next;
120 else
121 o -> prev -> next = o -> next;
122
123 if (E -> operand_tail == o)
124 E -> operand_tail = o -> prev;
125 else
126 o -> next -> prev = o -> prev;
127
128 r = o -> p;
129 lw_free(o);
130 return r;
131 }
132
133 void lw_expr_destroy(lw_expr_t E);
134 static void lw_expr_remove_operands(lw_expr_t E)
135 {
136 while (E -> operands)
137 lw_expr_destroy(lw_expr_remove_operand(E, E -> operands));
138 }
139
114 void lw_expr_destroy(lw_expr_t E) 140 void lw_expr_destroy(lw_expr_t E)
115 { 141 {
116 struct lw_expr_opers *o;
117 if (!E) 142 if (!E)
118 return; 143 return;
119 while (E -> operands) 144 lw_expr_remove_operands(E);
120 {
121 o = E -> operands;
122 E -> operands = o -> next;
123 lw_expr_destroy(o -> p);
124 lw_free(o);
125 }
126 if (E -> type == lw_expr_type_var) 145 if (E -> type == lw_expr_type_var)
127 lw_free(E -> value2); 146 lw_free(E -> value2);
128 lw_free(E); 147 lw_free(E);
129 } 148 }
130 149
151 return r; 170 return r;
152 } 171 }
153 172
154 void lw_expr_add_operand(lw_expr_t E, lw_expr_t O) 173 void lw_expr_add_operand(lw_expr_t E, lw_expr_t O)
155 { 174 {
156 struct lw_expr_opers *o, *t; 175 struct lw_expr_opers *o;
157 176
158 o = lw_alloc(sizeof(struct lw_expr_opers)); 177 o = lw_alloc(sizeof(struct lw_expr_opers));
159 o -> p = lw_expr_copy(O); 178 o -> p = lw_expr_copy(O);
160 o -> next = NULL; 179 o -> next = NULL;
161 for (t = E -> operands; t && t -> next; t = t -> next) 180 o -> prev = E -> operand_tail;
162 /* do nothing */ ; 181
163 182 if (E -> operands)
164 if (t) 183 E -> operand_tail -> next = o;
165 t -> next = o;
166 else 184 else
167 E -> operands = o; 185 E -> operands = o;
186 E -> operand_tail = o;
168 } 187 }
169 188
170 lw_expr_t lw_expr_build_aux(int exprtype, va_list args) 189 lw_expr_t lw_expr_build_aux(int exprtype, va_list args)
171 { 190 {
172 lw_expr_t r; 191 lw_expr_t r;
420 { 439 {
421 if (o -> p -> type == lw_expr_type_oper && (o -> p -> value == lw_expr_oper_times || o -> p -> value == lw_expr_oper_plus)) 440 if (o -> p -> type == lw_expr_type_oper && (o -> p -> value == lw_expr_oper_times || o -> p -> value == lw_expr_oper_plus))
422 lw_expr_simplify_sortconstfirst(o -> p); 441 lw_expr_simplify_sortconstfirst(o -> p);
423 } 442 }
424 443
425 for (o = E -> operands; o; o = o -> next) 444 for (o = E -> operands; o; )
426 { 445 {
446 struct lw_expr_opers *o2;
447 o2 = o -> next;
427 if (o -> p -> type == lw_expr_type_int && o != E -> operands) 448 if (o -> p -> type == lw_expr_type_int && o != E -> operands)
428 { 449 {
429 struct lw_expr_opers *o2; 450 // because o cannot be the first operand, we don't have to
430 for (o2 = E -> operands; o2 -> next != o; o2 = o2 -> next) 451 // handle the single element list here
431 /* do nothing */ ; 452 o2 = o -> next;
432 o2 -> next = o -> next; 453 if (E -> operand_tail == o)
454 E -> operand_tail = o -> prev;
455 o -> prev -> next = o -> next;
456 if (o -> next)
457 o -> next -> prev = o -> prev;
458 E -> operands -> prev = o;
433 o -> next = E -> operands; 459 o -> next = E -> operands;
460 o -> prev = NULL;
434 E -> operands = o; 461 E -> operands = o;
435 o = o2; 462 E -> operands = o;
436 } 463 }
464 o = o2;
437 } 465 }
438 } 466 }
439 467
440 void lw_expr_sortoperandlist(struct lw_expr_opers **o) 468 void lw_expr_sortoperandlist(struct lw_expr_opers **o)
441 { 469 {
583 lw_expr_destroy(o -> p); 611 lw_expr_destroy(o -> p);
584 if (E -> type == lw_expr_type_var) 612 if (E -> type == lw_expr_type_var)
585 lw_free(E -> value2); 613 lw_free(E -> value2);
586 *E = *te; 614 *E = *te;
587 E -> operands = NULL; 615 E -> operands = NULL;
588 616 E -> operand_tail = NULL;
617
589 if (te -> type == lw_expr_type_var) 618 if (te -> type == lw_expr_type_var)
590 E -> value2 = lw_strdup(te -> value2); 619 E -> value2 = lw_strdup(te -> value2);
591 for (o = te -> operands; o; o = o -> next) 620 for (o = te -> operands; o; o = o -> next)
592 { 621 {
593 lw_expr_t xxx; 622 lw_expr_t xxx;
614 lw_expr_destroy(o -> p); 643 lw_expr_destroy(o -> p);
615 if (E -> type == lw_expr_type_var) 644 if (E -> type == lw_expr_type_var)
616 lw_free(E -> value2); 645 lw_free(E -> value2);
617 *E = *te; 646 *E = *te;
618 E -> operands = NULL; 647 E -> operands = NULL;
648 E -> operand_tail = NULL;
619 649
620 if (te -> type == lw_expr_type_var) 650 if (te -> type == lw_expr_type_var)
621 E -> value2 = lw_strdup(te -> value2); 651 E -> value2 = lw_strdup(te -> value2);
622 for (o = te -> operands; o; o = o -> next) 652 for (o = te -> operands; o; o = o -> next)
623 { 653 {
639 tryagainplus: 669 tryagainplus:
640 for (o = E -> operands; o; o = o -> next) 670 for (o = E -> operands; o; o = o -> next)
641 { 671 {
642 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_plus) 672 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_plus)
643 { 673 {
644 struct lw_expr_opers *o2; 674 if (o -> p -> operands)
645 // we have a + operation - bring operands up 675 {
646 676 if (E -> operands == NULL)
647 for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next) 677 {
648 /* do nothing */ ; 678 E -> operands = o -> p -> operands;
649 if (o2) 679 E -> operand_tail = o -> p -> operand_tail;
650 o2 -> next = o -> p -> operands; 680 }
651 else 681 else
652 E -> operands = o -> p -> operands; 682 {
653 for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next) 683 E -> operand_tail -> next = o -> p -> operands;
654 /* do nothing */ ; 684 o -> p -> operands -> prev = E -> operand_tail;
655 o2 -> next = o -> next; 685 E -> operand_tail = o -> p -> operand_tail;
686 }
687 o -> p -> operands = NULL;
688 o -> p -> operand_tail = NULL;
689 }
656 o -> p -> operands = NULL; 690 o -> p -> operands = NULL;
657 lw_expr_destroy(o -> p); 691 lw_expr_destroy(o -> p);
692 if (o -> prev)
693 o -> prev -> next = o -> next;
694 else
695 E -> operands = o -> next;
696 if (o -> next)
697 o -> next -> prev = o -> prev;
698 else
699 E -> operand_tail = o -> prev;
658 lw_free(o); 700 lw_free(o);
659 goto tryagainplus; 701 goto tryagainplus;
660 } 702 }
661 } 703 }
662 } 704 }
667 tryagaintimes: 709 tryagaintimes:
668 for (o = E -> operands; o; o = o -> next) 710 for (o = E -> operands; o; o = o -> next)
669 { 711 {
670 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times) 712 if (o -> p -> type == lw_expr_type_oper && o -> p -> value == lw_expr_oper_times)
671 { 713 {
672 struct lw_expr_opers *o2; 714 if (o -> p -> operands)
673 // we have a + operation - bring operands up 715 {
674 716 if (E -> operands == NULL)
675 for (o2 = E -> operands; o2 && o2 -> next != o; o2 = o2 -> next) 717 {
676 /* do nothing */ ; 718 E -> operands = o -> p -> operands;
677 if (o2) 719 E -> operand_tail = o -> p -> operand_tail;
678 o2 -> next = o -> p -> operands; 720 }
679 else 721 else
680 E -> operands = o -> p -> operands; 722 {
681 for (o2 = o -> p -> operands; o2 -> next; o2 = o2 -> next) 723 E -> operand_tail -> next = o -> p -> operands;
682 /* do nothing */ ; 724 o -> p -> operands -> prev = E -> operand_tail;
683 o2 -> next = o -> next; 725 E -> operand_tail = o -> p -> operand_tail;
726 }
727 o -> p -> operands = NULL;
728 o -> p -> operand_tail = NULL;
729 }
684 o -> p -> operands = NULL; 730 o -> p -> operands = NULL;
685 lw_expr_destroy(o -> p); 731 lw_expr_destroy(o -> p);
732 if (o -> prev)
733 o -> prev -> next = o -> next;
734 else
735 E -> operands = o -> next;
736 if (o -> next)
737 o -> next -> prev = o -> prev;
738 else
739 E -> operand_tail = o -> prev;
686 lw_free(o); 740 lw_free(o);
687 goto tryagaintimes; 741 goto tryagaintimes;
688 } 742 }
689 } 743 }
690 } 744 }
783 tr = E -> operands -> p -> value || E -> operands -> next -> p -> value; 837 tr = E -> operands -> p -> value || E -> operands -> next -> p -> value;
784 break; 838 break;
785 839
786 } 840 }
787 841
788 while (E -> operands) 842 lw_expr_remove_operands(E);
789 {
790 o = E -> operands;
791 E -> operands = o -> next;
792 lw_expr_destroy(o -> p);
793 lw_free(o);
794 }
795 E -> type = lw_expr_type_int; 843 E -> type = lw_expr_type_int;
796 E -> value = tr; 844 E -> value = tr;
797 return; 845 return;
798 } 846 }
799 847
802 lw_expr_t e1; 850 lw_expr_t e1;
803 int cval = 0; 851 int cval = 0;
804 852
805 e1 = lw_expr_create(); 853 e1 = lw_expr_create();
806 e1 -> operands = E -> operands; 854 e1 -> operands = E -> operands;
855 e1 -> operand_tail = E -> operand_tail;
807 E -> operands = 0; 856 E -> operands = 0;
857 E -> operand_tail = NULL;
808 858
809 for (o = e1 -> operands; o; o = o -> next) 859 for (o = e1 -> operands; o; o = o -> next)
810 { 860 {
811 if (o -> p -> type == lw_expr_type_int) 861 if (o -> p -> type == lw_expr_type_int)
812 cval += o -> p -> value; 862 cval += o -> p -> value;
827 lw_expr_t e1; 877 lw_expr_t e1;
828 int cval = 1; 878 int cval = 1;
829 879
830 e1 = lw_expr_create(); 880 e1 = lw_expr_create();
831 e1 -> operands = E -> operands; 881 e1 -> operands = E -> operands;
882 e1 -> operand_tail = E -> operand_tail;
832 E -> operands = 0; 883 E -> operands = 0;
884 E -> operand_tail = NULL;
833 885
834 for (o = e1 -> operands; o; o = o -> next) 886 for (o = e1 -> operands; o; o = o -> next)
835 { 887 {
836 if (o -> p -> type == lw_expr_type_int) 888 if (o -> p -> type == lw_expr_type_int)
837 cval *= o -> p -> value; 889 cval *= o -> p -> value;
852 for (o = E -> operands; o; o = o -> next) 904 for (o = E -> operands; o; o = o -> next)
853 { 905 {
854 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) 906 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0)
855 { 907 {
856 // one operand of times is 0, replace operation with 0 908 // one operand of times is 0, replace operation with 0
857 while (E -> operands) 909 lw_expr_remove_operands(E);
858 {
859 o = E -> operands;
860 E -> operands = o -> next;
861 lw_expr_destroy(o -> p);
862 lw_free(o);
863 }
864 E -> type = lw_expr_type_int; 910 E -> type = lw_expr_type_int;
865 E -> value = 0; 911 E -> value = 0;
866 return; 912 return;
867 } 913 }
868 } 914 }
962 o = E -> operands; 1008 o = E -> operands;
963 if (o -> p -> type != lw_expr_type_int || o -> p -> value != 0) 1009 if (o -> p -> type != lw_expr_type_int || o -> p -> value != 0)
964 { 1010 {
965 r = lw_expr_copy(o -> p); 1011 r = lw_expr_copy(o -> p);
966 } 1012 }
967 E -> operands = o -> next; 1013 lw_expr_destroy(lw_expr_remove_operand(E, E -> operands));
968 lw_expr_destroy(o -> p);
969 lw_free(o);
970 } 1014 }
971 *E = *r; 1015 *E = *r;
972 lw_free(r); 1016 lw_free(r);
973 return; 1017 return;
974 } 1018 }
975 else if (c == 0) 1019 else if (c == 0)
976 { 1020 {
977 // replace with 0 1021 // replace with 0
978 while (E -> operands) 1022 lw_expr_remove_operands(E);
979 {
980 o = E -> operands;
981 E -> operands = o -> next;
982 lw_expr_destroy(o -> p);
983 lw_free(o);
984 }
985 E -> type = lw_expr_type_int; 1023 E -> type = lw_expr_type_int;
986 E -> value = 0; 1024 E -> value = 0;
987 return; 1025 return;
988 } 1026 }
989 else if (c != t) 1027 else if (c != t)
990 { 1028 {
991 // collapse out zero terms 1029 // collapse out zero terms
992 struct lw_expr_opers *o2; 1030 struct lw_expr_opers *o2;
993 1031
994 for (o = E -> operands; o; o = o -> next) 1032 for (o = E -> operands; o; o = o2)
995 { 1033 {
1034 o2 = o -> next;
996 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0) 1035 if (o -> p -> type == lw_expr_type_int && o -> p -> value == 0)
997 { 1036 {
998 if (o == E -> operands) 1037 lw_expr_destroy(lw_expr_remove_operand(E, o));
999 {
1000 E -> operands = o -> next;
1001 lw_expr_destroy(o -> p);
1002 lw_free(o);
1003 o = E -> operands;
1004 }
1005 else
1006 {
1007 for (o2 = E -> operands; o2 -> next == o; o2 = o2 -> next)
1008 /* do nothing */ ;
1009 o2 -> next = o -> next;
1010 lw_expr_destroy(o -> p);
1011 lw_free(o);
1012 o = o2;
1013 }
1014 } 1038 }
1015 } 1039 }
1016 } 1040 }
1017 return; 1041 return;
1018 } 1042 }
1033 if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus) 1057 if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus)
1034 { 1058 {
1035 lw_free(E -> operands -> next); 1059 lw_free(E -> operands -> next);
1036 lw_free(E -> operands); 1060 lw_free(E -> operands);
1037 E -> operands = NULL; 1061 E -> operands = NULL;
1062 E -> operand_tail = NULL;
1038 E -> value = lw_expr_oper_plus; 1063 E -> value = lw_expr_oper_plus;
1039 1064
1040 for (o = E2 -> operands; o; o = o -> next) 1065 for (o = E2 -> operands; o; o = o -> next)
1041 { 1066 {
1042 t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p); 1067 t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p);
1043 lw_expr_add_operand(E, t1); 1068 lw_expr_add_operand(E, t1);
1044 lw_expr_destroy(t1); 1069 lw_expr_destroy(t1);
1045 } 1070 }
1046
1047 lw_expr_destroy(E2);
1048 lw_expr_destroy(E3);
1049 } 1071 }
1050 } 1072 }
1051 else if (E -> operands -> next -> p -> type == lw_expr_type_int) 1073 else if (E -> operands -> next -> p -> type == lw_expr_type_int)
1052 { 1074 {
1053 /* <other> TIMES <int> */ 1075 /* <other> TIMES <int> */
1056 if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus) 1078 if (E2 -> type == lw_expr_type_oper && E2 -> value == lw_expr_oper_plus)
1057 { 1079 {
1058 lw_free(E -> operands -> next); 1080 lw_free(E -> operands -> next);
1059 lw_free(E -> operands); 1081 lw_free(E -> operands);
1060 E -> operands = NULL; 1082 E -> operands = NULL;
1083 E -> operand_tail = NULL;
1061 E -> value = lw_expr_oper_plus; 1084 E -> value = lw_expr_oper_plus;
1062 1085
1063 for (o = E2 -> operands; o; o = o -> next) 1086 for (o = E2 -> operands; o; o = o -> next)
1064 { 1087 {
1065 t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p); 1088 t1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_times, E3, o -> p);