WordSetU* HG_(newWordSetU) ( void* (*alloc_nofail)( HChar*, SizeT ), HChar* cc, void (*dealloc)(void*), Word cacheSize ) { WordSetU* wsu; WordVec* empty; wsu = alloc_nofail( cc, sizeof(WordSetU) ); VG_(memset)( wsu, 0, sizeof(WordSetU) ); wsu->alloc = alloc_nofail; wsu->cc = cc; wsu->dealloc = dealloc; wsu->vec2ix = VG_(newFM)( alloc_nofail, cc, dealloc, cmp_WordVecs_for_FM ); wsu->ix2vec_used = 0; wsu->ix2vec_size = 0; wsu->ix2vec = NULL; wsu->ix2vec_free = NULL; WCache_INIT(wsu->cache_addTo, cacheSize); WCache_INIT(wsu->cache_delFrom, cacheSize); WCache_INIT(wsu->cache_intersect, cacheSize); WCache_INIT(wsu->cache_minus, cacheSize); empty = new_WV_of_size( wsu, 0 ); wsu->empty = add_or_dealloc_WordVec( wsu, empty ); return wsu; }
WordSet HG_(delFromWS) ( WordSetU* wsu, WordSet ws, Word w ) { Int i, j, k; WordVec* wv_new; WordSet result = (WordSet)(-1); /* bogus */ WordVec* wv = do_ix2vec( wsu, ws ); wsu->n_del++; /* special case empty set */ if (wv->size == 0) { tl_assert(ws == wsu->empty); return ws; } WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_delFrom, ws, w); wsu->n_del_uncached++; /* If not already present, this is a no-op. */ for (i = 0; i < wv->size; i++) { if (wv->words[i] == w) break; } if (i == wv->size) { result = ws; goto out; } /* So w is present in ws, and the new set will be one element smaller. */ tl_assert(i >= 0 && i < wv->size); tl_assert(wv->size > 0); wv_new = new_WV_of_size( wsu, wv->size - 1 ); j = k = 0; for (; j < wv->size; j++) { if (j == i) continue; wv_new->words[k++] = wv->words[j]; } tl_assert(k == wv_new->size); result = add_or_dealloc_WordVec( wsu, wv_new ); if (wv->size == 1) { tl_assert(result == wsu->empty); } out: WCache_UPDATE(wsu->cache_delFrom, ws, w, result); return result; }
WordSet HG_(delFromWS) ( WordSetU* wsu, WordSet ws, UWord w ) { UWord i, j, k; WordVec* wv_new; WordSet result = (WordSet)(-1); WordVec* wv = do_ix2vec( wsu, ws ); wsu->n_del++; if (wv->size == 0) { tl_assert(ws == wsu->empty); return ws; } WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_delFrom, ws, w); wsu->n_del_uncached++; for (i = 0; i < wv->size; i++) { if (wv->words[i] == w) break; } if (i == wv->size) { result = ws; goto out; } tl_assert(i >= 0 && i < wv->size); tl_assert(wv->size > 0); wv_new = new_WV_of_size( wsu, wv->size - 1 ); j = k = 0; for (; j < wv->size; j++) { if (j == i) continue; wv_new->words[k++] = wv->words[j]; } tl_assert(k == wv_new->size); result = add_or_dealloc_WordVec( wsu, wv_new ); if (wv->size == 1) { tl_assert(result == wsu->empty); } out: WCache_UPDATE(wsu->cache_delFrom, ws, w, result); return result; }
WordSet HG_(doubletonWS) ( WordSetU* wsu, Word w1, Word w2 ) { WordVec* wv; wsu->n_doubleton++; if (w1 == w2) { wv = new_WV_of_size(wsu, 1); wv->words[0] = w1; } else if (w1 < w2) { wv = new_WV_of_size(wsu, 2); wv->words[0] = w1; wv->words[1] = w2; } else { tl_assert(w1 > w2); wv = new_WV_of_size(wsu, 2); wv->words[0] = w2; wv->words[1] = w1; } return add_or_dealloc_WordVec( wsu, wv ); }
WordSet HG_(addToWS) ( WordSetU* wsu, WordSet ws, Word w ) { Int k, j; WordVec* wv_new; WordVec* wv; WordSet result = (WordSet)(-1); /* bogus */ wsu->n_add++; WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_addTo, ws, w); wsu->n_add_uncached++; /* If already present, this is a no-op. */ wv = do_ix2vec( wsu, ws ); for (k = 0; k < wv->size; k++) { if (wv->words[k] == w) { result = ws; goto out; } } /* Ok, not present. Build a new one ... */ wv_new = new_WV_of_size( wsu, wv->size + 1 ); k = j = 0; for (; k < wv->size && wv->words[k] < w; k++) { wv_new->words[j++] = wv->words[k]; } wv_new->words[j++] = w; for (; k < wv->size; k++) { tl_assert(wv->words[k] > w); wv_new->words[j++] = wv->words[k]; } tl_assert(j == wv_new->size); /* Find any existing copy, or add the new one. */ result = add_or_dealloc_WordVec( wsu, wv_new ); tl_assert(result != (WordSet)(-1)); out: WCache_UPDATE(wsu->cache_addTo, ws, w, result); return result; }
WordSet HG_(addToWS) ( WordSetU* wsu, WordSet ws, UWord w ) { UWord k, j; WordVec* wv_new; WordVec* wv; WordSet result = (WordSet)(-1); wsu->n_add++; WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_addTo, ws, w); wsu->n_add_uncached++; wv = do_ix2vec( wsu, ws ); for (k = 0; k < wv->size; k++) { if (wv->words[k] == w) { result = ws; goto out; } } wv_new = new_WV_of_size( wsu, wv->size + 1 ); k = j = 0; for (; k < wv->size && wv->words[k] < w; k++) { wv_new->words[j++] = wv->words[k]; } wv_new->words[j++] = w; for (; k < wv->size; k++) { tl_assert(wv->words[k] > w); wv_new->words[j++] = wv->words[k]; } tl_assert(j == wv_new->size); result = add_or_dealloc_WordVec( wsu, wv_new ); tl_assert(result != (WordSet)(-1)); out: WCache_UPDATE(wsu->cache_addTo, ws, w, result); return result; }
WordSet HG_(minusWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 ) { Int i1, i2, k, sz; WordSet ws_new = (WordSet)(-1); /* bogus */ WordVec* wv_new; WordVec* wv1; WordVec* wv2; wsu->n_minus++; WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_minus, ws1, ws2); wsu->n_minus_uncached++; wv1 = do_ix2vec( wsu, ws1 ); wv2 = do_ix2vec( wsu, ws2 ); sz = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; if (wv1->words[i1] < wv2->words[i2]) { sz++; i1++; } else if (wv1->words[i1] > wv2->words[i2]) { i2++; } else { i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); if (i2 == wv2->size && i1 < wv1->size) { sz += (wv1->size - i1); } wv_new = new_WV_of_size( wsu, sz ); k = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; if (wv1->words[i1] < wv2->words[i2]) { wv_new->words[k++] = wv1->words[i1]; i1++; } else if (wv1->words[i1] > wv2->words[i2]) { i2++; } else { i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); if (i2 == wv2->size && i1 < wv1->size) { while (i1 < wv1->size) wv_new->words[k++] = wv1->words[i1++]; } tl_assert(k == sz); ws_new = add_or_dealloc_WordVec( wsu, wv_new ); if (sz == 0) { tl_assert(ws_new == wsu->empty); } tl_assert(ws_new != (WordSet)(-1)); WCache_UPDATE(wsu->cache_minus, ws1, ws2, ws_new); return ws_new; }
WordSet HG_(intersectWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 ) { Int i1, i2, k, sz; WordSet ws_new = (WordSet)(-1); /* bogus */ WordVec* wv_new; WordVec* wv1; WordVec* wv2; wsu->n_intersect++; /* Deal with an obvious case fast. */ if (ws1 == ws2) return ws1; /* Since intersect(x,y) == intersect(y,x), convert both variants to the same query. This reduces the number of variants the cache has to deal with. */ if (ws1 > ws2) { WordSet wst = ws1; ws1 = ws2; ws2 = wst; } WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_intersect, ws1, ws2); wsu->n_intersect_uncached++; wv1 = do_ix2vec( wsu, ws1 ); wv2 = do_ix2vec( wsu, ws2 ); sz = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; if (wv1->words[i1] < wv2->words[i2]) { i1++; } else if (wv1->words[i1] > wv2->words[i2]) { i2++; } else { sz++; i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); wv_new = new_WV_of_size( wsu, sz ); k = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; if (wv1->words[i1] < wv2->words[i2]) { i1++; } else if (wv1->words[i1] > wv2->words[i2]) { i2++; } else { wv_new->words[k++] = wv1->words[i1]; i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); tl_assert(k == sz); ws_new = add_or_dealloc_WordVec( wsu, wv_new ); if (sz == 0) { tl_assert(ws_new == wsu->empty); } tl_assert(ws_new != (WordSet)(-1)); WCache_UPDATE(wsu->cache_intersect, ws1, ws2, ws_new); return ws_new; }
WordSet HG_(unionWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 ) { Int i1, i2, k, sz; WordVec* wv_new; WordVec* wv1 = do_ix2vec( wsu, ws1 ); WordVec* wv2 = do_ix2vec( wsu, ws2 ); wsu->n_union++; sz = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; sz++; if (wv1->words[i1] < wv2->words[i2]) { i1++; } else if (wv1->words[i1] > wv2->words[i2]) { i2++; } else { i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); if (i1 == wv1->size && i2 < wv2->size) { sz += (wv2->size - i2); } if (i2 == wv2->size && i1 < wv1->size) { sz += (wv1->size - i1); } wv_new = new_WV_of_size( wsu, sz ); k = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; if (wv1->words[i1] < wv2->words[i2]) { wv_new->words[k++] = wv1->words[i1]; i1++; } else if (wv1->words[i1] > wv2->words[i2]) { wv_new->words[k++] = wv2->words[i2]; i2++; } else { wv_new->words[k++] = wv1->words[i1]; i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); if (i1 == wv1->size && i2 < wv2->size) { while (i2 < wv2->size) wv_new->words[k++] = wv2->words[i2++]; } if (i2 == wv2->size && i1 < wv1->size) { while (i1 < wv1->size) wv_new->words[k++] = wv1->words[i1++]; } tl_assert(k == sz); return add_or_dealloc_WordVec( wsu, wv_new ); }
WordSet HG_(intersectWS) ( WordSetU* wsu, WordSet ws1, WordSet ws2 ) { UWord i1, i2, k, sz; WordSet ws_new = (WordSet)(-1); WordVec* wv_new; WordVec* wv1; WordVec* wv2; wsu->n_intersect++; if (ws1 == ws2) return ws1; if (ws1 > ws2) { WordSet wst = ws1; ws1 = ws2; ws2 = wst; } WCache_LOOKUP_AND_RETURN(WordSet, wsu->cache_intersect, ws1, ws2); wsu->n_intersect_uncached++; wv1 = do_ix2vec( wsu, ws1 ); wv2 = do_ix2vec( wsu, ws2 ); sz = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; if (wv1->words[i1] < wv2->words[i2]) { i1++; } else if (wv1->words[i1] > wv2->words[i2]) { i2++; } else { sz++; i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); wv_new = new_WV_of_size( wsu, sz ); k = 0; i1 = i2 = 0; while (1) { if (i1 >= wv1->size || i2 >= wv2->size) break; if (wv1->words[i1] < wv2->words[i2]) { i1++; } else if (wv1->words[i1] > wv2->words[i2]) { i2++; } else { wv_new->words[k++] = wv1->words[i1]; i1++; i2++; } } tl_assert(i1 <= wv1->size); tl_assert(i2 <= wv2->size); tl_assert(i1 == wv1->size || i2 == wv2->size); tl_assert(k == sz); ws_new = add_or_dealloc_WordVec( wsu, wv_new ); if (sz == 0) { tl_assert(ws_new == wsu->empty); } tl_assert(ws_new != (WordSet)(-1)); WCache_UPDATE(wsu->cache_intersect, ws1, ws2, ws_new); return ws_new; }