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 "ppg_chord.h"
18 : #include "ppg_debug.h"
19 : #include "detail/ppg_context_detail.h"
20 : #include "detail/ppg_aggregate_detail.h"
21 : #include "detail/ppg_pattern_detail.h"
22 : #include "detail/ppg_token_detail.h"
23 : #include "detail/ppg_token_precedence_detail.h"
24 :
25 : typedef PPG_Aggregate PPG_Chord;
26 :
27 336 : static bool ppg_chord_match_event(
28 : PPG_Chord *chord,
29 : PPG_Event *event,
30 : bool modify_only_if_consuming)
31 : {
32 336 : PPG_LOG("Ch. chord\n");
33 :
34 336 : bool input_part_of_chord = false;
35 :
36 336 : PPG_ASSERT(chord->n_members != 0);
37 :
38 : /* Check if the input is part of the current chord
39 : */
40 750 : for(PPG_Count i = 0; i < chord->n_members; ++i) {
41 :
42 700 : if(chord->inputs[i] == event->input) {
43 :
44 286 : input_part_of_chord = true;
45 :
46 286 : if(event->flags & PPG_Event_Active) {
47 145 : if(!ppg_bitfield_get_bit(&chord->member_active, i)) {
48 145 : ppg_bitfield_set_bit(&chord->member_active, i, true);
49 145 : ++chord->n_inputs_active;
50 : }
51 : }
52 : else {
53 :
54 141 : if( ((chord->super.misc.flags & PPG_Aggregate_All_Active) == 0)
55 66 : && (chord->super.misc.flags &
56 : PPG_Chord_Flags_Disallow_Input_Deactivation)) {
57 :
58 0 : if(!modify_only_if_consuming) {
59 0 : chord->super.misc.state = PPG_Token_Invalid;
60 : }
61 :
62 0 : return false;
63 : }
64 :
65 141 : if(ppg_bitfield_get_bit(&chord->member_active, i)) {
66 115 : ppg_bitfield_set_bit(&chord->member_active, i, false);
67 115 : --chord->n_inputs_active;
68 : }
69 : else {
70 :
71 : // The event deactivates an input that
72 : // was not previously registered as active.
73 : // Thus, we conclude that the event must be related
74 : // to a previous match. Ignore the event.
75 : //
76 26 : return false;
77 : }
78 : }
79 260 : break;
80 : }
81 : }
82 :
83 : #if PPG_HAVE_LOGGING
84 1240 : for(PPG_Count i = 0; i < chord->n_members; ++i) {
85 930 : PPG_LOG("%d: 0x%d = %d\n",
86 : i,
87 : chord->inputs[i],
88 : ppg_bitfield_get_bit(&chord->member_active, i)
89 : );
90 : }
91 : #endif
92 :
93 310 : if(!input_part_of_chord) {
94 50 : if(event->flags & PPG_Event_Active) {
95 :
96 44 : if(!modify_only_if_consuming) {
97 44 : chord->super.misc.state = PPG_Token_Invalid;
98 : }
99 : }
100 :
101 : // Chords ignore unmatching deactivation events
102 :
103 50 : return false;
104 : }
105 :
106 260 : chord->super.misc.state = PPG_Token_Activation_In_Progress;
107 :
108 260 : if(chord->n_inputs_active == chord->n_members) {
109 :
110 25 : chord->super.misc.flags |= PPG_Aggregate_All_Active;
111 :
112 : /* Chord matches
113 : */
114 25 : chord->super.misc.state = PPG_Token_Matches;
115 : // PPG_LOG("C");
116 : }
117 235 : else if(chord->n_inputs_active == 0) {
118 :
119 47 : if(chord->super.misc.flags & PPG_Aggregate_All_Active) {
120 :
121 25 : if(chord->super.misc.flags & PPG_Token_Flags_Pedantic) {
122 : /* Chord matches
123 : */
124 0 : chord->super.misc.state = PPG_Token_Matches;
125 : }
126 : else {
127 25 : chord->super.misc.state = PPG_Token_Finalized;
128 : }
129 : }
130 : }
131 : else {
132 188 : if(chord->super.misc.flags & PPG_Aggregate_All_Active) {
133 50 : chord->super.misc.state = PPG_Token_Deactivation_In_Progress;
134 : }
135 : }
136 :
137 260 : return true;
138 : }
139 :
140 142 : static PPG_Count ppg_chord_token_precedence(PPG_Token__ *token)
141 : {
142 : PPG_UNUSED(token);
143 142 : return PPG_Token_Precedence_Chord;
144 : }
145 :
146 12 : static size_t ppg_chord_dynamic_member_size(PPG_Token *token)
147 : {
148 12 : return sizeof(PPG_Chord)
149 12 : + ppg_aggregate_dynamic_member_size((PPG_Aggregate *)token);
150 : }
151 :
152 12 : static char *ppg_chord_placement_clone(PPG_Token__ *token, char *buffer)
153 : {
154 12 : PPG_Chord *chord = (PPG_Chord *)token;
155 :
156 12 : *((PPG_Chord *)buffer) = *chord;
157 :
158 12 : PPG_Token__ *clone = (PPG_Token__ *)buffer;
159 :
160 : // printf("Replacing children pointer %p with %p\n", clone->children, (PPG_Token__ **)(buffer + sizeof(PPG_Chord)));
161 :
162 12 : clone->children = (PPG_Token__ **)(buffer + sizeof(PPG_Chord));
163 :
164 12 : return ppg_aggregate_copy_dynamic_members(token, clone, buffer + sizeof(PPG_Chord));
165 : }
166 :
167 : #if PPG_PRINT_SELF_ENABLED
168 250 : static void ppg_chord_print_self(PPG_Chord *c, PPG_Count indent, bool recurse)
169 : {
170 250 : PPG_I PPG_LOG("<*** chrd (0x%" PRIXPTR ") ***>\n", (uintptr_t)c);
171 250 : ppg_token_print_self_start((PPG_Token__*)c, indent);
172 250 : PPG_I PPG_LOG("\tn mem: %d\n", c->n_members);
173 250 : PPG_I PPG_LOG("\tn I actv: %d\n", c->n_inputs_active);
174 :
175 1000 : for(PPG_Count i = 0; i < c->n_members; ++i) {
176 750 : PPG_I PPG_LOG("\t\tI: 0x%d, actv: %d\n",
177 : c->inputs[i],
178 : ppg_bitfield_get_bit(&c->member_active, i));
179 : }
180 250 : ppg_token_print_self_end((PPG_Token__*)c, indent, recurse);
181 250 : }
182 : #endif
183 :
184 : PPG_Token_Vtable ppg_chord_vtable =
185 : {
186 : .match_event
187 : = (PPG_Token_Match_Event_Fun) ppg_chord_match_event,
188 : .reset
189 : = (PPG_Token_Reset_Fun) ppg_aggregate_reset,
190 : .destroy
191 : = (PPG_Token_Destroy_Fun) ppg_aggregate_destroy,
192 : .equals
193 : = (PPG_Token_Equals_Fun) ppg_aggregates_equal,
194 : .token_precedence
195 : = (PPG_Token_Precedence_Fun)ppg_chord_token_precedence,
196 : .dynamic_size
197 : = (PPG_Token_Dynamic_Size_Requirement_Fun)ppg_chord_dynamic_member_size,
198 : .placement_clone
199 : = (PPG_Token_Placement_Clone_Fun)ppg_chord_placement_clone,
200 : .register_ptrs_for_compression
201 : = (PPG_Token_Register_Pointers_For_Compression)ppg_token_register_pointers_for_compression,
202 : .addresses_to_relative
203 : = (PPG_Token_Addresses_To_Relative)ppg_aggregate_addresses_to_relative,
204 : .addresses_to_absolute
205 : = (PPG_Token_Addresses_To_Absolute)ppg_aggregate_addresses_to_absolute
206 :
207 : #if PPG_PRINT_SELF_ENABLED
208 : ,
209 : .print_self
210 : = (PPG_Token_Print_Self_Fun) ppg_chord_print_self
211 : #endif
212 :
213 : #if PPG_HAVE_DEBUGGING
214 : ,
215 : .check_initialized
216 : = (PPG_Token_Check_Initialized_Fun)ppg_aggregate_check_initialized
217 : #endif
218 : };
219 :
220 20 : PPG_Token ppg_chord_create(
221 : PPG_Count n_inputs,
222 : PPG_Input_Id inputs[])
223 : {
224 20 : PPG_Chord *chord = (PPG_Chord*)ppg_aggregate_new(ppg_aggregate_alloc());
225 :
226 20 : chord->super.vtable = &ppg_chord_vtable;
227 :
228 : // PPG_LOG("in def: 0x%" PRIXPTR "\n", (uintptr_t)ppg_chord_match_event);
229 :
230 20 : return ppg_global_initialize_aggregate(chord, n_inputs, inputs);
231 : }
232 :
233 20 : PPG_Token ppg_chord(
234 : PPG_Layer layer,
235 : PPG_Action action,
236 : PPG_Count n_inputs,
237 : PPG_Input_Id inputs[])
238 : {
239 : // PPG_LOG("Adding chord\n");
240 :
241 20 : PPG_Token__ *token =
242 20 : (PPG_Token__ *)ppg_chord_create(n_inputs, inputs);
243 :
244 20 : token->action = action;
245 :
246 20 : PPG_Token__ *tokens[1] = { token };
247 :
248 20 : PPG_Token__ *leaf_token
249 20 : = ppg_pattern_from_list(NULL, layer, 1, tokens);
250 :
251 20 : return leaf_token;
252 : }
|