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 >= 0); \
89 tl_assert(_cache->inUse <= _cache->dynMax); \
90 if (_cache->inUse > 0) { \
91 if (_cache->ent[0].arg1 == _arg1 \
92 && _cache->ent[0].arg2 == _arg2) \
93 return (_retty)_cache->ent[0].res; \
94 for (_i = 1; _i < _cache->inUse; _i++) { \
95 if (_cache->ent[_i].arg1 == _arg1 \
96 && _cache->ent[_i].arg2 == _arg2) { \
97 WCacheEnt tmp = _cache->ent[_i-1]; \
98 _cache->ent[_i-1] = _cache->ent[_i]; \
99 _cache->ent[_i] = tmp; \
100 return (_retty)_cache->ent[_i-1].res; \
106 #define WCache_UPDATE(_zzcache,_zzarg1,_zzarg2,_zzresult) \
109 UWord _arg1 = (UWord)(_zzarg1); \
110 UWord _arg2 = (UWord)(_zzarg2); \
111 UWord _res = (UWord)(_zzresult); \
112 WCache* _cache = &(_zzcache); \
113 tl_assert(_cache->dynMax >= 1); \
114 tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX); \
115 tl_assert(_cache->inUse >= 0); \
116 tl_assert(_cache->inUse <= _cache->dynMax); \
117 if (_cache->inUse < _cache->dynMax) \
119 for (_i = _cache->inUse-1; _i >= 1; _i--) \
120 _cache->ent[_i] = _cache->ent[_i-1]; \
121 _cache->ent[0].arg1 = _arg1; \
122 _cache->ent[0].arg2 = _arg2; \
123 _cache->ent[0].res = _res; \
127 //------------------------------------------------------------------//
129 //--- Implementation ---//
130 //------------------------------------------------------------------//
134 WordSetU
* owner
; /* for sanity checking */
136 UWord size
; /* Really this should be SizeT */
140 /* ix2vec[0 .. ix2vec_used-1] are pointers to the lock sets (WordVecs)
141 really. vec2ix is the inverse mapping, mapping WordVec* to the
142 corresponding ix2vec entry number. The two mappings are mutually
145 If a WordVec WV is marked as dead by HG(dieWS), WV is removed from
146 vec2ix. The entry of the dead WVs in ix2vec are used to maintain a
147 linked list of free (to be re-used) ix2vec entries. */
149 void* (*alloc
)(const HChar
*,SizeT
);
151 void (*dealloc
)(void*);
152 WordFM
* vec2ix
; /* WordVec-to-WordSet mapping tree */
153 WordVec
** ix2vec
; /* WordSet-to-WordVec mapping array */
156 WordVec
** ix2vec_free
;
157 WordSet empty
; /* cached, for speed */
158 /* Caches for some operations */
160 WCache cache_delFrom
;
161 WCache cache_intersect
;
165 UWord n_add_uncached
;
167 UWord n_del_uncached
;
171 UWord n_intersect_uncached
;
173 UWord n_minus_uncached
;
178 UWord n_anyElementOf
;
182 /* Create a new WordVec of the given size. */
184 static WordVec
* new_WV_of_size ( WordSetU
* wsu
, UWord sz
)
188 wv
= wsu
->alloc( wsu
->cc
, sizeof(WordVec
) );
193 wv
->words
= wsu
->alloc( wsu
->cc
, (SizeT
)sz
* sizeof(UWord
) );
198 static void delete_WV ( WordVec
* wv
)
200 void (*dealloc
)(void*) = wv
->owner
->dealloc
;
206 static void delete_WV_for_FM ( UWord wv
) {
207 delete_WV( (WordVec
*)wv
);
210 static Word
cmp_WordVecs_for_FM ( UWord wv1W
, UWord wv2W
)
213 WordVec
* wv1
= (WordVec
*)wv1W
;
214 WordVec
* wv2
= (WordVec
*)wv2W
;
216 // WordVecs with smaller size are smaller.
217 if (wv1
->size
< wv2
->size
) {
220 if (wv1
->size
> wv2
->size
) {
224 // Sizes are equal => order based on content.
225 for (i
= 0; i
< wv1
->size
; i
++) {
226 if (wv1
->words
[i
] == wv2
->words
[i
])
228 if (wv1
->words
[i
] < wv2
->words
[i
])
230 if (wv1
->words
[i
] > wv2
->words
[i
])
234 return 0; /* identical */
237 static void ensure_ix2vec_space ( WordSetU
* wsu
)
241 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
242 if (wsu
->ix2vec_used
< wsu
->ix2vec_size
)
244 new_sz
= 2 * wsu
->ix2vec_size
;
245 if (new_sz
== 0) new_sz
= 1;
246 new_vec
= wsu
->alloc( wsu
->cc
, new_sz
* sizeof(WordVec
*) );
248 for (i
= 0; i
< wsu
->ix2vec_size
; i
++)
249 new_vec
[i
] = wsu
->ix2vec
[i
];
251 wsu
->dealloc(wsu
->ix2vec
);
252 wsu
->ix2vec
= new_vec
;
253 wsu
->ix2vec_size
= new_sz
;
256 /* True if wv is a dead entry (i.e. is in the linked list of free to be re-used
257 entries in ix2vec). */
258 static inline Bool
is_dead ( WordSetU
* wsu
, WordVec
* wv
)
260 if (wv
== NULL
) /* last element in free linked list in ix2vec */
263 return (WordVec
**)wv
>= &(wsu
->ix2vec
[1])
264 && (WordVec
**)wv
< &(wsu
->ix2vec
[wsu
->ix2vec_size
]);
266 /* Index into a WordSetU, doing the obvious range check. Failure of
267 the assertions marked XXX and YYY is an indication of passing the
268 wrong WordSetU* in the public API of this module.
269 Accessing a dead ws will assert. */
270 static WordVec
* do_ix2vec ( WordSetU
* wsu
, WordSet ws
)
273 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
274 if (wsu
->ix2vec_used
> 0)
275 tl_assert(wsu
->ix2vec
);
276 /* If this assertion fails, it may mean you supplied a 'ws'
277 that does not come from the 'wsu' universe. */
278 tl_assert(ws
< wsu
->ix2vec_used
); /* XXX */
279 wv
= wsu
->ix2vec
[ws
];
280 /* Make absolutely sure that 'ws' is a non dead member of 'wsu'. */
282 tl_assert(!is_dead(wsu
,wv
));
283 tl_assert(wv
->owner
== wsu
); /* YYY */
287 /* Same as do_ix2vec but returns NULL for a dead ws. */
288 static WordVec
* do_ix2vec_with_dead ( WordSetU
* wsu
, WordSet ws
)
291 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
292 if (wsu
->ix2vec_used
> 0)
293 tl_assert(wsu
->ix2vec
);
294 /* If this assertion fails, it may mean you supplied a 'ws'
295 that does not come from the 'wsu' universe. */
296 tl_assert(ws
< wsu
->ix2vec_used
); /* XXX */
297 wv
= wsu
->ix2vec
[ws
];
298 /* Make absolutely sure that 'ws' is either dead or a member of 'wsu'. */
302 tl_assert(wv
->owner
== wsu
); /* YYY */
306 /* See if wv is contained within wsu. If so, deallocate wv and return
307 the index of the already-present copy. If not, add wv to both the
308 vec2ix and ix2vec mappings and return its index.
310 static WordSet
add_or_dealloc_WordVec( WordSetU
* wsu
, WordVec
* wv_new
)
314 UWord
/*Set*/ ix_old
= -1;
315 /* Really WordSet, but need something that can safely be casted to
316 a Word* in the lookupFM. Making it WordSet (which is 32 bits)
317 causes failures on a 64-bit platform. */
318 tl_assert(wv_new
->owner
== wsu
);
319 have
= VG_(lookupFM
)( wsu
->vec2ix
,
320 (UWord
*)&wv_old
, (UWord
*)&ix_old
,
323 tl_assert(wv_old
!= wv_new
);
325 tl_assert(wv_old
->owner
== wsu
);
326 tl_assert(ix_old
< wsu
->ix2vec_used
);
327 tl_assert(wsu
->ix2vec
[ix_old
] == wv_old
);
329 return (WordSet
)ix_old
;
330 } else if (wsu
->ix2vec_free
) {
332 tl_assert(is_dead(wsu
,(WordVec
*)wsu
->ix2vec_free
));
333 ws
= wsu
->ix2vec_free
- &(wsu
->ix2vec
[0]);
334 tl_assert(wsu
->ix2vec
[ws
] == NULL
|| is_dead(wsu
,wsu
->ix2vec
[ws
]));
335 wsu
->ix2vec_free
= (WordVec
**) wsu
->ix2vec
[ws
];
336 wsu
->ix2vec
[ws
] = wv_new
;
337 VG_(addToFM
)( wsu
->vec2ix
, (UWord
)wv_new
, ws
);
338 if (HG_DEBUG
) VG_(printf
)("aodW %s re-use free %d %p\n", wsu
->cc
, (Int
)ws
, wv_new
);
341 ensure_ix2vec_space( wsu
);
342 tl_assert(wsu
->ix2vec
);
343 tl_assert(wsu
->ix2vec_used
< wsu
->ix2vec_size
);
344 wsu
->ix2vec
[wsu
->ix2vec_used
] = wv_new
;
345 VG_(addToFM
)( wsu
->vec2ix
, (Word
)wv_new
, (Word
)wsu
->ix2vec_used
);
346 if (HG_DEBUG
) VG_(printf
)("aodW %s %d %p\n", wsu
->cc
, (Int
)wsu
->ix2vec_used
, wv_new
);
348 tl_assert(wsu
->ix2vec_used
<= wsu
->ix2vec_size
);
349 return (WordSet
)(wsu
->ix2vec_used
- 1);
354 WordSetU
* HG_(newWordSetU
) ( void* (*alloc_nofail
)( const HChar
*, SizeT
),
356 void (*dealloc
)(void*),
362 wsu
= alloc_nofail( cc
, sizeof(WordSetU
) );
363 VG_(memset
)( wsu
, 0, sizeof(WordSetU
) );
364 wsu
->alloc
= alloc_nofail
;
366 wsu
->dealloc
= dealloc
;
367 wsu
->vec2ix
= VG_(newFM
)( alloc_nofail
, cc
,
368 dealloc
, cmp_WordVecs_for_FM
);
369 wsu
->ix2vec_used
= 0;
370 wsu
->ix2vec_size
= 0;
372 wsu
->ix2vec_free
= NULL
;
373 WCache_INIT(wsu
->cache_addTo
, cacheSize
);
374 WCache_INIT(wsu
->cache_delFrom
, cacheSize
);
375 WCache_INIT(wsu
->cache_intersect
, cacheSize
);
376 WCache_INIT(wsu
->cache_minus
, cacheSize
);
377 empty
= new_WV_of_size( wsu
, 0 );
378 wsu
->empty
= add_or_dealloc_WordVec( wsu
, empty
);
383 void HG_(deleteWordSetU
) ( WordSetU
* wsu
)
385 void (*dealloc
)(void*) = wsu
->dealloc
;
386 tl_assert(wsu
->vec2ix
);
387 VG_(deleteFM
)( wsu
->vec2ix
, delete_WV_for_FM
, NULL
/*val-finalizer*/ );
389 dealloc(wsu
->ix2vec
);
393 WordSet
HG_(emptyWS
) ( WordSetU
* wsu
)
398 Bool
HG_(isEmptyWS
) ( WordSetU
* wsu
, WordSet ws
)
400 WordVec
* wv
= do_ix2vec( wsu
, ws
);
403 tl_assert(ws
== wsu
->empty
);
406 tl_assert(ws
!= wsu
->empty
);
411 Bool
HG_(isSingletonWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
415 wsu
->n_isSingleton
++;
416 wv
= do_ix2vec( wsu
, ws
);
417 return (Bool
)(wv
->size
== 1 && wv
->words
[0] == w
);
420 UWord
HG_(cardinalityWS
) ( WordSetU
* wsu
, WordSet ws
)
424 wv
= do_ix2vec( wsu
, ws
);
425 tl_assert(wv
->size
>= 0);
429 UWord
HG_(anyElementOfWS
) ( WordSetU
* wsu
, WordSet ws
)
433 wsu
->n_anyElementOf
++;
434 wv
= do_ix2vec( wsu
, ws
);
435 tl_assert(wv
->size
>= 1);
439 UWord
HG_(cardinalityWSU
) ( WordSetU
* wsu
)
442 return wsu
->ix2vec_used
;
445 void HG_(getPayloadWS
) ( /*OUT*/UWord
** words
, /*OUT*/UWord
* nWords
,
446 WordSetU
* wsu
, WordSet ws
)
449 if (HG_DEBUG
) VG_(printf
)("getPayloadWS %s %d\n", wsu
->cc
, (Int
)ws
);
451 wv
= do_ix2vec( wsu
, ws
);
452 tl_assert(wv
->size
>= 0);
457 void HG_(dieWS
) ( WordSetU
* wsu
, WordSet ws
)
459 WordVec
* wv
= do_ix2vec_with_dead( wsu
, ws
);
460 WordVec
* wv_in_vec2ix
;
461 UWord
/*Set*/ wv_ix
= -1;
463 if (HG_DEBUG
) VG_(printf
)("dieWS %s %d %p\n", wsu
->cc
, (Int
)ws
, wv
);
466 return; // we never die the empty set.
469 return; // already dead. (or a bug ?).
474 wsu
->ix2vec
[ws
] = (WordVec
*) wsu
->ix2vec_free
;
475 wsu
->ix2vec_free
= &wsu
->ix2vec
[ws
];
477 VG_(delFromFM
) ( wsu
->vec2ix
,
478 (UWord
*)&wv_in_vec2ix
, (UWord
*)&wv_ix
,
481 if (HG_DEBUG
) VG_(printf
)("dieWS wv_ix %d\n", (Int
)wv_ix
);
483 tl_assert (wv_ix
== ws
);
487 wsu
->cache_addTo
.inUse
= 0;
488 wsu
->cache_delFrom
.inUse
= 0;
489 wsu
->cache_intersect
.inUse
= 0;
490 wsu
->cache_minus
.inUse
= 0;
493 Bool
HG_(plausibleWS
) ( WordSetU
* wsu
, WordSet ws
)
495 if (wsu
== NULL
) return False
;
496 if (ws
< 0 || ws
>= wsu
->ix2vec_used
)
501 Bool
HG_(saneWS_SLOW
) ( WordSetU
* wsu
, WordSet ws
)
505 if (wsu
== NULL
) return False
;
506 if (ws
< 0 || ws
>= wsu
->ix2vec_used
)
508 wv
= do_ix2vec( wsu
, ws
);
509 /* can never happen .. do_ix2vec will assert instead. Oh well. */
510 if (wv
->owner
!= wsu
) return False
;
511 if (wv
->size
< 0) return False
;
513 for (i
= 0; i
< wv
->size
-1; i
++) {
514 if (wv
->words
[i
] >= wv
->words
[i
+1])
521 Bool
HG_(elemWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
524 WordVec
* wv
= do_ix2vec( wsu
, ws
);
526 for (i
= 0; i
< wv
->size
; i
++) {
527 if (wv
->words
[i
] == w
)
533 WordSet
HG_(doubletonWS
) ( WordSetU
* wsu
, UWord w1
, UWord w2
)
538 wv
= new_WV_of_size(wsu
, 1);
542 wv
= new_WV_of_size(wsu
, 2);
548 wv
= new_WV_of_size(wsu
, 2);
552 return add_or_dealloc_WordVec( wsu
, wv
);
555 WordSet
HG_(singletonWS
) ( WordSetU
* wsu
, UWord w
)
557 return HG_(doubletonWS
)( wsu
, w
, w
);
560 WordSet
HG_(isSubsetOf
) ( WordSetU
* wsu
, WordSet small
, WordSet big
)
563 return small
== HG_(intersectWS
)( wsu
, small
, big
);
566 void HG_(ppWS
) ( WordSetU
* wsu
, WordSet ws
)
571 wv
= do_ix2vec( wsu
, ws
);
573 for (i
= 0; i
< wv
->size
; i
++) {
574 VG_(printf
)("%p", (void*)wv
->words
[i
]);
581 void HG_(ppWSUstats
) ( WordSetU
* wsu
, const HChar
* name
)
583 VG_(printf
)(" WordSet \"%s\":\n", name
);
584 VG_(printf
)(" addTo %10lu (%lu uncached)\n",
585 wsu
->n_add
, wsu
->n_add_uncached
);
586 VG_(printf
)(" delFrom %10lu (%lu uncached)\n",
587 wsu
->n_del
, wsu
->n_del_uncached
);
588 VG_(printf
)(" union %10lu\n", wsu
->n_union
);
589 VG_(printf
)(" intersect %10lu (%lu uncached) "
590 "[nb. incl isSubsetOf]\n",
591 wsu
->n_intersect
, wsu
->n_intersect_uncached
);
592 VG_(printf
)(" minus %10lu (%lu uncached)\n",
593 wsu
->n_minus
, wsu
->n_minus_uncached
);
594 VG_(printf
)(" elem %10lu\n", wsu
->n_elem
);
595 VG_(printf
)(" doubleton %10lu\n", wsu
->n_doubleton
);
596 VG_(printf
)(" isEmpty %10lu\n", wsu
->n_isEmpty
);
597 VG_(printf
)(" isSingleton %10lu\n", wsu
->n_isSingleton
);
598 VG_(printf
)(" anyElementOf %10lu\n", wsu
->n_anyElementOf
);
599 VG_(printf
)(" isSubsetOf %10lu\n", wsu
->n_isSubsetOf
);
600 VG_(printf
)(" dieWS %10lu\n", wsu
->n_die
);
603 WordSet
HG_(addToWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
608 WordSet result
= (WordSet
)(-1); /* bogus */
611 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_addTo
, ws
, w
);
612 wsu
->n_add_uncached
++;
614 /* If already present, this is a no-op. */
615 wv
= do_ix2vec( wsu
, ws
);
616 for (k
= 0; k
< wv
->size
; k
++) {
617 if (wv
->words
[k
] == w
) {
622 /* Ok, not present. Build a new one ... */
623 wv_new
= new_WV_of_size( wsu
, wv
->size
+ 1 );
625 for (; k
< wv
->size
&& wv
->words
[k
] < w
; k
++) {
626 wv_new
->words
[j
++] = wv
->words
[k
];
628 wv_new
->words
[j
++] = w
;
629 for (; k
< wv
->size
; k
++) {
630 tl_assert(wv
->words
[k
] > w
);
631 wv_new
->words
[j
++] = wv
->words
[k
];
633 tl_assert(j
== wv_new
->size
);
635 /* Find any existing copy, or add the new one. */
636 result
= add_or_dealloc_WordVec( wsu
, wv_new
);
637 tl_assert(result
!= (WordSet
)(-1));
640 WCache_UPDATE(wsu
->cache_addTo
, ws
, w
, result
);
644 WordSet
HG_(delFromWS
) ( WordSetU
* wsu
, WordSet ws
, UWord w
)
648 WordSet result
= (WordSet
)(-1); /* bogus */
649 WordVec
* wv
= do_ix2vec( wsu
, ws
);
653 /* special case empty set */
655 tl_assert(ws
== wsu
->empty
);
659 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_delFrom
, ws
, w
);
660 wsu
->n_del_uncached
++;
662 /* If not already present, this is a no-op. */
663 for (i
= 0; i
< wv
->size
; i
++) {
664 if (wv
->words
[i
] == w
)
671 /* So w is present in ws, and the new set will be one element
673 tl_assert(i
>= 0 && i
< wv
->size
);
674 tl_assert(wv
->size
> 0);
676 wv_new
= new_WV_of_size( wsu
, wv
->size
- 1 );
678 for (; j
< wv
->size
; j
++) {
681 wv_new
->words
[k
++] = wv
->words
[j
];
683 tl_assert(k
== wv_new
->size
);
685 result
= add_or_dealloc_WordVec( wsu
, wv_new
);
687 tl_assert(result
== wsu
->empty
);
691 WCache_UPDATE(wsu
->cache_delFrom
, ws
, w
, result
);
695 WordSet
HG_(unionWS
) ( WordSetU
* wsu
, WordSet ws1
, WordSet ws2
)
699 WordVec
* wv1
= do_ix2vec( wsu
, ws1
);
700 WordVec
* wv2
= do_ix2vec( wsu
, ws2
);
705 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
708 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
711 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
718 tl_assert(i1
<= wv1
->size
);
719 tl_assert(i2
<= wv2
->size
);
720 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
721 if (i1
== wv1
->size
&& i2
< wv2
->size
) {
722 sz
+= (wv2
->size
- i2
);
724 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
725 sz
+= (wv1
->size
- i1
);
728 wv_new
= new_WV_of_size( wsu
, sz
);
733 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
735 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
736 wv_new
->words
[k
++] = wv1
->words
[i1
];
739 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
740 wv_new
->words
[k
++] = wv2
->words
[i2
];
743 wv_new
->words
[k
++] = wv1
->words
[i1
];
748 tl_assert(i1
<= wv1
->size
);
749 tl_assert(i2
<= wv2
->size
);
750 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
751 if (i1
== wv1
->size
&& i2
< wv2
->size
) {
752 while (i2
< wv2
->size
)
753 wv_new
->words
[k
++] = wv2
->words
[i2
++];
755 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
756 while (i1
< wv1
->size
)
757 wv_new
->words
[k
++] = wv1
->words
[i1
++];
762 return add_or_dealloc_WordVec( wsu
, wv_new
);
765 WordSet
HG_(intersectWS
) ( WordSetU
* wsu
, WordSet ws1
, WordSet ws2
)
768 WordSet ws_new
= (WordSet
)(-1); /* bogus */
775 /* Deal with an obvious case fast. */
779 /* Since intersect(x,y) == intersect(y,x), convert both variants to
780 the same query. This reduces the number of variants the cache
783 WordSet wst
= ws1
; ws1
= ws2
; ws2
= wst
;
786 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_intersect
, ws1
, ws2
);
787 wsu
->n_intersect_uncached
++;
789 wv1
= do_ix2vec( wsu
, ws1
);
790 wv2
= do_ix2vec( wsu
, ws2
);
794 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
796 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
799 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
807 tl_assert(i1
<= wv1
->size
);
808 tl_assert(i2
<= wv2
->size
);
809 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
811 wv_new
= new_WV_of_size( wsu
, sz
);
816 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
818 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
821 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
824 wv_new
->words
[k
++] = wv1
->words
[i1
];
829 tl_assert(i1
<= wv1
->size
);
830 tl_assert(i2
<= wv2
->size
);
831 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
835 ws_new
= add_or_dealloc_WordVec( wsu
, wv_new
);
837 tl_assert(ws_new
== wsu
->empty
);
840 tl_assert(ws_new
!= (WordSet
)(-1));
841 WCache_UPDATE(wsu
->cache_intersect
, ws1
, ws2
, ws_new
);
846 WordSet
HG_(minusWS
) ( WordSetU
* wsu
, WordSet ws1
, WordSet ws2
)
849 WordSet ws_new
= (WordSet
)(-1); /* bogus */
855 WCache_LOOKUP_AND_RETURN(WordSet
, wsu
->cache_minus
, ws1
, ws2
);
856 wsu
->n_minus_uncached
++;
858 wv1
= do_ix2vec( wsu
, ws1
);
859 wv2
= do_ix2vec( wsu
, ws2
);
863 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
865 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
869 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
876 tl_assert(i1
<= wv1
->size
);
877 tl_assert(i2
<= wv2
->size
);
878 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
879 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
880 sz
+= (wv1
->size
- i1
);
883 wv_new
= new_WV_of_size( wsu
, sz
);
888 if (i1
>= wv1
->size
|| i2
>= wv2
->size
)
890 if (wv1
->words
[i1
] < wv2
->words
[i2
]) {
891 wv_new
->words
[k
++] = wv1
->words
[i1
];
894 if (wv1
->words
[i1
] > wv2
->words
[i2
]) {
901 tl_assert(i1
<= wv1
->size
);
902 tl_assert(i2
<= wv2
->size
);
903 tl_assert(i1
== wv1
->size
|| i2
== wv2
->size
);
904 if (i2
== wv2
->size
&& i1
< wv1
->size
) {
905 while (i1
< wv1
->size
)
906 wv_new
->words
[k
++] = wv1
->words
[i1
++];
911 ws_new
= add_or_dealloc_WordVec( wsu
, wv_new
);
913 tl_assert(ws_new
== wsu
->empty
);
916 tl_assert(ws_new
!= (WordSet
)(-1));
917 WCache_UPDATE(wsu
->cache_minus
, ws1
, ws2
, ws_new
);
922 static __attribute__((unused
))
923 void show_WS ( WordSetU
* wsu
, WordSet ws
)
926 WordVec
* wv
= do_ix2vec( wsu
, ws
);
927 VG_(printf
)("#%u{", ws
);
928 for (i
= 0; i
< wv
->size
; i
++) {
929 VG_(printf
)("%lu", wv
->words
[i
]);
936 //------------------------------------------------------------------//
937 //--- end WordSet ---//
938 //--- Implementation ---//
939 //------------------------------------------------------------------//
941 /*--------------------------------------------------------------------*/
942 /*--- end hg_wordset.c ---*/
943 /*--------------------------------------------------------------------*/