Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: SDTS Translator 4 : * Purpose: Implmementation of SDTSIndexedReader class. This base class for 5 : * various reader classes provides indexed caching of features for 6 : * quick fetching when assembling composite features for other 7 : * readers. 8 : * Author: Frank Warmerdam, warmerdam@pobox.com 9 : * 10 : ****************************************************************************** 11 : * Copyright (c) 1999, Frank Warmerdam 12 : * 13 : * SPDX-License-Identifier: MIT 14 : ****************************************************************************/ 15 : 16 : #include "sdts_al.h" 17 : 18 : /************************************************************************/ 19 : /* SDTSIndexedReader() */ 20 : /************************************************************************/ 21 : 22 8 : SDTSIndexedReader::SDTSIndexedReader() 23 8 : : nIndexSize(-1), papoFeatures(nullptr), iCurrentFeature(0) 24 : { 25 8 : } 26 : 27 : /************************************************************************/ 28 : /* ~SDTSIndexedReader() */ 29 : /************************************************************************/ 30 : 31 8 : SDTSIndexedReader::~SDTSIndexedReader() 32 : 33 : { 34 8 : ClearIndex(); 35 8 : } 36 : 37 : /************************************************************************/ 38 : /* IsIndexed() */ 39 : /************************************************************************/ 40 : 41 : /** 42 : Returns TRUE if the module is indexed, otherwise it returns FALSE. 43 : 44 : If the module is indexed all the feature have already been read into 45 : memory, and searches based on the record number can be performed 46 : efficiently. 47 : */ 48 : 49 392 : int SDTSIndexedReader::IsIndexed() const 50 : 51 : { 52 392 : return nIndexSize >= 0; 53 : } 54 : 55 : /************************************************************************/ 56 : /* ClearIndex() */ 57 : /************************************************************************/ 58 : 59 : /** 60 : Free all features in the index (if filled). 61 : 62 : After this the reader is considered to not be indexed, and IsIndexed() 63 : will return FALSE until the index is forcibly filled again. 64 : */ 65 : 66 11 : void SDTSIndexedReader::ClearIndex() 67 : 68 : { 69 439 : for (int i = 0; i < nIndexSize; i++) 70 : { 71 428 : if (papoFeatures[i] != nullptr) 72 226 : delete papoFeatures[i]; 73 : } 74 : 75 11 : CPLFree(papoFeatures); 76 : 77 11 : papoFeatures = nullptr; 78 11 : nIndexSize = 0; 79 11 : } 80 : 81 : /************************************************************************/ 82 : /* GetNextFeature() */ 83 : /************************************************************************/ 84 : 85 : /** 86 : Fetch the next available feature from this reader. 87 : 88 : The returned SDTSFeature * is to an internal indexed object if the 89 : IsIndexed() method returns TRUE, otherwise the returned feature becomes the 90 : responsibility of the caller to destroy with delete. 91 : 92 : Note that the Rewind() method can be used to start over at the beginning of 93 : the modules feature list. 94 : 95 : @return next feature, or NULL if no more are left. Please review above 96 : ownership/delete semantics. 97 : 98 : */ 99 : 100 455 : SDTSFeature *SDTSIndexedReader::GetNextFeature() 101 : 102 : { 103 455 : if (nIndexSize < 0) 104 353 : return GetNextRawFeature(); 105 : 106 309 : while (iCurrentFeature < nIndexSize) 107 : { 108 306 : if (papoFeatures[iCurrentFeature] != nullptr) 109 99 : return papoFeatures[iCurrentFeature++]; 110 : else 111 207 : iCurrentFeature++; 112 : } 113 : 114 3 : return nullptr; 115 : } 116 : 117 : /************************************************************************/ 118 : /* GetIndexedFeatureRef() */ 119 : /************************************************************************/ 120 : 121 : /** 122 : Fetch a feature based on its record number. 123 : 124 : This method will forcibly fill the feature cache, reading all the 125 : features in the file into memory, if they haven't already been loaded. 126 : The ClearIndex() method can be used to flush this cache when no longer 127 : needed. 128 : 129 : @param iRecordId the record to fetch, normally based on the nRecord 130 : field of an SDTSModId. 131 : 132 : @return a pointer to an internal feature (not to be deleted) or NULL 133 : if there is no matching feature. 134 : */ 135 : 136 56 : SDTSFeature *SDTSIndexedReader::GetIndexedFeatureRef(int iRecordId) 137 : 138 : { 139 56 : if (nIndexSize < 0) 140 2 : FillIndex(); 141 : 142 56 : if (iRecordId < 0 || iRecordId >= nIndexSize) 143 0 : return nullptr; 144 : 145 56 : return papoFeatures[iRecordId]; 146 : } 147 : 148 : /************************************************************************/ 149 : /* FillIndex() */ 150 : /************************************************************************/ 151 : 152 : /** 153 : Read all features into a memory indexed cached. 154 : 155 : The ClearIndex() method can be used to free all indexed features. 156 : FillIndex() does nothing, if an index has already been built. 157 : */ 158 : 159 3 : void SDTSIndexedReader::FillIndex() 160 : 161 : { 162 3 : if (nIndexSize >= 0) 163 0 : return; 164 : 165 3 : Rewind(); 166 3 : nIndexSize = 0; 167 : 168 3 : SDTSFeature *poFeature = nullptr; 169 229 : while ((poFeature = GetNextRawFeature()) != nullptr) 170 : { 171 226 : const int iRecordId = poFeature->oModId.nRecord; 172 : 173 226 : if (iRecordId < 0 || iRecordId >= 1000000) 174 : { 175 0 : delete poFeature; 176 0 : continue; 177 : } 178 226 : if (iRecordId < nIndexSize && papoFeatures[iRecordId] != nullptr) 179 : { 180 0 : delete poFeature; 181 0 : continue; 182 : } 183 : 184 226 : if (iRecordId >= nIndexSize) 185 : { 186 4 : const int nNewSize = static_cast<int>(iRecordId * 1.25 + 100); 187 : 188 4 : papoFeatures = reinterpret_cast<SDTSFeature **>( 189 4 : CPLRealloc(papoFeatures, sizeof(void *) * nNewSize)); 190 : 191 432 : for (int i = nIndexSize; i < nNewSize; i++) 192 428 : papoFeatures[i] = nullptr; 193 : 194 4 : nIndexSize = nNewSize; 195 : } 196 : 197 226 : papoFeatures[iRecordId] = poFeature; 198 : } 199 : } 200 : 201 : /************************************************************************/ 202 : /* ScanModuleReferences() */ 203 : /************************************************************************/ 204 : 205 : /** 206 : Scan an entire SDTS module for record references with the given field 207 : name. 208 : 209 : The fields are required to have a MODN subfield from which the 210 : module is extracted. 211 : 212 : This method is normally used to find all the attribute modules referred 213 : to by a point, line or polygon module to build a unified schema. 214 : 215 : This method will have the side effect of rewinding unindexed readers 216 : because the scanning operation requires reading all records in the module 217 : from disk. 218 : 219 : @param pszFName the field name to search for. By default "ATID" is 220 : used. 221 : 222 : @return a NULL terminated list of module names. Free with CSLDestroy(). 223 : */ 224 : 225 5 : char **SDTSIndexedReader::ScanModuleReferences(const char *pszFName) 226 : 227 : { 228 5 : return SDTSScanModuleReferences(&oDDFModule, pszFName); 229 : } 230 : 231 : /************************************************************************/ 232 : /* Rewind() */ 233 : /************************************************************************/ 234 : 235 : /** 236 : Rewind so that the next feature returned by GetNextFeature() will be the 237 : first in the module. 238 : 239 : */ 240 : 241 23 : void SDTSIndexedReader::Rewind() 242 : 243 : { 244 23 : if (nIndexSize >= 0) 245 5 : iCurrentFeature = 0; 246 : else 247 18 : oDDFModule.Rewind(); 248 23 : }