struct _DedupPoolAlloc {
SizeT poolSzB; /* Minimum size of a pool. */
SizeT fixedSzb; /* If using VG_(allocFixedEltDedupPA), size of elements */
+ Bool strPA; /* True if this is a string dedup pool */
SizeT eltAlign;
void* (*alloc_fn)(const HChar*, SizeT); /* pool allocator */
const HChar* cc; /* pool allocator's cost centre */
struct _ht_node {
struct _ht_node *next; // Read/Write by hashtable (pub_tool_hashtable.h)
UWord key; // Read by hashtable (pub_tool_hashtable.h)
- SizeT eltSzB;
+ SizeT eltSzBorStrNr; // for a normal pool, elt size
+ // for a string pool, the unique str number
const void *elt;
}
ht_node;
VG_(memset)(ddpa, 0, sizeof(*ddpa));
ddpa->poolSzB = poolSzB;
ddpa->fixedSzb = 0;
+ ddpa->strPA = False;
ddpa->eltAlign = eltAlign;
ddpa->alloc_fn = alloc_fn;
ddpa->cc = cc;
/* As this function is called by hashtable, that has already checked
for key equality, it is likely that it is the 'good' element.
So, we handle the equal case first. */
- if (hnode1->eltSzB == hnode2->eltSzB)
- return VG_(memcmp) (hnode1->elt, hnode2->elt, hnode1->eltSzB);
- else if (hnode1->eltSzB < hnode2->eltSzB)
+ if (hnode1->eltSzBorStrNr == hnode2->eltSzBorStrNr)
+ return VG_(memcmp) (hnode1->elt, hnode2->elt, hnode1->eltSzBorStrNr);
+ else if (hnode1->eltSzBorStrNr < hnode2->eltSzBorStrNr)
return -1;
else
return 1;
}
+/* String compare function for 'gen' hash table.
+ Similarly to cmp_pool_elt, no need to compare the key. */
+static Word cmp_pool_str (const void* node1, const void* node2 )
+{
+ const ht_node* hnode1 = node1;
+ const ht_node* hnode2 = node2;
+
+ return VG_(strcmp)(hnode1->elt, hnode2->elt);
+}
+
/* Print some stats. */
static void print_stats (DedupPoolAlloc *ddpa)
{
VG_(sizeXA)(ddpa->pools),
ddpa->curpool ?
(long int) (ddpa->curpool_limit - ddpa->curpool_free + 1) : 0);
- VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_elt);
+ if (ddpa->strPA)
+ VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_str);
+ else
+ VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_elt);
}
/* Dummy free, as the ht elements are allocated in a pool, and
return h;
}
-const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, SizeT eltSzB,
- const void *elt)
+static ht_node* allocEltDedupPA (DedupPoolAlloc *ddpa, SizeT eltSzB,
+ const void *elt)
{
ht_node ht_elt;
void* elt_ins;
ht_elt.key = sdbm_hash (elt, eltSzB);
- ht_elt.eltSzB = eltSzB;
ht_elt.elt = elt;
- ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_elt);
+ if (ddpa->strPA)
+ ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_str);
+ else {
+ ht_elt.eltSzBorStrNr = eltSzB;
+ ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_elt);
+ }
if (ht_ins)
- return ht_ins->elt;
+ return ht_ins;
/* Not found -> we need to allocate a new element from the pool
and insert it in the hash table of inserted elements. */
VG_(memcpy)(elt_ins, elt, eltSzB);
ht_ins = VG_(allocEltPA) (ddpa->ht_node_pa);
ht_ins->key = ht_elt.key;
- ht_ins->eltSzB = eltSzB;
+ if (ddpa->strPA)
+ ht_ins->eltSzBorStrNr = VG_(HT_count_nodes)(ddpa->ht_elements) + 1;
+ else
+ ht_ins->eltSzBorStrNr = eltSzB;
ht_ins->elt = elt_ins;
VG_(HT_add_node)(ddpa->ht_elements, ht_ins);
- return elt_ins;
+ return ht_ins;
+}
+
+const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, SizeT eltSzB,
+ const void *elt)
+{
+ return allocEltDedupPA(ddpa, eltSzB, elt)->elt;
+}
+
+UInt VG_(allocStrDedupPA) (DedupPoolAlloc *ddpa,
+ const HChar* str,
+ Bool* newStr)
+{
+ if (!ddpa->strPA) {
+ // First insertion in this ddpa
+ vg_assert (ddpa->nr_alloc_calls == 0);
+ vg_assert (ddpa->fixedSzb == 0);
+ ddpa->strPA = True;
+ }
+
+ const UInt nr_str = VG_(HT_count_nodes)(ddpa->ht_elements);
+ const ht_node* ht_ins = allocEltDedupPA(ddpa, VG_(strlen)(str)+1, str);
+
+ *newStr = nr_str < VG_(HT_count_nodes)(ddpa->ht_elements);
+ return ht_ins->eltSzBorStrNr;
}
static __inline__
{
if (ddpa->fixedSzb == 0) {
// First insertion in this ddpa
+ vg_assert (!ddpa->strPA);
vg_assert (ddpa->nr_alloc_calls == 0);
vg_assert (eltSzB > 0);
ddpa->fixedSzb = eltSzB;
// individually.
// Once allocated, an element must not be modified anymore.
//
-// Elements can be inserted in the pool using VG_(allocEltDedupPA)
-// or using VG_(allocFixedEltDedupPA).
+// Elements can be inserted in the pool using VG_(allocEltDedupPA),
+// VG_(allocFixedEltDedupPA) or VG_(allocStrDedupPA).
//
// Use VG_(allocFixedEltDedupPA) to allocate elements that are all of
// the same size and that you want to identify with a (small) number:
// The address of an element allocated with VG_(allocEltDedupPA) does
// not change, even if new elements are inserted in the pool.
//
+// Use VG_(allocStrDedupPA) to create a pool of strings (in other words, a
+// dictionnary of strings). Similarly to VG_(allocFixedEltDedupPA), strings
+// inserted in a dedup pool can be identified by an element number.
+//
// In the same pool, you can only use one of the allocate element functions.
//
// A dedup pool allocator has significantly less memory overhead than
const HChar* cc,
void (*free_fn)(void*) );
-/* Allocates a new element from ddpa with eltSzB bytes to store elt.
+/* Allocates or retrieve element from ddpa with eltSzB bytes to store elt.
This function never returns NULL.
If ddpa already contains an element equal to elt, then the address of
the already existing element is returned.
Equality between elements is done by comparing all bytes.
So, if void *elt points to a struct, be sure to initialise all components
and the holes between components. */
-extern const void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa,
- SizeT eltSzB, const void *elt);
+extern const void* VG_(allocEltDedupPA) (DedupPoolAlloc* ddpa,
+ SizeT eltSzB, const void* elt);
-/* Allocates a new (fixed size) element from ddpa. Returns the
- unique number identifying this element. This function never returns NULL.
+/* Allocates or retrieve a (fixed size) element from ddpa. Returns the
+ unique number identifying this element.
Similarly to VG_(allocEltDedupPA), this will return the unique number
of an already existing identical element to elt. */
-extern UInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc *ddpa,
- SizeT eltSzB, const void *elt);
+extern UInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc* ddpa,
+ SizeT eltSzB, const void* elt);
/* Translate an element number to its address. Note that the address
corresponding to eltNr can change if new elements are inserted
in the pool. */
-extern void* VG_(indexEltNumber) (DedupPoolAlloc *ddpa,
+extern void* VG_(indexEltNumber) (DedupPoolAlloc* ddpa,
UInt eltNr);
+/* Allocates or retrieve a string element from ddpa. Returns the
+ unique number identifying this string.
+ newStr is set to True if the str is a newly inserted string, False
+ if the str was already present in the pool.
+ Similarly to VG_(allocEltDedupPA), this will return the unique number
+ of an already existing identical string. */
+extern UInt VG_(allocStrDedupPA) (DedupPoolAlloc *ddpa,
+ const HChar* str,
+ Bool* newStr);
+/* Note: Implementing a function to return the string value from its strNr
+ implies some overhead, so will be done only if/when needed. */
+
+
/* The Dedup Pool Allocator must maintain a data structure to avoid
duplicates as long as new elements can be allocated from the pool.
Once no new elements will be allocated, this dedup data structure
it is an error to call VG_(allocEltDedupPA) or VG_(allocFixedEltDedupPA).
If shrink_block is not NULL, the last pool will be shrunk using
shrink_block. */
-extern void VG_(freezeDedupPA) (DedupPoolAlloc *ddpa,
+extern void VG_(freezeDedupPA) (DedupPoolAlloc* ddpa,
void (*shrink_block)(void*, SizeT));
/* How many (unique) elements are there in this ddpa now? */
-extern UInt VG_(sizeDedupPA) (DedupPoolAlloc *ddpa);
+extern UInt VG_(sizeDedupPA) (DedupPoolAlloc* ddpa);
/* Free all memory associated with a DedupPoolAlloc. */
-extern void VG_(deleteDedupPA) ( DedupPoolAlloc *ddpa);
+extern void VG_(deleteDedupPA) ( DedupPoolAlloc* ddpa);
#endif // __PUB_TOOL_DEDUPPOOLALLOC_