1 (* Copyright (C) Doom 2D: Forever Developers
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, version 3 of the License ONLY.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *)
15 {$INCLUDE a_modes.inc}
16 {.$DEFINE IDPOOL_CHECKS}
19 interface
21 {$IFDEF USE_MEMPOOL}
22 uses
23 mempool;
24 {$ENDIF}
27 // ////////////////////////////////////////////////////////////////////////// //
28 type
29 //TODO: implement getting n sequential ids
31 public
34 private
35 type
40 private
46 private
55 public
61 // returns InvalidId if there are no more free ids (or throws)
64 // returns InvalidId if there are no more free ids (or throws)
67 // it is NOT ok to release already released id
73 public
85 implementation
87 uses
88 SysUtils;
91 // ////////////////////////////////////////////////////////////////////////// //
93 begin
101 begin
108 var
110 begin
113 begin
116 if (f > 0) and (mRanges[f-1].last >= mRanges[f].first) then raise Exception.Create('invalid range order');
117 if (f > 0) and (mRanges[f-1].last+1 = mRanges[f].first) then raise Exception.Create('unmerged ranges');
124 var
126 begin
128 begin
129 if (mRanges[f].first > mRanges[f].last) then begin dump(); raise Exception.Create('invalid range'); end;
132 if (f > 0) and (mRanges[f-1].last >= mRanges[f].first) then begin dump(); raise Exception.Create('invalid range order'); end;
133 if (f > 0) and (mRanges[f-1].last+1 = mRanges[f].first) then begin dump(); raise Exception.Create('unmerged ranges'); end;
139 begin
148 function TIdPool.getFreeIds (): Integer; inline; begin result := Integer(mMaxId+1-mUsedIds); end;
153 var
156 begin
159 // -1: not found
163 // yay! use binary search to find the range
167 begin
169 //!assert((mid >= 0) and (mid < len));
180 var
182 begin
192 var
194 begin
198 if (ii >= 0) then result := not ((aid >= mRanges[ii].first) and (aid <= mRanges[ii].last)) else result := true;
202 // returns InvalidId if there are no more free ids (or throws)
204 var
206 begin
208 begin
209 // no more ids
212 exit;
215 // delete first range?
217 begin
220 end
221 else
222 begin
230 // returns InvalidId if there are no more free ids (or throws)
232 var
234 begin
236 begin
237 // no more ids
240 exit;
242 // invalid?
244 begin
247 exit;
249 // find range with this id
252 begin
255 exit;
257 // always return requested id
259 // can we shrink range head?
261 begin
262 // yep; range with the only id?
264 begin
265 // delete this range
268 end
269 else
270 begin
275 exit;
277 // can we shrink range tail?
279 begin
280 // yep; simply shrink, 'cause range with one id was processed in the previous `if`
284 exit;
286 // split this range to two
297 // it is NOT ok to release already released id
299 var
301 begin
302 if (aid > mMaxId) then raise Exception.Create(Format('TIdPool: cannot release invalid id %u', [aid]));
303 // no available ids?
305 begin
306 // just create new range
313 exit;
315 // before first available id?
317 begin
318 // can we grow first range?
320 begin
321 // yep
323 end
324 else
325 begin
326 // nope, insert new first range
336 exit;
338 // after last available id?
340 begin
341 // can we grow last range?
343 begin
344 // yep
346 end
347 else
348 begin
349 // nope, insert new last range
358 exit;
360 // alas, no more easy cases; find the nearest range
362 if (ii < 0) then raise Exception.Create(Format('TIdPool: cannot release invalid id %u', [aid]));
363 if (aid >= mRanges[ii].first) and (aid <= mRanges[ii].last) then raise Exception.Create(Format('TIdPool: cannot release unallocated id %u', [aid]));
364 // ii should contain range where `first` is less than `aid`
367 {$IF DEFINED(IDPOOL_DEBUG_DUMPS)}writeln('aid=', aid, '; ii=', ii, ': [', mRanges[ii].first, '-', mRanges[ii].last, ']');{$ENDIF}
368 // can grow this range at the end?
370 begin
372 // yep; can merge ranges?
374 begin
375 // merge
380 end
381 else
382 begin
383 // change
385 {$IF DEFINED(IDPOOL_DEBUG_DUMPS)}if (ii+1 < mRangeUsed) then writeln(' ii+1=', ii+1, ': [', mRanges[ii+1].first, '-', mRanges[ii+1].last, ']');{$ENDIF}
390 exit;
392 // can grow next range at the start?
394 begin
395 // yep; can merge ranges?
397 begin
398 // merge
402 end
403 else
404 begin
405 // change
410 exit;
412 // cannot grow anything, insert empty range after ii