Loading...
Searching...
No Matches
index_generator.tpp
1/*---------------------------------------------------------------------------*\
2 *
3 * bitpit
4 *
5 * Copyright (C) 2015-2021 OPTIMAD engineering Srl
6 *
7 * -------------------------------------------------------------------------
8 * License
9 * This file is part of bitpit.
10 *
11 * bitpit is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License v3 (LGPL)
13 * as published by the Free Software Foundation.
14 *
15 * bitpit is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
18 * License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with bitpit. If not, see <http://www.gnu.org/licenses/>.
22 *
23\*---------------------------------------------------------------------------*/
24
25#ifndef __BITPIT_INDEX_GENERATOR_TPP__
26#define __BITPIT_INDEX_GENERATOR_TPP__
27
28namespace bitpit {
29
30template<typename id_t>
31const typename IndexGenerator<id_t>::id_type IndexGenerator<id_t>::NULL_ID = std::numeric_limits<typename IndexGenerator<id_t>::id_type>::min();
32
36template<typename id_t>
38 : m_latest(NULL_ID), m_lowest(NULL_ID), m_highest(NULL_ID)
39{
40
41}
42
51template<typename id_t>
52typename IndexGenerator<id_t>::id_type IndexGenerator<id_t>::generate()
54 // If the trash is empty generate a new id otherwise recycle the first id
55 // in the trash.
56 if (m_trash.empty()) {
57 if (m_lowest == NULL_ID) {
58 m_lowest = 0;
59 m_highest = 0;
60 m_latest = m_lowest;
61 } else if (m_lowest > 0) {
62 --m_lowest;
63 m_latest = m_lowest;
64 } else {
65 assert(m_highest < std::numeric_limits<id_type>::max());
66 ++m_highest;
67 m_latest = m_highest;
68 }
69 } else {
70 m_latest = *(m_trash.begin());
71 m_trash.erase(m_trash.begin());
72 }
73
74 return m_latest;
75}
76
82template<typename id_t>
83typename IndexGenerator<id_t>::id_type IndexGenerator<id_t>::getLatest()
84{
85 return m_latest;
86}
87
93template<typename id_t>
94typename IndexGenerator<id_t>::id_type IndexGenerator<id_t>::getHighest()
95{
96 return m_highest;
97}
98
104template<typename id_t>
106{
107 // If the latest id is valid, it is assigned by definition
108 if (m_latest >= 0 && id == m_latest) {
109 return true;
110 }
111
112 // Ids past the highest one are not assigned
113 if (id > m_highest) {
114 return false;
115 }
116
117 // Ids before the lowest one are not assigned
118 if (id < m_lowest) {
119 return false;
120 }
121
122 // The id is assigned only if is not in the trash
123 if (m_trash.count(id) > 0) {
124 return false;
125 }
126
127 return true;
128}
129
135template<typename id_t>
136void IndexGenerator<id_t>::setAssigned(typename IndexGenerator<id_t>::id_type id)
137{
138 // Check if the id has already been assigned
139 if (isAssigned(id)) {
140 throw std::runtime_error("Requested id has already been assigned.");
141 }
142
143 // If the id is past the highest assigned id we need to trash all the ids
144 // from the highest assigned to this one (the generator only handles
145 // contiguous ids), otherwise look for the id in the trash and, if found,
146 // recycle it (if the id is not in the trash, this means it was already
147 // an assigned id).
148 if (m_highest == NULL_ID && m_lowest == NULL_ID) {
149 m_lowest = id;
150 m_highest = id;
151 } else if (id > m_highest) {
152 typename std::set<id_type>::iterator trashIterator = m_trash.end();
153 for (id_type wasteId = m_highest + 1; wasteId < id; ++wasteId) {
154 trashIterator = m_trash.insert(trashIterator, wasteId);
155 }
156
157 m_highest = id;
158 } else if (id < m_lowest) {
159 typename std::set<id_type>::iterator trashIterator = m_trash.end();
160 for (id_type wasteId = id + 1; wasteId < m_lowest; ++wasteId) {
161 trashIterator = m_trash.insert(trashIterator, wasteId);
162 }
163
164 m_lowest = id;
165 } else {
166 assert(m_trash.count(id) > 0);
167 eraseFromTrash(id);
168 }
169
170 // This is the latest assigned id
171 m_latest = id;
172}
173
181template<typename id_t>
182void IndexGenerator<id_t>::trash(typename IndexGenerator<id_t>::id_type id)
183{
184 assert(id != NULL_ID);
185 assert(m_trash.count(id) == 0);
186 assert(id >= m_lowest && id <= m_highest);
187
188 // If we are trashing the highest or the lowest id we can update the
189 // limits of the generator, otherwise we add the id to the trash.
190 if (id == m_highest && id == m_lowest) {
191 // If highest and lowest values are equal it means that we have
192 // generated only one id. Since we are now trashing the only id
193 // that has been generated, the trash must be emtpy.
194 assert(m_trash.empty());
195
196 m_lowest = NULL_ID;
197 m_highest = NULL_ID;
198 } else if (id == m_highest) {
199 --m_highest;
200 auto trashIterator = m_trash.end();
201 while (!m_trash.empty()) {
202 --trashIterator;
203 if (*trashIterator != m_highest) {
204 break;
205 }
206
207 trashIterator = m_trash.erase(trashIterator);
208 if (m_highest != 0) {
209 --m_highest;
210 } else {
211 assert(m_trash.empty());
212 m_highest = NULL_ID;
213 break;
214 }
215 }
216 } else if (id == m_lowest) {
217 ++m_lowest;
218 auto trashIterator = m_trash.begin();
219 while (!m_trash.empty()) {
220 if (*trashIterator != m_lowest) {
221 break;
222 }
223
224 trashIterator = m_trash.erase(trashIterator);
225 ++m_lowest;
226 }
227 } else {
228 m_trash.insert(id);
229 }
230
231 // We only keep track of the latest assigned id, if we trash that id we
232 // have no information of the previous assigned id.
233 if (id == m_latest) {
234 m_latest = NULL_ID;
235 }
236}
237
241template<typename id_t>
243{
244 m_latest = NULL_ID;
245 m_lowest = NULL_ID;
246 m_highest = NULL_ID;
247
248 m_trash.clear();
249}
250
256template<typename id_t>
258{
259 // Erase the index
260 m_trash.erase(id);
261}
262
268template<typename id_t>
269int IndexGenerator<id_t>::getBinaryArchiveVersion() const
270{
271 return 1;
272}
273
279template<typename id_t>
280void IndexGenerator<id_t>::dump(std::ostream &stream) const
281{
282 utils::binary::write(stream, getBinaryArchiveVersion());
283 utils::binary::write(stream, m_latest);
284 utils::binary::write(stream, m_lowest);
285 utils::binary::write(stream, m_highest);
286
287 utils::binary::write(stream, m_trash.size());
288 for (id_type id : m_trash) {
289 utils::binary::write(stream, id);
290 }
291}
292
298template<typename id_t>
299void IndexGenerator<id_t>::restore(std::istream &stream)
300{
301 // Version
302 int version;
303 utils::binary::read(stream, version);
304 if (version != getBinaryArchiveVersion()) {
305 throw std::runtime_error ("The version of the file does not match the required version");
306 }
307
308 // Generator data
309 utils::binary::read(stream, m_latest);
310 utils::binary::read(stream, m_lowest);
311 utils::binary::read(stream, m_highest);
312
313 size_t nTrashedIds;
314 utils::binary::read(stream, nTrashedIds);
315
316 std::set<id_type>().swap(m_trash);
317
318 for (size_t i = 0; i < nTrashedIds; ++i) {
319 id_type id;
320 utils::binary::read(stream, id);
321 m_trash.insert(id);
322 }
323}
324
325}
326
327#endif
The IndexGenerator class allows to generate unique ids.
bool isAssigned(id_type id)
void setAssigned(id_type id)
void restore(std::istream &stream)
void dump(std::ostream &stream) const
std::array< T, d > min(const std::array< T, d > &x, const std::array< T, d > &y)
void write(std::ostream &stream, const std::vector< bool > &container)
void read(std::istream &stream, std::vector< bool > &container)
--- layout: doxygen_footer ---