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