LCOV - code coverage report
Current view: top level - data/source/storage - data_change_notifier.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 97.1 % 68 66
Test Date: 2025-05-01 10:10:14 Functions: 100.0 % 5 5

            Line data    Source code
       1              : /* File: data_change_notifier.c; Copyright and License: see below */
       2              : 
       3              : #include "entity/data_id.h"
       4              : #include "storage/data_change_notifier.h"
       5              : #include "storage/data_change_message.h"
       6              : #include "u8/u8_trace.h"
       7              : #include "u8/u8_log.h"
       8              : #include <glib-object.h>
       9              : #include <string.h>
      10              : #include <assert.h>
      11              : 
      12              : static bool data_change_notifier_glib_signal_initialized = false;
      13              : static guint data_change_notifier_glib_signal_id = 0;
      14              : const char *DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME = "cfu_data_changed";
      15              : 
      16           64 : void data_change_notifier_init ( data_change_notifier_t *this_ )
      17              : {
      18           64 :     U8_TRACE_BEGIN();
      19              : 
      20           64 :     (*this_).num_listeners = 0;
      21           64 :     memset( (*this_).listener_array, '\0', sizeof( (*this_).listener_array ) );
      22           64 :     (*this_).stealth_mode = false;
      23              : 
      24              :     /* define a new signal */
      25           64 :     if ( ! data_change_notifier_glib_signal_initialized )
      26              :     {
      27            1 :         data_change_notifier_glib_signal_id = g_signal_new (
      28              :             DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME,
      29              :             G_TYPE_OBJECT,
      30              :             G_SIGNAL_RUN_FIRST,
      31              :             0,
      32              :             NULL,
      33              :             NULL,
      34              :             g_cclosure_marshal_VOID__POINTER,
      35              :             G_TYPE_NONE,
      36              :             1,
      37              :             G_TYPE_POINTER /* data_id_t*: id of the record that was created, updated or deleted */
      38              :         );
      39            1 :         data_change_notifier_glib_signal_initialized = true;
      40            1 :         U8_TRACE_INFO_INT( "g_signal_new(\"cfu_data_changed\") returned new signal id", data_change_notifier_glib_signal_id );
      41              :     }
      42              : 
      43           64 :     U8_TRACE_END();
      44           64 : }
      45              : 
      46           64 : void data_change_notifier_destroy ( data_change_notifier_t *this_ )
      47              : {
      48           64 :     U8_TRACE_BEGIN();
      49              : 
      50           64 :     U8_TRACE_END();
      51           64 : }
      52              : 
      53         1970 : void data_change_notifier_emit_signal ( data_change_notifier_t *this_,
      54              :                                         data_change_event_type_t event_type,
      55              :                                         data_table_t table,
      56              :                                         data_row_t row_id,
      57              :                                         data_table_t parent_table,
      58              :                                         data_row_t parent_row_id )
      59              : {
      60         1970 :     U8_TRACE_BEGIN();
      61              : 
      62         1970 :     if ( (*this_).stealth_mode )
      63              :     {
      64            8 :         U8_TRACE_INFO( "stealth mode: no signal sent" );
      65              :     }
      66              :     else
      67              :     {
      68              :         /* prepare */
      69              :         data_id_t modified_element_id;
      70              :         data_id_t parent_element_id;
      71              :         data_change_message_t message;
      72              : 
      73         1962 :         data_id_init( &modified_element_id, table, row_id );
      74         1962 :         data_id_init( &parent_element_id, parent_table, parent_row_id );
      75         1962 :         data_change_message_init( &message,
      76              :                                   event_type,
      77              :                                   modified_element_id,
      78              :                                   parent_element_id
      79              :                                 );
      80              : 
      81         1962 :         data_change_message_trace( &message );
      82              : 
      83              :         /* send messages */
      84         1962 :         for ( int32_t pos = 0; pos < (*this_).num_listeners; pos ++ )
      85              :         {
      86            0 :             U8_TRACE_INFO_INT( "g_signal_emit to listener", pos );
      87            0 :             g_signal_emit( (*this_).listener_array[pos], data_change_notifier_glib_signal_id, 0, &message );
      88              :         }
      89              : 
      90              :         /* clean up */
      91         1962 :         data_id_destroy( &modified_element_id );
      92         1962 :         data_id_destroy( &parent_element_id );
      93         1962 :         data_change_message_destroy( &message );
      94              :     }
      95              : 
      96         1970 :     U8_TRACE_END();
      97         1970 : }
      98              : 
      99           52 : u8_error_t data_change_notifier_add_listener ( data_change_notifier_t *this_, GObject *new_listener )
     100              : {
     101           52 :     U8_TRACE_BEGIN();
     102           52 :     assert( NULL != new_listener );
     103           52 :     u8_error_t result = U8_ERROR_NONE;
     104              : 
     105              :     /* check for duplicates */
     106           52 :     bool duplicate = false;
     107         1231 :     for ( int32_t pos = 0; pos < (*this_).num_listeners; pos ++ )
     108              :     {
     109         1179 :         if( new_listener == (*this_).listener_array[pos] )
     110              :         {
     111            1 :             duplicate = true;
     112            1 :             result = U8_ERROR_INVALID_REQUEST;
     113            1 :             U8_LOG_ERROR( "duplicate call to data_change_notifier_add_listener for same listener." );
     114              :         }
     115              :     }
     116              : 
     117              :     /* if not a duplicate */
     118           52 :     if ( ! duplicate ) {
     119           51 :         if ( (*this_).num_listeners + 1 <= DATA_CHANGE_NOTIFIER_MAX_LISTENERS )
     120              :         {
     121           50 :             (*this_).listener_array[(*this_).num_listeners] = new_listener;  /* possibly increases reference count */
     122           50 :             (*this_).num_listeners ++;
     123              :         }
     124              :         else
     125              :         {
     126            1 :             result = U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     127            1 :             U8_LOG_ERROR( "data_change_notifier_add_listener has too many listeners." );
     128              :         }
     129              :     }
     130              : 
     131           52 :     U8_TRACE_END_ERR( result );
     132           52 :     return result;
     133              : }
     134              : 
     135           54 : u8_error_t data_change_notifier_remove_listener ( data_change_notifier_t *this_, GObject *no_listener )
     136              : {
     137           54 :     U8_TRACE_BEGIN();
     138           54 :     assert( NULL != no_listener );
     139           54 :     u8_error_t result = U8_ERROR_NONE;
     140              : 
     141              :     /* search listener to remove */
     142           54 :     int32_t found_at_pos = -1;  /* -1 means: not found */
     143         1236 :     for ( int32_t pos = 0; pos < (*this_).num_listeners; pos ++ )
     144              :     {
     145         1182 :         if( no_listener == (*this_).listener_array[pos] )
     146              :         {
     147           50 :             found_at_pos = pos;
     148              :         }
     149              :     }
     150              : 
     151              :     /* remove if found */
     152           54 :     if ( found_at_pos != -1 ) {
     153           50 :         U8_TRACE_INFO_INT( "unsubscribing from pos", found_at_pos );
     154           50 :         (*this_).listener_array[found_at_pos] = NULL;
     155           50 :         if ( found_at_pos + 1 != (*this_).num_listeners )
     156              :         {
     157           24 :             (*this_).listener_array[found_at_pos] = (*this_).listener_array[(*this_).num_listeners-1];
     158           24 :             (*this_).listener_array[(*this_).num_listeners-1] = NULL;
     159              :         }
     160           50 :         (*this_).num_listeners --;
     161              :     }
     162              :     else
     163              :     {
     164            4 :         result = U8_ERROR_INVALID_REQUEST;
     165            4 :         U8_LOG_ERROR( "data_change_notifier_remove_listener did not find listener to remove." );
     166              :     }
     167              : 
     168           54 :     U8_TRACE_END_ERR( result );
     169           54 :     return result;
     170              : }
     171              : 
     172              : 
     173              : /*
     174              : Copyright 2016-2025 Andreas Warnke
     175              : 
     176              : Licensed under the Apache License, Version 2.0 (the "License");
     177              : you may not use this file except in compliance with the License.
     178              : You may obtain a copy of the License at
     179              : 
     180              :     http://www.apache.org/licenses/LICENSE-2.0
     181              : 
     182              : Unless required by applicable law or agreed to in writing, software
     183              : distributed under the License is distributed on an "AS IS" BASIS,
     184              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     185              : See the License for the specific language governing permissions and
     186              : limitations under the License.
     187              : */
        

Generated by: LCOV version 2.0-1