LCOV - code coverage report
Current view: top level - data/source/set - data_visible_set.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.65.6_covts Lines: 135 142 95.1 %
Date: 2025-09-25 21:07:53 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* File: data_visible_set.c; Copyright and License: see below */
       2             : 
       3             : #include "set/data_visible_set.h"
       4             : #include "data_rules.h"
       5             : #include "u8/u8_trace.h"
       6             : #include <stdio.h>
       7             : #include <stdlib.h>
       8             : #include <assert.h>
       9             : 
      10          17 : void data_visible_set_init( data_visible_set_t *this_ )
      11             : {
      12          17 :     U8_TRACE_BEGIN();
      13          17 :     U8_TRACE_INFO_INT( "sizeof(data_visible_set_t):", sizeof(data_visible_set_t) );
      14             : 
      15          17 :     data_diagram_init_empty( &((*this_).diagram) );
      16          17 :     (*this_).visible_classifier_count = 0;
      17          17 :     (*this_).feature_count = 0;
      18          17 :     (*this_).relationship_count = 0;
      19             : 
      20          17 :     U8_TRACE_END();
      21          17 : }
      22             : 
      23           1 : void data_visible_set_reinit( data_visible_set_t *this_ )
      24             : {
      25           1 :     U8_TRACE_BEGIN();
      26             : 
      27           1 :     data_diagram_reinit_empty( &((*this_).diagram) );
      28           1 :     data_visible_set_private_destroy_visible_classifiers( this_ );
      29           1 :     data_visible_set_private_destroy_features( this_ );
      30           1 :     data_visible_set_private_destroy_relationships( this_ );
      31             : 
      32           1 :     U8_TRACE_END();
      33             : 
      34           1 : }
      35             : 
      36           7 : void data_visible_set_destroy( data_visible_set_t *this_ )
      37             : {
      38           7 :     U8_TRACE_BEGIN();
      39             : 
      40           7 :     data_diagram_destroy( &((*this_).diagram) );
      41           7 :     data_visible_set_private_destroy_visible_classifiers( this_ );
      42           7 :     data_visible_set_private_destroy_features( this_ );
      43           7 :     data_visible_set_private_destroy_relationships( this_ );
      44             : 
      45           7 :     U8_TRACE_END();
      46           7 : }
      47             : 
      48           8 : u8_error_t data_visible_set_load( data_visible_set_t *this_, data_row_t diagram_id, data_database_reader_t *db_reader )
      49             : {
      50           8 :     U8_TRACE_BEGIN();
      51           8 :     assert( NULL != db_reader );
      52           8 :     u8_error_t result = U8_ERROR_NONE;
      53             : 
      54           8 :     if ( DATA_ROW_VOID == diagram_id )
      55             :     {
      56             :         /* re-init */
      57           1 :         data_diagram_reinit_empty( &((*this_).diagram) );
      58             : 
      59           1 :         data_visible_set_private_destroy_visible_classifiers( this_ );
      60           1 :         data_visible_set_private_destroy_features( this_ );
      61           1 :         data_visible_set_private_destroy_relationships( this_ );
      62             :     }
      63             :     else
      64             :     {
      65           7 :         data_diagram_destroy( &((*this_).diagram) );
      66           7 :         data_visible_set_private_destroy_visible_classifiers( this_ );
      67           7 :         data_visible_set_private_destroy_features( this_ );
      68           7 :         data_visible_set_private_destroy_relationships( this_ );
      69             : 
      70             :         data_rules_t rules;
      71           7 :         data_rules_init( &rules );
      72             : 
      73             :         /* load diagram */
      74             :         {
      75             :             const u8_error_t diag_err
      76           7 :                 = data_database_reader_get_diagram_by_id ( db_reader, diagram_id, &((*this_).diagram) );
      77           7 :             if ( u8_error_contains( diag_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) )
      78             :             {
      79           0 :                 U8_LOG_ERROR( "U8_ERROR_STRING_BUFFER_EXCEEDED at loading a diagram" );
      80             :             }
      81           7 :             if ( u8_error_more_than( diag_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) )
      82             :             {
      83             :                 /* error at loading */
      84           1 :                 data_diagram_reinit_empty( &((*this_).diagram) );
      85             :             }
      86           7 :             result |= diag_err;  /* collect error flags */
      87             :         }
      88             : 
      89             :         /* load classifiers */
      90             :         {
      91           7 :             u8_error_t c_err = U8_ERROR_NONE;
      92           7 :             (*this_).visible_classifier_count = 0;
      93             :             data_visible_classifier_iterator_t visible_classifier_iterator;
      94           7 :             c_err |= data_visible_classifier_iterator_init_empty( &visible_classifier_iterator );
      95           7 :             c_err |= data_database_reader_get_visible_classifiers_by_diagram_id( db_reader,
      96             :                                                                                  diagram_id,
      97             :                                                                                  &visible_classifier_iterator
      98             :                                                                                );
      99         193 :             while ( data_visible_classifier_iterator_has_next( &visible_classifier_iterator )
     100         193 :                 && ( ! u8_error_more_than( c_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) ) )
     101             :             {
     102         186 :                 if ( (*this_).visible_classifier_count < DATA_VISIBLE_SET_MAX_CLASSIFIERS )
     103             :                 {
     104         185 :                     data_visible_classifier_t *const current_visible_classifier
     105         185 :                         = &((*this_).visible_classifiers[(*this_).visible_classifier_count]);
     106         185 :                     c_err |= data_visible_classifier_iterator_next( &visible_classifier_iterator,
     107             :                                                                     current_visible_classifier
     108             :                                                                   );
     109         185 :                     if ( ! u8_error_more_than( c_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) )
     110             :                     {
     111         185 :                         (*this_).visible_classifier_count ++;
     112             :                     }
     113             :                 }
     114             :                 else
     115             :                 {
     116           1 :                     c_err |= U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     117           1 :                     U8_LOG_ERROR( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at loading visible classifiers of a diagram" );
     118             :                 }
     119             :             }
     120           7 :             c_err |= data_visible_classifier_iterator_destroy( &visible_classifier_iterator );
     121           7 :             result |= c_err;  /* collect error flags */
     122             :         }
     123             : 
     124             :         /* load features */
     125             :         {
     126           7 :             u8_error_t f_err = U8_ERROR_NONE;
     127           7 :             (*this_).feature_count = 0;
     128             :             data_feature_iterator_t feature_iterator;
     129           7 :             f_err |= data_feature_iterator_init_empty( &feature_iterator );
     130           7 :             f_err |= data_database_reader_get_features_by_diagram_id( db_reader,
     131             :                                                                       diagram_id,
     132             :                                                                       &feature_iterator
     133             :                                                                     );
     134         269 :             while ( data_feature_iterator_has_next( &feature_iterator )
     135         269 :                 && ( ! u8_error_more_than( f_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) ) )
     136             :             {
     137         262 :                 if ( (*this_).feature_count < DATA_VISIBLE_SET_MAX_FEATURES )
     138             :                 {
     139         261 :                     data_feature_t *const current_feature = &((*this_).features[(*this_).feature_count]);
     140         261 :                     f_err |= data_feature_iterator_next( &feature_iterator, current_feature );
     141         261 :                     if ( ! u8_error_more_than( f_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) )
     142             :                     {
     143             :                         /* Ignore lifelines (== is_scenario) that do not belong to current diagram */
     144             :                         /* NOTE: The iteraltor already filters lifelines that do not belong to the current diagram, see DATA_FEATURE_ITERATOR_SELECT_FEATURES_BY_DIAGRAM_ID */
     145             : #if 0
     146             :                         const bool is_scenario =
     147             :                             data_rules_feature_is_scenario_cond( &rules, data_feature_get_main_type( current_feature ) );
     148             :                         bool is_foreign_scenario = is_scenario;
     149             :                         for( uint_fast32_t vc_idx = 0; vc_idx < (*this_).visible_classifier_count; vc_idx ++ )
     150             :                         {
     151             :                             const data_diagramelement_t *const diag_ele
     152             :                                 = data_visible_classifier_get_diagramelement_const( &((*this_).visible_classifiers[vc_idx]) );
     153             :                             const data_row_t focus_id = data_diagramelement_get_focused_feature_row_id( diag_ele );
     154             :                             if ( data_feature_get_row_id( current_feature ) == focus_id )
     155             :                             {
     156             :                                 is_foreign_scenario = false;
     157             :                             }
     158             :                         }
     159             :                         if ( ! is_foreign_scenario ) /* either not a scenario or a scenario that is in scope of the diagram */
     160             :                         {
     161             : #endif
     162         261 :                             (*this_).feature_count++;
     163             : #if 0
     164             :                         }
     165             :                         else
     166             :                         {
     167             :                             U8_TRACE_INFO_INT( "filtered a foreign scenario lifeline:",
     168             :                                                data_feature_get_row_id( current_feature )
     169             :                                              );
     170             :                         }
     171             : #endif
     172             :                     }
     173             :                 }
     174             :                 else
     175             :                 {
     176           1 :                     f_err |= U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     177           1 :                     U8_LOG_ERROR( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at loading features of a diagram" );
     178             :                 }
     179             :             }
     180           7 :             f_err |= data_feature_iterator_destroy( &feature_iterator );
     181           7 :             result |= f_err;  /* collect error flags */
     182             :         }
     183             : 
     184             :         /* load relationships */
     185             :         {
     186           7 :             u8_error_t r_err = U8_ERROR_NONE;
     187           7 :             (*this_).relationship_count = 0;
     188             :             data_relationship_iterator_t rel_iterator;
     189           7 :             r_err |= data_relationship_iterator_init_empty( &rel_iterator );
     190           7 :             r_err |= data_database_reader_get_relationships_by_diagram_id( db_reader,
     191             :                                                                            diagram_id,
     192             :                                                                            &rel_iterator
     193             :                                                                          );
     194         402 :             while ( data_relationship_iterator_has_next( &rel_iterator )
     195         402 :                 && ( ! u8_error_more_than( r_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) ) )
     196             :             {
     197         395 :                 if ( (*this_).relationship_count < DATA_VISIBLE_SET_MAX_RELATIONSHIPS )
     198             :                 {
     199         394 :                     data_relationship_t *const current_relationship = &((*this_).relationships[(*this_).relationship_count]);
     200         394 :                     r_err |= data_relationship_iterator_next( &rel_iterator, current_relationship );
     201         394 :                     if ( ! u8_error_more_than( r_err, U8_ERROR_STRING_BUFFER_EXCEEDED ) )
     202             :                     {
     203             :                         /* Ignore relationships that have not both ends in current diagram - e.g. messages between foreign lifelines */
     204         394 :                         const data_row_t from_feat_row_id = data_relationship_get_from_feature_row_id( current_relationship );
     205         394 :                         const data_row_t to_feat_row_id = data_relationship_get_to_feature_row_id( current_relationship );
     206         394 :                         bool from_known = ( from_feat_row_id == DATA_ROW_VOID );
     207         394 :                         bool to_known = ( to_feat_row_id == DATA_ROW_VOID );
     208       98717 :                         for( uint_fast32_t f_idx = 0; f_idx < (*this_).feature_count; f_idx ++ )
     209             :                         {
     210       98323 :                             const data_feature_t *const probe_feature = &((*this_).features[f_idx]);
     211       98323 :                             const data_row_t probe_feat_id = data_feature_get_row_id( probe_feature );
     212       98323 :                             if ( probe_feat_id == from_feat_row_id )
     213             :                             {
     214           4 :                                 from_known = true;
     215             :                             }
     216       98323 :                             if ( probe_feat_id == to_feat_row_id )
     217             :                             {
     218           3 :                                 to_known = true;
     219             :                             }
     220             :                         }
     221         394 :                         if ( from_known && to_known )  /* check that both relationship ends are in this data_visible_set_t */
     222             :                         {
     223         391 :                             (*this_).relationship_count++;
     224             :                         }
     225             :                         else
     226             :                         {
     227           3 :                             U8_TRACE_INFO_INT( "filtered a foreign scenario message:",
     228             :                                                data_relationship_get_row_id( current_relationship )
     229             :                                              );
     230             :                         }
     231             :                     }
     232             :                 }
     233             :                 else
     234             :                 {
     235           1 :                     r_err |= U8_ERROR_ARRAY_BUFFER_EXCEEDED;
     236           1 :                     U8_LOG_ERROR( "U8_ERROR_ARRAY_BUFFER_EXCEEDED at loading relationships of a diagram" );
     237             :                 }
     238             :             }
     239           7 :             r_err |= data_relationship_iterator_destroy( &rel_iterator );
     240           7 :             result |= r_err;  /* collect error flags */
     241             :         }
     242             : 
     243           7 :         data_rules_destroy( &rules );
     244             :     }
     245             : 
     246             :     /* update the containment cache */
     247           8 :     data_visible_set_update_containment_cache( this_ );
     248             : 
     249           8 :     U8_TRACE_END_ERR(result);
     250           8 :     return result;
     251             : }
     252             : 
     253          18 : void data_visible_set_update_containment_cache ( data_visible_set_t *this_ )
     254             : {
     255          18 :     U8_TRACE_BEGIN();
     256          18 :     assert( (*this_).relationship_count <= DATA_VISIBLE_SET_MAX_RELATIONSHIPS );
     257          18 :     assert( (*this_).visible_classifier_count <= DATA_VISIBLE_SET_MAX_CLASSIFIERS );
     258             : 
     259             :     /* reset the containment array */
     260          18 :     memset( &((*this_).containment_cache), '\0', sizeof( (*this_).containment_cache ) );
     261             : 
     262             :     static const int MAX_SEARCH_PASSES = 4;  /* with 4 passes, we can find ancesters and decendants which are related via 2*4=8 links and more */
     263          18 :     bool new_containments_found = true;
     264             : 
     265          36 :     for ( int pass = 0; ( pass < MAX_SEARCH_PASSES ) && new_containments_found; pass ++ )
     266             :     {
     267          18 :         new_containments_found = false;
     268             : 
     269        2748 :         for ( uint32_t rel_idx = 0; rel_idx < (*this_).relationship_count; rel_idx ++ )
     270             :         {
     271             :             data_relationship_t *the_relationship;
     272        2730 :             the_relationship = &((*this_).relationships[rel_idx]);
     273             : 
     274             :             data_relationship_type_t the_type;
     275        2730 :             the_type = data_relationship_get_main_type ( the_relationship );
     276             : 
     277        2730 :             if ( DATA_RELATIONSHIP_TYPE_UML_CONTAINMENT == the_type )
     278             :             {
     279             :                 data_row_t parent_id;
     280             :                 data_row_t child_id;
     281         385 :                 parent_id = data_relationship_get_from_classifier_row_id ( the_relationship );
     282         385 :                 child_id = data_relationship_get_to_classifier_row_id ( the_relationship );
     283             :                 int32_t parent_index;
     284             :                 int32_t child_index;
     285         385 :                 parent_index = data_visible_set_get_classifier_index ( this_, parent_id );
     286         385 :                 child_index = data_visible_set_get_classifier_index ( this_, child_id );
     287         385 :                 if ( ( parent_index != -1 )&&( child_index != -1 ) )
     288             :                 {
     289         385 :                     assert ( 0 <= parent_index );
     290         385 :                     assert ( parent_index < (*this_).visible_classifier_count );
     291         385 :                     assert ( 0 <= child_index );
     292         385 :                     assert ( child_index < (*this_).visible_classifier_count );
     293             : 
     294             :                     /* add the current relation to the containment_cache */
     295         385 :                     (*this_).containment_cache[parent_index][child_index] = true;
     296             : 
     297             :                     /* all ancestors of parent are ancestors of child */
     298       49539 :                     for ( uint32_t ancestor_index = 0; ancestor_index < (*this_).visible_classifier_count; ancestor_index ++ )
     299             :                     {
     300       49154 :                         if ( (*this_).containment_cache[ancestor_index][parent_index] )
     301             :                         {
     302           0 :                             if ( ! (*this_).containment_cache[ancestor_index][child_index] )
     303             :                             {
     304           0 :                                 new_containments_found = true;
     305           0 :                                 (*this_).containment_cache[ancestor_index][child_index] = true;
     306             :                             }
     307             :                         }
     308             :                     }
     309             : 
     310             :                     /* all descendants of child are descendants of parent */
     311       49539 :                     for ( uint32_t descendant_index = 0; descendant_index < (*this_).visible_classifier_count; descendant_index ++ )
     312             :                     {
     313       49154 :                         if ( (*this_).containment_cache[child_index][descendant_index] )
     314             :                         {
     315           0 :                             if ( ! (*this_).containment_cache[parent_index][descendant_index] )
     316             :                             {
     317           0 :                                 new_containments_found = true;
     318           0 :                                 (*this_).containment_cache[parent_index][descendant_index] = true;
     319             :                             }
     320             :                         }
     321             :                     }
     322             : 
     323             :                 }
     324             :                 /* else relation points outside the set of classifiers visible in current diagram */
     325             :             }
     326             :         }
     327             :     }
     328             : 
     329          18 :     U8_TRACE_END();
     330          18 : }
     331             : 
     332             : 
     333             : /*
     334             : Copyright 2016-2025 Andreas Warnke
     335             : 
     336             : Licensed under the Apache License, Version 2.0 (the "License");
     337             : you may not use this file except in compliance with the License.
     338             : You may obtain a copy of the License at
     339             : 
     340             :     http://www.apache.org/licenses/LICENSE-2.0
     341             : 
     342             : Unless required by applicable law or agreed to in writing, software
     343             : distributed under the License is distributed on an "AS IS" BASIS,
     344             : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     345             : See the License for the specific language governing permissions and
     346             : limitations under the License.
     347             : */

Generated by: LCOV version 1.16