LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/s57 - ddfrecordindex.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 62 104 59.6 %
Date: 2024-04-28 18:08:58 Functions: 10 12 83.3 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  S-57 Translator
       4             :  * Purpose:  Implements DDFRecordIndex class.  This class is used to cache
       5             :  *           ISO8211 records for spatial objects so they can be efficiently
       6             :  *           assembled later as features.
       7             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 1999, 2001, Frank Warmerdam
      11             :  *
      12             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "cpl_conv.h"
      32             : #include "s57.h"
      33             : 
      34             : /************************************************************************/
      35             : /*                           DDFRecordIndex()                           */
      36             : /************************************************************************/
      37             : 
      38         185 : DDFRecordIndex::DDFRecordIndex()
      39             :     : bSorted(false), nRecordCount(0), nRecordMax(0), nLastObjlPos(0),
      40         185 :       nLastObjl(0), pasRecords(nullptr)
      41             : {
      42         185 : }
      43             : 
      44             : /************************************************************************/
      45             : /*                          ~DDFRecordIndex()                           */
      46             : /************************************************************************/
      47             : 
      48         370 : DDFRecordIndex::~DDFRecordIndex()
      49             : 
      50             : {
      51         185 :     Clear();
      52         185 : }
      53             : 
      54             : /************************************************************************/
      55             : /*                               Clear()                                */
      56             : /*                                                                      */
      57             : /*      Clear all entries from the index and deallocate all index       */
      58             : /*      resources.                                                      */
      59             : /************************************************************************/
      60             : 
      61         370 : void DDFRecordIndex::Clear()
      62             : 
      63             : {
      64             :     // Deleting these records is very expensive
      65             :     // due to the linear search in DDFModule::RemoveClone().  For now,
      66             :     // just leave the clones depending on DDFModule::~DDFModule() to clean
      67             :     // them up eventually.
      68             : 
      69             :     // for( int i = 0; i < nRecordCount; i++ )
      70             :     //   delete pasRecords[i].poRecord;
      71             : 
      72         370 :     bSorted = false;
      73             : 
      74         370 :     nRecordCount = 0;
      75         370 :     nRecordMax = 0;
      76             : 
      77         370 :     nLastObjlPos = 0;
      78         370 :     nLastObjl = 0;
      79             : 
      80         370 :     CPLFree(pasRecords);
      81         370 :     pasRecords = nullptr;
      82         370 : }
      83             : 
      84             : /************************************************************************/
      85             : /*                             AddRecord()                              */
      86             : /*                                                                      */
      87             : /*      Add a record to the index.  The index will assume ownership     */
      88             : /*      of the record.  If passing a record just read from a            */
      89             : /*      DDFModule it is imperative that the caller Clone()'s the        */
      90             : /*      record first.                                                   */
      91             : /************************************************************************/
      92             : 
      93        1358 : void DDFRecordIndex::AddRecord(int nKey, DDFRecord *poRecord)
      94             : 
      95             : {
      96        1358 :     if (nRecordCount == nRecordMax)
      97             :     {
      98          70 :         nRecordMax = static_cast<int>(nRecordCount * 1.3 + 100);
      99          70 :         pasRecords = static_cast<DDFIndexedRecord *>(
     100          70 :             CPLRealloc(pasRecords, sizeof(DDFIndexedRecord) * nRecordMax));
     101             :     }
     102             : 
     103        1358 :     bSorted = false;
     104             : 
     105        1358 :     pasRecords[nRecordCount].nKey = nKey;
     106        1358 :     pasRecords[nRecordCount].poRecord = poRecord;
     107        1358 :     pasRecords[nRecordCount].pClientData = nullptr;
     108             : 
     109        1358 :     nRecordCount++;
     110        1358 : }
     111             : 
     112             : /************************************************************************/
     113             : /*                             FindRecord()                             */
     114             : /*                                                                      */
     115             : /*      Though the returned pointer is not const, it should be          */
     116             : /*      considered internal to the index and not modified or freed      */
     117             : /*      by application code.                                            */
     118             : /************************************************************************/
     119             : 
     120        8861 : DDFRecord *DDFRecordIndex::FindRecord(int nKey)
     121             : 
     122             : {
     123        8861 :     if (!bSorted)
     124          17 :         Sort();
     125             : 
     126             :     /* -------------------------------------------------------------------- */
     127             :     /*      Do a binary search based on the key to find the desired record. */
     128             :     /* -------------------------------------------------------------------- */
     129        8861 :     int nMinIndex = 0;
     130        8861 :     int nMaxIndex = nRecordCount - 1;
     131             : 
     132       32067 :     while (nMinIndex <= nMaxIndex)
     133             :     {
     134       32067 :         const int nTestIndex = (nMaxIndex + nMinIndex) / 2;
     135             : 
     136       32067 :         if (pasRecords[nTestIndex].nKey < nKey)
     137       11361 :             nMinIndex = nTestIndex + 1;
     138       20706 :         else if (pasRecords[nTestIndex].nKey > nKey)
     139       11845 :             nMaxIndex = nTestIndex - 1;
     140             :         else
     141        8861 :             return pasRecords[nTestIndex].poRecord;
     142             :     }
     143             : 
     144           0 :     return nullptr;
     145             : }
     146             : 
     147             : /************************************************************************/
     148             : /*                       FindRecordByObjl()                             */
     149             : /*      Rodney Jensen                                                   */
     150             : /*      Though the returned pointer is not const, it should be          */
     151             : /*      considered internal to the index and not modified or freed      */
     152             : /*      by application code.                                            */
     153             : /************************************************************************/
     154             : 
     155           0 : DDFRecord *DDFRecordIndex::FindRecordByObjl(int nObjl)
     156             : {
     157           0 :     if (!bSorted)
     158           0 :         Sort();
     159             : 
     160             :     /* -------------------------------------------------------------------- */
     161             :     /*      Do a linear search based on the nObjl to find the desired record. */
     162             :     /* -------------------------------------------------------------------- */
     163           0 :     int nMinIndex = 0;
     164           0 :     if (nLastObjl != nObjl)
     165           0 :         nLastObjlPos = 0;
     166             : 
     167           0 :     for (nMinIndex = nLastObjlPos; nMinIndex < nRecordCount; nMinIndex++)
     168             :     {
     169           0 :         if (nObjl == pasRecords[nMinIndex].poRecord->GetIntSubfield("FRID", 0,
     170             :                                                                     "OBJL", 0))
     171             :         {
     172             :             // Add 1.  Do not want to look at same again.
     173           0 :             nLastObjlPos = nMinIndex + 1;
     174           0 :             nLastObjl = nObjl;
     175           0 :             return pasRecords[nMinIndex].poRecord;
     176             :         }
     177             :     }
     178             : 
     179           0 :     nLastObjlPos = 0;
     180           0 :     nLastObjl = 0;
     181             : 
     182           0 :     return nullptr;
     183             : }
     184             : 
     185             : /************************************************************************/
     186             : /*                            RemoveRecord()                            */
     187             : /************************************************************************/
     188             : 
     189           0 : bool DDFRecordIndex::RemoveRecord(int nKey)
     190             : 
     191             : {
     192           0 :     if (!bSorted)
     193           0 :         Sort();
     194             : 
     195             :     /* -------------------------------------------------------------------- */
     196             :     /*      Do a binary search based on the key to find the desired record. */
     197             :     /* -------------------------------------------------------------------- */
     198           0 :     int nMinIndex = 0;
     199           0 :     int nMaxIndex = nRecordCount - 1;
     200           0 :     int nTestIndex = 0;
     201             : 
     202           0 :     while (nMinIndex <= nMaxIndex)
     203             :     {
     204           0 :         nTestIndex = (nMaxIndex + nMinIndex) / 2;
     205             : 
     206           0 :         if (pasRecords[nTestIndex].nKey < nKey)
     207           0 :             nMinIndex = nTestIndex + 1;
     208           0 :         else if (pasRecords[nTestIndex].nKey > nKey)
     209           0 :             nMaxIndex = nTestIndex - 1;
     210             :         else
     211           0 :             break;
     212             :     }
     213             : 
     214           0 :     if (nMinIndex > nMaxIndex)
     215           0 :         return false;
     216             : 
     217             :     /* -------------------------------------------------------------------- */
     218             :     /*      Delete this record.                                             */
     219             :     /* -------------------------------------------------------------------- */
     220           0 :     delete pasRecords[nTestIndex].poRecord;
     221             : 
     222             :     /* -------------------------------------------------------------------- */
     223             :     /*      Move all the list entries back one to fill the hole, and        */
     224             :     /*      update the total count.                                         */
     225             :     /* -------------------------------------------------------------------- */
     226           0 :     memmove(pasRecords + nTestIndex, pasRecords + nTestIndex + 1,
     227           0 :             (nRecordCount - nTestIndex - 1) * sizeof(DDFIndexedRecord));
     228             : 
     229           0 :     nRecordCount--;
     230             : 
     231           0 :     return true;
     232             : }
     233             : 
     234             : /************************************************************************/
     235             : /*                             DDFCompare()                             */
     236             : /*                                                                      */
     237             : /*      Compare two DDFIndexedRecord objects for qsort().               */
     238             : /************************************************************************/
     239             : 
     240        2557 : static int DDFCompare(const void *pRec1, const void *pRec2)
     241             : 
     242             : {
     243        2557 :     if (((const DDFIndexedRecord *)pRec1)->nKey ==
     244        2557 :         ((const DDFIndexedRecord *)pRec2)->nKey)
     245           0 :         return 0;
     246        2557 :     if (((const DDFIndexedRecord *)pRec1)->nKey <
     247        2557 :         ((const DDFIndexedRecord *)pRec2)->nKey)
     248        1918 :         return -1;
     249             : 
     250         639 :     return 1;
     251             : }
     252             : 
     253             : /************************************************************************/
     254             : /*                                Sort()                                */
     255             : /*                                                                      */
     256             : /*      Sort the records based on the key.                              */
     257             : /************************************************************************/
     258             : 
     259          42 : void DDFRecordIndex::Sort()
     260             : 
     261             : {
     262          42 :     if (bSorted)
     263           0 :         return;
     264             : 
     265          42 :     qsort(pasRecords, nRecordCount, sizeof(DDFIndexedRecord), DDFCompare);
     266             : 
     267          42 :     bSorted = true;
     268             : }
     269             : 
     270             : /************************************************************************/
     271             : /*                             GetByIndex()                             */
     272             : /************************************************************************/
     273             : 
     274        1618 : DDFRecord *DDFRecordIndex::GetByIndex(int nIndex)
     275             : 
     276             : {
     277        1618 :     if (!bSorted)
     278          25 :         Sort();
     279             : 
     280        1618 :     if (nIndex < 0 || nIndex >= nRecordCount)
     281           0 :         return nullptr;
     282             : 
     283        1618 :     return pasRecords[nIndex].poRecord;
     284             : }
     285             : 
     286             : /************************************************************************/
     287             : /*                        GetClientInfoByIndex()                        */
     288             : /************************************************************************/
     289             : 
     290        8389 : void *DDFRecordIndex::GetClientInfoByIndex(int nIndex)
     291             : 
     292             : {
     293        8389 :     if (!bSorted)
     294           0 :         Sort();
     295             : 
     296        8389 :     if (nIndex < 0 || nIndex >= nRecordCount)
     297           0 :         return nullptr;
     298             : 
     299        8389 :     return pasRecords[nIndex].pClientData;
     300             : }
     301             : 
     302             : /************************************************************************/
     303             : /*                        SetClientInfoByIndex()                        */
     304             : /************************************************************************/
     305             : 
     306         345 : void DDFRecordIndex::SetClientInfoByIndex(int nIndex, void *pClientData)
     307             : 
     308             : {
     309         345 :     if (!bSorted)
     310           0 :         Sort();
     311             : 
     312         345 :     if (nIndex < 0 || nIndex >= nRecordCount)
     313           0 :         return;
     314             : 
     315         345 :     pasRecords[nIndex].pClientData = pClientData;
     316             : }

Generated by: LCOV version 1.14