LCOV - code coverage report
Current view: top level - src - ichiring.c (source / functions) Coverage Total Hit
Test: InChI Unit Test Coverage Lines: 77.2 % 114 88
Test Date: 2026-05-04 07:05:02 Functions: 100.0 % 11 11
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 53.1 % 98 52

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * International Chemical Identifier (InChI)
       3                 :             :  * Version 1
       4                 :             :  * Software version 1.07
       5                 :             :  * April 30, 2024
       6                 :             :  *
       7                 :             :  * MIT License
       8                 :             :  *
       9                 :             :  * Copyright (c) 2024 IUPAC and InChI Trust
      10                 :             :  *
      11                 :             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
      12                 :             :  * of this software and associated documentation files (the "Software"), to deal
      13                 :             :  * in the Software without restriction, including without limitation the rights
      14                 :             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      15                 :             :  * copies of the Software, and to permit persons to whom the Software is
      16                 :             :  * furnished to do so, subject to the following conditions:
      17                 :             :  *
      18                 :             :  * The above copyright notice and this permission notice shall be included in all
      19                 :             :  * copies or substantial portions of the Software.
      20                 :             :  *
      21                 :             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22                 :             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      24                 :             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      26                 :             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      27                 :             :  * SOFTWARE.
      28                 :             : *
      29                 :             : * The InChI library and programs are free software developed under the
      30                 :             :  * auspices of the International Union of Pure and Applied Chemistry (IUPAC).
      31                 :             :  * Originally developed at NIST.
      32                 :             :  * Modifications and additions by IUPAC and the InChI Trust.
      33                 :             :  * Some portions of code were developed/changed by external contributors
      34                 :             :  * (either contractor or volunteer) which are listed in the file
      35                 :             :  * 'External-contributors' included in this distribution.
      36                 :             :  *
      37                 :             :  * info@inchi-trust.org
      38                 :             :  *
      39                 :             : */
      40                 :             : 
      41                 :             : #include "mode.h"
      42                 :             : #include "ichiring.h"
      43                 :             : 
      44                 :             : #include "bcf_s.h"
      45                 :             : 
      46                 :             : /* Local prototypes */
      47                 :             : int GetMinRingSize( inp_ATOM* atom, QUEUE *q, AT_RANK *nAtomLevel, S_CHAR *cSource, AT_RANK nMaxRingSize );
      48                 :             : 
      49                 :             : /*  add to the queue */
      50                 :             : int QueueAdd( QUEUE *q, QINT_TYPE *Val );
      51                 :             : /*  read & remove from the queue */
      52                 :             : int QueueGet( QUEUE *q, QINT_TYPE *Val );
      53                 :             : /*  read from the queue */
      54                 :             : int QueueGetAny( QUEUE *q, QINT_TYPE *, int ord );
      55                 :             : /*  initialize the queue */
      56                 :             : int QueueReinit( QUEUE *q );
      57                 :             : /*  current queue length */
      58                 :             : int QueueLength( QUEUE *q );
      59                 :             : /*  number of used queue internal elements */
      60                 :             : int QueueWrittenLength( QUEUE *q );
      61                 :             : 
      62                 :             : 
      63                 :             : #if ( QUEUE_QINT == 1 )  /* { */
      64                 :             : 
      65                 :             : 
      66                 :             : /****************************************************************************/
      67                 :          69 : QUEUE *QueueCreate( int nTotLength, int nSize )
      68                 :             : {
      69                 :          69 :     QUEUE     *q = NULL;
      70                 :          69 :     QINT_TYPE *Val = NULL;
      71   [ +  -  +  - ]:          69 :     if (nTotLength < 1 || nSize != ( int )sizeof( QINT_TYPE ) ||
      72         [ +  - ]:          69 :          !( q = (QUEUE     *) inchi_calloc( 1, sizeof( QUEUE ) ) ) ||
      73         [ -  + ]:          69 :          !( Val = (QINT_TYPE *) inchi_calloc( nTotLength, nSize ) ))
      74                 :             :     {
      75   [ #  #  #  # ]:           0 :         if (q) inchi_free( q );
      76                 :           0 :         return NULL;
      77                 :             :     }
      78                 :          69 :     q->Val = Val;
      79                 :             :     /* q->nSize      = nSize; */
      80                 :          69 :     q->nTotLength = nTotLength;
      81                 :             : 
      82                 :          69 :     return q;
      83                 :             : }
      84                 :             : 
      85                 :             : 
      86                 :             : /****************************************************************************/
      87                 :         176 : int QueueAdd( QUEUE *q, QINT_TYPE *Val )
      88                 :             : {
      89   [ +  -  +  -  :         176 :     if (q && Val && q->nLength < q->nTotLength)
                   +  - ]
      90                 :             :     {
      91                 :         176 :         q->Val[( q->nFirst + q->nLength ) % q->nTotLength] = *Val;
      92                 :         176 :         q->nLength++;
      93                 :         176 :         return q->nLength;
      94                 :             :     }
      95                 :             : 
      96                 :           0 :     return -1;
      97                 :             : }
      98                 :             : 
      99                 :             : 
     100                 :             : /****************************************************************************/
     101                 :         158 : int QueueGet( QUEUE *q, QINT_TYPE *Val )
     102                 :             : {
     103   [ +  -  +  -  :         158 :     if (q && Val && q->nLength > 0)
                   +  - ]
     104                 :             :     {
     105                 :         158 :         *Val = q->Val[q->nFirst];
     106                 :             :         /* new: do not allow to overwrite the retrieved value */
     107         [ +  - ]:         158 :         q->nFirst = ( q->nFirst == q->nTotLength - 1 ) ? 0 : q->nFirst + 1;
     108                 :         158 :         q->nLength--;
     109                 :             :         /* -- old --
     110                 :             :         if ( -- q->nLength ) {
     111                 :             :             q->nFirst = (q->nFirst == q->nTotLength - 1)? 0 : q->nFirst + 1;
     112                 :             :         }
     113                 :             :         */
     114                 :         158 :         return q->nLength;
     115                 :             :     }
     116                 :             : 
     117                 :           0 :     return -1;
     118                 :             : }
     119                 :             : 
     120                 :             : 
     121                 :             : /****************************************************************************/
     122                 :         176 : int QueueGetAny( QUEUE *q, QINT_TYPE *Val, int ord )
     123                 :             : {
     124   [ +  -  +  - ]:         176 :     if (0 <= ord && ord < q->nTotLength)
     125                 :             :     {
     126                 :         176 :         *Val = q->Val[ord];
     127                 :         176 :         return  1; /*  success */
     128                 :             :     }
     129                 :             :     else
     130                 :             :     {
     131                 :           0 :         return -1; /*  error */
     132                 :             :     }
     133                 :             : }
     134                 :             : 
     135                 :             : #else  /* } QUEUE_QINT == 1 { */
     136                 :             : 
     137                 :             : 
     138                 :             : /****************************************************************************/
     139                 :             : QUEUE *QueueCreate( int nTotLength, int nSize )
     140                 :             : {
     141                 :             :     QUEUE     *q = NULL;
     142                 :             :     QINT_TYPE *Val = NULL;
     143                 :             :     if (nTotLength < 1 || nSize < 1 ||
     144                 :             :          !( q = (QUEUE     *) inchi_calloc( 1, sizeof( QUEUE ) ) ) ||
     145                 :             :          !( Val = (QINT_TYPE *) inchi_calloc( nTotLength, nSize ) ))
     146                 :             :     {
     147                 :             :         if (q) inchi_free( q );
     148                 :             :         return NULL;
     149                 :             :     }
     150                 :             :     q->Val = Val;
     151                 :             :     q->nSize = nSize;
     152                 :             :     q->nTotLength = nTotLength;
     153                 :             :     return q;
     154                 :             : }
     155                 :             : int QueueAdd( QUEUE *q, QINT_TYPE *Val )
     156                 :             : {
     157                 :             :     if (q && Val && q->nLength < q->nTotLength)
     158                 :             :     {
     159                 :             :         memcpy( (char*) q->Val + ( ( q->nFirst + q->nLength ) % q->nTotLength )*q->nSize, Val, q->nSize );
     160                 :             :         q->nLength++;
     161                 :             :         return q->nLength;
     162                 :             :     }
     163                 :             : 
     164                 :             :     return -1;
     165                 :             : }
     166                 :             : 
     167                 :             : 
     168                 :             : /****************************************************************************/
     169                 :             : int QueueGet( QUEUE *q, QINT_TYPE *Val )
     170                 :             : {
     171                 :             :     if (q && Val && q->nLength > 0)
     172                 :             :     {
     173                 :             :         memcpy( Val, (char*) q->Val + q->nFirst * q->nSize, q->nSize );
     174                 :             :         if (--q->nLength)
     175                 :             :         {
     176                 :             :             q->nFirst = ( q->nFirst == q->nTotLength - 1 ) ? 0 : q->nFirst + 1;
     177                 :             :         }
     178                 :             :         return q->nLength;
     179                 :             :     }
     180                 :             : 
     181                 :             :     return -1;
     182                 :             : }
     183                 :             : 
     184                 :             : 
     185                 :             : /****************************************************************************/
     186                 :             : int QueueGetAny( QUEUE *q, QINT_TYPE *Val, int ord )
     187                 :             : {
     188                 :             :     if (0 <= ord && ord < q->nTotLength)
     189                 :             :     {
     190                 :             :         memcpy( Val, (char*) q->Val + ord * q->nSize, q->nSize );
     191                 :             :         return  1; /*  success */
     192                 :             :     }
     193                 :             :     else
     194                 :             :     {
     195                 :             :         return -1; /*  error */
     196                 :             :     }
     197                 :             : }
     198                 :             : 
     199                 :             : #endif /* } QUEUE_QINT == 1 */
     200                 :             : 
     201                 :             : 
     202                 :             : /****************************************************************************/
     203                 :          69 : QUEUE *QueueDelete( QUEUE *q )
     204                 :             : {
     205         [ +  - ]:          69 :     if (q)
     206                 :             :     {
     207   [ +  -  +  - ]:          69 :         if (q->Val) inchi_free( q->Val );
     208         [ +  - ]:          69 :         inchi_free( q );
     209                 :             :     }
     210                 :             : 
     211                 :          69 :     return NULL;
     212                 :             : }
     213                 :             : 
     214                 :             : 
     215                 :             : /****************************************************************************/
     216                 :          16 : int QueueReinit( QUEUE *q )
     217                 :             : {
     218         [ +  - ]:          16 :     if (q)
     219                 :             :     {
     220                 :          16 :         q->nFirst = 0;
     221                 :          16 :         q->nLength = 0;
     222                 :             :         /* memset( q->Val, 0, q->nTotLength*sizeof(q->Val[0])); */ /*  for debug only */
     223                 :          16 :         return q->nTotLength;
     224                 :             :     }
     225                 :             : 
     226                 :           0 :     return -1;
     227                 :             : }
     228                 :             : 
     229                 :             : 
     230                 :             : /****************************************************************************/
     231                 :          72 : int QueueLength( QUEUE *q )
     232                 :             : {
     233         [ +  - ]:          72 :     if (q)
     234                 :             :     {
     235                 :          72 :         return q->nLength;
     236                 :             :     }
     237                 :             :     else
     238                 :             :     {
     239                 :           0 :         return 0;
     240                 :             :     }
     241                 :             : }
     242                 :             : 
     243                 :             : 
     244                 :             : /****************************************************************************/
     245                 :          16 : int QueueWrittenLength( QUEUE *q )
     246                 :             : {
     247         [ +  - ]:          16 :     if (q)
     248                 :             :     {
     249                 :          16 :         int len = q->nFirst + q->nLength;
     250                 :          16 :         return ( len > q->nTotLength ) ? q->nTotLength : len;
     251                 :             :     }
     252                 :             :     else
     253                 :             :     {
     254                 :           0 :         return 0;
     255                 :             :     }
     256                 :             : }
     257                 :             : 
     258                 :             : 
     259                 :             : /****************************************************************************
     260                 :             :   BFS: Breadth First Search
     261                 :             : ****************************************************************************/
     262                 :          16 : int GetMinRingSize( inp_ATOM* atom,
     263                 :             :                     QUEUE *q,
     264                 :             :                     AT_RANK *nAtomLevel,
     265                 :             :                     S_CHAR *cSource,
     266                 :             :                     AT_RANK nMaxRingSize )
     267                 :             : {
     268                 :             :     int qLen, i, j;
     269                 :          16 :     AT_RANK nCurLevel, nRingSize, nMinRingSize = MAX_ATOMS + 1;
     270                 :             :     qInt at_no, next;
     271                 :             :     int  iat_no, inext;
     272                 :             : 
     273         [ +  + ]:          72 :     while ((qLen = QueueLength( q ))) /* djb-rwth: addressing LLVM warning */
     274                 :             :     {
     275                 :             :         /*  traverse the next level (next outer ring) */
     276         [ +  + ]:         214 :         for (i = 0; i < qLen; i++)
     277                 :             :         {
     278         [ +  - ]:         158 :             if (0 <= QueueGet( q, &at_no ))
     279                 :             :             {
     280                 :         158 :                 iat_no = (int) at_no;
     281                 :         158 :                 nCurLevel = nAtomLevel[iat_no] + 1;
     282         [ +  + ]:         158 :                 if (2 * nCurLevel > nMaxRingSize + 4)
     283                 :             :                 {
     284                 :             :                     /*  2*nCurLevel = nRingSize + 3 + k, k = 0 or 1  */
     285         [ +  - ]:          10 :                     if (nMinRingSize < MAX_ATOMS + 1)
     286                 :             :                     {
     287         [ +  - ]:          10 :                         return ( nMinRingSize >= nMaxRingSize ) ? 0 : nMinRingSize;
     288                 :             :                     }
     289                 :           0 :                     return 0; /*  min. ring size > nMaxRingSize */
     290                 :             :                 }
     291         [ +  + ]:         474 :                 for (j = 0; j < atom[iat_no].valence; j++)
     292                 :             :                 {
     293                 :         326 :                     next = (qInt) atom[iat_no].neighbor[j];
     294                 :         326 :                     inext = (int) next;
     295         [ +  + ]:         326 :                     if (!nAtomLevel[inext])
     296                 :             :                     {
     297                 :             :                         /*  the at_no neighbor has not been traversed yet. Add it to the queue */
     298         [ +  - ]:         140 :                         if (0 <= QueueAdd( q, &next ))
     299                 :             :                         {
     300                 :         140 :                             nAtomLevel[inext] = nCurLevel;
     301                 :         140 :                             cSource[inext] = cSource[iat_no]; /*  keep the path number */
     302                 :             :                         }
     303                 :             :                         else
     304                 :             :                         {
     305                 :           0 :                             return -1; /*  error */
     306                 :             :                         }
     307                 :             :                     }
     308                 :             :                     else
     309                 :             :                     {
     310         [ +  + ]:         186 :                         if (nAtomLevel[inext] + 1 >= nCurLevel &&
     311         [ +  + ]:          24 :                                 cSource[inext] != cSource[iat_no]
     312                 :             :                                 /*  && cSource[(int)next] != -1 */
     313                 :             :                               )
     314                 :             :                         {
     315                 :             :                             /*  found a ring closure */
     316                 :             :                             /*  debug */
     317         [ -  + ]:          20 :                             if (cSource[inext] == -1)
     318                 :             :                             {
     319                 :           0 :                                 return -1;  /*  error */
     320                 :             :                             }
     321         [ +  + ]:          20 :                             if (( nRingSize = nAtomLevel[inext] + nCurLevel - 2 ) < nMinRingSize)
     322                 :             :                             {
     323                 :          16 :                                 nMinRingSize = nRingSize;
     324                 :             :                             }
     325                 :             :                             /* return (nRingSize >= nMaxRingSize)? 0 : nRingSize; */
     326                 :             :                         }
     327                 :             :                     }
     328                 :             :                 }
     329                 :             :             }
     330                 :             :             else
     331                 :             :             {
     332                 :           0 :                 return -1; /*  error */
     333                 :             :             }
     334                 :             :         }
     335                 :             :     }
     336                 :             : 
     337         [ +  - ]:           6 :     if (nMinRingSize < MAX_ATOMS + 1)
     338                 :             :     {
     339         [ +  - ]:           6 :         return ( nMinRingSize >= nMaxRingSize ) ? 0 : nMinRingSize;
     340                 :             :     }
     341                 :             : 
     342                 :           0 :     return 0;
     343                 :             : }
     344                 :             : 
     345                 :             : 
     346                 :             : /****************************************************************************
     347                 :             :    Return value:
     348                 :             :      0:    nMaxRingSize < 3 or
     349                 :             :            min. ring size >= nMaxRingSize or
     350                 :             :            not a ring bond (the last is currently impossible: bond is known to belong to a ring system.
     351                 :             :      n>0:  min. ring size < nMaxRingSize
     352                 :             :      n<0:  error
     353                 :             : 
     354                 :             :   Input:
     355                 :             :      atom[]
     356                 :             :      at_no      number of the 1st atom adjacent to the bond
     357                 :             :      neigh_ord  ordering number of the bond in question: at[at_no].bond_type[neigh_ord]
     358                 :             :      q          queue structure
     359                 :             :      nAtomLevel work array, DFS distance
     360                 :             :      cSource    work array, origin mark
     361                 :             : ****************************************************************************/
     362                 :          16 : int is_bond_in_Nmax_memb_ring( inp_ATOM* atom,
     363                 :             :                                int at_no,
     364                 :             :                                int neigh_ord,
     365                 :             :                                QUEUE *q,
     366                 :             :                                AT_RANK *nAtomLevel,
     367                 :             :                                S_CHAR *cSource,
     368                 :             :                                AT_RANK nMaxRingSize )
     369                 :             : {
     370                 :          16 :     int  nMinRingSize = -1, i;
     371                 :             :     qInt n;
     372                 :             :     int  nTotLen;
     373                 :             : 
     374         [ -  + ]:          16 :     if (nMaxRingSize < 3)
     375                 :             :     {
     376                 :           0 :         return 0;
     377                 :             :     }
     378                 :             : 
     379                 :          16 :     QueueReinit( q );
     380                 :             : 
     381                 :             :     /*  mark the starting atom */
     382                 :          16 :     nAtomLevel[at_no] = 1;
     383                 :          16 :     cSource[at_no] = -1;
     384                 :             :     /*  add neighbors */
     385         [ +  + ]:          52 :     for (i = 0; i < atom[at_no].valence; i++)
     386                 :             :     {
     387                 :          36 :         n = (qInt) atom[at_no].neighbor[i];
     388                 :          36 :         nAtomLevel[(int) n] = 2;
     389         [ +  + ]:          36 :         cSource[(int) n] = 1 + ( i == neigh_ord );
     390                 :          36 :         QueueAdd( q, &n );
     391                 :             :     }
     392                 :             : 
     393                 :          16 :     nMinRingSize = GetMinRingSize( atom, q, nAtomLevel, cSource, nMaxRingSize );
     394                 :             :     /*  cleanup */
     395                 :          16 :     nTotLen = QueueWrittenLength( q );
     396         [ +  + ]:         192 :     for (i = 0; i < nTotLen; i++)
     397                 :             :     {
     398         [ +  - ]:         176 :         if (0 < QueueGetAny( q, &n, i ))
     399                 :             :         {
     400                 :         176 :             nAtomLevel[(int) n] = 0;
     401                 :         176 :             cSource[(int) n] = 0;
     402                 :             :         }
     403                 :             :     }
     404                 :          16 :     nAtomLevel[at_no] = 0;
     405                 :          16 :     cSource[at_no] = 0;
     406                 :             : 
     407                 :             :     /*
     408                 :             :     if ( nAtomLevel )
     409                 :             :         inchi_free ( nAtomLevel );
     410                 :             :     if ( cSource )
     411                 :             :         inchi_free ( cSource );
     412                 :             :     QueueDelete( q );
     413                 :             :     */
     414                 :             : 
     415                 :          16 :     return nMinRingSize;
     416                 :             : }
     417                 :             : 
     418                 :             : 
     419                 :             : /****************************************************************************/
     420                 :          34 : int is_atom_in_3memb_ring( inp_ATOM* atom, int at_no )
     421                 :             : {
     422                 :             :     AT_NUMB   neigh_neigh;
     423                 :             :     int       i, j, k, val, val_neigh, neigh;
     424                 :             : 
     425         [ +  - ]:          34 :     if (atom[at_no].nNumAtInRingSystem < 3)
     426                 :             :     {
     427                 :          34 :         return 0;
     428                 :             :     }
     429                 :             : 
     430         [ #  # ]:           0 :     for (i = 0, val = atom[at_no].valence; i < val; i++)
     431                 :             :     {
     432                 :           0 :         neigh = (int) atom[at_no].neighbor[i];
     433         [ #  # ]:           0 :         if (atom[at_no].nRingSystem != atom[neigh].nRingSystem)
     434                 :             :         {
     435                 :           0 :             continue;
     436                 :             :         }
     437         [ #  # ]:           0 :         for (j = 0, val_neigh = atom[neigh].valence; j < val_neigh; j++)
     438                 :             :         {
     439                 :           0 :             neigh_neigh = atom[neigh].neighbor[j];
     440         [ #  # ]:           0 :             if ((int) neigh_neigh == at_no)
     441                 :             :             {
     442                 :           0 :                 continue;
     443                 :             :             }
     444         [ #  # ]:           0 :             for (k = 0; k < val; k++)
     445                 :             :             {
     446         [ #  # ]:           0 :                 if (atom[at_no].neighbor[k] == neigh_neigh)
     447                 :             :                 {
     448                 :           0 :                     return 1;
     449                 :             :                 }
     450                 :             :             }
     451                 :             :         }
     452                 :             :     }
     453                 :             : 
     454                 :           0 :     return 0;
     455                 :             : }
        

Generated by: LCOV version 2.0-1