Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: ISO 8211 Access 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 : * SPDX-License-Identifier: MIT 13 : ****************************************************************************/ 14 : 15 : #include "cpl_conv.h" 16 : #include "ddfrecordindex.h" 17 : 18 : #include <algorithm> 19 : 20 : /************************************************************************/ 21 : /* DDFRecordIndex() */ 22 : /************************************************************************/ 23 : 24 : DDFRecordIndex::DDFRecordIndex() = default; 25 : 26 : /************************************************************************/ 27 : /* ~DDFRecordIndex() */ 28 : /************************************************************************/ 29 : 30 2680 : DDFRecordIndex::~DDFRecordIndex() 31 : 32 : { 33 2680 : Clear(); 34 2680 : } 35 : 36 : /************************************************************************/ 37 : /* Clear() */ 38 : /* */ 39 : /* Clear all entries from the index and deallocate all index */ 40 : /* resources. */ 41 : /************************************************************************/ 42 : 43 2875 : void DDFRecordIndex::Clear() 44 : 45 : { 46 2875 : bSorted = false; 47 2875 : asRecords.clear(); 48 2875 : oMapKeyToRecord.clear(); 49 2875 : } 50 : 51 : /************************************************************************/ 52 : /* AddRecord() */ 53 : /* */ 54 : /* Add a record to the index. The index will assume ownership */ 55 : /* of the record. If passing a record just read from a */ 56 : /* DDFModule it is imperative that the caller Clone()'s the */ 57 : /* record first. */ 58 : /************************************************************************/ 59 : 60 29095 : void DDFRecordIndex::AddRecord(int nKey, std::unique_ptr<DDFRecord> poRecord) 61 : 62 : { 63 29095 : DDFIndexedRecord indexRec; 64 29095 : indexRec.nKey = nKey; 65 29095 : indexRec.poRecord = std::move(poRecord); 66 29095 : asRecords.push_back(std::move(indexRec)); 67 29095 : oMapKeyToRecord[nKey] = asRecords.back().poRecord.get(); 68 29095 : bSorted = false; 69 29095 : } 70 : 71 : /************************************************************************/ 72 : /* FindRecord() */ 73 : /* */ 74 : /* Though the returned pointer is not const, it should not */ 75 : /* be freed by application code. */ 76 : /************************************************************************/ 77 : 78 124338 : DDFRecord *DDFRecordIndex::FindRecord(int nKey) const 79 : 80 : { 81 124338 : auto oIter = oMapKeyToRecord.find(nKey); 82 124338 : if (oIter == oMapKeyToRecord.end()) 83 1552 : return nullptr; 84 122786 : return oIter->second; 85 : } 86 : 87 : /************************************************************************/ 88 : /* RemoveRecord() */ 89 : /************************************************************************/ 90 : 91 18 : bool DDFRecordIndex::RemoveRecord(int nKey) 92 : 93 : { 94 18 : if (!bSorted) 95 8 : Sort(); 96 : 97 18 : if (asRecords.empty() || nKey < asRecords[0].nKey) 98 0 : return false; 99 : 100 : /* -------------------------------------------------------------------- */ 101 : /* Do a binary search based on the key to find the desired record. */ 102 : /* -------------------------------------------------------------------- */ 103 18 : size_t nMinIndex = 0; 104 18 : size_t nMaxIndex = asRecords.size() - 1; 105 18 : size_t nTestIndex = 0; 106 : 107 145 : while (nMinIndex <= nMaxIndex) 108 : { 109 145 : nTestIndex = (nMaxIndex + nMinIndex) / 2; 110 : 111 145 : if (asRecords[nTestIndex].nKey < nKey) 112 110 : nMinIndex = nTestIndex + 1; 113 35 : else if (asRecords[nTestIndex].nKey > nKey) 114 17 : nMaxIndex = nTestIndex - 1; 115 : else 116 18 : break; 117 : } 118 : 119 18 : if (nMinIndex > nMaxIndex) 120 0 : return false; 121 : 122 : /* -------------------------------------------------------------------- */ 123 : /* Delete this record. */ 124 : /* -------------------------------------------------------------------- */ 125 18 : asRecords.erase(asRecords.begin() + nTestIndex); 126 : 127 18 : auto oIter = oMapKeyToRecord.find(nKey); 128 18 : CPLAssert(oIter != oMapKeyToRecord.end()); 129 18 : oMapKeyToRecord.erase(oIter); 130 : 131 18 : return true; 132 : } 133 : 134 : /************************************************************************/ 135 : /* Sort() */ 136 : /* */ 137 : /* Sort the records based on the key. */ 138 : /************************************************************************/ 139 : 140 715 : void DDFRecordIndex::Sort() const 141 : 142 : { 143 715 : if (bSorted) 144 0 : return; 145 : 146 715 : std::sort(asRecords.begin(), asRecords.end(), 147 214231 : [](const DDFIndexedRecord &a, const DDFIndexedRecord &b) 148 214231 : { return a.nKey < b.nKey; }); 149 : 150 715 : bSorted = true; 151 : } 152 : 153 : /************************************************************************/ 154 : /* GetByIndex() */ 155 : /************************************************************************/ 156 : 157 34485 : const DDFRecord *DDFRecordIndex::GetByIndex(int nIndex) const 158 : 159 : { 160 34485 : if (!bSorted) 161 707 : Sort(); 162 : 163 34485 : if (nIndex < 0 || nIndex >= GetCount()) 164 0 : return nullptr; 165 : 166 34485 : return asRecords[nIndex].poRecord.get(); 167 : } 168 : 169 : /************************************************************************/ 170 : /* GetClientInfoByIndex() */ 171 : /************************************************************************/ 172 : 173 331300 : const void *DDFRecordIndex::GetClientInfoByIndex(int nIndex) const 174 : 175 : { 176 331300 : if (!bSorted) 177 0 : Sort(); 178 : 179 331300 : if (nIndex < 0 || nIndex >= GetCount()) 180 0 : return nullptr; 181 : 182 331300 : return asRecords[nIndex].pClientData; 183 : } 184 : 185 : /************************************************************************/ 186 : /* SetClientInfoByIndex() */ 187 : /************************************************************************/ 188 : 189 7207 : void DDFRecordIndex::SetClientInfoByIndex(int nIndex, const void *pClientData) 190 : 191 : { 192 7207 : if (!bSorted) 193 0 : Sort(); 194 : 195 7207 : if (nIndex < 0 || nIndex >= GetCount()) 196 0 : return; 197 : 198 7207 : asRecords[nIndex].pClientData = pClientData; 199 : }