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, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *)
16 {$INCLUDE a_modes.inc}
17 {.$DEFINE IDPOOL_CHECKS}
20 interface
22 // ////////////////////////////////////////////////////////////////////////// //
23 type
24 //TODO: implement getting n sequential ids
26 public
29 private
30 type
35 private
41 private
50 public
56 // returns InvalidId if there are no more free ids (or throws)
59 // returns InvalidId if there are no more free ids (or throws)
62 // it is NOT ok to release already released id
68 public
80 implementation
82 uses
83 SysUtils;
86 // ////////////////////////////////////////////////////////////////////////// //
88 begin
96 begin
103 var
105 begin
108 begin
111 if (f > 0) and (mRanges[f-1].last >= mRanges[f].first) then raise Exception.Create('invalid range order');
112 if (f > 0) and (mRanges[f-1].last+1 = mRanges[f].first) then raise Exception.Create('unmerged ranges');
119 var
121 begin
123 begin
124 if (mRanges[f].first > mRanges[f].last) then begin dump(); raise Exception.Create('invalid range'); end;
127 if (f > 0) and (mRanges[f-1].last >= mRanges[f].first) then begin dump(); raise Exception.Create('invalid range order'); end;
128 if (f > 0) and (mRanges[f-1].last+1 = mRanges[f].first) then begin dump(); raise Exception.Create('unmerged ranges'); end;
134 begin
143 function TIdPool.getFreeIds (): Integer; inline; begin result := Integer(mMaxId+1-mUsedIds); end;
148 var
151 begin
154 // -1: not found
158 // yay! use binary search to find the range
162 begin
164 //!assert((mid >= 0) and (mid < len));
175 var
177 begin
187 var
189 begin
193 if (ii >= 0) then result := not ((aid >= mRanges[ii].first) and (aid <= mRanges[ii].last)) else result := true;
197 // returns InvalidId if there are no more free ids (or throws)
199 var
201 begin
203 begin
204 // no more ids
207 exit;
210 // delete first range?
212 begin
215 end
216 else
217 begin
225 // returns InvalidId if there are no more free ids (or throws)
227 var
229 begin
231 begin
232 // no more ids
235 exit;
237 // invalid?
239 begin
242 exit;
244 // find range with this id
247 begin
250 exit;
252 // always return requested id
254 // can we shrink range head?
256 begin
257 // yep; range with the only id?
259 begin
260 // delete this range
263 end
264 else
265 begin
270 exit;
272 // can we shrink range tail?
274 begin
275 // yep; simply shrink, 'cause range with one id was processed in the previous `if`
279 exit;
281 // split this range to two
292 // it is NOT ok to release already released id
294 var
296 begin
297 if (aid > mMaxId) then raise Exception.Create(Format('TIdPool: cannot release invalid id %u', [aid]));
298 // no available ids?
300 begin
301 // just create new range
308 exit;
310 // before first available id?
312 begin
313 // can we grow first range?
315 begin
316 // yep
318 end
319 else
320 begin
321 // nope, insert new first range
331 exit;
333 // after last available id?
335 begin
336 // can we grow last range?
338 begin
339 // yep
341 end
342 else
343 begin
344 // nope, insert new last range
353 exit;
355 // alas, no more easy cases; find the nearest range
357 if (ii < 0) then raise Exception.Create(Format('TIdPool: cannot release invalid id %u', [aid]));
358 if (aid >= mRanges[ii].first) and (aid <= mRanges[ii].last) then raise Exception.Create(Format('TIdPool: cannot release unallocated id %u', [aid]));
359 // ii should contain range where `first` is less than `aid`
362 {$IF DEFINED(IDPOOL_DEBUG_DUMPS)}writeln('aid=', aid, '; ii=', ii, ': [', mRanges[ii].first, '-', mRanges[ii].last, ']');{$ENDIF}
363 // can grow this range at the end?
365 begin
367 // yep; can merge ranges?
369 begin
370 // merge
375 end
376 else
377 begin
378 // change
380 {$IF DEFINED(IDPOOL_DEBUG_DUMPS)}if (ii+1 < mRangeUsed) then writeln(' ii+1=', ii+1, ': [', mRanges[ii+1].first, '-', mRanges[ii+1].last, ']');{$ENDIF}
385 exit;
387 // can grow next range at the start?
389 begin
390 // yep; can merge ranges?
392 begin
393 // merge
397 end
398 else
399 begin
400 // change
405 exit;
407 // cannot grow anything, insert empty range after ii