Line data Source code
1 : /* Copyright 2017 noseglasses <shinynoseglasses@gmail.com>
2 : *
3 : * This program is free software: you can redistribute it and/or modify
4 : * it under the terms of the GNU Lesser General Public License as published by
5 : * the Free Software Foundation, either version 3 of the License, or
6 : * (at your option) any later version.
7 : *
8 : * This program is distributed in the hope that it will be useful,
9 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 : * GNU Lesser General Public License for more details.
12 : *
13 : * You should have received a copy of the GNU Lesser General Public License
14 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 : */
16 :
17 : #include "detail/ppg_pattern_detail.h"
18 : #include "detail/ppg_token_detail.h"
19 : #include "detail/ppg_context_detail.h"
20 : #include "ppg_debug.h"
21 : #include "ppg_action.h"
22 :
23 869 : PPG_Token ppg_pattern_from_list(
24 : PPG_Token__ *parent_token,
25 : PPG_Layer layer,
26 : PPG_Count n_tokens,
27 : PPG_Token__ *tokens[])
28 : {
29 869 : if(!parent_token) {
30 860 : parent_token = ppg_context->pattern_root;
31 : }
32 :
33 869 : PPG_LOG("\troot: %p\n", parent_token);
34 :
35 869 : PPG_LOG("\t%d memb\n", n_tokens);
36 :
37 4243 : for (PPG_Count i = 0; i < n_tokens; i++) {
38 :
39 3374 : if(tokens[i] == NULL) {
40 : // Ignore empty members. This is helpful
41 : // when an additional NULL ptr needs to be added
42 : // in generation macros.
43 : }
44 :
45 3374 : PPG_Token__ *cur_token = tokens[i];
46 :
47 3374 : PPG_Token__ *equivalent_child
48 : = ppg_token_get_equivalent_child(parent_token, cur_token);
49 :
50 3374 : PPG_LOG("\tmemb %d: ", i);
51 :
52 3374 : if(equivalent_child == cur_token) {
53 :
54 2052 : PPG_LOG("identical t: 0x%" PRIXPTR "\n", (uintptr_t)equivalent_child);
55 :
56 2052 : parent_token = equivalent_child;
57 : }
58 1322 : else if( equivalent_child
59 :
60 : /* Only share interior nodes and ...
61 : */
62 42 : && equivalent_child->children
63 :
64 : /* ... only if the
65 : * newly registered node on the respective level is
66 : * not a leaf node.
67 : */
68 36 : && (i < (n_tokens - 1))
69 :
70 : // And only if the actions associated with both nodes are equal
71 : //
72 72 : && (cur_token->action.callback.func
73 36 : == equivalent_child->action.callback.func)
74 :
75 72 : && (cur_token->action.callback.user_data
76 36 : == equivalent_child->action.callback.user_data)
77 : ) {
78 :
79 36 : PPG_LOG("alrd prsntt: 0x%" PRIXPTR "\n", (uintptr_t)equivalent_child);
80 :
81 36 : parent_token = equivalent_child;
82 :
83 36 : if(layer < equivalent_child->layer) {
84 :
85 0 : equivalent_child->layer = layer;
86 : }
87 :
88 : /* The child is already registered in the search tree. Delete the newly created version.
89 : */
90 36 : ppg_token_free(cur_token);
91 : }
92 : else {
93 :
94 1286 : PPG_LOG("new def: 0x%" PRIXPTR "\n", (uintptr_t)cur_token);
95 :
96 1286 : PPG_LOG(" act. clbk. 0x%" PRIXPTR "\n", (uintptr_t)cur_token->action.callback.func);
97 1286 : PPG_LOG(" act. u.d. 0x%" PRIXPTR "\n", (uintptr_t)cur_token->action.callback.user_data);
98 :
99 : #if PPG_HAVE_ASSERTIONS
100 :
101 : /* Detect pattern ambiguities
102 : */
103 1286 : if(equivalent_child) {
104 6 : if(
105 : /* Melodies are ambiguous if ...
106 : * the conflicting nodes/tokens are both leaf tokens
107 : */
108 6 : (i == (n_tokens - 1))
109 6 : && !equivalent_child->children
110 :
111 : /* And defined for the same layer
112 : */
113 6 : && (equivalent_child->layer == layer)
114 : ) {
115 : // Conflicting melodies detected
116 : //
117 0 : PPG_ERROR("Conf mel det.\n")
118 :
119 : #if PPG_PRINT_SELF_ENABLED
120 0 : PPG_ERROR(
121 : "Tk of conf. patt:\n");
122 :
123 0 : PPG_ERROR("Prev def:\n");
124 :
125 0 : PPG_PRINT_TOKEN(equivalent_child)
126 :
127 0 : PPG_ERROR("Confl:\n");
128 0 : for (PPG_Count i = 0; i < n_tokens; i++) {
129 0 : PPG_PRINT_TOKEN(tokens[i])
130 : }
131 : #endif
132 : }
133 : }
134 : #endif /* if PPG_HAVE_LOGGING */
135 :
136 1286 : cur_token->layer = layer;
137 :
138 : // printf("Adding %p to %p\n", cur_token, parent_token);
139 1286 : ppg_token_add_child(parent_token, cur_token);
140 :
141 1286 : parent_token = cur_token;
142 : }
143 : }
144 :
145 : /* Return the leaf token
146 : */
147 869 : return parent_token;
148 : }
149 :
150 1318 : PPG_Count ppg_branch_depth(PPG_Token__ *token)
151 : {
152 1318 : if(!token) { return 0; }
153 :
154 1318 : PPG_Count max_depth = 0;
155 :
156 2604 : for(PPG_Count i = 0; i < token->n_children; ++i) {
157 :
158 1286 : PPG_Count cur_depth =
159 1286 : ppg_branch_depth(token->children[i]);
160 :
161 1286 : if(cur_depth > max_depth) {
162 461 : max_depth = cur_depth;
163 : }
164 : }
165 :
166 1318 : return 1 + max_depth;
167 : }
168 :
169 32 : PPG_Count ppg_pattern_tree_depth(void)
170 : {
171 32 : return ppg_branch_depth(ppg_context->pattern_root);
172 : }
|