Ability to store an extra portion data of fixed, yet unknown during compilation, size with every value

extra-data
Vitaliy Filippov 2020-11-28 00:09:59 +03:00
parent 5dc108754a
commit 8dad748216
3 changed files with 131 additions and 137 deletions

210
btree.h
View File

@ -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>

View File

@ -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);
} }

View File

@ -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;