hg_wordset.c revision c17be797ee1df34bc98b7f1e0690d87732209906
1
2/*--------------------------------------------------------------------*/
3/*--- Sets of words, with unique set identifiers.                  ---*/
4/*---                                                 hg_wordset.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8   This file is part of Helgrind, a Valgrind tool for detecting errors
9   in threaded programs.
10
11   Copyright (C) 2007-2007 OpenWorks LLP
12       info@open-works.co.uk
13
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.
18
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.
23
24   You should have received a copy of the GNU General Public License
25   along with this program; if not, write to the Free Software
26   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27   02111-1307, USA.
28
29   The GNU General Public License is contained in the file COPYING.
30
31   Neither the names of the U.S. Department of Energy nor the
32   University of California nor the names of its contributors may be
33   used to endorse or promote products derived from this software
34   without prior written permission.
35*/
36
37#include "pub_tool_basics.h"
38#include "pub_tool_libcassert.h"
39#include "pub_tool_libcbase.h"
40#include "pub_tool_libcprint.h"
41
42#define HG_(str) VGAPPEND(vgHelgrind_,str)
43#include "hg_wordfm.h"
44#include "hg_wordset.h"
45
46//------------------------------------------------------------------//
47//--- Word Cache                                                 ---//
48//------------------------------------------------------------------//
49
50typedef
51   struct { UWord arg1; UWord arg2; UWord res; }
52   WCacheEnt;
53
54/* Each cache is a fixed sized array of N_WCACHE_STAT_MAX entries.
55   However only the first .dynMax are used.  This is because at some
56   point, expanding the cache further overall gives a slowdown because
57   searching more entries more than negates any performance advantage
58   from caching those entries in the first place.  Hence use .dynMax
59   to allow the size of the cache(s) to be set differently for each
60   different WordSetU. */
61#define N_WCACHE_STAT_MAX 32
62typedef
63   struct {
64      WCacheEnt ent[N_WCACHE_STAT_MAX];
65      Word      dynMax; /* 1 .. N_WCACHE_STAT_MAX inclusive */
66      Word      inUse;  /* 0 .. dynMax inclusive */
67   }
68   WCache;
69
70#define WCache_INIT(_zzcache,_zzdynmax)                              \
71   do {                                                              \
72      tl_assert((_zzdynmax) >= 1);                                   \
73      tl_assert((_zzdynmax) <= N_WCACHE_STAT_MAX);                   \
74      (_zzcache).dynMax = (_zzdynmax);                               \
75      (_zzcache).inUse = 0;                                          \
76   } while (0)
77
78#define WCache_LOOKUP_AND_RETURN(_retty,_zzcache,_zzarg1,_zzarg2)    \
79   do {                                                              \
80      Word    _i;                                                    \
81      UWord   _arg1  = (UWord)(_zzarg1);                             \
82      UWord   _arg2  = (UWord)(_zzarg2);                             \
83      WCache* _cache = &(_zzcache);                                  \
84      tl_assert(_cache->dynMax >= 1);                                \
85      tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX);                \
86      tl_assert(_cache->inUse >= 0);                                 \
87      tl_assert(_cache->inUse <= _cache->dynMax);                    \
88      if (_cache->inUse > 0) {                                       \
89         if (_cache->ent[0].arg1 == _arg1                            \
90             && _cache->ent[0].arg2 == _arg2)                        \
91            return (_retty)_cache->ent[0].res;                       \
92         for (_i = 1; _i < _cache->inUse; _i++) {                    \
93            if (_cache->ent[_i].arg1 == _arg1                        \
94                && _cache->ent[_i].arg2 == _arg2) {                  \
95               WCacheEnt tmp     = _cache->ent[_i-1];                \
96               _cache->ent[_i-1] = _cache->ent[_i];                  \
97               _cache->ent[_i]   = tmp;                              \
98               return (_retty)_cache->ent[_i-1].res;                 \
99            }                                                        \
100         }                                                           \
101      }                                                              \
102   } while (0)
103
104#define WCache_UPDATE(_zzcache,_zzarg1,_zzarg2,_zzresult)            \
105   do {                                                              \
106      Word    _i;                                                    \
107      UWord   _arg1  = (UWord)(_zzarg1);                             \
108      UWord   _arg2  = (UWord)(_zzarg2);                             \
109      UWord   _res   = (UWord)(_zzresult);                           \
110      WCache* _cache = &(_zzcache);                                  \
111      tl_assert(_cache->dynMax >= 1);                                \
112      tl_assert(_cache->dynMax <= N_WCACHE_STAT_MAX);                \
113      tl_assert(_cache->inUse >= 0);                                 \
114      tl_assert(_cache->inUse <= _cache->dynMax);                    \
115      if (_cache->inUse < _cache->dynMax)                            \
116         _cache->inUse++;                                            \
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;                                    \
122   } while (0)
123
124
125//------------------------------------------------------------------//
126//---                          WordSet                           ---//
127//---                       Implementation                       ---//
128//------------------------------------------------------------------//
129
130typedef
131   struct {
132      WordSetU* owner; /* for sanity checking */
133      Word*     words;
134      Int       size; /* Really this should be SizeT */
135   }
136   WordVec;
137
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
141   redundant. */
142struct _WordSetU {
143      void*     (*alloc)(SizeT);
144      void      (*dealloc)(void*);
145      WordFM*   vec2ix; /* WordVec-to-WordSet mapping tree */
146      WordVec** ix2vec; /* WordSet-to-WordVec mapping array */
147      UInt      ix2vec_size;
148      UInt      ix2vec_used;
149      WordSet   empty; /* cached, for speed */
150      /* Caches for some operations */
151      WCache    cache_addTo;
152      WCache    cache_delFrom;
153      WCache    cache_intersect;
154      WCache    cache_minus;
155      /* Stats */
156      UWord     n_add;
157      UWord     n_add_uncached;
158      UWord     n_del;
159      UWord     n_del_uncached;
160      UWord     n_union;
161      UWord     n_intersect;
162      UWord     n_intersect_uncached;
163      UWord     n_minus;
164      UWord     n_minus_uncached;
165      UWord     n_elem;
166      UWord     n_doubleton;
167      UWord     n_isEmpty;
168      UWord     n_isSingleton;
169      UWord     n_anyElementOf;
170      UWord     n_isSubsetOf;
171   };
172
173/* Create a new WordVec of the given size. */
174
175static WordVec* new_WV_of_size ( WordSetU* wsu, Int sz )
176{
177   WordVec* wv;
178   tl_assert(sz >= 0);
179   wv = wsu->alloc( sizeof(WordVec) );
180   wv->owner = wsu;
181   wv->words = NULL;
182   wv->size = sz;
183   if (sz > 0) {
184     wv->words = wsu->alloc( (SizeT)sz * sizeof(Word) );
185   }
186   return wv;
187}
188
189static void delete_WV ( WordVec* wv )
190{
191   void (*dealloc)(void*) = wv->owner->dealloc;
192   if (wv->words) {
193      dealloc(wv->words);
194   }
195   dealloc(wv);
196}
197static void delete_WV_for_FM ( Word wv ) {
198   delete_WV( (WordVec*)wv );
199}
200
201static Word cmp_WordVecs_for_FM ( Word wv1W, Word wv2W )
202{
203   Int      i;
204   WordVec* wv1    = (WordVec*)wv1W;
205   WordVec* wv2    = (WordVec*)wv2W;
206   Int      common = wv1->size < wv2->size ? wv1->size : wv2->size;
207   for (i = 0; i < common; i++) {
208      if (wv1->words[i] == wv2->words[i])
209         continue;
210      if (wv1->words[i] < wv2->words[i])
211         return -1;
212      if (wv1->words[i] > wv2->words[i])
213         return 1;
214      tl_assert(0);
215   }
216   /* Ok, the common sections are identical.  So now consider the
217      tails.  Both sets are considered to finish in an implied
218      sequence of -infinity. */
219   if (wv1->size < wv2->size) {
220      tl_assert(common == wv1->size);
221      return -1; /* impliedly, wv1 contains some -infinitys in places
222                    where wv2 doesn't. */
223   }
224   if (wv1->size > wv2->size) {
225      tl_assert(common == wv2->size);
226      return 1;
227   }
228   tl_assert(common == wv1->size);
229   return 0; /* identical */
230}
231
232static void ensure_ix2vec_space ( WordSetU* wsu )
233{
234   UInt      i, new_sz;
235   WordVec** new_vec;
236   tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size);
237   if (wsu->ix2vec_used < wsu->ix2vec_size)
238      return;
239   new_sz = 2 * wsu->ix2vec_size;
240   if (new_sz == 0) new_sz = 2;
241   new_vec = wsu->alloc( new_sz * sizeof(WordVec*) );
242   tl_assert(new_vec);
243   for (i = 0; i < wsu->ix2vec_size; i++)
244      new_vec[i] = wsu->ix2vec[i];
245   if (wsu->ix2vec)
246      wsu->dealloc(wsu->ix2vec);
247   wsu->ix2vec = new_vec;
248   wsu->ix2vec_size = new_sz;
249}
250
251/* Index into a WordSetU, doing the obvious range check.  Failure of
252   the assertions marked XXX and YYY is an indication of passing the
253   wrong WordSetU* in the public API of this module. */
254static WordVec* do_ix2vec ( WordSetU* wsu, WordSet ws )
255{
256   WordVec* wv;
257   tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size);
258   if (wsu->ix2vec_used > 0)
259      tl_assert(wsu->ix2vec);
260   /* If this assertion fails, it may mean you supplied a 'ws'
261      that does not come from the 'wsu' universe. */
262   tl_assert(ws < wsu->ix2vec_used); /* XXX */
263   wv = wsu->ix2vec[ws];
264   /* Make absolutely sure that 'ws' is a member of 'wsu'. */
265   tl_assert(wv);
266   tl_assert(wv->owner == wsu); /* YYY */
267   return wv;
268}
269
270/* See if wv is contained within wsu.  If so, deallocate wv and return
271   the index of the already-present copy.  If not, add wv to both the
272   vec2ix and ix2vec mappings and return its index.
273*/
274static WordSet add_or_dealloc_WordVec( WordSetU* wsu, WordVec* wv_new )
275{
276   Bool     have;
277   WordVec* wv_old;
278   Word/*Set*/ ix_old = -1;
279   /* Really WordSet, but need something that can safely be casted to
280      a Word* in the lookupFM.  Making it WordSet (which is 32 bits)
281      causes failures on a 64-bit platform. */
282   tl_assert(wv_new->owner == wsu);
283   have = HG_(lookupFM)( wsu->vec2ix,
284                         (Word*)(HChar*)&wv_old, (Word*)&ix_old,
285                         (Word)wv_new );
286   if (have) {
287      tl_assert(wv_old != wv_new);
288      tl_assert(wv_old);
289      tl_assert(wv_old->owner == wsu);
290      tl_assert(ix_old < wsu->ix2vec_used);
291      tl_assert(wsu->ix2vec[ix_old] == wv_old);
292      delete_WV( wv_new );
293      return (WordSet)ix_old;
294   } else {
295      ensure_ix2vec_space( wsu );
296      tl_assert(wsu->ix2vec);
297      tl_assert(wsu->ix2vec_used < wsu->ix2vec_size);
298      wsu->ix2vec[wsu->ix2vec_used] = wv_new;
299      HG_(addToFM)( wsu->vec2ix, (Word)wv_new, (Word)wsu->ix2vec_used );
300      if (0) VG_(printf)("aodW %d\n", (Int)wsu->ix2vec_used );
301      wsu->ix2vec_used++;
302      tl_assert(wsu->ix2vec_used <= wsu->ix2vec_size);
303      return (WordSet)(wsu->ix2vec_used - 1);
304   }
305}
306
307
308WordSetU* HG_(newWordSetU) ( void* (*alloc_nofail)( SizeT ),
309                             void  (*dealloc)(void*),
310                             Word  cacheSize )
311{
312   WordSetU* wsu;
313   WordVec*  empty;
314
315   wsu          = alloc_nofail( sizeof(WordSetU) );
316   VG_(memset)( wsu, 0, sizeof(WordSetU) );
317   wsu->alloc   = alloc_nofail;
318   wsu->dealloc = dealloc;
319   wsu->vec2ix  = HG_(newFM)( alloc_nofail, dealloc, cmp_WordVecs_for_FM );
320   wsu->ix2vec_used = 0;
321   wsu->ix2vec_size = 0;
322   wsu->ix2vec      = NULL;
323   WCache_INIT(wsu->cache_addTo,     cacheSize);
324   WCache_INIT(wsu->cache_delFrom,   cacheSize);
325   WCache_INIT(wsu->cache_intersect, cacheSize);
326   WCache_INIT(wsu->cache_minus,     cacheSize);
327   empty = new_WV_of_size( wsu, 0 );
328   wsu->empty = add_or_dealloc_WordVec( wsu, empty );
329
330   return wsu;
331}
332
333void HG_(deleteWordSetU) ( WordSetU* wsu )
334{
335   void (*dealloc)(void*) = wsu->dealloc;
336   tl_assert(wsu->vec2ix);
337   HG_(deleteFM)( wsu->vec2ix, delete_WV_for_FM, NULL/*val-finalizer*/ );
338   if (wsu->ix2vec)
339      dealloc(wsu->ix2vec);
340   dealloc(wsu);
341}
342
343WordSet HG_(emptyWS) ( WordSetU* wsu )
344{
345   return wsu->empty;
346}
347
348Bool HG_(isEmptyWS) ( WordSetU* wsu, WordSet ws )
349{
350   WordVec* wv = do_ix2vec( wsu, ws );
351   wsu->n_isEmpty++;
352   if (wv->size == 0) {
353      tl_assert(ws == wsu->empty);
354      return True;
355   } else {
356      tl_assert(ws != wsu->empty);
357      return False;
358   }
359}
360
361Bool HG_(isSingletonWS) ( WordSetU* wsu, WordSet ws, Word w )
362{
363   WordVec* wv;
364   tl_assert(wsu);
365   wsu->n_isSingleton++;
366   wv = do_ix2vec( wsu, ws );
367   return (Bool)(wv->size == 1 && wv->words[0] == w);
368}
369
370Int HG_(cardinalityWS) ( WordSetU* wsu, WordSet ws )
371{
372   WordVec* wv;
373   tl_assert(wsu);
374   wv = do_ix2vec( wsu, ws );
375   tl_assert(wv->size >= 0);
376   return wv->size;
377}
378
379Word HG_(anyElementOfWS) ( WordSetU* wsu, WordSet ws )
380{
381   WordVec* wv;
382   tl_assert(wsu);
383   wsu->n_anyElementOf++;
384   wv = do_ix2vec( wsu, ws );
385   tl_assert(wv->size >= 1);
386   return wv->words[0];
387}
388
389Int HG_(cardinalityWSU) ( WordSetU* wsu )
390{
391   tl_assert(wsu);
392   return (Int)wsu->ix2vec_used;
393}
394
395void HG_(getPayloadWS) ( /*OUT*/Word** words, /*OUT*/Word* nWords,
396                         WordSetU* wsu, WordSet ws )
397{
398   WordVec* wv;
399   tl_assert(wsu);
400   wv = do_ix2vec( wsu, ws );
401   tl_assert(wv->size >= 0);
402   *nWords = wv->size;
403   *words  = wv->words;
404}
405
406Bool HG_(plausibleWS) ( WordSetU* wsu, WordSet ws )
407{
408   if (wsu == NULL) return False;
409   if (ws < 0 || ws >= wsu->ix2vec_used)
410      return False;
411   return True;
412}
413
414Bool HG_(saneWS_SLOW) ( WordSetU* wsu, WordSet ws )
415{
416   WordVec* wv;
417   Int      i;
418   if (wsu == NULL) return False;
419   if (ws < 0 || ws >= wsu->ix2vec_used)
420      return False;
421   wv = do_ix2vec( wsu, ws );
422   /* can never happen .. do_ix2vec will assert instead.  Oh well. */
423   if (wv->owner != wsu) return False;
424   if (wv->size < 0) return False;
425   if (wv->size > 0) {
426      for (i = 0; i < wv->size-1; i++) {
427         if (wv->words[i] >= wv->words[i+1])
428            return False;
429      }
430   }
431   return True;
432}
433
434Bool HG_(elemWS) ( WordSetU* wsu, WordSet ws, Word w )
435{
436   Int      i;
437   WordVec* wv = do_ix2vec( wsu, ws );
438   wsu->n_elem++;
439   for (i = 0; i < wv->size; i++) {
440      if (wv->words[i] == w)
441         return True;
442   }
443   return False;
444}
445
446WordSet HG_(doubletonWS) ( WordSetU* wsu, Word w1, Word w2 )
447{
448   WordVec* wv;
449   wsu->n_doubleton++;
450   if (w1 == w2) {
451      wv = new_WV_of_size(wsu, 1);
452      wv->words[0] = w1;
453   }
454   else if (w1 < w2) {
455      wv = new_WV_of_size(wsu, 2);
456      wv->words[0] = w1;
457      wv->words[1] = w2;
458   }
459   else {
460      tl_assert(w1 > w2);
461      wv = new_WV_of_size(wsu, 2);
462      wv->words[0] = w2;
463      wv->words[1] = w1;
464   }
465   return add_or_dealloc_WordVec( wsu, wv );
466}
467
468WordSet HG_(singletonWS) ( WordSetU* wsu, Word w )
469{
470   return HG_(doubletonWS)( wsu, w, w );
471}
472
473WordSet HG_(isSubsetOf) ( WordSetU* wsu, WordSet small, WordSet big )
474{
475   wsu->n_isSubsetOf++;
476   return small == HG_(intersectWS)( wsu, small, big );
477}
478
479void HG_(ppWS) ( WordSetU* wsu, WordSet ws )
480{
481   Int      i;
482   WordVec* wv;
483   tl_assert(wsu);
484   wv = do_ix2vec( wsu, ws );
485   VG_(printf)("{");
486   for (i = 0; i < wv->size; i++) {
487      VG_(printf)("%p", (void*)wv->words[i]);
488      if (i < wv->size-1)
489         VG_(printf)(",");
490   }
491   VG_(printf)("}");
492}
493
494void HG_(ppWSUstats) ( WordSetU* wsu, HChar* name )
495{
496   VG_(printf)("   WordSet \"%s\":\n", name);
497   VG_(printf)("      addTo        %10u (%u uncached)\n",
498               wsu->n_add, wsu->n_add_uncached);
499   VG_(printf)("      delFrom      %10u (%u uncached)\n",
500               wsu->n_del, wsu->n_del_uncached);
501   VG_(printf)("      union        %10u\n", wsu->n_union);
502   VG_(printf)("      intersect    %10u (%u uncached) [nb. incl isSubsetOf]\n",
503               wsu->n_intersect, wsu->n_intersect_uncached);
504   VG_(printf)("      minus        %10u (%u uncached)\n",
505               wsu->n_minus, wsu->n_minus_uncached);
506   VG_(printf)("      elem         %10u\n",   wsu->n_elem);
507   VG_(printf)("      doubleton    %10u\n",   wsu->n_doubleton);
508   VG_(printf)("      isEmpty      %10u\n",   wsu->n_isEmpty);
509   VG_(printf)("      isSingleton  %10u\n",   wsu->n_isSingleton);
510   VG_(printf)("      anyElementOf %10u\n",   wsu->n_anyElementOf);
511   VG_(printf)("      isSubsetOf   %10u\n",   wsu->n_isSubsetOf);
512}
513
514WordSet HG_(addToWS) ( WordSetU* wsu, WordSet ws, Word w )
515{
516   Int      k, j;
517   WordVec* wv_new;
518   WordVec* wv;
519   WordSet  result = (WordSet)(-1); /* bogus */
520
521   wsu->n_add++;
522   WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_addTo, ws, w);
523   wsu->n_add_uncached++;
524
525   /* If already present, this is a no-op. */
526   wv = do_ix2vec( wsu, ws );
527   for (k = 0; k < wv->size; k++) {
528      if (wv->words[k] == w) {
529         result = ws;
530         goto out;
531      }
532   }
533   /* Ok, not present.  Build a new one ... */
534   wv_new = new_WV_of_size( wsu, wv->size + 1 );
535   k = j = 0;
536   for (; k < wv->size && wv->words[k] < w; k++) {
537      wv_new->words[j++] = wv->words[k];
538   }
539   wv_new->words[j++] = w;
540   for (; k < wv->size; k++) {
541      tl_assert(wv->words[k] > w);
542      wv_new->words[j++] = wv->words[k];
543   }
544   tl_assert(j == wv_new->size);
545
546   /* Find any existing copy, or add the new one. */
547   result = add_or_dealloc_WordVec( wsu, wv_new );
548   tl_assert(result != (WordSet)(-1));
549
550  out:
551   WCache_UPDATE(wsu->cache_addTo, ws, w, result);
552   return result;
553}
554
555WordSet HG_(delFromWS) ( WordSetU* wsu, WordSet ws, Word w )
556{
557   Int      i, j, k;
558   WordVec* wv_new;
559   WordSet  result = (WordSet)(-1); /* bogus */
560   WordVec* wv = do_ix2vec( wsu, ws );
561
562   wsu->n_del++;
563
564   /* special case empty set */
565   if (wv->size == 0) {
566      tl_assert(ws == wsu->empty);
567      return ws;
568   }
569
570   WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_delFrom, ws, w);
571   wsu->n_del_uncached++;
572
573   /* If not already present, this is a no-op. */
574   for (i = 0; i < wv->size; i++) {
575      if (wv->words[i] == w)
576         break;
577   }
578   if (i == wv->size) {
579      result = ws;
580      goto out;
581   }
582   /* So w is present in ws, and the new set will be one element
583      smaller. */
584   tl_assert(i >= 0 && i < wv->size);
585   tl_assert(wv->size > 0);
586
587   wv_new = new_WV_of_size( wsu, wv->size - 1 );
588   j = k = 0;
589   for (; j < wv->size; j++) {
590      if (j == i)
591         continue;
592      wv_new->words[k++] = wv->words[j];
593   }
594   tl_assert(k == wv_new->size);
595
596   result = add_or_dealloc_WordVec( wsu, wv_new );
597   if (wv->size == 1) {
598      tl_assert(result == wsu->empty);
599   }
600
601  out:
602   WCache_UPDATE(wsu->cache_delFrom, ws, w, result);
603   return result;
604}
605
606WordSet HG_(unionWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 )
607{
608   Int      i1, i2, k, sz;
609   WordVec* wv_new;
610   WordVec* wv1 = do_ix2vec( wsu, ws1 );
611   WordVec* wv2 = do_ix2vec( wsu, ws2 );
612   wsu->n_union++;
613   sz = 0;
614   i1 = i2 = 0;
615   while (1) {
616      if (i1 >= wv1->size || i2 >= wv2->size)
617         break;
618      sz++;
619      if (wv1->words[i1] < wv2->words[i2]) {
620         i1++;
621      } else
622      if (wv1->words[i1] > wv2->words[i2]) {
623         i2++;
624      } else {
625         i1++;
626         i2++;
627      }
628   }
629   tl_assert(i1 <= wv1->size);
630   tl_assert(i2 <= wv2->size);
631   tl_assert(i1 == wv1->size || i2 == wv2->size);
632   if (i1 == wv1->size && i2 < wv2->size) {
633      sz += (wv2->size - i2);
634   }
635   if (i2 == wv2->size && i1 < wv1->size) {
636      sz += (wv1->size - i1);
637   }
638
639   wv_new = new_WV_of_size( wsu, sz );
640   k = 0;
641
642   i1 = i2 = 0;
643   while (1) {
644      if (i1 >= wv1->size || i2 >= wv2->size)
645         break;
646      if (wv1->words[i1] < wv2->words[i2]) {
647         wv_new->words[k++] = wv1->words[i1];
648         i1++;
649      } else
650      if (wv1->words[i1] > wv2->words[i2]) {
651         wv_new->words[k++] = wv2->words[i2];
652         i2++;
653      } else {
654         wv_new->words[k++] = wv1->words[i1];
655         i1++;
656         i2++;
657      }
658   }
659   tl_assert(i1 <= wv1->size);
660   tl_assert(i2 <= wv2->size);
661   tl_assert(i1 == wv1->size || i2 == wv2->size);
662   if (i1 == wv1->size && i2 < wv2->size) {
663      while (i2 < wv2->size)
664         wv_new->words[k++] = wv2->words[i2++];
665   }
666   if (i2 == wv2->size && i1 < wv1->size) {
667      while (i1 < wv1->size)
668         wv_new->words[k++] = wv1->words[i1++];
669   }
670
671   tl_assert(k == sz);
672
673   return add_or_dealloc_WordVec( wsu, wv_new );
674}
675
676WordSet HG_(intersectWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 )
677{
678   Int      i1, i2, k, sz;
679   WordSet  ws_new = (WordSet)(-1); /* bogus */
680   WordVec* wv_new;
681   WordVec* wv1;
682   WordVec* wv2;
683
684   wsu->n_intersect++;
685
686   /* Deal with an obvious case fast. */
687   if (ws1 == ws2)
688      return ws1;
689
690   /* Since intersect(x,y) == intersect(y,x), convert both variants to
691      the same query.  This reduces the number of variants the cache
692      has to deal with. */
693   if (ws1 > ws2) {
694      WordSet wst = ws1; ws1 = ws2; ws2 = wst;
695   }
696
697   WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_intersect, ws1, ws2);
698   wsu->n_intersect_uncached++;
699
700   wv1 = do_ix2vec( wsu, ws1 );
701   wv2 = do_ix2vec( wsu, ws2 );
702   sz = 0;
703   i1 = i2 = 0;
704   while (1) {
705      if (i1 >= wv1->size || i2 >= wv2->size)
706         break;
707      if (wv1->words[i1] < wv2->words[i2]) {
708         i1++;
709      } else
710      if (wv1->words[i1] > wv2->words[i2]) {
711         i2++;
712      } else {
713         sz++;
714         i1++;
715         i2++;
716      }
717   }
718   tl_assert(i1 <= wv1->size);
719   tl_assert(i2 <= wv2->size);
720   tl_assert(i1 == wv1->size || i2 == wv2->size);
721
722   wv_new = new_WV_of_size( wsu, sz );
723   k = 0;
724
725   i1 = i2 = 0;
726   while (1) {
727      if (i1 >= wv1->size || i2 >= wv2->size)
728         break;
729      if (wv1->words[i1] < wv2->words[i2]) {
730         i1++;
731      } else
732      if (wv1->words[i1] > wv2->words[i2]) {
733         i2++;
734      } else {
735         wv_new->words[k++] = wv1->words[i1];
736         i1++;
737         i2++;
738      }
739   }
740   tl_assert(i1 <= wv1->size);
741   tl_assert(i2 <= wv2->size);
742   tl_assert(i1 == wv1->size || i2 == wv2->size);
743
744   tl_assert(k == sz);
745
746   ws_new = add_or_dealloc_WordVec( wsu, wv_new );
747   if (sz == 0) {
748      tl_assert(ws_new == wsu->empty);
749   }
750
751   tl_assert(ws_new != (WordSet)(-1));
752   WCache_UPDATE(wsu->cache_intersect, ws1, ws2, ws_new);
753
754   return ws_new;
755}
756
757WordSet HG_(minusWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 )
758{
759   Int      i1, i2, k, sz;
760   WordSet  ws_new = (WordSet)(-1); /* bogus */
761   WordVec* wv_new;
762   WordVec* wv1;
763   WordVec* wv2;
764
765   wsu->n_minus++;
766   WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_minus, ws1, ws2);
767   wsu->n_minus_uncached++;
768
769   wv1 = do_ix2vec( wsu, ws1 );
770   wv2 = do_ix2vec( wsu, ws2 );
771   sz = 0;
772   i1 = i2 = 0;
773   while (1) {
774      if (i1 >= wv1->size || i2 >= wv2->size)
775         break;
776      if (wv1->words[i1] < wv2->words[i2]) {
777         sz++;
778         i1++;
779      } else
780      if (wv1->words[i1] > wv2->words[i2]) {
781         i2++;
782      } else {
783         i1++;
784         i2++;
785      }
786   }
787   tl_assert(i1 <= wv1->size);
788   tl_assert(i2 <= wv2->size);
789   tl_assert(i1 == wv1->size || i2 == wv2->size);
790   if (i2 == wv2->size && i1 < wv1->size) {
791      sz += (wv1->size - i1);
792   }
793
794   wv_new = new_WV_of_size( wsu, sz );
795   k = 0;
796
797   i1 = i2 = 0;
798   while (1) {
799      if (i1 >= wv1->size || i2 >= wv2->size)
800         break;
801      if (wv1->words[i1] < wv2->words[i2]) {
802         wv_new->words[k++] = wv1->words[i1];
803         i1++;
804      } else
805      if (wv1->words[i1] > wv2->words[i2]) {
806         i2++;
807      } else {
808         i1++;
809         i2++;
810      }
811   }
812   tl_assert(i1 <= wv1->size);
813   tl_assert(i2 <= wv2->size);
814   tl_assert(i1 == wv1->size || i2 == wv2->size);
815   if (i2 == wv2->size && i1 < wv1->size) {
816      while (i1 < wv1->size)
817         wv_new->words[k++] = wv1->words[i1++];
818   }
819
820   tl_assert(k == sz);
821
822   ws_new = add_or_dealloc_WordVec( wsu, wv_new );
823   if (sz == 0) {
824      tl_assert(ws_new == wsu->empty);
825   }
826
827   tl_assert(ws_new != (WordSet)(-1));
828   WCache_UPDATE(wsu->cache_minus, ws1, ws2, ws_new);
829
830   return ws_new;
831}
832
833static __attribute__((unused))
834void show_WS ( WordSetU* wsu, WordSet ws )
835{
836   Int i;
837   WordVec* wv = do_ix2vec( wsu, ws );
838   VG_(printf)("#%u{", ws);
839   for (i = 0; i < wv->size; i++) {
840      VG_(printf)("%lu", wv->words[i]);
841      if (i < wv->size-1)
842         VG_(printf)(",");
843   }
844   VG_(printf)("}\n");
845}
846
847//------------------------------------------------------------------//
848//---                        end WordSet                         ---//
849//---                       Implementation                       ---//
850//------------------------------------------------------------------//
851
852/*--------------------------------------------------------------------*/
853/*--- end                                             hg_wordset.c ---*/
854/*--------------------------------------------------------------------*/
855