1 //------------------------------------------------------------------------
2 // SELECTION SET
3 //------------------------------------------------------------------------
4 //
5 // Eureka DOOM Editor
6 //
7 // Copyright (C) 2001-2019 Andrew Apted
8 // Copyright (C) 1997-2003 André Majorel et al
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 //------------------------------------------------------------------------
21 //
22 // Based on Yadex which incorporated code from DEU 5.21 that was put
23 // in the public domain in 1994 by Raphaël Quinet and Brendon Wyber.
24 //
25 //------------------------------------------------------------------------
26
27 #include "main.h"
28
29 #include "m_select.h"
30 #include "e_objects.h"
31
32
33 //#define NEED_SLOW_CLEAR
34
35 #define INITIAL_BITVEC_SIZE 1024
36 #define INITIAL_EXTENDED_SIZE 256
37
38
selection_c(obj_type_e _type,bool _extended)39 selection_c::selection_c(obj_type_e _type, bool _extended) :
40 type(_type),
41 count(0), bv(NULL),
42 extended(NULL), ext_size(0),
43 maxobj(-1), first_obj(-1)
44 {
45 if (_extended)
46 {
47 ext_size = INITIAL_EXTENDED_SIZE;
48 extended = new byte[ext_size];
49
50 memset(extended, 0, (size_t)ext_size);
51 }
52 }
53
~selection_c()54 selection_c::~selection_c()
55 {
56 if (bv)
57 delete bv;
58
59 if (extended)
60 delete[] extended;
61 }
62
63
change_type(obj_type_e new_type)64 void selection_c::change_type(obj_type_e new_type)
65 {
66 type = new_type;
67
68 clear_all();
69 }
70
71
empty() const72 bool selection_c::empty() const
73 {
74 return count == 0;
75 }
76
77
count_obj() const78 int selection_c::count_obj() const
79 {
80 return count;
81 }
82
83
get(int n) const84 bool selection_c::get(int n) const
85 {
86 if (extended)
87 return get_ext(n) != 0;
88
89 if (bv)
90 return bv->get(n);
91
92 for (int i = 0 ; i < count ; i++)
93 if (objs[i] == n)
94 return true;
95
96 return false;
97 }
98
99
set(int n)100 void selection_c::set(int n)
101 {
102 if (extended)
103 {
104 set_ext(n, 1);
105 return;
106 }
107
108 if (get(n))
109 return;
110
111 if (maxobj < n)
112 maxobj = n;
113
114 if (first_obj < 0 && empty())
115 first_obj = n;
116
117 if (!bv && count >= MAX_STORE_SEL)
118 {
119 ConvertToBitvec();
120 }
121
122 if (bv)
123 {
124 bv->set(n);
125 count++;
126 return;
127 }
128
129 objs[count++] = n;
130 }
131
132
clear(int n)133 void selection_c::clear(int n)
134 {
135 if (extended)
136 {
137 if (get_ext(n) == 0)
138 return;
139
140 // n should be safe to access directly, due to above check
141 extended[n] = 0;
142 count--;
143 }
144 else if (bv)
145 {
146 if (! get(n))
147 return;
148
149 bv->clear(n);
150 count--;
151 }
152 else
153 {
154 int i;
155
156 for (i = 0 ; i < count ; i++)
157 if (objs[i] == n)
158 break;
159
160 if (i >= count)
161 return; // not present
162
163 count--;
164
165 #ifdef NEED_SLOW_CLEAR
166 for ( ; i < count ; i++)
167 objs[i] = objs[i+1];
168 #else
169 if (i < count)
170 objs[i] = objs[count];
171 #endif
172 }
173
174 if (maxobj == n)
175 RecomputeMaxObj();
176
177 if (first_obj == n)
178 first_obj = -1;
179 }
180
181
toggle(int n)182 void selection_c::toggle(int n)
183 {
184 if (get(n))
185 clear(n);
186 else
187 set(n);
188 }
189
190
clear_all()191 void selection_c::clear_all()
192 {
193 count = 0;
194 maxobj = -1;
195 first_obj = -1;
196
197 if (extended)
198 {
199 memset(extended, 0, (size_t)ext_size);
200 }
201 else if (bv)
202 {
203 delete bv;
204 bv = NULL;
205 }
206 }
207
208
get_ext(int n) const209 byte selection_c::get_ext(int n) const
210 {
211 if (! extended)
212 return get(n) ? 255 : 0;
213
214 if (n >= ext_size)
215 return 0;
216
217 return extended[n];
218 }
219
220
set_ext(int n,byte value)221 void selection_c::set_ext(int n, byte value)
222 {
223 // set_ext() should not be used with plain selections
224 if (! extended)
225 return;
226
227 if (value == 0)
228 {
229 clear(n);
230 return;
231 }
232
233 if (maxobj < n)
234 maxobj = n;
235
236 if (first_obj < 0 && empty())
237 first_obj = n;
238
239 // need to resize the array?
240 while (n >= ext_size)
241 {
242 ResizeExtended(ext_size * 2);
243 }
244
245 if (extended[n] == 0)
246 count++;
247
248 extended[n] = value;
249 }
250
251
frob(int n,sel_op_e op)252 void selection_c::frob(int n, sel_op_e op)
253 {
254 switch (op)
255 {
256 case BOP_ADD: set(n); break;
257 case BOP_REMOVE: clear(n); break;
258 default: toggle(n); break;
259 }
260 }
261
262
frob_range(int n1,int n2,sel_op_e op)263 void selection_c::frob_range(int n1, int n2, sel_op_e op)
264 {
265 for ( ; n1 <= n2 ; n1++)
266 {
267 frob(n1, op);
268 }
269 }
270
271
merge(const selection_c & other)272 void selection_c::merge(const selection_c& other)
273 {
274 if (extended && other.extended)
275 {
276 for (int i = 0 ; i <= other.maxobj ; i++)
277 {
278 byte value = other.get_ext(i);
279
280 set_ext(i, get_ext(i) | value);
281 }
282 }
283 else if (other.bv || other.extended)
284 {
285 for (int i = 0 ; i <= other.maxobj ; i++)
286 if (other.get(i) && !get(i))
287 set(i);
288 }
289 else
290 {
291 for (int i = 0 ; i < other.count ; i++)
292 if (!get(other.objs[i]))
293 set(other.objs[i]);
294 }
295 }
296
297
unmerge(const selection_c & other)298 void selection_c::unmerge(const selection_c& other)
299 {
300 if (other.bv || other.extended)
301 {
302 for (int i = 0 ; i <= other.maxobj ; i++)
303 if (other.get(i))
304 clear(i);
305 }
306 else
307 {
308 for (int i = 0 ; i < other.count ; i++)
309 clear(other.objs[i]);
310 }
311 }
312
313
intersect(const selection_c & other)314 void selection_c::intersect(const selection_c& other)
315 {
316 for (int i = 0 ; i <= maxobj ; i++)
317 if (get(i) && !other.get(i))
318 clear(i);
319 }
320
321
test_equal(const selection_c & other)322 bool selection_c::test_equal(const selection_c& other)
323 {
324 if (type != other.type)
325 return false;
326
327 if (maxobj != other.maxobj)
328 return false;
329
330 if (count_obj() != other.count_obj())
331 return false;
332
333 // the quick tests have passed, now perform the expensive one
334
335 for (sel_iter_c it(this) ; !it.done() ; it.next())
336 if (! other.get(*it))
337 return false;
338
339 return true;
340 }
341
342
ConvertToBitvec()343 void selection_c::ConvertToBitvec()
344 {
345 SYS_ASSERT(! bv);
346
347 int size = INITIAL_BITVEC_SIZE;
348
349 if (size < maxobj+1)
350 size = maxobj+1;
351
352 bv = new bitvec_c(size);
353
354 for (int i = 0 ; i < count ; i++)
355 {
356 bv->set(objs[i]);
357 }
358 }
359
360
RecomputeMaxObj()361 void selection_c::RecomputeMaxObj()
362 {
363 maxobj = -1;
364
365 if (extended)
366 {
367 // search backwards so we can early out
368 for (int i = ext_size-1 ; i >= 0 ; i--)
369 {
370 if (get_ext(i))
371 {
372 maxobj = i;
373 break;
374 }
375 }
376 }
377 else if (bv)
378 {
379 // search backwards so we can early out
380 for (int i = bv->size()-1 ; i >= 0 ; i--)
381 {
382 if (bv->get(i))
383 {
384 maxobj = i;
385 break;
386 }
387 }
388 }
389 else
390 {
391 // cannot optimise here, values are not sorted
392 for (int i = 0 ; i < count ; i++)
393 {
394 maxobj = MAX(maxobj, objs[i]);
395 }
396 }
397 }
398
399
ResizeExtended(int new_size)400 void selection_c::ResizeExtended(int new_size)
401 {
402 SYS_ASSERT(new_size > 0);
403
404 byte *d = new byte[new_size];
405
406 // copy existing values
407 memcpy(d, extended, (size_t)MIN(ext_size, new_size));
408
409 // clear values at top end
410 if (new_size > ext_size)
411 memset(d+ext_size, 0, (size_t)(new_size - ext_size));
412
413 delete[] extended;
414
415 extended = d;
416 ext_size = new_size;
417 }
418
419
find_first() const420 int selection_c::find_first() const
421 {
422 if (first_obj >= 0)
423 {
424 SYS_ASSERT(get(first_obj));
425
426 return first_obj;
427 }
428
429 sel_iter_c it(this);
430
431 return it.done() ? -1 : *it;
432 }
433
434
find_second() const435 int selection_c::find_second() const
436 {
437 sel_iter_c it(this);
438
439 if (it.done())
440 return -1;
441
442 // the logic here is trickier than it looks.
443 //
444 // When first_obj exists AND is the same as the very first object
445 // in the group, then this test fails and we move onto the next
446 // object in the group.
447 if (first_obj >= 0 && *it != first_obj)
448 return *it;
449
450 it.next();
451
452 return it.done() ? -1 : *it;
453 }
454
455
456 //------------------------------------------------------------------------
457 // ITERATOR STUFF
458 //------------------------------------------------------------------------
459
sel_iter_c()460 sel_iter_c::sel_iter_c()
461 {
462 // dummy values -- cannot use a bare iterator
463 sel = NULL;
464 pos = -777777;
465 }
466
467
sel_iter_c(const sel_iter_c & other)468 sel_iter_c::sel_iter_c(const sel_iter_c& other)
469 {
470 sel = other.sel;
471 pos = other.pos;
472 }
473
474
sel_iter_c(const selection_c * _sel)475 sel_iter_c::sel_iter_c(const selection_c *_sel)
476 {
477 sel = _sel;
478 pos = 0;
479
480 if (sel->bv || sel->extended)
481 {
482 // for bit vector, need to find the first one bit.
483 // Note: this logic is slightly hacky...
484
485 pos = -1; next();
486 }
487 }
488
489
sel_iter_c(const selection_c & _sel)490 sel_iter_c::sel_iter_c(const selection_c& _sel)
491 {
492 sel = &_sel;
493 pos = 0;
494
495 if (sel->bv || sel->extended)
496 {
497 pos = -1; next();
498 }
499 }
500
501
done() const502 bool sel_iter_c::done() const
503 {
504 SYS_ASSERT(sel);
505
506 if (sel->extended)
507 return (pos >= sel->ext_size);
508 else if (sel->bv)
509 return (pos >= sel->bv->size());
510 else
511 return (pos >= sel->count);
512 }
513
514
operator *() const515 int sel_iter_c::operator* () const
516 {
517 SYS_ASSERT(sel);
518
519 if (sel->bv || sel->extended)
520 return pos;
521 else
522 return sel->objs[pos];
523 }
524
525
next()526 void sel_iter_c::next()
527 {
528 SYS_ASSERT(sel);
529
530 pos++;
531
532 if (sel->extended)
533 {
534 while (pos < sel->ext_size && sel->extended[pos] == 0)
535 pos++;
536 }
537 else if (sel->bv)
538 {
539 // this could be optimised....
540 while (pos < sel->bv->size() && !sel->bv->get(pos))
541 pos++;
542 }
543 }
544
545
546 //--- editor settings ---
547 // vi:ts=4:sw=4:noexpandtab
548