LCOV - code coverage report
Current view: top level - src/detail - ppg_active_tokens_detail.c (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 106 123 86.2 %
Date: 2018-01-08 Functions: 11 11 100.0 %

          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_active_tokens_detail.h"
      18             : #include "detail/ppg_token_detail.h"
      19             : #include "detail/ppg_context_detail.h"
      20             : #include "detail/ppg_malloc_detail.h"
      21             : 
      22             : #include "ppg_debug.h"
      23             : 
      24             : #include <assert.h>
      25             : #include <string.h>
      26             : 
      27          50 : void ppg_active_tokens_resize(PPG_Active_Tokens *active_tokens,
      28             :                               PPG_Count new_size)
      29             : {
      30          50 :    PPG_ASSERT(active_tokens);
      31             :    
      32          50 :    if(new_size <= active_tokens->max_tokens) { return; }
      33             :    
      34          50 :    PPG_Token__ **new_tokens
      35          50 :       = (PPG_Token__**)PPG_MALLOC(sizeof(PPG_Token__*)*new_size);
      36             :       
      37          50 :    active_tokens->max_tokens = new_size;
      38             :    
      39          50 :    if(active_tokens->tokens && (active_tokens->n_tokens > 0)) {
      40           0 :       memcpy(new_tokens, active_tokens->tokens, 
      41           0 :              sizeof(PPG_Token__ *)*active_tokens->n_tokens);
      42             :    }
      43             :    
      44          50 :    active_tokens->tokens = new_tokens;
      45             : }
      46             : 
      47          41 : void ppg_active_tokens_init(PPG_Active_Tokens *active_tokens)
      48             : {
      49          41 :    active_tokens->tokens = NULL;
      50          41 :    active_tokens->n_tokens = 0;
      51          41 :    active_tokens->max_tokens = 0;
      52             :    
      53          41 :    ppg_active_tokens_resize(active_tokens, PPG_MAX_ACTIVE_TOKENS);
      54             :    
      55       10496 :    for(size_t i = 0; i < PPG_MAX_ACTIVE_TOKENS; ++i) {
      56       10455 :       active_tokens->tokens[i] = NULL;
      57             :    }
      58          41 : }
      59             : 
      60           9 : void ppg_active_tokens_restore(PPG_Active_Tokens *active_tokens)
      61             : {
      62           9 :    PPG_Count saved_size = active_tokens->max_tokens;
      63             :    
      64           9 :    active_tokens->tokens = NULL;
      65           9 :    active_tokens->max_tokens = 0; // This forces resize 
      66             :    
      67           9 :    ppg_active_tokens_resize(active_tokens, saved_size);
      68           9 : }
      69             : 
      70          41 : void ppg_active_tokens_free(PPG_Active_Tokens *active_tokens)
      71             : {
      72          41 :    if(!active_tokens->tokens) { return; }
      73             :    
      74          41 :    free(active_tokens->tokens);
      75             :    
      76          41 :    active_tokens->tokens = NULL;
      77             : }
      78             : 
      79         235 : static void ppg_active_tokens_add(PPG_Token__ *token)
      80             : {
      81         235 :    PPG_GAT.tokens[PPG_GAT.n_tokens] = token;
      82             :    
      83         235 :    PPG_ASSERT(PPG_GAT.n_tokens < PPG_MAX_ACTIVE_TOKENS);
      84             : 
      85         235 :    ++PPG_GAT.n_tokens;
      86         235 : }
      87             : 
      88         235 : static void ppg_active_tokens_remove(PPG_Count id)
      89             : {
      90         565 :    for(PPG_Count i = id; i < PPG_GAT.n_tokens - 1; ++i) {
      91         330 :       PPG_GAT.tokens[i] = PPG_GAT.tokens[i + 1];
      92             :    }
      93             :    
      94         235 :    --PPG_GAT.n_tokens;
      95         235 : }
      96             : 
      97         241 : static void ppg_active_tokens_search_remove(PPG_Token__ *token)
      98             : {
      99         253 :    for(PPG_Count i = 0; i < PPG_GAT.n_tokens; ++i) {
     100         247 :       if(token == PPG_GAT.tokens[i]) {
     101         235 :          ppg_active_tokens_remove(i);
     102         235 :          break;
     103             :       }
     104             :    }
     105         241 : }
     106             : 
     107         337 : static void ppg_active_tokens_on_deactivation(PPG_Token__ *consumer,
     108             :                                               PPG_Count state,
     109             :                                               bool changed
     110             :                                              )
     111             : {
     112             :    // The event deactivates an input
     113             : 
     114         337 :    if(consumer) {
     115             :       
     116         337 :       if(consumer->misc.flags & PPG_Token_Flags_Pedantic) {
     117             :          
     118           0 :          if(   (state 
     119             :                         == PPG_Token_Matches) 
     120           0 :             && (changed)) {
     121             :                
     122             : //             PPG_LOG("   Cs act & deact\n");
     123             :          
     124           0 :             if(consumer->misc.action_state == PPG_Action_Enabled) {
     125             :                      
     126             : //                PPG_LOG("      T.a.a.\n");
     127             :                      
     128           0 :                consumer->action.callback.func(true /* signal deactivation */,
     129             :                         consumer->action.callback.user_data);
     130             :                
     131           0 :                consumer->misc.action_state = PPG_Action_Activation_Triggered;
     132             :                      
     133           0 :                consumer->action.callback.func(false /* signal deactivation */,
     134             :                         consumer->action.callback.user_data);
     135             :                      
     136           0 :                consumer->misc.action_state = PPG_Action_Deactivation_Triggered;
     137             :             }
     138             :             
     139           0 :             ppg_active_tokens_search_remove(consumer);
     140             :          }
     141             :          
     142           0 :          return;
     143             :       }
     144             :       
     145             :       // It there is a consumer listed, this means that the event was
     146             :       // consumed by one of the tokens of the matching branch
     147             :       
     148         337 :       if(changed) {
     149             :          
     150             :          // Token state just changed...
     151             :          
     152         260 :          if(state 
     153             :                      == PPG_Token_Deactivation_In_Progress) {
     154             :             
     155             : //             PPG_LOG("   C. d.\n");
     156             :          
     157             :             // It turned from state "matching" to state
     158             :             // "deactivation in progress"
     159             :             
     160          25 :             if(consumer->misc.action_flags & PPG_Action_Deactivate_On_Token_Unmatch) {
     161             : 
     162           0 :                if(consumer->misc.action_state == PPG_Action_Enabled) {
     163             :                   
     164             : //                   PPG_LOG("      T.e.a.\n");
     165           0 :                   consumer->action.callback.func(false /* signal deactivation */,
     166             :                      consumer->action.callback.user_data);
     167             :                   
     168           0 :                   consumer->misc.action_state = PPG_Action_Deactivation_Triggered;
     169             :                }
     170             :             }
     171             :          }
     172         235 :          else if(state 
     173             :                            == PPG_Token_Finalized) {
     174             :             
     175             : //             PPG_LOG("   Causes finalization of 0x%" PRIXPTR "\n", (uintptr_t)consumer);
     176             : //             PPG_LOG("Fin\n");
     177             :             // The token just became initialized, i.e. all related inputs were deactivated
     178             :             // again.
     179             :             
     180         235 :             if(   ((consumer->misc.action_flags & PPG_Action_Deactivate_On_Token_Unmatch) == 0)
     181           0 :                || (consumer->misc.action_state != PPG_Action_Deactivation_Triggered)) {
     182             :                
     183         235 :                if(consumer->misc.action_state == PPG_Action_Enabled) {
     184             : //                   PPG_LOG("      T.a.a.\n");
     185           2 :                   consumer->action.callback.func(true /* signal deactivation */,
     186             :                      consumer->action.callback.user_data);
     187             :                   
     188           2 :                   consumer->misc.action_state = PPG_Action_Activation_Triggered;
     189             :                }
     190             :                
     191         235 :                if(consumer->misc.action_state == PPG_Action_Activation_Triggered) {
     192             : //                   PPG_LOG("      T.d.a.\n");
     193          85 :                   consumer->action.callback.func(false /* signal deactivation */,
     194             :                      consumer->action.callback.user_data);
     195             :                   
     196          85 :                   consumer->misc.action_state = PPG_Action_Deactivation_Triggered;
     197             :                }
     198             :             }
     199             :             
     200             :             // Remove it from the active set as no further events will affect it
     201             :             //
     202         235 :             ppg_active_tokens_search_remove(consumer);
     203             :          }
     204             :       }
     205             :    }
     206             : }
     207             : 
     208         890 : bool ppg_active_tokens_check_consumption(
     209             :                                     PPG_Event *event)
     210             : {
     211         890 :    if(PPG_GAT.n_tokens == 0) {
     212         575 :       return false;
     213             :    }
     214             :    
     215             :    // No consumer (token) is listed for the deactivation event. 
     216             :    // This means that the input deactivation that
     217             :    // is represented by the token is related to an input from the
     218             :    // active set that has been registered in one of the previous pattern matching rounds
     219             :    // and whose inputs have not all been deactivated yet. 
     220             :    
     221         315 :    PPG_Token__ *consumer = NULL;
     222         315 :    bool event_consumed = false;
     223             :    PPG_Count i;
     224         315 :    bool state_changed = false;
     225             :    PPG_Count new_state;
     226             :    
     227             :    // Thus, we first have to find it in the active token set.
     228             :    //
     229         654 :    for(i = 0; i < PPG_GAT.n_tokens; ++i) {
     230             :       
     231         327 :       consumer = PPG_GAT.tokens[i];
     232             :       
     233             : //       PPG_LOG("   consumer: 0x%" PRIXPTR "\n", (uintptr_t)consumer);
     234             : //       PPG_LOG("   consumer action state: %d\n", consumer->misc.action_state);
     235             :       
     236         327 :       PPG_Count old_state = consumer->misc.state;
     237             :       
     238         327 :       event_consumed = consumer
     239         327 :                               ->vtable->match_event(  
     240             :                                        consumer, 
     241             :                                        event,
     242             :                                        true /*modify only if consuming*/
     243             :                                  );
     244             :                          
     245         327 :       PPG_PRINT_TOKEN(consumer)
     246             :       
     247         327 :       if(!event_consumed) {
     248          12 :          continue;
     249             :       }
     250             :       
     251         315 :       new_state = consumer->misc.state;
     252             :       
     253         315 :       if(old_state != new_state) {
     254         254 :          state_changed = true;
     255             :       }
     256             :       
     257         315 :       break;
     258             :    }
     259             :    
     260         315 :    if(!event_consumed) {
     261           0 :       return false;
     262             :    }
     263             :    
     264             : //    PPG_LOG("   consumed\n");
     265             : //    PPG_LOG("   new_state: %d\n", new_state);
     266             : //    PPG_LOG("   state_changed: %d\n", state_changed);
     267             : 
     268             :    // The token just became initialized, i.e. all related inputs were deactivated
     269             :    // again.
     270             :    
     271         315 :    if((event->flags & PPG_Event_Active) == 0) {
     272             :       
     273         311 :       ppg_active_tokens_on_deactivation(consumer,
     274             :                                         new_state,
     275             :                                         state_changed);
     276             : 
     277             :    }
     278             :       
     279             :    // One of the tokens from the active set consumed our deactivation event
     280             :    
     281             :    // Mark it, so the user can recognize it as consumed during event 
     282             :    // buffer itearation.
     283             :    //
     284         315 :    event->flags |= PPG_Event_Considered;
     285             :    
     286         315 :    return true;
     287             : }
     288             : 
     289         469 : static void ppg_active_tokens_update_aux(
     290             :                                     PPG_Event_Queue_Entry *eqe,
     291             :                                     void *user_data)
     292             : {
     293             :    PPG_UNUSED(user_data);
     294             :    
     295             : //    PPG_LOG("Event: Input 0x%d, active: %d\n",
     296             : //            eqe->event.input,
     297             : //            eqe->event.flags & PPG_Event_Active);
     298             :    
     299             :    // Check if the event has already been considered 
     300             :    // This is the case for deactivation events that
     301             :    // have been consumed by unfinished tokens of a previous pattern match.
     302             :    //
     303         469 :    if(eqe->event.flags & PPG_Event_Considered) {
     304           0 :       return;
     305             :    }
     306             :       
     307         469 :    if(eqe->consumer) {
     308             : //       PPG_LOG("   consumer: 0x%" PRIXPTR "\n", (uintptr_t)eqe->consumer);
     309             : //       PPG_LOG("   consumer action state: %d\n", eqe->consumer->misc.action_state);
     310         359 :       PPG_PRINT_TOKEN(eqe->consumer)
     311             :    }
     312             :   
     313         469 :    if(eqe->event.flags & PPG_Event_Active) {
     314             :       
     315             :       // The event activates an input
     316             :       
     317         333 :       if(   (eqe->token_state.state == PPG_Token_Matches)
     318         235 :          && eqe->token_state.changed
     319             :       ) {
     320             : //          PPG_LOG("   Causes token match\n");
     321             :          
     322             :          // The last event led to a match
     323             :             
     324             :          // Add the token to the active set
     325             :          //
     326         235 :          PPG_ASSERT(eqe->consumer);
     327         235 :          ppg_active_tokens_add(eqe->consumer);
     328             :           
     329             :          // In pedantic tokens mode, tokens can only trigger actions 
     330             :          // when all their related inputs became inactive
     331             :          //
     332         235 :          if((eqe->consumer->misc.flags & PPG_Token_Flags_Pedantic) == 0) {
     333             :             
     334             :             // As the token just matched. Lets check if
     335             :             // we are allowed to trigger the respective action.
     336             :             //
     337         235 :             if(eqe->consumer->misc.action_state == PPG_Action_Enabled) {
     338             :                
     339             : //                PPG_LOG("      Triggering activation action\n");
     340             :                
     341         166 :                eqe->consumer->action.callback.func(true /* signal activation */,
     342          83 :                   eqe->consumer->action.callback.user_data);
     343             :                
     344          83 :                eqe->consumer->misc.action_state = PPG_Action_Activation_Triggered;
     345             :             }
     346             :          }
     347             :       }
     348             :       
     349         333 :       eqe->event.flags |= PPG_Event_Considered;
     350             :       
     351         333 :       if(eqe->consumer->misc.flags & PPG_Token_Flags_Done) {
     352           6 :          ppg_active_tokens_search_remove(eqe->consumer);
     353             :       }
     354             :    }
     355             :    else {
     356             :         
     357             :       // The event deactivates an input
     358             :       
     359         136 :       if(eqe->consumer) {
     360          52 :          ppg_active_tokens_on_deactivation(eqe->consumer,
     361          26 :                                         eqe->token_state.state,
     362          26 :                                         eqe->token_state.changed);
     363             : 
     364          26 :          eqe->event.flags |= PPG_Event_Considered;
     365             :       }
     366             :       else {
     367             :          
     368             : //          PPG_LOG("   Not part of current match branch\n");
     369             :          
     370         110 :          ppg_active_tokens_check_consumption(&eqe->event);
     371             :       }
     372             :    }
     373             : }
     374             : 
     375         102 : void ppg_active_tokens_update(void)
     376             : {
     377             : //    PPG_LOG("************************\n")
     378             : //    PPG_LOG("Activating active tokens\n")
     379         102 :    ppg_event_buffer_iterate2(
     380             :       (PPG_Event_Processor_Visitor)ppg_active_tokens_update_aux, 
     381             :       NULL);
     382         102 : }

Generated by: LCOV version 1.10