Compare commits
1 Commits
master
...
extra-data
Author | SHA1 | Date |
---|---|---|
Vitaliy Filippov | 8dad748216 |
210
btree.h
210
btree.h
|
@ -260,15 +260,12 @@ struct btree_key_comparer<Key, Compare, true> {
|
||||||
// depending on whether we have a compare-to functor or not (which depends on
|
// depending on whether we have a compare-to functor or not (which depends on
|
||||||
// whether Compare is derived from btree_key_compare_to_tag).
|
// whether Compare is derived from btree_key_compare_to_tag).
|
||||||
template <typename Key, typename Compare>
|
template <typename Key, typename Compare>
|
||||||
static bool btree_compare_keys(
|
static bool btree_compare_keys(const Compare &comp, const Key &x, const Key &y) {
|
||||||
const Compare &comp, const Key &x, const Key &y) {
|
typedef btree_key_comparer<Key, Compare, btree_is_key_compare_to<Compare>::value> key_comparer;
|
||||||
typedef btree_key_comparer<Key, Compare,
|
|
||||||
btree_is_key_compare_to<Compare>::value> key_comparer;
|
|
||||||
return key_comparer::bool_compare(comp, x, y);
|
return key_comparer::bool_compare(comp, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Key, typename Compare,
|
template <typename Key, typename Compare, typename Alloc, int NodeValues>
|
||||||
typename Alloc, int TargetNodeSize, int ValueSize>
|
|
||||||
struct btree_common_params {
|
struct btree_common_params {
|
||||||
// If Compare is derived from btree_key_compare_to_tag then use it as the
|
// If Compare is derived from btree_key_compare_to_tag then use it as the
|
||||||
// key_compare type. Otherwise, use btree_key_compare_to_adapter<> which will
|
// key_compare type. Otherwise, use btree_key_compare_to_adapter<> which will
|
||||||
|
@ -286,27 +283,19 @@ struct btree_common_params {
|
||||||
typedef ptrdiff_t difference_type;
|
typedef ptrdiff_t difference_type;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kTargetNodeSize = TargetNodeSize,
|
kNodeValues = NodeValues,
|
||||||
|
|
||||||
// Available space for values. This is largest for leaf nodes,
|
|
||||||
// which has overhead no fewer than two pointers.
|
|
||||||
kNodeValueSpace = TargetNodeSize - 2 * sizeof(void*),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is an integral type large enough to hold as many
|
// This is an integral type large enough to hold NodeValues+1.
|
||||||
// ValueSize-values as will fit a node of TargetNodeSize bytes.
|
|
||||||
typedef typename if_<
|
typedef typename if_<
|
||||||
(kNodeValueSpace / ValueSize) >= 256,
|
NodeValues >= 255,
|
||||||
uint16_t,
|
uint16_t,
|
||||||
uint8_t>::type node_count_type;
|
uint8_t>::type node_count_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A parameters structure for holding the type parameters for a btree_map.
|
// A parameters structure for holding the type parameters for a btree_map.
|
||||||
template <typename Key, typename Data, typename Compare,
|
template <typename Key, typename Data, typename Compare, typename Alloc, int NodeValues>
|
||||||
typename Alloc, int TargetNodeSize>
|
struct btree_map_params : public btree_common_params<Key, Compare, Alloc, NodeValues> {
|
||||||
struct btree_map_params
|
|
||||||
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize,
|
|
||||||
sizeof(Key) + sizeof(Data)> {
|
|
||||||
typedef Data data_type;
|
typedef Data data_type;
|
||||||
typedef Data mapped_type;
|
typedef Data mapped_type;
|
||||||
typedef std::pair<const Key, data_type> value_type;
|
typedef std::pair<const Key, data_type> value_type;
|
||||||
|
@ -316,10 +305,6 @@ struct btree_map_params
|
||||||
typedef value_type& reference;
|
typedef value_type& reference;
|
||||||
typedef const value_type& const_reference;
|
typedef const value_type& const_reference;
|
||||||
|
|
||||||
enum {
|
|
||||||
kValueSize = sizeof(Key) + sizeof(data_type),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Key& key(const value_type &x) { return x.first; }
|
static const Key& key(const value_type &x) { return x.first; }
|
||||||
static const Key& key(const mutable_value_type &x) { return x.first; }
|
static const Key& key(const mutable_value_type &x) { return x.first; }
|
||||||
static void swap(mutable_value_type *a, mutable_value_type *b) {
|
static void swap(mutable_value_type *a, mutable_value_type *b) {
|
||||||
|
@ -329,10 +314,8 @@ struct btree_map_params
|
||||||
};
|
};
|
||||||
|
|
||||||
// A parameters structure for holding the type parameters for a btree_set.
|
// A parameters structure for holding the type parameters for a btree_set.
|
||||||
template <typename Key, typename Compare, typename Alloc, int TargetNodeSize>
|
template <typename Key, typename Compare, typename Alloc, int NodeValues>
|
||||||
struct btree_set_params
|
struct btree_set_params : public btree_common_params<Key, Compare, Alloc, NodeValues> {
|
||||||
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize,
|
|
||||||
sizeof(Key)> {
|
|
||||||
typedef std::false_type data_type;
|
typedef std::false_type data_type;
|
||||||
typedef std::false_type mapped_type;
|
typedef std::false_type mapped_type;
|
||||||
typedef Key value_type;
|
typedef Key value_type;
|
||||||
|
@ -342,18 +325,13 @@ struct btree_set_params
|
||||||
typedef value_type& reference;
|
typedef value_type& reference;
|
||||||
typedef const value_type& const_reference;
|
typedef const value_type& const_reference;
|
||||||
|
|
||||||
enum {
|
|
||||||
kValueSize = sizeof(Key),
|
|
||||||
};
|
|
||||||
|
|
||||||
static const Key& key(const value_type &x) { return x; }
|
static const Key& key(const value_type &x) { return x; }
|
||||||
static void swap(mutable_value_type *a, mutable_value_type *b) {
|
static void swap(mutable_value_type *a, mutable_value_type *b) {
|
||||||
btree_swap_helper<mutable_value_type>(*a, *b);
|
btree_swap_helper<mutable_value_type>(*a, *b);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// An adapter class that converts a lower-bound compare into an upper-bound
|
// An adapter class that converts a lower-bound compare into an upper-bound compare.
|
||||||
// compare.
|
|
||||||
template <typename Key, typename Compare>
|
template <typename Key, typename Compare>
|
||||||
struct btree_upper_bound_adapter : public Compare {
|
struct btree_upper_bound_adapter : public Compare {
|
||||||
btree_upper_bound_adapter(Compare c) : Compare(c) {}
|
btree_upper_bound_adapter(Compare c) : Compare(c) {}
|
||||||
|
@ -389,8 +367,7 @@ struct btree_linear_search_compare_to {
|
||||||
return n.linear_search_compare_to(k, 0, n.count(), comp);
|
return n.linear_search_compare_to(k, 0, n.count(), comp);
|
||||||
}
|
}
|
||||||
static int upper_bound(const K &k, const N &n, CompareTo comp) {
|
static int upper_bound(const K &k, const N &n, CompareTo comp) {
|
||||||
typedef btree_upper_bound_adapter<K,
|
typedef btree_upper_bound_adapter<K, btree_key_comparer<K, CompareTo, true> > upper_compare;
|
||||||
btree_key_comparer<K, CompareTo, true> > upper_compare;
|
|
||||||
return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp));
|
return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -414,8 +391,7 @@ struct btree_binary_search_compare_to {
|
||||||
return n.binary_search_compare_to(k, 0, n.count(), CompareTo());
|
return n.binary_search_compare_to(k, 0, n.count(), CompareTo());
|
||||||
}
|
}
|
||||||
static int upper_bound(const K &k, const N &n, CompareTo comp) {
|
static int upper_bound(const K &k, const N &n, CompareTo comp) {
|
||||||
typedef btree_upper_bound_adapter<K,
|
typedef btree_upper_bound_adapter<K, btree_key_comparer<K, CompareTo, true> > upper_compare;
|
||||||
btree_key_comparer<K, CompareTo, true> > upper_compare;
|
|
||||||
return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp));
|
return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -467,12 +443,21 @@ class btree_node {
|
||||||
std::is_integral<key_type>::value ||
|
std::is_integral<key_type>::value ||
|
||||||
std::is_floating_point<key_type>::value,
|
std::is_floating_point<key_type>::value,
|
||||||
linear_search_type, binary_search_type>::type search_type;
|
linear_search_type, binary_search_type>::type search_type;
|
||||||
|
enum {
|
||||||
|
kLeaf = 0,
|
||||||
|
kInternal = 1,
|
||||||
|
kRoot = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: pack structure
|
||||||
struct base_fields {
|
struct base_fields {
|
||||||
typedef typename Params::node_count_type field_type;
|
typedef typename Params::node_count_type field_type;
|
||||||
|
|
||||||
// A boolean indicating whether the node is a leaf or not.
|
// A number indicating whether the node is leaf, internal or root.
|
||||||
bool leaf;
|
uint8_t node_type;
|
||||||
|
// Value size (stored in every node even though it's not 100% required...)
|
||||||
|
// FIXME: uint16_t -> template
|
||||||
|
uint16_t value_size;
|
||||||
// The position of the node in the node's parent.
|
// The position of the node in the node's parent.
|
||||||
field_type position;
|
field_type position;
|
||||||
// The maximum number of values the node can hold.
|
// The maximum number of values the node can hold.
|
||||||
|
@ -484,27 +469,13 @@ class btree_node {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kValueSize = params_type::kValueSize,
|
|
||||||
kTargetNodeSize = params_type::kTargetNodeSize,
|
|
||||||
|
|
||||||
// Compute how many values we can fit onto a leaf node.
|
|
||||||
kNodeTargetValues = (kTargetNodeSize - sizeof(base_fields)) / kValueSize,
|
|
||||||
// We need a minimum of 3 values per internal node in order to perform
|
|
||||||
// splitting (1 value for the two nodes involved in the split and 1 value
|
|
||||||
// propagated to the parent as the delimiter for the split).
|
|
||||||
kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3,
|
|
||||||
|
|
||||||
kExactMatch = 1 << 30,
|
kExactMatch = 1 << 30,
|
||||||
kMatchMask = kExactMatch - 1,
|
kMatchMask = kExactMatch - 1,
|
||||||
|
kNodeValues = Params::kNodeValues,
|
||||||
|
kMinNodeValues = kNodeValues / 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct leaf_fields : public base_fields {
|
struct internal_fields : public base_fields {
|
||||||
// The array of values. Only the first count of these values have been
|
|
||||||
// constructed and are valid.
|
|
||||||
mutable_value_type values[kNodeValues];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct internal_fields : public leaf_fields {
|
|
||||||
// The array of child pointers. The keys in children_[i] are all less than
|
// The array of child pointers. The keys in children_[i] are all less than
|
||||||
// key(i). The keys in children_[i + 1] are all greater than key(i). There
|
// key(i). The keys in children_[i + 1] are all greater than key(i). There
|
||||||
// are always count + 1 children.
|
// are always count + 1 children.
|
||||||
|
@ -519,7 +490,7 @@ class btree_node {
|
||||||
public:
|
public:
|
||||||
// Getter/setter for whether this is a leaf node or not. This value doesn't
|
// Getter/setter for whether this is a leaf node or not. This value doesn't
|
||||||
// change after the node is created.
|
// change after the node is created.
|
||||||
bool leaf() const { return fields_.leaf; }
|
bool leaf() const { return fields_.node_type == kLeaf; }
|
||||||
|
|
||||||
// Getter for the position of this node in its parent.
|
// Getter for the position of this node in its parent.
|
||||||
int position() const { return fields_.position; }
|
int position() const { return fields_.position; }
|
||||||
|
@ -549,25 +520,34 @@ class btree_node {
|
||||||
size_type size() const { return fields_.size; }
|
size_type size() const { return fields_.size; }
|
||||||
size_type* mutable_size() { return &fields_.size; }
|
size_type* mutable_size() { return &fields_.size; }
|
||||||
|
|
||||||
|
// Getter for the value size
|
||||||
|
uint16_t value_size() const { return fields_.value_size; }
|
||||||
|
|
||||||
// Getters for the key/value at position i in the node.
|
// Getters for the key/value at position i in the node.
|
||||||
const key_type& key(int i) const {
|
const key_type& key(int i) const {
|
||||||
return params_type::key(fields_.values[i]);
|
return params_type::key(*((value_type*)data(i)));
|
||||||
}
|
}
|
||||||
reference value(int i) {
|
reference value(int i) {
|
||||||
mutable_value_type *ptr = (mutable_value_type*)&fields_.values[i];
|
mutable_value_type *ptr = (mutable_value_type*)data(i);
|
||||||
return reinterpret_cast<reference>(*ptr);
|
return reinterpret_cast<reference>(*ptr);
|
||||||
}
|
}
|
||||||
const_reference value(int i) const {
|
const_reference value(int i) const {
|
||||||
value_type *ptr = (value_type*)&fields_.values[i];
|
value_type *ptr = (value_type*)data(i);
|
||||||
return reinterpret_cast<const_reference>(*ptr);
|
return reinterpret_cast<const_reference>(*ptr);
|
||||||
}
|
}
|
||||||
mutable_value_type* mutable_value(int i) {
|
mutable_value_type* mutable_value(int i) {
|
||||||
return &fields_.values[i];
|
return (mutable_value_type*)data(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap value i in this node with value j in node x.
|
// Swap value i in this node with value j in node x.
|
||||||
void value_swap(int i, btree_node *x, int j) {
|
void value_swap(int i, btree_node *x, int j) {
|
||||||
params_type::swap(mutable_value(i), x->mutable_value(j));
|
params_type::swap(mutable_value(i), x->mutable_value(j));
|
||||||
|
if (value_size() > sizeof(value_type)) {
|
||||||
|
uint8_t extra[value_size()-sizeof(value_type)];
|
||||||
|
memcpy(extra, mutable_value(i)+1, value_size()-sizeof(value_type));
|
||||||
|
memcpy(mutable_value(i)+1, x->mutable_value(j)+1, value_size()-sizeof(value_type));
|
||||||
|
memcpy(x->mutable_value(j)+1, extra, value_size()-sizeof(value_type));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters/setter for the child at position i in the node.
|
// Getters/setter for the child at position i in the node.
|
||||||
|
@ -593,8 +573,7 @@ class btree_node {
|
||||||
// Returns the position of the first value whose key is not less than k using
|
// Returns the position of the first value whose key is not less than k using
|
||||||
// linear search performed using plain compare.
|
// linear search performed using plain compare.
|
||||||
template <typename Compare>
|
template <typename Compare>
|
||||||
int linear_search_plain_compare(
|
int linear_search_plain_compare(const key_type &k, int s, int e, const Compare &comp) const {
|
||||||
const key_type &k, int s, int e, const Compare &comp) const {
|
|
||||||
while (s < e) {
|
while (s < e) {
|
||||||
if (!btree_compare_keys(comp, key(s), k)) {
|
if (!btree_compare_keys(comp, key(s), k)) {
|
||||||
break;
|
break;
|
||||||
|
@ -607,8 +586,7 @@ class btree_node {
|
||||||
// Returns the position of the first value whose key is not less than k using
|
// Returns the position of the first value whose key is not less than k using
|
||||||
// linear search performed using compare-to.
|
// linear search performed using compare-to.
|
||||||
template <typename Compare>
|
template <typename Compare>
|
||||||
int linear_search_compare_to(
|
int linear_search_compare_to(const key_type &k, int s, int e, const Compare &comp) const {
|
||||||
const key_type &k, int s, int e, const Compare &comp) const {
|
|
||||||
while (s < e) {
|
while (s < e) {
|
||||||
int c = comp(key(s), k);
|
int c = comp(key(s), k);
|
||||||
if (c == 0) {
|
if (c == 0) {
|
||||||
|
@ -624,8 +602,7 @@ class btree_node {
|
||||||
// Returns the position of the first value whose key is not less than k using
|
// Returns the position of the first value whose key is not less than k using
|
||||||
// binary search performed using plain compare.
|
// binary search performed using plain compare.
|
||||||
template <typename Compare>
|
template <typename Compare>
|
||||||
int binary_search_plain_compare(
|
int binary_search_plain_compare(const key_type &k, int s, int e, const Compare &comp) const {
|
||||||
const key_type &k, int s, int e, const Compare &comp) const {
|
|
||||||
while (s != e) {
|
while (s != e) {
|
||||||
int mid = (s + e) / 2;
|
int mid = (s + e) / 2;
|
||||||
if (btree_compare_keys(comp, key(mid), k)) {
|
if (btree_compare_keys(comp, key(mid), k)) {
|
||||||
|
@ -640,8 +617,7 @@ class btree_node {
|
||||||
// Returns the position of the first value whose key is not less than k using
|
// Returns the position of the first value whose key is not less than k using
|
||||||
// binary search performed using compare-to.
|
// binary search performed using compare-to.
|
||||||
template <typename CompareTo>
|
template <typename CompareTo>
|
||||||
int binary_search_compare_to(
|
int binary_search_compare_to(const key_type &k, int s, int e, const CompareTo &comp) const {
|
||||||
const key_type &k, int s, int e, const CompareTo &comp) const {
|
|
||||||
while (s != e) {
|
while (s != e) {
|
||||||
int mid = (s + e) / 2;
|
int mid = (s + e) / 2;
|
||||||
int c = comp(key(mid), k);
|
int c = comp(key(mid), k);
|
||||||
|
@ -684,29 +660,36 @@ class btree_node {
|
||||||
void swap(btree_node *src);
|
void swap(btree_node *src);
|
||||||
|
|
||||||
// Node allocation/deletion routines.
|
// Node allocation/deletion routines.
|
||||||
static btree_node* init_leaf(
|
static btree_node* init_base(base_fields *f, btree_node *parent, int max_count, int value_size) {
|
||||||
leaf_fields *f, btree_node *parent, int max_count) {
|
|
||||||
btree_node *n = reinterpret_cast<btree_node*>(f);
|
btree_node *n = reinterpret_cast<btree_node*>(f);
|
||||||
f->leaf = 1;
|
|
||||||
f->position = 0;
|
f->position = 0;
|
||||||
|
f->value_size = value_size;
|
||||||
f->max_count = max_count;
|
f->max_count = max_count;
|
||||||
f->count = 0;
|
f->count = 0;
|
||||||
f->parent = parent;
|
f->parent = parent;
|
||||||
if (!NDEBUG) {
|
if (!NDEBUG) {
|
||||||
memset(&f->values, 0, max_count * sizeof(value_type));
|
memset(n->data(0), 0, max_count * value_size);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
static btree_node* init_internal(internal_fields *f, btree_node *parent) {
|
static btree_node* init_leaf(base_fields *f, btree_node *parent, int max_count, int value_size) {
|
||||||
btree_node *n = init_leaf(f, parent, kNodeValues);
|
f->node_type = kLeaf;
|
||||||
f->leaf = 0;
|
return init_base(f, parent, max_count, value_size);
|
||||||
|
}
|
||||||
|
static btree_node* init_internal(internal_fields *f, btree_node *parent, int value_size) {
|
||||||
|
f->node_type = kInternal;
|
||||||
|
btree_node *n = init_base(f, parent, kNodeValues, value_size);
|
||||||
if (!NDEBUG) {
|
if (!NDEBUG) {
|
||||||
memset(f->children, 0, sizeof(f->children));
|
memset(f->children, 0, sizeof(f->children));
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
static btree_node* init_root(root_fields *f, btree_node *parent) {
|
static btree_node* init_root(root_fields *f, btree_node *parent, int value_size) {
|
||||||
btree_node *n = init_internal(f, parent);
|
f->node_type = kRoot;
|
||||||
|
btree_node *n = init_base(f, parent, kNodeValues, value_size);
|
||||||
|
if (!NDEBUG) {
|
||||||
|
memset(f->children, 0, sizeof(f->children));
|
||||||
|
}
|
||||||
f->rightmost = parent;
|
f->rightmost = parent;
|
||||||
f->size = parent->count();
|
f->size = parent->count();
|
||||||
return n;
|
return n;
|
||||||
|
@ -719,13 +702,19 @@ class btree_node {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void value_init(int i) {
|
void value_init(int i) {
|
||||||
new (&fields_.values[i]) mutable_value_type;
|
new (data(i)) mutable_value_type;
|
||||||
}
|
}
|
||||||
void value_init(int i, const value_type &x) {
|
void value_init(int i, const value_type &x) {
|
||||||
new (&fields_.values[i]) mutable_value_type(x);
|
new (data(i)) mutable_value_type(x);
|
||||||
}
|
}
|
||||||
void value_destroy(int i) {
|
void value_destroy(int i) {
|
||||||
fields_.values[i].~mutable_value_type();
|
((mutable_value_type*)data(i))->~mutable_value_type();
|
||||||
|
}
|
||||||
|
void* data(int i) const {
|
||||||
|
return (void*)((uint8_t*)&fields_ + (fields_.node_type == kLeaf
|
||||||
|
? sizeof(base_fields)
|
||||||
|
: (fields_.node_type == kInternal ? sizeof(internal_fields) : sizeof(root_fields)))
|
||||||
|
+ i * value_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -857,7 +846,6 @@ class btree : public Params::key_compare {
|
||||||
typedef btree<Params> self_type;
|
typedef btree<Params> self_type;
|
||||||
typedef btree_node<Params> node_type;
|
typedef btree_node<Params> node_type;
|
||||||
typedef typename node_type::base_fields base_fields;
|
typedef typename node_type::base_fields base_fields;
|
||||||
typedef typename node_type::leaf_fields leaf_fields;
|
|
||||||
typedef typename node_type::internal_fields internal_fields;
|
typedef typename node_type::internal_fields internal_fields;
|
||||||
typedef typename node_type::root_fields root_fields;
|
typedef typename node_type::root_fields root_fields;
|
||||||
typedef typename Params::is_key_compare_to is_key_compare_to;
|
typedef typename Params::is_key_compare_to is_key_compare_to;
|
||||||
|
@ -870,11 +858,10 @@ class btree : public Params::key_compare {
|
||||||
btree_internal_locate_plain_compare>::type internal_locate_type;
|
btree_internal_locate_plain_compare>::type internal_locate_type;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
kNodeValues = node_type::kNodeValues,
|
|
||||||
kMinNodeValues = kNodeValues / 2,
|
|
||||||
kValueSize = node_type::kValueSize,
|
|
||||||
kExactMatch = node_type::kExactMatch,
|
kExactMatch = node_type::kExactMatch,
|
||||||
kMatchMask = node_type::kMatchMask,
|
kMatchMask = node_type::kMatchMask,
|
||||||
|
kNodeValues = node_type::kNodeValues,
|
||||||
|
kMinNodeValues = node_type::kMinNodeValues,
|
||||||
};
|
};
|
||||||
|
|
||||||
// A helper class to get the empty base class optimization for 0-size
|
// A helper class to get the empty base class optimization for 0-size
|
||||||
|
@ -932,7 +919,7 @@ class btree : public Params::key_compare {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
btree(const key_compare &comp, const allocator_type &alloc);
|
btree(const key_compare &comp, const allocator_type &alloc, int value_size);
|
||||||
|
|
||||||
// Copy constructor.
|
// Copy constructor.
|
||||||
btree(const self_type &x);
|
btree(const self_type &x);
|
||||||
|
@ -1176,21 +1163,21 @@ class btree : public Params::key_compare {
|
||||||
node_stats stats = internal_stats(root());
|
node_stats stats = internal_stats(root());
|
||||||
if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) {
|
if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) {
|
||||||
return sizeof(*this) +
|
return sizeof(*this) +
|
||||||
sizeof(base_fields) + root()->max_count() * sizeof(value_type);
|
sizeof(base_fields) + root()->max_count() * value_size_;
|
||||||
} else {
|
} else {
|
||||||
return sizeof(*this) +
|
return sizeof(*this) +
|
||||||
sizeof(root_fields) - sizeof(internal_fields) +
|
sizeof(root_fields) - sizeof(internal_fields) +
|
||||||
stats.leaf_nodes * sizeof(leaf_fields) +
|
stats.leaf_nodes * (sizeof(base_fields) + root()->max_count() * value_size_) +
|
||||||
stats.internal_nodes * sizeof(internal_fields);
|
stats.internal_nodes * sizeof(internal_fields);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The average number of bytes used per value stored in the btree.
|
// The average number of bytes used per value stored in the btree.
|
||||||
static double average_bytes_per_value() {
|
double average_bytes_per_value() {
|
||||||
// Returns the number of bytes per value on a leaf node that is 75%
|
// Returns the number of bytes per value on a leaf node that is 75%
|
||||||
// full. Experimentally, this matches up nicely with the computed number of
|
// full. Experimentally, this matches up nicely with the computed number of
|
||||||
// bytes per value in trees that had their values inserted in random order.
|
// bytes per value in trees that had their values inserted in random order.
|
||||||
return sizeof(leaf_fields) / (kNodeValues * 0.75);
|
return value_size_ / 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The fullness of the btree. Computed as the number of elements in the btree
|
// The fullness of the btree. Computed as the number of elements in the btree
|
||||||
|
@ -1198,7 +1185,7 @@ class btree : public Params::key_compare {
|
||||||
// of nodes could hold. A value of 1 indicates perfect space
|
// of nodes could hold. A value of 1 indicates perfect space
|
||||||
// utilization. Smaller values indicate space wastage.
|
// utilization. Smaller values indicate space wastage.
|
||||||
double fullness() const {
|
double fullness() const {
|
||||||
return double(size()) / (nodes() * kNodeValues);
|
return double(size()) / (nodes() * Params::kNodeValues);
|
||||||
}
|
}
|
||||||
// The overhead of the btree structure in bytes per node. Computed as the
|
// The overhead of the btree structure in bytes per node. Computed as the
|
||||||
// total number of bytes used by the btree minus the number of bytes used for
|
// total number of bytes used by the btree minus the number of bytes used for
|
||||||
|
@ -1207,7 +1194,7 @@ class btree : public Params::key_compare {
|
||||||
if (empty()) {
|
if (empty()) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
return (bytes_used() - size() * kValueSize) / double(size());
|
return (bytes_used() - size() * value_size_) / double(size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1243,41 +1230,40 @@ class btree : public Params::key_compare {
|
||||||
// Node creation/deletion routines.
|
// Node creation/deletion routines.
|
||||||
node_type* new_internal_node(node_type *parent) {
|
node_type* new_internal_node(node_type *parent) {
|
||||||
internal_fields *p = reinterpret_cast<internal_fields*>(
|
internal_fields *p = reinterpret_cast<internal_fields*>(
|
||||||
mutable_internal_allocator()->allocate(sizeof(internal_fields)));
|
mutable_internal_allocator()->allocate(sizeof(internal_fields) + value_size_ * Params::kNodeValues));
|
||||||
return node_type::init_internal(p, parent);
|
return node_type::init_internal(p, parent, value_size_);
|
||||||
}
|
}
|
||||||
node_type* new_internal_root_node() {
|
node_type* new_internal_root_node() {
|
||||||
root_fields *p = reinterpret_cast<root_fields*>(
|
root_fields *p = reinterpret_cast<root_fields*>(
|
||||||
mutable_internal_allocator()->allocate(sizeof(root_fields)));
|
mutable_internal_allocator()->allocate(sizeof(root_fields) + value_size_ * Params::kNodeValues));
|
||||||
return node_type::init_root(p, root()->parent());
|
return node_type::init_root(p, root()->parent(), value_size_);
|
||||||
}
|
}
|
||||||
node_type* new_leaf_node(node_type *parent) {
|
node_type* new_leaf_node(node_type *parent) {
|
||||||
leaf_fields *p = reinterpret_cast<leaf_fields*>(
|
base_fields *p = reinterpret_cast<base_fields*>(
|
||||||
mutable_internal_allocator()->allocate(sizeof(leaf_fields)));
|
mutable_internal_allocator()->allocate(sizeof(base_fields) + value_size_ * Params::kNodeValues));
|
||||||
return node_type::init_leaf(p, parent, kNodeValues);
|
return node_type::init_leaf(p, parent, Params::kNodeValues, value_size_);
|
||||||
}
|
}
|
||||||
node_type* new_leaf_root_node(int max_count) {
|
node_type* new_leaf_root_node(int max_count) {
|
||||||
leaf_fields *p = reinterpret_cast<leaf_fields*>(
|
base_fields *p = reinterpret_cast<base_fields*>(
|
||||||
mutable_internal_allocator()->allocate(
|
mutable_internal_allocator()->allocate(sizeof(base_fields) + value_size_ * Params::kNodeValues));
|
||||||
sizeof(base_fields) + max_count * sizeof(value_type)));
|
return node_type::init_leaf(p, reinterpret_cast<node_type*>(p), Params::kNodeValues, value_size_);
|
||||||
return node_type::init_leaf(p, reinterpret_cast<node_type*>(p), max_count);
|
|
||||||
}
|
}
|
||||||
void delete_internal_node(node_type *node) {
|
void delete_internal_node(node_type *node) {
|
||||||
node->destroy();
|
node->destroy();
|
||||||
assert(node != root());
|
assert(node != root());
|
||||||
mutable_internal_allocator()->deallocate(
|
mutable_internal_allocator()->deallocate(
|
||||||
reinterpret_cast<char*>(node), sizeof(internal_fields));
|
reinterpret_cast<char*>(node), sizeof(internal_fields) + value_size_ * Params::kNodeValues);
|
||||||
}
|
}
|
||||||
void delete_internal_root_node() {
|
void delete_internal_root_node() {
|
||||||
root()->destroy();
|
root()->destroy();
|
||||||
mutable_internal_allocator()->deallocate(
|
mutable_internal_allocator()->deallocate(
|
||||||
reinterpret_cast<char*>(root()), sizeof(root_fields));
|
reinterpret_cast<char*>(root()), sizeof(root_fields) + value_size_ * Params::kNodeValues);
|
||||||
}
|
}
|
||||||
void delete_leaf_node(node_type *node) {
|
void delete_leaf_node(node_type *node) {
|
||||||
node->destroy();
|
node->destroy();
|
||||||
mutable_internal_allocator()->deallocate(
|
mutable_internal_allocator()->deallocate(
|
||||||
reinterpret_cast<char*>(node),
|
reinterpret_cast<char*>(node),
|
||||||
sizeof(base_fields) + node->max_count() * sizeof(value_type));
|
sizeof(base_fields) + node->max_count() * value_size_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebalances or splits the node iter points to.
|
// Rebalances or splits the node iter points to.
|
||||||
|
@ -1379,6 +1365,7 @@ class btree : public Params::key_compare {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
empty_base_handle<internal_allocator_type, node_type*> root_;
|
empty_base_handle<internal_allocator_type, node_type*> root_;
|
||||||
|
int value_size_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// A never instantiated helper function that returns big_ if we have a
|
// A never instantiated helper function that returns big_ if we have a
|
||||||
|
@ -1405,9 +1392,8 @@ class btree : public Params::key_compare {
|
||||||
sizeof(big_),
|
sizeof(big_),
|
||||||
key_comparison_function_must_return_bool);
|
key_comparison_function_must_return_bool);
|
||||||
|
|
||||||
// Note: We insist on kTargetValues, which is computed from
|
// Note: We insist on kTargetValues must fit the base_fields::field_type.
|
||||||
// Params::kTargetNodeSize, must fit the base_fields::field_type.
|
COMPILE_ASSERT(Params::kNodeValues <
|
||||||
COMPILE_ASSERT(kNodeValues <
|
|
||||||
(1 << (8 * sizeof(typename base_fields::field_type))),
|
(1 << (8 * sizeof(typename base_fields::field_type))),
|
||||||
target_node_size_too_large);
|
target_node_size_too_large);
|
||||||
|
|
||||||
|
@ -1727,9 +1713,11 @@ void btree_iterator<N, R, P>::decrement_slow() {
|
||||||
////
|
////
|
||||||
// btree methods
|
// btree methods
|
||||||
template <typename P>
|
template <typename P>
|
||||||
btree<P>::btree(const key_compare &comp, const allocator_type &alloc)
|
btree<P>::btree(const key_compare &comp, const allocator_type &alloc, int value_size)
|
||||||
: key_compare(comp),
|
: key_compare(comp),
|
||||||
root_(alloc, NULL) {
|
root_(alloc, NULL),
|
||||||
|
value_size_(value_size) {
|
||||||
|
assert(value_size >= sizeof(value_type));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
|
|
|
@ -47,8 +47,8 @@ class btree_container {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
btree_container(const key_compare &comp, const allocator_type &alloc)
|
btree_container(const key_compare &comp, const allocator_type &alloc, int value_size)
|
||||||
: tree_(comp, alloc) {
|
: tree_(comp, alloc, value_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy constructor.
|
// Copy constructor.
|
||||||
|
@ -160,8 +160,9 @@ class btree_unique_container : public btree_container<Tree> {
|
||||||
public:
|
public:
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
btree_unique_container(const key_compare &comp = key_compare(),
|
btree_unique_container(const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type(),
|
||||||
: super_type(comp, alloc) {
|
int value_size = sizeof(value_type))
|
||||||
|
: super_type(comp, alloc, value_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy constructor.
|
// Copy constructor.
|
||||||
|
@ -172,9 +173,10 @@ class btree_unique_container : public btree_container<Tree> {
|
||||||
// Range constructor.
|
// Range constructor.
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
btree_unique_container(InputIterator b, InputIterator e,
|
btree_unique_container(InputIterator b, InputIterator e,
|
||||||
|
int value_size = sizeof(value_type),
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type())
|
||||||
: super_type(comp, alloc) {
|
: super_type(comp, alloc, value_size) {
|
||||||
insert(b, e);
|
insert(b, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,8 +249,9 @@ class btree_map_container : public btree_unique_container<Tree> {
|
||||||
public:
|
public:
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
btree_map_container(const key_compare &comp = key_compare(),
|
btree_map_container(const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type(),
|
||||||
: super_type(comp, alloc) {
|
int value_size = sizeof(value_type))
|
||||||
|
: super_type(comp, alloc, value_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy constructor.
|
// Copy constructor.
|
||||||
|
@ -260,8 +263,9 @@ class btree_map_container : public btree_unique_container<Tree> {
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
btree_map_container(InputIterator b, InputIterator e,
|
btree_map_container(InputIterator b, InputIterator e,
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type(),
|
||||||
: super_type(b, e, comp, alloc) {
|
int value_size = sizeof(value_type))
|
||||||
|
: super_type(b, e, comp, alloc, value_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertion routines.
|
// Insertion routines.
|
||||||
|
@ -288,8 +292,9 @@ class btree_multi_container : public btree_container<Tree> {
|
||||||
public:
|
public:
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
btree_multi_container(const key_compare &comp = key_compare(),
|
btree_multi_container(const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type(),
|
||||||
: super_type(comp, alloc) {
|
int value_size = sizeof(value_type))
|
||||||
|
: super_type(comp, alloc, value_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy constructor.
|
// Copy constructor.
|
||||||
|
@ -301,8 +306,9 @@ class btree_multi_container : public btree_container<Tree> {
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
btree_multi_container(InputIterator b, InputIterator e,
|
btree_multi_container(InputIterator b, InputIterator e,
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type(),
|
||||||
: super_type(comp, alloc) {
|
int value_size = sizeof(value_type))
|
||||||
|
: super_type(comp, alloc, value_size) {
|
||||||
insert(b, e);
|
insert(b, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
btree_map.h
26
btree_map.h
|
@ -37,13 +37,12 @@ namespace btree {
|
||||||
template <typename Key, typename Value,
|
template <typename Key, typename Value,
|
||||||
typename Compare = std::less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
int TargetNodeSize = 256>
|
int NodeValues = 16>
|
||||||
class btree_map : public btree_map_container<
|
class btree_map : public btree_map_container<
|
||||||
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
btree<btree_map_params<Key, Value, Compare, Alloc, NodeValues> > > {
|
||||||
|
|
||||||
typedef btree_map<Key, Value, Compare, Alloc, TargetNodeSize> self_type;
|
typedef btree_map<Key, Value, Compare, Alloc, NodeValues> self_type;
|
||||||
typedef btree_map_params<
|
typedef btree_map_params<Key, Value, Compare, Alloc, NodeValues> params_type;
|
||||||
Key, Value, Compare, Alloc, TargetNodeSize> params_type;
|
|
||||||
typedef btree<params_type> btree_type;
|
typedef btree<params_type> btree_type;
|
||||||
typedef btree_map_container<btree_type> super_type;
|
typedef btree_map_container<btree_type> super_type;
|
||||||
|
|
||||||
|
@ -53,9 +52,10 @@ class btree_map : public btree_map_container<
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Default constructor.
|
// Default constructor.
|
||||||
btree_map(const key_compare &comp = key_compare(),
|
btree_map(int extra_size = 0,
|
||||||
|
const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type())
|
||||||
: super_type(comp, alloc) {
|
: super_type(comp, alloc, sizeof(typename btree_type::value_type)+extra_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy constructor.
|
// Copy constructor.
|
||||||
|
@ -66,9 +66,10 @@ class btree_map : public btree_map_container<
|
||||||
// Range constructor.
|
// Range constructor.
|
||||||
template <class InputIterator>
|
template <class InputIterator>
|
||||||
btree_map(InputIterator b, InputIterator e,
|
btree_map(InputIterator b, InputIterator e,
|
||||||
|
int extra_size = 0,
|
||||||
const key_compare &comp = key_compare(),
|
const key_compare &comp = key_compare(),
|
||||||
const allocator_type &alloc = allocator_type())
|
const allocator_type &alloc = allocator_type())
|
||||||
: super_type(b, e, comp, alloc) {
|
: super_type(b, e, comp, alloc, sizeof(typename btree_type::value_type)+extra_size) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -82,13 +83,12 @@ inline void swap(btree_map<K, V, C, A, N> &x,
|
||||||
template <typename Key, typename Value,
|
template <typename Key, typename Value,
|
||||||
typename Compare = std::less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
int TargetNodeSize = 256>
|
int NodeValues = 16>
|
||||||
class btree_multimap : public btree_multi_container<
|
class btree_multimap : public btree_multi_container<
|
||||||
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
btree<btree_map_params<Key, Value, Compare, Alloc, NodeValues> > > {
|
||||||
|
|
||||||
typedef btree_multimap<Key, Value, Compare, Alloc, TargetNodeSize> self_type;
|
typedef btree_multimap<Key, Value, Compare, Alloc, NodeValues> self_type;
|
||||||
typedef btree_map_params<
|
typedef btree_map_params<Key, Value, Compare, Alloc, NodeValues> params_type;
|
||||||
Key, Value, Compare, Alloc, TargetNodeSize> params_type;
|
|
||||||
typedef btree<params_type> btree_type;
|
typedef btree<params_type> btree_type;
|
||||||
typedef btree_multi_container<btree_type> super_type;
|
typedef btree_multi_container<btree_type> super_type;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue