LCOV - code coverage report
Current view: top level - data/source/storage - data_change_notifier.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.57.0_covts Lines: 66 68 97.1 %
Date: 2024-04-07 11:14:42 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* File: data_change_notifier.c; Copyright and License: see below */
       2             : 
       3             : #include "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          59 : void data_change_notifier_init ( data_change_notifier_t *this_ )
      17             : {
      18          59 :     U8_TRACE_BEGIN();
      19             : 
      20          59 :     (*this_).num_listeners = 0;
      21          59 :     memset( (*this_).listener_array, '\0', sizeof( (*this_).listener_array ) );
      22          59 :     (*this_).stealth_mode = false;
      23             : 
      24             :     /* define a new signal */
      25          59 :     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          59 :     U8_TRACE_END();
      44          59 : }
      45             : 
      46          59 : void data_change_notifier_destroy ( data_change_notifier_t *this_ )
      47             : {
      48          59 :     U8_TRACE_BEGIN();
      49             : 
      50          59 :     U8_TRACE_END();
      51          59 : }
      52             : 
      53         969 : 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_id_t row_id,
      57             :                                         data_table_t parent_table,
      58             :                                         data_row_id_t parent_row_id )
      59             : {
      60         969 :     U8_TRACE_BEGIN();
      61             : 
      62         969 :     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         961 :         data_id_init( &modified_element_id, table, row_id );
      74         961 :         data_id_init( &parent_element_id, parent_table, parent_row_id );
      75         961 :         data_change_message_init( &message,
      76             :                                   event_type,
      77             :                                   modified_element_id,
      78             :                                   parent_element_id
      79             :                                 );
      80             : 
      81         961 :         data_change_message_trace( &message );
      82             : 
      83             :         /* send messages */
      84         961 :         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         961 :         data_id_destroy( &modified_element_id );
      92         961 :         data_id_destroy( &parent_element_id );
      93         961 :         data_change_message_destroy( &message );
      94             :     }
      95             : 
      96         969 :     U8_TRACE_END();
      97         969 : }
      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-2024 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 1.16