2 /*--------------------------------------------------------------------*/
3 /*--- Sets of words, with unique set identifiers. ---*/
4 /*--- hg_wordset.c ---*/
5 /*--------------------------------------------------------------------*/
8 This file is part of Helgrind, a Valgrind tool for detecting errors
11 Copyright (C) 2007-2017 OpenWorks LLP
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, see <http://www.gnu.org/licenses/>.
27 The GNU General Public License is contained in the file COPYING.
29 Neither the names of the U.S. Department of Energy nor the
30 University of California nor the names of its contributors may be
31 used to endorse or promote products derived from this software
32 without prior written permission.
35 #include "pub_tool_basics.h"
36 #include "pub_tool_libcassert.h"
37 #include "pub_tool_libcbase.h"
38 #include "pub_tool_libcprint.h"
39 #include "pub_tool_threadstate.h"
40 #include "pub_tool_wordfm.h"
42 #include "hg_basics.h"
43 #include "hg_wordset.h" /* self */
45 // define to 1 to have (a lot of) debugging of add/re-use/die WSU entries.
48 //------------------------------------------------------------------//
49 //--- Word Cache ---//
50 //------------------------------------------------------------------//
53 struct { UWord arg1
; UWord arg2
; UWord res
; }
56 /* Each cache is a fixed sized array of N_WCACHE_STAT_MAX entries.
57 However only the first .dynMax are used. This is because at some
58 point, expanding the cache further overall gives a slowdown because
59 searching more entries more than negates any performance advantage
60 from caching those entries in the first place. Hence use .dynMax
61 to allow the size of the cache(s) to be set differently for each
62 different WordSetU. */
63 #define N_WCACHE_STAT_MAX 32
66 WCacheEnt ent
[N_WCACHE_STAT_MAX
];
67 UWord dynMax
; /* 1 .. N_WCACHE_STAT_MAX inclusive */
68 UWord inUse
; /* 0 .. dynMax inclusive */
72 #define WCache_INIT(_zzcache,_zzdynmax) \
74 tl_assert((_zzdynmax) >= 1); \
75 tl_assert((_zzdynmax) <= N_WCACHE_STAT_MAX); \
76 (_zzcache).dynMax = (_zzdynmax); \
77 (_zzcache).inUse = 0; \
80 #define WCache_LOOKUP_AND_RETURN(_retty,_zzcache,_zzarg1,_zzarg2) \
83 UWord _arg1 = (UWord)(_zzarg1); \
84 UWord _arg2 = (UWord)(_zzarg2); \
85 WCache* _cache = &(_zzcache); \
86 tl_assert(_cache->dynMax >= 1); \
87 tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX); \
88 tl_assert(_cache->inUse <= _cache->dynMax); \
89 if (_cache->inUse > 0) { \
90 if (_cache->ent[0].arg1 == _arg1 \
91 && _cache->ent[0].arg2 == _arg2) \
92 return (_retty)_cache->ent[0].res; \
93 for (_i = 1; _i < _cache->inUse; _i++) { \
94 if (_cache->ent[_i].arg1 == _arg1 \
95 && _cache->ent[_i].arg2 == _arg2) { \
96 WCacheEnt tmp = _cache->ent[_i-1]; \
97 _cache->ent[_i-1] = _cache->ent[_i]; \
98 _cache->ent[_i] = tmp; \
99 return (_retty)_cache->ent[_i-1].res; \
105 #define WCache_UPDATE(_zzcache,_zzarg1,_zzarg2,_zzresult) \
108 UWord _arg1 = (UWord)(_zzarg1); \
109 UWord _arg2 = (UWord)(_zzarg2); \
110 UWord _res = (UWord)(_zzresult); \
111 WCache* _cache = &(_zzcache); \
112 tl_assert(_cache->dynMax >= 1); \
113 tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX); \
114 tl_assert(_cache->inUse <= _cache->dynMax); \
115 if (_cache->inUse < _cache->dynMax) \
117 for (_i = _cache->inUse-1; _i >= 1; _i--) \
118 _cache->ent[_i] = _cache->ent[_i-1]; \
119 _cache->ent[0].arg1 = _arg1; \
120 _cache->ent[0].arg2 = _arg2; \
121 _cache->ent[0].res = _res; \
125 //------------------------------------------------------------------//
127 //--- Implementation ---//
128 //------------------------------------------------------------------//
132 WordSetU
* owner
; /* for sanity checking */
134 UWord size
; /* Really this should be SizeT */
138 /* ix2vec[0 .. ix2vec_used-1] are pointers to the lock sets (WordVecs)
139 really. vec2ix is the inverse mapping, mapping WordVec* to the
140 corresponding ix2vec entry number. The two mappings are mutually
143 If a WordVec WV is marked as dead by HG(dieWS), WV is removed from
144 vec2ix. The entry of the dead WVs in ix2vec are used to maintain a
145 linked list of free (to be re-used) ix2vec entries. */
147 void* (*alloc
)(const HChar
*,SizeT
);
149 void (*dealloc
)(void*);
150 WordFM
* vec2ix
; /* WordVec-to-WordSet mapping tree */
151 WordVec
** ix2vec
; /* WordSet-to-WordVec mapping array */
154 WordVec
** ix2vec_free
;
155 WordSet empty
; /* cached, for speed */
156 /* Caches for some operations */
158 WCache cache_delFrom
;
159 WCache cache_intersect
;
163 UWord n_add_uncached
;
165 UWord n_del_uncached
;
169 UWord n_intersect_uncached
;
171 UWord n_minus_uncached
;
176 UWord n_anyElementOf
;
180 /* Create a new WordVec of the given size. */
182 static WordVec
* new_WV_of_size ( WordSetU
* wsu
, UWord sz
)
185 wv
= wsu
->alloc( wsu
->cc
, sizeof(WordVec
) );
190 wv
->words
= wsu
->alloc( wsu
->cc
, (SizeT
)sz
* sizeof(UWord
) );
195 static void delete_WV ( WordVec
* wv
)
197 void (*dealloc
)(void*) = wv
->owner
->dealloc
;
203 static void delete_WV_for_FM ( UWord wv
) {
204 delete_WV( (WordVec
*)wv
);
207 static Word
cmp_WordVecs_for_FM ( UWord wv1W
, UWord wv2W
)
210 WordVec
* wv1
= (WordVec
*)wv1W
;
211 WordVec
* wv2
= (WordVec
*)wv2W
;
213 // WordVecs with smaller size are smaller.
214 if (wv1
->size
< wv2
->size
) {
217 if (wv1
->size
> wv2
->size
) {
221 // Sizes are equal => order based on content.
222 for (i
= 0; i
< wv1
->size
; i
++) {
223 if (wv1
->words
[i
] == wv2
->words
[i
])
225 if (wv1
->words
[i
] < wv2
->words
[i
])
227 if (wv1
->words
[i
] > wv2
->words
[i
])
231 return 0; /* identical */
234 static void ensure_ix2vec_space ( WordSetU
* wsu
)
238 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
239 if (wsu
->ix2vec_used
< wsu
->ix2vec_size
)
241 new_sz
= 2 * wsu
->ix2vec_size
;
242 if (new_sz
== 0) new_sz
= 1;
243 new_vec
= wsu
->alloc( wsu
->cc
, new_sz
* sizeof(WordVec
*) );
245 for (i
= 0; i
< wsu
->ix2vec_size
; i
++)
246 new_vec
[i
] = wsu
->ix2vec
[i
];
248 wsu
->dealloc(wsu
->ix2vec
);
249 wsu
->ix2vec
= new_vec
;
250 wsu
->ix2vec_size
= new_sz
;
253 /* True if wv is a dead entry (i.e. is in the linked list of free to be re-used
254 entries in ix2vec). */
255 static inline Bool
is_dead ( WordSetU
* wsu
, WordVec
* wv
)
257 if (wv
== NULL
) /* last element in free linked list in ix2vec */
260 return (WordVec
**)wv
>= &(wsu
->ix2vec
[1])
261 && (WordVec
**)wv
< &(wsu
->ix2vec
[wsu
->ix2vec_size
]);
263 /* Index into a WordSetU, doing the obvious range check. Failure of
264 the assertions marked XXX and YYY is an indication of passing the
265 wrong WordSetU* in the public API of this module.
266 Accessing a dead ws will assert. */
267 static WordVec
* do_ix2vec ( WordSetU
* wsu
, WordSet ws
)
270 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
271 if (wsu
->ix2vec_used
> 0)
272 tl_assert(wsu
->ix2vec
);
273 /* If this assertion fails, it may mean you supplied a 'ws'
274 that does not come from the 'wsu' universe. */
275 tl_assert(ws
< wsu
->ix2vec_used
); /* XXX */
276 wv
= wsu
->ix2vec
[ws
];
277 /* Make absolutely sure that 'ws' is a non dead member of 'wsu'. */
279 tl_assert(!is_dead(wsu
,wv
));
280 tl_assert(wv
->owner
== wsu
); /* YYY */
284 /* Same as do_ix2vec but returns NULL for a dead ws. */
285 static WordVec
* do_ix2vec_with_dead ( WordSetU
* wsu
, WordSet ws
)
288 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
289 if (wsu
->ix2vec_used
> 0)
290 tl_assert(wsu
->ix2vec
);
291 /* If this assertion fails, it may mean you supplied a 'ws'
292 that does not come from the 'wsu' universe. */
293 tl_assert(ws
< wsu
->ix2vec_used
); /* XXX */
294 wv
= wsu
->ix2vec
[ws
];
295 /* Make absolutely sure that 'ws' is either dead or a member of 'wsu'. */
299 tl_assert(wv
->owner
== wsu
); /* YYY */
303 /* See if wv is contained within wsu. If so, deallocate wv and return
304 the index of the already-present copy. If not, add wv to both the
305 vec2ix and ix2vec mappings and return its index.
307 static WordSet
add_or_dealloc_WordVec( WordSetU
* wsu
, WordVec
* wv_new
)
311 UWord
/*Set*/ ix_old
= -1;
312 /* Really WordSet, but need something that can safely be casted to
313 a Word* in the lookupFM. Making it WordSet (which is 32 bits)
314 causes failures on a 64-bit platform. */
315 tl_assert(wv_new
->owner
== wsu
);
316 have
= VG_(lookupFM
)( wsu
->vec2ix
,
317 (UWord
*)&wv_old
, (UWord
*)&ix_old
,
320 tl_assert(wv_old
!= wv_new
);
322 tl_assert(wv_old
->owner
== wsu
);
323 tl_assert(ix_old
< wsu
->ix2vec_used
);
324 tl_assert(wsu
->ix2vec
[ix_old
] == wv_old
);
326 return (WordSet
)ix_old
;
327 } else if (wsu
->ix2vec_free
) {
329 tl_assert(is_dead(wsu
,(WordVec
*)wsu
->ix2vec_free
));
330 ws
= wsu
->ix2vec_free
- &(wsu
->ix2vec
[0]);
331 tl_assert(wsu
->ix2vec
[ws
] == NULL
|| is_dead(wsu
,wsu
->ix2vec
[ws
]));
332 wsu
->ix2vec_free
= (WordVec
**) wsu
->ix2vec
[ws
];
333 wsu
->ix2vec
[ws
] = wv_new
;
334 VG_(addToFM
)( wsu
->vec2ix
, (UWord
)wv_new
, ws
);
335 if (HG_DEBUG
) VG_(printf
)("aodW %s re-use free %d %p\n", wsu
->cc
, (Int
)ws
, wv_new
);
338 ensure_ix2vec_space( wsu
);
339 tl_assert(wsu
->ix2vec
);
340 tl_assert(wsu
->ix2vec_used
< wsu
->ix2vec_size
);
341 wsu
->ix2vec
[wsu
->ix2vec_used
] = wv_new
;
342 VG_(addToFM
)( wsu
->vec2ix
, (Word
)wv_new
, (Word
)wsu
->ix2vec_used
);
343 if (HG_DEBUG
) VG_(printf
)("aodW %s %d %p\n", wsu
->cc
, (Int
)wsu
->ix2vec_used
, wv_new
);
345 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
346 return (WordSet
)(wsu
->ix2vec_used
- 1);
351 WordSetU
* HG_(newWordSetU
) ( void* (*alloc_nofail
)( const HChar
*, SizeT
),
353 void (*dealloc
)(void*),
359 wsu
= alloc_nofail( cc
, sizeof(WordSetU
) );
360 VG_(memset
)( wsu
, 0, sizeof(WordSetU
) );
361 wsu
->alloc
= alloc_nofail
;
363 wsu
->dealloc
= dealloc
;
364 wsu
->vec2ix
= VG_(newFM
)( alloc_nofail
, cc
,
365 dealloc
, cmp_WordVecs_for_FM
);
366 wsu
->ix2vec_used
= 0;
367 wsu
->ix2vec_size
= 0;
369 wsu
->ix2vec_free
= NULL
;
370 WCache_INIT(wsu
->cache_addTo
, cacheSize
);
371 WCache_INIT(wsu
->cache_delFrom
, cacheSize
);
372 WCache_INIT(wsu
->cache_intersect
, cacheSize
);
373 WCache_INIT(wsu
->cache_minus
, cacheSize
);
374 empty
= new_WV_of_size( wsu
, 0 );
375 wsu
->empty
= add_or_dealloc_WordVec( wsu
, empty
);
380 void HG_(deleteWordSetU
) ( WordSetU
* wsu
)
382 void (*dealloc
)(void*) = wsu
->dealloc
;
383 tl_assert(wsu
->vec2ix
);
384 VG_(deleteFM
)( wsu
->vec2ix
, delete_WV_for_FM
, NULL
/*val-finalizer*/ );
386 dealloc(wsu
->ix2vec
);
390 WordSet
HG_(emptyWS
) ( WordSetU
* wsu
)
395 Bool
HG_(isEmptyWS
) ( WordSetU
* wsu
, WordSet ws
)
397 WordVec
* wv
= do_ix2vec( wsu
, ws
);
400 tl_assert(ws
== wsu
->empty
);
403 tl_assert(ws
!= wsu
->empty
);
408 Bool
HG_(isSingletonWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
412 wsu
->n_isSingleton
++;
413 wv
= do_ix2vec( wsu
, ws
);
414 return (Bool
)(wv
->size
== 1 && wv
->words
[0] == w
);
417 UWord
HG_(cardinalityWS
) ( WordSetU
* wsu
, WordSet ws
)
421 wv
= do_ix2vec( wsu
, ws
);
425 UWord
HG_(anyElementOfWS
) ( WordSetU
* wsu
, WordSet ws
)
429 wsu
->n_anyElementOf
++;
430 wv
= do_ix2vec( wsu
, ws
);
431 tl_assert(wv
->size
>= 1);
435 UWord
HG_(cardinalityWSU
) ( WordSetU
* wsu
)
438 return wsu
->ix2vec_used
;
441 void HG_(getPayloadWS
) ( /*OUT*/UWord
** words
, /*OUT*/UWord
* nWords
,
442 WordSetU
* wsu
, WordSet ws
)
445 if (HG_DEBUG
) VG_(printf
)("getPayloadWS %s %d\n", wsu
->cc
, (Int
)ws
);
447 wv
= do_ix2vec( wsu
, ws
);
452 void HG_(dieWS
) ( WordSetU
* wsu
, WordSet ws
)
454 WordVec
* wv
= do_ix2vec_with_dead( wsu
, ws
);
455 WordVec
* wv_in_vec2ix
;
456 UWord
/*Set*/ wv_ix
= -1;
458 if (HG_DEBUG
) VG_(printf
)("dieWS %s %d %p\n", wsu
->cc
, (Int
)ws
, wv
);
461 return; // we never die the empty set.
464 return; // already dead. (or a bug ?).
469 wsu
->ix2vec
[ws
] = (WordVec
*) wsu
->ix2vec_free
;
470 wsu
->ix2vec_free
= &wsu
->ix2vec
[ws
];
472 VG_(delFromFM
) ( wsu
->vec2ix
,
473 (UWord
*)&wv_in_vec2ix
, (UWord
*)&wv_ix
,
476 if (HG_DEBUG
) VG_(printf
)("dieWS wv_ix %d\n", (Int
)wv_ix
);
478 tl_assert (wv_ix
== ws
);
482 wsu
->cache_addTo
.inUse
= 0;
483 wsu
->cache_delFrom
.inUse
= 0;
484 wsu
->cache_intersect
.inUse
= 0;
485 wsu
->cache_minus
.inUse
= 0;
488 Bool
HG_(plausibleWS
) ( WordSetU
* wsu
, WordSet ws
)
490 if (wsu
== NULL
) return False
;
491 if (ws
>= wsu
->ix2vec_used
)
496 Bool
HG_(saneWS_SLOW
) ( WordSetU
* wsu
, WordSet ws
)
500 if (wsu
== NULL
) return False
;
501 if (ws
< 0 || ws
>= wsu
->ix2vec_used
)
503 wv
= do_ix2vec( wsu
, ws
);
504 /* can never happen .. do_ix2vec will assert instead. Oh well. */
505 if (wv
->owner
!= wsu
) return False
;
506 if (wv
->size
< 0) return False
;
508 for (i
= 0; i
< wv
->size
-1; i
++) {
509 if (wv
->words
[i
] >= wv
->words
[i
+1])
516 Bool
HG_(elemWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
519 WordVec
* wv
= do_ix2vec( wsu
, ws
);
521 for (i
= 0; i
< wv
->size
; i
++) {
522 if (wv
->words
[i
] == w
)
528 WordSet
HG_(doubletonWS
) ( WordSetU
* wsu
, UWord w1
, UWord w2
)
533 wv
= new_WV_of_size(wsu
, 1);
537 wv
= new_WV_of_size(wsu
, 2);
543 wv
= new_WV_of_size(wsu
, 2);
547 return add_or_dealloc_WordVec( wsu
, wv
);
550 WordSet
HG_(singletonWS
) ( WordSetU
* wsu
, UWord w
)
552 return HG_(doubletonWS
)( wsu
, w
, w
);
555 WordSet
HG_(isSubsetOf
) ( WordSetU
* wsu
, WordSet small
, WordSet big
)
558 return small
== HG_(intersectWS
)( wsu
, small
, big
);
561 void HG_(ppWS
) ( WordSetU
* wsu
, WordSet ws
)
566 wv
= do_ix2vec( wsu
, ws
);
568 for (i
= 0; i
< wv
->size
; i
++) {
569 VG_(printf
)("%p", (void*)wv
->words
[i
]);
576 void HG_(ppWSUstats
) ( WordSetU
* wsu
, const HChar
* name
)
578 VG_(printf
)(" WordSet \"%s\":\n", name
);
579 VG_(printf
)(" addTo %10lu (%lu uncached)\n",
580 wsu
->n_add
, wsu
->n_add_uncached
);
581 VG_(printf
)(" delFrom %10lu (%lu uncached)\n",
582 wsu
->n_del
, wsu
->n_del_uncached
);
583 VG_(printf
)(" union %10lu\n", wsu
->n_union
);
584 VG_(printf
)(" intersect %10lu (%lu uncached) "
585 "[nb. incl isSubsetOf]\n",
586 wsu
->n_intersect
, wsu
->n_intersect_uncached
);
587 VG_(printf
)(" minus %10lu (%lu uncached)\n",
588 wsu
->n_minus
, wsu
->n_minus_uncached
);
589 VG_(printf
)(" elem %10lu\n", wsu
->n_elem
);
590 VG_(printf
)(" doubleton %10lu\n", wsu
->n_doubleton
);
591 VG_(printf
)(" isEmpty %10lu\n", wsu
->n_isEmpty
);
592 VG_(printf
)(" isSingleton %10lu\n", wsu
->n_isSingleton
);
593 VG_(printf
)(" anyElementOf %10lu\n", wsu
->n_anyElementOf
);
594 VG_(printf
)(" isSubsetOf %10lu\n", wsu
->n_isSubsetOf
);
595 VG_(printf
)(" dieWS %10lu\n", wsu
->n_die
);
598 WordSet
HG_(addToWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
603 WordSet result
= (WordSet
)(-1); /* bogus */
606 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_addTo
, ws
, w
);
607 wsu
->n_add_uncached
++;
609 /* If already present, this is a no-op. */
610 wv
= do_ix2vec( wsu
, ws
);
611 for (k
= 0; k
< wv
->size
; k
++) {
612 if (wv
->words
[k
] == w
) {
617 /* Ok, not present. Build a new one ... */
618 wv_new
= new_WV_of_size( wsu
, wv
->size
+ 1 );
620 for (; k
< wv
->size
&& wv
->words
[k
] < w
; k
++) {
621 wv_new
->words
[j
++] = wv
->words
[k
];
623 wv_new
->words
[j
++] = w
;
624 for (; k
< wv
->size
; k
++) {
625 tl_assert(wv
->words
[k
] > w
);
626 wv_new
->words
[j
++] = wv
->words
[k
];
628 tl_assert(j
== wv_new
->size
);
630 /* Find any existing copy, or add the new one. */
631 result
= add_or_dealloc_WordVec( wsu
, wv_new
);
632 tl_assert(result
!= (WordSet
)(-1));
635 WCache_UPDATE(wsu
->cache_addTo
, ws
, w
, result
);
639 WordSet
HG_(delFromWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
643 WordSet result
= (WordSet
)(-1); /* bogus */
644 WordVec
* wv
= do_ix2vec( wsu
, ws
);
648 /* special case empty set */
650 tl_assert(ws
== wsu
->empty
);
654 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_delFrom
, ws
, w
);
655 wsu
->n_del_uncached
++;
657 /* If not already present, this is a no-op. */
658 for (i
= 0; i
< wv
->size
; i
++) {
659 if (wv
->words
[i
] == w
)
666 /* So w is present in ws, and the new set will be one element
668 tl_assert(i
< wv
->size
);
669 tl_assert(wv
->size
> 0);
671 wv_new
= new_WV_of_size( wsu
, wv
->size
- 1 );
673 for (; j
< wv
->size
; j
++) {
676 wv_new
->words
[k
++] = wv
->words
[j
];
678 tl_assert(k
== wv_new
->size
);
680 result
= add_or_dealloc_WordVec( wsu
, wv_new
);
682 tl_assert(result
== wsu
->empty
);
686 WCache_UPDATE(wsu
->cache_delFrom
, ws
, w
, result
);
690 WordSet
HG_(unionWS
) ( WordSetU
* wsu
, WordSet ws1
, WordSet ws2
)
694 WordVec
* wv1
= do_ix2vec( wsu
, ws1
);
695 WordVec
* wv2
= do_ix2vec( wsu
, ws2
);
700 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
703 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
706 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
713 tl_assert(i1
<= wv1
->size
);
714 tl_assert(i2
<= wv2
->size
);
715 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
716 if (i1
== wv1
->size
&& i2
< wv2
->size
) {
717 sz
+= (wv2
->size
- i2
);
719 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
720 sz
+= (wv1
->size
- i1
);
723 wv_new
= new_WV_of_size( wsu
, sz
);
728 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
730 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
731 wv_new
->words
[k
++] = wv1
->words
[i1
];
734 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
735 wv_new
->words
[k
++] = wv2
->words
[i2
];
738 wv_new
->words
[k
++] = wv1
->words
[i1
];
743 tl_assert(i1
<= wv1
->size
);
744 tl_assert(i2
<= wv2
->size
);
745 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
746 if (i1
== wv1
->size
&& i2
< wv2
->size
) {
747 while (i2
< wv2
->size
)
748 wv_new
->words
[k
++] = wv2
->words
[i2
++];
750 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
751 while (i1
< wv1
->size
)
752 wv_new
->words
[k
++] = wv1
->words
[i1
++];
757 return add_or_dealloc_WordVec( wsu
, wv_new
);
760 WordSet
HG_(intersectWS
) ( WordSetU
* wsu
, WordSet ws1
, WordSet ws2
)
763 WordSet ws_new
= (WordSet
)(-1); /* bogus */
770 /* Deal with an obvious case fast. */
774 /* Since intersect(x,y) == intersect(y,x), convert both variants to
775 the same query. This reduces the number of variants the cache
778 WordSet wst
= ws1
; ws1
= ws2
; ws2
= wst
;
781 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_intersect
, ws1
, ws2
);
782 wsu
->n_intersect_uncached
++;
784 wv1
= do_ix2vec( wsu
, ws1
);
785 wv2
= do_ix2vec( wsu
, ws2
);
789 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
791 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
794 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
802 tl_assert(i1
<= wv1
->size
);
803 tl_assert(i2
<= wv2
->size
);
804 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
806 wv_new
= new_WV_of_size( wsu
, sz
);
811 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
813 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
816 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
819 wv_new
->words
[k
++] = wv1
->words
[i1
];
824 tl_assert(i1
<= wv1
->size
);
825 tl_assert(i2
<= wv2
->size
);
826 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
830 ws_new
= add_or_dealloc_WordVec( wsu
, wv_new
);
832 tl_assert(ws_new
== wsu
->empty
);
835 tl_assert(ws_new
!= (WordSet
)(-1));
836 WCache_UPDATE(wsu
->cache_intersect
, ws1
, ws2
, ws_new
);
841 WordSet
HG_(minusWS
) ( WordSetU
* wsu
, WordSet ws1
, WordSet ws2
)
844 WordSet ws_new
= (WordSet
)(-1); /* bogus */
850 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_minus
, ws1
, ws2
);
851 wsu
->n_minus_uncached
++;
853 wv1
= do_ix2vec( wsu
, ws1
);
854 wv2
= do_ix2vec( wsu
, ws2
);
858 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
860 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
864 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
871 tl_assert(i1
<= wv1
->size
);
872 tl_assert(i2
<= wv2
->size
);
873 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
874 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
875 sz
+= (wv1
->size
- i1
);
878 wv_new
= new_WV_of_size( wsu
, sz
);
883 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
885 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
886 wv_new
->words
[k
++] = wv1
->words
[i1
];
889 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
896 tl_assert(i1
<= wv1
->size
);
897 tl_assert(i2
<= wv2
->size
);
898 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
899 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
900 while (i1
< wv1
->size
)
901 wv_new
->words
[k
++] = wv1
->words
[i1
++];
906 ws_new
= add_or_dealloc_WordVec( wsu
, wv_new
);
908 tl_assert(ws_new
== wsu
->empty
);
911 tl_assert(ws_new
!= (WordSet
)(-1));
912 WCache_UPDATE(wsu
->cache_minus
, ws1
, ws2
, ws_new
);
917 static __attribute__((unused
))
918 void show_WS ( WordSetU
* wsu
, WordSet ws
)
921 WordVec
* wv
= do_ix2vec( wsu
, ws
);
922 VG_(printf
)("#%u{", ws
);
923 for (i
= 0; i
< wv
->size
; i
++) {
924 VG_(printf
)("%lu", wv
->words
[i
]);
931 //------------------------------------------------------------------//
932 //--- end WordSet ---//
933 //--- Implementation ---//
934 //------------------------------------------------------------------//
936 /*--------------------------------------------------------------------*/
937 /*--- end hg_wordset.c ---*/
938 /*--------------------------------------------------------------------*/