* When looking up a value using a Heaviside function, we get the value and its index.
*
* We can also split an DMT into two DMTs, splitting the weight of the values evenly.
* Find a value $j$ such that the values to the left of $j$ have about the same total weight as the values to the right of $j$.
* The resulting two DMTs contain the values to the left of $j$ and the values to the right of $j$ respectively.
* All of the values from the original DMT go into one of the new DMTs.
* If the weights of the values don't split exactly evenly, then the implementation has the freedom to choose whether
* the new left DMT or the new right DMT is larger.
*
* Performance:
* Insertion and deletion should run with $O(\log |V|)$ time and $O(\log |V|)$ calls to the Heaviside function.
* The memory required is O(|V|).
*
* Usage:
* The dmt is templated by two parameters:
* The dmt is templated by three parameters:
* - dmtdata_t is what will be stored within the dmt. These could be pointers or real data types (ints, structs).
* - dmtdataout_t is what will be returned by find and related functions. By default, it is the same as dmtdata_t, but you can set it to (dmtdata_t *).
* - dmtwriter_t is a class that effectively handles (de)serialization between the value stored in the dmt and outside the dmt.
* To create an dmt which will store "TXNID"s, for example, it is a good idea to typedef the template:
* typedef dmt<TXNID> txnid_dmt_t;
* If you are storing structs, you may want to be able to get a pointer to the data actually stored in the dmt (see find_zero). To do this, use the second template parameter:
* If you are storing structs (or you want to edit what is stored), you may want to be able to get a pointer to the data actually stored in the dmt (see find_zero). To do this, use the second template parameter:
* Effect: Return the size (in bytes) of the dmt, as it resides in main memory. If the data stored are pointers, don't include the size of what they all point to.
* Effect: Return the size (in bytes) of the dmt, as it resides in main memory.
* If the data stored are pointers, don't include the size of what they all point to.
* //TODO(leif or yoni): (maybe rename and) return memory footprint instead of allocated size
*/
size_tmemory_size(void);
// Returns whether all values in the dmt are known to be the same size.
// Note:
// There are no false positives, but false negatives are allowed.
// A false negative can happen if this dmt had 2 (or more) different size values,
// and then enough were deleted so that all the remaining ones are the same size.
// Once that happens, this dmt will never again return true for this function unless/until
// ::clear() is called
boolvalue_length_is_fixed(void)const;
// If this dmt is empty, return value is undefined.
// else if value_length_is_fixed() then it returns the fixed length.
// else returns 0
uint32_tget_fixed_length(void)const;
// Preprocesses the dmt so that serialization can happen quickly.
// After this call, serialize_values() can be called but no other mutator function can be called in between.
voidprepare_for_serialize(void);
private:
...
...
@@ -544,29 +577,49 @@ class dmt {
structdmt_treet;
}d;
// Returns pad bytes per element (for alignment) or 0 if not fixed length.