Build outside of Google; add CMakeLists.txt, README

pull/5/head
Josh MacDonald 2012-07-17 17:25:01 -07:00
parent 9783752d62
commit 88853fbc9e
14 changed files with 626 additions and 644 deletions

23
CMakeLists.txt Normal file
View File

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 2.6)
project(cppbtree CXX)
option(build_tests "Build B-tree tests" OFF)
add_definitions(-std=c++0x)
set(CMAKE_CXX_FLAGS "-g")
# CMake doesn't have a way to pure template library,
add_library(cppbtree btree.h btree_map.h btree_set.h safe_btree.h safe_btree_map.h safe_btree_set.h)
set_target_properties(cppbtree PROPERTIES LINKER_LANGUAGE CXX)
if(build_tests)
enable_testing()
include_directories($ENV{GTEST_ROOT}/include)
link_directories($ENV{GTEST_ROOT})
add_executable(btree_test btree_test.cc btree_test_flags.cc)
add_executable(safe_btree_test safe_btree_test.cc btree_test_flags.cc)
add_executable(btree_bench btree_bench.cc btree_test_flags.cc)
target_link_libraries(btree_test gtest_main gflags)
target_link_libraries(safe_btree_test gtest_main gflags)
target_link_libraries(btree_bench gflags)
endif()

15
README Normal file
View File

@ -0,0 +1,15 @@
This library is a C++ template library and, as such, there is no
library to build and install.
----
To build and run the provided tests, however, you will need to install
CMake and the Google C++ Test framework.
Download CMake from http://www.cmake.org
Download the GoogleTest framework from http://code.google.com/p/googletest
export GTEST_ROOT=/path/for/gtest-x.y
cmake . -Dbuild_tests=ON

381
btree.h
View File

@ -35,11 +35,6 @@
//
// btree_bench --benchmarks=. 2>&1 | ./benchmarks.awk
//
// NOTE(pmattis): My warpstation (pmattis-warp.nyc) often produces slower
// results when running the benchmarks on CPUs 0 and 1 vs CPUs 2 and 3. To get
// consistent benchmark results, I run "taskset 0xc <command>" to run the
// benchmark on CPUs 2 and 3.
//
// Run on pmattis-warp.nyc (4 X 2200 MHz CPUs); 2010/03/04-15:23:06
// Benchmark STL(ns) B-Tree(ns) @ <size>
// --------------------------------------------------------
@ -91,61 +86,29 @@
// BM_map_string_mixedaddrem 6400 5200 +18.75% <256> [72.0, 57.8]
// BM_map_string_fifo 398 596 -49.75% <256> [72.0, 44.0]
// BM_map_string_fwditer 243 113 +53.50% <256> [72.0, 55.8]
// BM_set_cord_insert 3661 2680 +26.80% <256> [40.0, 10.5]
// BM_set_cord_lookup 2920 2293 +21.47% <256> [40.0, 10.5]
// BM_set_cord_fulllookup 2960 2267 +23.41% <256> [40.0, 8.8]
// BM_set_cord_delete 4679 2535 +45.82% <256> [40.0, 10.5]
// BM_set_cord_queueaddrem 8230 5600 +31.96% <256> [40.0, 11.3]
// BM_set_cord_mixedaddrem 8497 6080 +28.45% <256> [40.0, 10.7]
// BM_set_cord_fifo 358 370 -3.35% <256> [40.0, 8.8]
// BM_set_cord_fwditer 352 193 +45.17% <256> [40.0, 10.5]
// BM_map_cord_insert 3680 2927 +20.46% <256> [48.0, 20.7]
// BM_map_cord_lookup 3018 2466 +18.29% <256> [48.0, 20.7]
// BM_map_cord_fulllookup 2943 2466 +16.21% <256> [48.0, 17.2]
// BM_map_cord_delete 4675 2775 +40.64% <256> [48.0, 20.7]
// BM_map_cord_queueaddrem 8383 6360 +24.13% <256> [48.0, 22.2]
// BM_map_cord_mixedaddrem 8952 6760 +24.49% <256> [48.0, 21.2]
// BM_map_cord_fifo 444 463 -4.28% <256> [48.0, 17.2]
// BM_map_cord_fwditer 391 225 +42.46% <256> [48.0, 20.7]
#ifndef UTIL_BTREE_BTREE_H__
#define UTIL_BTREE_BTREE_H__
#include <assert.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator> // IWYU pragma: export // Clients can rely on this.
#include <iterator>
#include <limits>
#include <type_traits>
#include <new>
#include <ostream> // IWYU pragma: export // Clients can rely on this.
#include <ostream>
#include <string>
#include <utility>
#include "base/gdb-scripting.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/template_util.h"
#include "base/type_traits.h"
#include "strings/cord.h"
#include "strings/stringpiece.h"
#ifndef NDEBUG
#define NDEBUG 1
#endif
// iwyu.py found std::swap in <vector>, but we include <algorithm>.
// IWYU pragma: no_include <vector>
//
// iwyu.py doesn't think we need <ostream>, so wants <iosfwd>.
// IWYU pragma: no_include <iosfwd>
//
// iwyu.py sure wants to bring in a lot of private STL headers.
// IWYU pragma: no_include <bits/ostream.tcc>
// IWYU pragma: no_include <bits/stl_iterator.h>
// IWYU pragma: no_include <bits/stl_iterator_base_funcs.h>
// IWYU pragma: no_include <bits/stl_iterator_base_types.h>
namespace util {
namespace btree {
// Inside a btree method, if we just call swap(), it will choose the
@ -161,6 +124,32 @@ inline void btree_swap_helper(T &a, T &b) {
swap(a, b);
}
// A template helper used to select A or B based on a condition.
template<bool cond, typename A, typename B>
struct if_{
typedef A type;
};
template<typename A, typename B>
struct if_<false, A, B> {
typedef B type;
};
// Types small_ and big_ are promise that sizeof(small_) < sizeof(big_)
typedef char small_;
struct big_ {
char dummy[2];
};
// A compile-time assertion.
template <bool>
struct CompileAssert {
};
#define COMPILE_ASSERT(expr, msg) \
typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
// A helper type used to indicate that a key-compare-to functor has been
// provided. A user can specify a key-compare-to functor by doing:
//
@ -180,7 +169,7 @@ struct btree_key_compare_to_tag {
// btree_key_compare_to_tag.
template <typename Compare>
struct btree_is_key_compare_to
: public base::is_convertible<Compare, btree_key_compare_to_tag> {
: public std::is_convertible<Compare, btree_key_compare_to_tag> {
};
// A helper class to convert a boolean comparison into a three-way "compare-to"
@ -201,77 +190,29 @@ struct btree_key_compare_to_adapter : Compare {
};
template <>
struct btree_key_compare_to_adapter<less<string> >
struct btree_key_compare_to_adapter<std::less<std::string> >
: public btree_key_compare_to_tag {
btree_key_compare_to_adapter() {}
btree_key_compare_to_adapter(const less<string>&) {}
btree_key_compare_to_adapter(const std::less<std::string>&) {}
btree_key_compare_to_adapter(
const btree_key_compare_to_adapter<less<string> >&) {}
int operator()(const string &a, const string &b) const {
const btree_key_compare_to_adapter<std::less<std::string> >&) {}
int operator()(const std::string &a, const std::string &b) const {
return a.compare(b);
}
};
template <>
struct btree_key_compare_to_adapter<greater<string> >
struct btree_key_compare_to_adapter<std::greater<std::string> >
: public btree_key_compare_to_tag {
btree_key_compare_to_adapter() {}
btree_key_compare_to_adapter(const greater<string>&) {}
btree_key_compare_to_adapter(const std::greater<std::string>&) {}
btree_key_compare_to_adapter(
const btree_key_compare_to_adapter<greater<string> >&) {}
int operator()(const string &a, const string &b) const {
const btree_key_compare_to_adapter<std::greater<std::string> >&) {}
int operator()(const std::string &a, const std::string &b) const {
return b.compare(a);
}
};
template <>
struct btree_key_compare_to_adapter<less<StringPiece> >
: public btree_key_compare_to_tag {
btree_key_compare_to_adapter() {}
btree_key_compare_to_adapter(const less<StringPiece>&) {}
btree_key_compare_to_adapter(
const btree_key_compare_to_adapter<less<StringPiece> >&) {}
int operator()(const StringPiece &a, const StringPiece &b) const {
return a.compare(b);
}
};
template <>
struct btree_key_compare_to_adapter<greater<StringPiece> >
: public btree_key_compare_to_tag {
btree_key_compare_to_adapter() {}
btree_key_compare_to_adapter(const greater<StringPiece>&) {}
btree_key_compare_to_adapter(
const btree_key_compare_to_adapter<greater<StringPiece> >&) {}
int operator()(const StringPiece &a, const StringPiece &b) const {
return b.compare(a);
}
};
template <>
struct btree_key_compare_to_adapter<less<Cord> >
: public btree_key_compare_to_tag {
btree_key_compare_to_adapter() {}
btree_key_compare_to_adapter(const less<Cord>&) {}
btree_key_compare_to_adapter(
const btree_key_compare_to_adapter<less<Cord> >&) {}
int operator()(const Cord &a, const Cord &b) const {
return a.CompareTo(b);
}
};
template <>
struct btree_key_compare_to_adapter<greater<Cord> >
: public btree_key_compare_to_tag {
btree_key_compare_to_adapter() {}
btree_key_compare_to_adapter(const greater<Cord>&) {}
btree_key_compare_to_adapter(
const btree_key_compare_to_adapter<greater<Cord> >&) {}
int operator()(const Cord &a, const Cord &b) const {
return b.CompareTo(a);
}
};
// A helper class that allows a compare-to functor to behave like a plain
// compare functor. This specialization is used when we do not have a
// compare-to functor.
@ -322,7 +263,7 @@ struct btree_common_params {
// 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
// fall-back to Compare if we don't have an appropriate specialization.
typedef typename base::if_<
typedef typename if_<
btree_is_key_compare_to<Compare>::value,
Compare, btree_key_compare_to_adapter<Compare> >::type key_compare;
// A type which indicates if we have a key-compare-to functor or a plain old
@ -344,10 +285,10 @@ struct btree_common_params {
// This is an integral type large enough to hold as many
// ValueSize-values as will fit a node of TargetNodeSize bytes.
typedef typename base::if_<
typedef typename if_<
(kNodeValueSpace / ValueSize) >= 256,
uint16,
uint8>::type node_count_type;
uint16_t,
uint8_t>::type node_count_type;
};
// A parameters structure for holding the type parameters for a btree_map.
@ -358,8 +299,8 @@ struct btree_map_params
sizeof(Key) + sizeof(Data)> {
typedef Data data_type;
typedef Data mapped_type;
typedef pair<const Key, data_type> value_type;
typedef pair<Key, data_type> mutable_value_type;
typedef std::pair<const Key, data_type> value_type;
typedef std::pair<Key, data_type> mutable_value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
@ -382,8 +323,8 @@ template <typename Key, typename Compare, typename Alloc, int TargetNodeSize>
struct btree_set_params
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize,
sizeof(Key)> {
typedef base::false_type data_type;
typedef base::false_type mapped_type;
typedef std::false_type data_type;
typedef std::false_type mapped_type;
typedef Key value_type;
typedef value_type mutable_value_type;
typedef value_type* pointer;
@ -499,22 +440,22 @@ class btree_node {
key_type, self_type, key_compare> binary_search_compare_to_type;
// If we have a valid key-compare-to type, use linear_search_compare_to,
// otherwise use linear_search_plain_compare.
typedef typename base::if_<
typedef typename if_<
Params::is_key_compare_to::value,
linear_search_compare_to_type,
linear_search_plain_compare_type>::type linear_search_type;
// If we have a valid key-compare-to type, use binary_search_compare_to,
// otherwise use binary_search_plain_compare.
typedef typename base::if_<
typedef typename if_<
Params::is_key_compare_to::value,
binary_search_compare_to_type,
binary_search_plain_compare_type>::type binary_search_type;
// If the key is an integral or floating point type, use linear search which
// is faster than binary search for such types. Might be wise to also
// configure linear search based on node-size.
typedef typename base::if_<
base::is_integral<key_type>::value ||
base::is_floating_point<key_type>::value,
typedef typename if_<
std::is_integral<key_type>::value ||
std::is_floating_point<key_type>::value,
linear_search_type, binary_search_type>::type search_type;
struct base_fields {
@ -586,7 +527,7 @@ class btree_node {
// be a leaf.
bool is_root() const { return parent()->leaf(); }
void make_root() {
DCHECK(parent()->is_root());
assert(parent()->is_root());
fields_.parent = fields_.parent->parent();
}
@ -739,7 +680,7 @@ class btree_node {
f->max_count = max_count;
f->count = 0;
f->parent = parent;
if (DEBUG_MODE) {
if (!NDEBUG) {
memset(&f->values, 0, max_count * sizeof(value_type));
}
return n;
@ -747,7 +688,7 @@ class btree_node {
static btree_node* init_internal(internal_fields *f, btree_node *parent) {
btree_node *n = init_leaf(f, parent, kNodeValues);
f->leaf = 0;
if (DEBUG_MODE) {
if (!NDEBUG) {
memset(f->children, 0, sizeof(f->children));
}
return n;
@ -779,7 +720,8 @@ class btree_node {
root_fields fields_;
private:
DISALLOW_EVIL_CONSTRUCTORS(btree_node);
btree_node(const btree_node&);
void operator=(const btree_node&);
};
template <typename Node, typename Reference, typename Pointer>
@ -790,7 +732,7 @@ struct btree_iterator {
typedef typename Node::params_type params_type;
typedef Node node_type;
typedef typename base::remove_const<Node>::type normal_node;
typedef typename std::remove_const<Node>::type normal_node;
typedef const Node const_node;
typedef typename params_type::value_type value_type;
typedef typename params_type::pointer normal_pointer;
@ -800,7 +742,7 @@ struct btree_iterator {
typedef Pointer pointer;
typedef Reference reference;
typedef bidirectional_iterator_tag iterator_category;
typedef std::bidirectional_iterator_tag iterator_category;
typedef btree_iterator<
normal_node, normal_reference, normal_pointer> iterator;
@ -885,7 +827,7 @@ struct btree_iterator {
// Dispatch helper class for using btree::internal_locate with plain compare.
struct btree_internal_locate_plain_compare {
template <typename K, typename T, typename Iter>
static pair<Iter, int> dispatch(const K &k, const T &t, Iter iter) {
static std::pair<Iter, int> dispatch(const K &k, const T &t, Iter iter) {
return t.internal_locate_plain_compare(k, iter);
}
};
@ -893,7 +835,7 @@ struct btree_internal_locate_plain_compare {
// Dispatch helper class for using btree::internal_locate with compare-to.
struct btree_internal_locate_compare_to {
template <typename K, typename T, typename Iter>
static pair<Iter, int> dispatch(const K &k, const T &t, Iter iter) {
static std::pair<Iter, int> dispatch(const K &k, const T &t, Iter iter) {
return t.internal_locate_compare_to(k, iter);
}
};
@ -910,7 +852,7 @@ class btree : public Params::key_compare {
friend class btree_internal_locate_plain_compare;
friend class btree_internal_locate_compare_to;
typedef typename base::if_<
typedef typename if_<
is_key_compare_to::value,
btree_internal_locate_compare_to,
btree_internal_locate_plain_compare>::type internal_locate_type;
@ -1037,11 +979,11 @@ class btree : public Params::key_compare {
// Finds the range of values which compare equal to key. The first member of
// the returned pair is equal to lower_bound(key). The second member pair of
// the pair is equal to upper_bound(key).
pair<iterator,iterator> equal_range(const key_type &key) {
return make_pair(lower_bound(key), upper_bound(key));
std::pair<iterator,iterator> equal_range(const key_type &key) {
return std::make_pair(lower_bound(key), upper_bound(key));
}
pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
return make_pair(lower_bound(key), upper_bound(key));
std::pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
return std::make_pair(lower_bound(key), upper_bound(key));
}
// Inserts a value into the btree only if it does not already exist. The
@ -1050,11 +992,11 @@ class btree : public Params::key_compare {
// is being inserted. Value is not dereferenced if the key already exists in
// the btree. See btree_map::operator[].
template <typename ValuePointer>
pair<iterator,bool> insert_unique(const key_type &key, ValuePointer value);
std::pair<iterator,bool> insert_unique(const key_type &key, ValuePointer value);
// Inserts a value into the btree only if it does not already exist. The
// boolean return value indicates whether insertion succeeded or failed.
pair<iterator,bool> insert_unique(const value_type &v) {
std::pair<iterator,bool> insert_unique(const value_type &v) {
return insert_unique(params_type::key(v), &v);
}
@ -1170,7 +1112,7 @@ class btree : public Params::key_compare {
// Dump the btree to the specified ostream. Requires that operator<< is
// defined for Key and Value.
void dump(ostream &os) const {
void dump(std::ostream &os) const {
if (root() != NULL) {
internal_dump(os, root(), 0);
}
@ -1185,7 +1127,7 @@ class btree : public Params::key_compare {
if (root()->leaf()) return root()->count();
return root()->size();
}
size_type max_size() const { return numeric_limits<size_type>::max(); }
size_type max_size() const { return std::numeric_limits<size_type>::max(); }
bool empty() const { return root() == NULL; }
// The height of the btree. An empty tree will have height 0.
@ -1310,7 +1252,7 @@ class btree : public Params::key_compare {
}
void delete_internal_node(node_type *node) {
node->destroy();
DCHECK(node != root());
assert(node != root());
mutable_internal_allocator()->deallocate(
reinterpret_cast<char*>(node), sizeof(internal_fields));
}
@ -1368,15 +1310,15 @@ class btree : public Params::key_compare {
// key was found in the tree) or -kExactMatch (if it wasn't) in the second
// field of the pair. The compare_to specialization allows the caller to
// avoid a subsequent comparison to determine if an exact match was made,
// speeding up string, cord and StringPiece keys.
// speeding up string keys.
template <typename IterType>
pair<IterType, int> internal_locate(
std::pair<IterType, int> internal_locate(
const key_type &key, IterType iter) const;
template <typename IterType>
pair<IterType, int> internal_locate_plain_compare(
std::pair<IterType, int> internal_locate_plain_compare(
const key_type &key, IterType iter) const;
template <typename IterType>
pair<IterType, int> internal_locate_compare_to(
std::pair<IterType, int> internal_locate_compare_to(
const key_type &key, IterType iter) const;
// Internal routine which implements lower_bound().
@ -1403,7 +1345,7 @@ class btree : public Params::key_compare {
void internal_clear(node_type *node);
// Dumps a node and all of its children to the specified ostream.
void internal_dump(ostream &os, const node_type *node, int level) const;
void internal_dump(std::ostream &os, const node_type *node, int level) const;
// Verifies the tree structure of node.
int internal_verify(const node_type *node,
@ -1427,14 +1369,14 @@ class btree : public Params::key_compare {
empty_base_handle<internal_allocator_type, node_type*> root_;
private:
// A never instantiated helper function that returns base::big_ if we have a
// key-compare-to functor or if R is bool and base::small_ otherwise.
// A never instantiated helper function that returns big_ if we have a
// key-compare-to functor or if R is bool and small_ otherwise.
template <typename R>
static typename base::if_<
base::if_<is_key_compare_to::value,
base::type_equals_<R, int>,
base::type_equals_<R, bool> >::type::value,
base::big_, base::small_>::type key_compare_checker(R);
static typename if_<
if_<is_key_compare_to::value,
std::is_same<R, int>,
std::is_same<R, bool> >::type::value,
big_, small_>::type key_compare_checker(R);
// A never instantiated helper function that returns the key comparison
// functor.
@ -1445,10 +1387,10 @@ class btree : public Params::key_compare {
// is never actually invoked. The compiler will select which
// key_compare_checker() to instantiate and then figure out the size of the
// return type of key_compare_checker() at compile time which we then check
// against the sizeof of base::big_.
// against the sizeof of big_.
COMPILE_ASSERT(
sizeof(key_compare_checker(key_compare_helper()(key_type(), key_type()))) ==
sizeof(base::big_),
sizeof(big_),
key_comparison_function_must_return_bool);
// Note: We insist on kTargetValues, which is computed from
@ -1466,7 +1408,7 @@ class btree : public Params::key_compare {
// btree_node methods
template <typename P>
inline void btree_node<P>::insert_value(int i, const value_type &x) {
DCHECK_LE(i, count());
assert(i <= count());
value_init(count(), x);
for (int j = count(); j > i; --j) {
value_swap(j, this, j - 1);
@ -1486,7 +1428,7 @@ inline void btree_node<P>::insert_value(int i, const value_type &x) {
template <typename P>
inline void btree_node<P>::remove_value(int i) {
if (!leaf()) {
DCHECK_EQ(child(i + 1)->count(), 0);
assert(child(i + 1)->count() == 0);
for (int j = i + 1; j < count(); ++j) {
*mutable_child(j) = child(j + 1);
child(j)->set_position(j);
@ -1503,11 +1445,11 @@ inline void btree_node<P>::remove_value(int i) {
template <typename P>
void btree_node<P>::rebalance_right_to_left(btree_node *src, int to_move) {
DCHECK_EQ(parent(), src->parent());
DCHECK_EQ(position() + 1, src->position());
DCHECK_GE(src->count(), count());
DCHECK_GE(to_move, 1);
DCHECK_LE(to_move, src->count());
assert(parent() == src->parent());
assert(position() + 1 == src->position());
assert(src->count() >= count());
assert(to_move >= 1);
assert(to_move <= src->count());
// Make room in the left node for the new values.
for (int i = 0; i < to_move; ++i) {
@ -1537,7 +1479,7 @@ void btree_node<P>::rebalance_right_to_left(btree_node *src, int to_move) {
set_child(1 + count() + i, src->child(i));
}
for (int i = 0; i <= src->count() - to_move; ++i) {
DCHECK_LE(i + to_move, src->max_count());
assert(i + to_move <= src->max_count());
src->set_child(i, src->child(i + to_move));
*src->mutable_child(i + to_move) = NULL;
}
@ -1550,11 +1492,11 @@ void btree_node<P>::rebalance_right_to_left(btree_node *src, int to_move) {
template <typename P>
void btree_node<P>::rebalance_left_to_right(btree_node *dest, int to_move) {
DCHECK_EQ(parent(), dest->parent());
DCHECK_EQ(position() + 1, dest->position());
DCHECK_GE(count(), dest->count());
DCHECK_GE(to_move, 1);
DCHECK_LE(to_move, count());
assert(parent() == dest->parent());
assert(position() + 1 == dest->position());
assert(count() >= dest->count());
assert(to_move >= 1);
assert(to_move <= count());
// Make room in the right node for the new values.
for (int i = 0; i < to_move; ++i) {
@ -1595,7 +1537,7 @@ void btree_node<P>::rebalance_left_to_right(btree_node *dest, int to_move) {
template <typename P>
void btree_node<P>::split(btree_node *dest, int insert_position) {
DCHECK_EQ(dest->count(), 0);
assert(dest->count() == 0);
// We bias the split based on the position being inserted. If we're
// inserting at the beginning of the left node then bias the split to put
@ -1609,7 +1551,7 @@ void btree_node<P>::split(btree_node *dest, int insert_position) {
dest->set_count(count() / 2);
}
set_count(count() - dest->count());
DCHECK_GE(count(), 1);
assert(count() >= 1);
// Move values from the left sibling to the right sibling.
for (int i = 0; i < dest->count(); ++i) {
@ -1627,7 +1569,7 @@ void btree_node<P>::split(btree_node *dest, int insert_position) {
if (!leaf()) {
for (int i = 0; i <= dest->count(); ++i) {
DCHECK(child(count() + i + 1) != NULL);
assert(child(count() + i + 1) != NULL);
dest->set_child(i, child(count() + i + 1));
*mutable_child(count() + i + 1) = NULL;
}
@ -1636,8 +1578,8 @@ void btree_node<P>::split(btree_node *dest, int insert_position) {
template <typename P>
void btree_node<P>::merge(btree_node *src) {
DCHECK_EQ(parent(), src->parent());
DCHECK_EQ(position() + 1, src->position());
assert(parent() == src->parent());
assert(position() + 1 == src->position());
// Move the delimiting value to the left node.
value_init(count());
@ -1668,7 +1610,7 @@ void btree_node<P>::merge(btree_node *src) {
template <typename P>
void btree_node<P>::swap(btree_node *x) {
DCHECK_EQ(leaf(), x->leaf());
assert(leaf() == x->leaf());
// Swap the values.
for (int i = count(); i < x->count(); ++i) {
@ -1677,7 +1619,7 @@ void btree_node<P>::swap(btree_node *x) {
for (int i = x->count(); i < count(); ++i) {
x->value_init(i);
}
int n = max(count(), x->count());
int n = std::max(count(), x->count());
for (int i = 0; i < n; ++i) {
value_swap(i, x, i);
}
@ -1710,10 +1652,10 @@ void btree_node<P>::swap(btree_node *x) {
template <typename N, typename R, typename P>
void btree_iterator<N, R, P>::increment_slow() {
if (node->leaf()) {
DCHECK_GE(position, node->count());
assert(position >= node->count());
self_type save(*this);
while (position == node->count() && !node->is_root()) {
DCHECK_EQ(node->parent()->child(node->position()), node);
assert(node->parent()->child(node->position()) == node);
position = node->position();
node = node->parent();
}
@ -1721,7 +1663,7 @@ void btree_iterator<N, R, P>::increment_slow() {
*this = save;
}
} else {
DCHECK_LT(position, node->count());
assert(position < node->count());
node = node->child(position + 1);
while (!node->leaf()) {
node = node->child(0);
@ -1735,7 +1677,7 @@ void btree_iterator<N, R, P>::increment_by(int count) {
while (count > 0) {
if (node->leaf()) {
int rest = node->count() - position;
position += min(rest, count);
position += std::min(rest, count);
count = count - rest;
if (position < node->count()) {
return;
@ -1750,10 +1692,10 @@ void btree_iterator<N, R, P>::increment_by(int count) {
template <typename N, typename R, typename P>
void btree_iterator<N, R, P>::decrement_slow() {
if (node->leaf()) {
DCHECK_LE(position, -1);
assert(position <= -1);
self_type save(*this);
while (position < 0 && !node->is_root()) {
DCHECK_EQ(node->parent()->child(node->position()), node);
assert(node->parent()->child(node->position()) == node);
position = node->position() - 1;
node = node->parent();
}
@ -1761,7 +1703,7 @@ void btree_iterator<N, R, P>::decrement_slow() {
*this = save;
}
} else {
DCHECK_GE(position, 0);
assert(position >= 0);
node = node->child(position);
while (!node->leaf()) {
node = node->child(node->count());
@ -1786,26 +1728,26 @@ btree<P>::btree(const self_type &x)
}
template <typename P> template <typename ValuePointer>
pair<typename btree<P>::iterator, bool>
std::pair<typename btree<P>::iterator, bool>
btree<P>::insert_unique(const key_type &key, ValuePointer value) {
if (empty()) {
*mutable_root() = new_leaf_root_node(1);
}
pair<iterator, int> res = internal_locate(key, iterator(root(), 0));
std::pair<iterator, int> res = internal_locate(key, iterator(root(), 0));
iterator &iter = res.first;
if (res.second == kExactMatch) {
// The key already exists in the tree, do nothing.
return make_pair(internal_last(iter), false);
return std::make_pair(internal_last(iter), false);
} else if (!res.second) {
iterator last = internal_last(iter);
if (last.node && !compare_keys(key, last.key())) {
// The key already exists in the tree, do nothing.
return make_pair(last, false);
return std::make_pair(last, false);
}
}
return make_pair(internal_insert(iter, *value), true);
return std::make_pair(internal_insert(iter, *value), true);
}
template <typename P>
@ -1912,8 +1854,8 @@ typename btree<P>::iterator btree<P>::erase(iterator iter) {
// Deletion of a value on an internal node. Swap the key with the largest
// value of our left child. This is easy, we just decrement iter.
iterator tmp_iter(iter--);
DCHECK(iter.node->leaf());
DCHECK(!compare_keys(tmp_iter.key(), iter.key()));
assert(iter.node->leaf());
assert(!compare_keys(tmp_iter.key(), iter.key()));
iter.node->value_swap(iter.position, tmp_iter.node, tmp_iter.position);
internal_delete = true;
--*mutable_size();
@ -2010,22 +1952,22 @@ void btree<P>::clear() {
template <typename P>
void btree<P>::swap(self_type &x) {
::swap(static_cast<key_compare&>(*this), static_cast<key_compare&>(x));
::swap(root_, x.root_);
std::swap(static_cast<key_compare&>(*this), static_cast<key_compare&>(x));
std::swap(root_, x.root_);
}
template <typename P>
void btree<P>::verify() const {
if (root() != NULL) {
CHECK_EQ(size(), internal_verify(root(), NULL, NULL));
CHECK_EQ(leftmost(), (++const_iterator(root(), -1)).node);
CHECK_EQ(rightmost(), (--const_iterator(root(), root()->count())).node);
CHECK(leftmost()->leaf());
CHECK(rightmost()->leaf());
assert(size() == internal_verify(root(), NULL, NULL));
assert(leftmost() == (++const_iterator(root(), -1)).node);
assert(rightmost() == (--const_iterator(root(), root()->count())).node);
assert(leftmost()->leaf());
assert(rightmost()->leaf());
} else {
CHECK_EQ(size(), 0);
CHECK(leftmost() == NULL);
CHECK(rightmost() == NULL);
assert(size() == 0);
assert(leftmost() == NULL);
assert(rightmost() == NULL);
}
}
@ -2033,7 +1975,7 @@ template <typename P>
void btree<P>::rebalance_or_split(iterator *iter) {
node_type *&node = iter->node;
int &insert_position = iter->position;
DCHECK_EQ(node->count(), node->max_count());
assert(node->count() == node->max_count());
// First try to make room on the node by rebalancing.
node_type *parent = node->parent();
@ -2047,20 +1989,20 @@ void btree<P>::rebalance_or_split(iterator *iter) {
// fill up the left node.
int to_move = (left->max_count() - left->count()) /
(1 + (insert_position < left->max_count()));
to_move = max(1, to_move);
to_move = std::max(1, to_move);
if (((insert_position - to_move) >= 0) ||
((left->count() + to_move) < left->max_count())) {
left->rebalance_right_to_left(node, to_move);
DCHECK_EQ(node->max_count() - node->count(), to_move);
assert(node->max_count() - node->count() == to_move);
insert_position = insert_position - to_move;
if (insert_position < 0) {
insert_position = insert_position + left->count() + 1;
node = left;
}
DCHECK_LT(node->count(), node->max_count());
assert(node->count() < node->max_count());
return;
}
}
@ -2075,7 +2017,7 @@ void btree<P>::rebalance_or_split(iterator *iter) {
// to fill up the right node.
int to_move = (right->max_count() - right->count()) /
(1 + (insert_position > 0));
to_move = max(1, to_move);
to_move = std::max(1, to_move);
if ((insert_position <= (node->count() - to_move)) ||
((right->count() + to_move) < right->max_count())) {
@ -2086,7 +2028,7 @@ void btree<P>::rebalance_or_split(iterator *iter) {
node = right;
}
DCHECK_LT(node->count(), node->max_count());
assert(node->count() < node->max_count());
return;
}
}
@ -2106,7 +2048,7 @@ void btree<P>::rebalance_or_split(iterator *iter) {
parent = new_internal_root_node();
parent->set_child(0, root());
*mutable_root() = parent;
DCHECK(*mutable_rightmost() == parent->child(0));
assert(*mutable_rightmost() == parent->child(0));
} else {
// The root node is an internal node. We do not want to create a new root
// node because the root node is special and holds the size of the tree
@ -2179,7 +2121,7 @@ bool btree<P>::try_merge_or_rebalance(iterator *iter) {
((iter->node->count() == 0) ||
(iter->position > 0))) {
int to_move = (right->count() - iter->node->count()) / 2;
to_move = min(to_move, right->count() - 1);
to_move = std::min(to_move, right->count() - 1);
iter->node->rebalance_right_to_left(right, to_move);
return false;
}
@ -2194,7 +2136,7 @@ bool btree<P>::try_merge_or_rebalance(iterator *iter) {
((iter->node->count() == 0) ||
(iter->position < iter->node->count()))) {
int to_move = (left->count() - iter->node->count()) / 2;
to_move = min(to_move, left->count() - 1);
to_move = std::min(to_move, left->count() - 1);
left->rebalance_left_to_right(iter->node, to_move);
iter->position += to_move;
return false;
@ -2210,7 +2152,7 @@ void btree<P>::try_shrink() {
}
// Deleted the last item on the root node, shrink the height of the tree.
if (root()->leaf()) {
DCHECK_EQ(size(), 0);
assert(size() == 0);
delete_leaf_node(root());
*mutable_root() = NULL;
} else {
@ -2256,9 +2198,9 @@ btree<P>::internal_insert(iterator iter, const value_type &v) {
if (iter.node->max_count() < kNodeValues) {
// Insertion into the root where the root is smaller that the full node
// size. Simply grow the size of the root node.
DCHECK(iter.node == root());
assert(iter.node == root());
iter.node = new_leaf_root_node(
min<int>(kNodeValues, 2 * iter.node->max_count()));
std::min<int>(kNodeValues, 2 * iter.node->max_count()));
iter.node->swap(root());
delete_leaf_node(root());
*mutable_root() = iter.node;
@ -2274,13 +2216,13 @@ btree<P>::internal_insert(iterator iter, const value_type &v) {
}
template <typename P> template <typename IterType>
inline pair<IterType, int> btree<P>::internal_locate(
inline std::pair<IterType, int> btree<P>::internal_locate(
const key_type &key, IterType iter) const {
return internal_locate_type::dispatch(key, *this, iter);
}
template <typename P> template <typename IterType>
inline pair<IterType, int> btree<P>::internal_locate_plain_compare(
inline std::pair<IterType, int> btree<P>::internal_locate_plain_compare(
const key_type &key, IterType iter) const {
for (;;) {
iter.position = iter.node->lower_bound(key, key_comp());
@ -2289,24 +2231,24 @@ inline pair<IterType, int> btree<P>::internal_locate_plain_compare(
}
iter.node = iter.node->child(iter.position);
}
return make_pair(iter, 0);
return std::make_pair(iter, 0);
}
template <typename P> template <typename IterType>
inline pair<IterType, int> btree<P>::internal_locate_compare_to(
inline std::pair<IterType, int> btree<P>::internal_locate_compare_to(
const key_type &key, IterType iter) const {
for (;;) {
int res = iter.node->lower_bound(key, key_comp());
iter.position = res & kMatchMask;
if (res & kExactMatch) {
return make_pair(iter, static_cast<int>(kExactMatch));
return std::make_pair(iter, static_cast<int>(kExactMatch));
}
if (iter.node->leaf()) {
break;
}
iter.node = iter.node->child(iter.position);
}
return make_pair(iter, -kExactMatch);
return std::make_pair(iter, -kExactMatch);
}
template <typename P> template <typename IterType>
@ -2346,7 +2288,7 @@ template <typename P> template <typename IterType>
IterType btree<P>::internal_find_unique(
const key_type &key, IterType iter) const {
if (iter.node) {
pair<IterType, int> res = internal_locate(key, iter);
std::pair<IterType, int> res = internal_locate(key, iter);
if (res.second == kExactMatch) {
return res.first;
}
@ -2393,7 +2335,7 @@ void btree<P>::internal_clear(node_type *node) {
template <typename P>
void btree<P>::internal_dump(
ostream &os, const node_type *node, int level) const {
std::ostream &os, const node_type *node, int level) const {
for (int i = 0; i < node->count(); ++i) {
if (!node->leaf()) {
internal_dump(os, node->child(i), level + 1);
@ -2411,23 +2353,23 @@ void btree<P>::internal_dump(
template <typename P>
int btree<P>::internal_verify(
const node_type *node, const key_type *lo, const key_type *hi) const {
CHECK_GT(node->count(), 0);
CHECK_LE(node->count(), node->max_count());
assert(node->count() > 0);
assert(node->count() <= node->max_count());
if (lo) {
CHECK(!compare_keys(node->key(0), *lo));
assert(!compare_keys(node->key(0), *lo));
}
if (hi) {
CHECK(!compare_keys(*hi, node->key(node->count() - 1)));
assert(!compare_keys(*hi, node->key(node->count() - 1)));
}
for (int i = 1; i < node->count(); ++i) {
CHECK(!compare_keys(node->key(i), node->key(i - 1)));
assert(!compare_keys(node->key(i), node->key(i - 1)));
}
int count = node->count();
if (!node->leaf()) {
for (int i = 0; i <= node->count(); ++i) {
CHECK(node->child(i) != NULL);
CHECK_EQ(node->child(i)->parent(), node);
CHECK_EQ(node->child(i)->position(), i);
assert(node->child(i) != NULL);
assert(node->child(i)->parent() == node);
assert(node->child(i)->position() == i);
count += internal_verify(
node->child(i),
(i == 0) ? lo : &node->key(i - 1),
@ -2438,8 +2380,5 @@ int btree<P>::internal_verify(
}
} // namespace btree
} // namespace util
DEFINE_GDB_AUTO_SCRIPT("util/btree/btree_printer.py")
#endif // UTIL_BTREE_BTREE_H__

View File

@ -26,7 +26,6 @@
DECLARE_int32(benchmark_max_iters);
namespace util {
namespace btree {
namespace {
@ -480,7 +479,6 @@ MY_BENCHMARK(multimap_cord);
} // namespace
} // namespace btree
} // namespace util
int main(int argc, char **argv) {
FLAGS_logtostderr = true;

View File

@ -8,9 +8,8 @@
#include <iosfwd>
#include <utility>
#include "util/btree/btree.h" // IWYU pragma: export
#include "btree.h"
namespace util {
namespace btree {
// A common base class for btree_set, btree_map, btree_multiset and
@ -70,10 +69,10 @@ class btree_container {
const_iterator upper_bound(const key_type &key) const {
return tree_.upper_bound(key);
}
pair<iterator,iterator> equal_range(const key_type &key) {
std::pair<iterator,iterator> equal_range(const key_type &key) {
return tree_.equal_range(key);
}
pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
std::pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
return tree_.equal_range(key);
}
@ -84,7 +83,7 @@ class btree_container {
void swap(self_type &x) {
tree_.swap(x.tree_);
}
void dump(ostream &os) const {
void dump(std::ostream &os) const {
tree_.dump(os);
}
void verify() const {
@ -128,7 +127,7 @@ class btree_container {
};
template <typename T>
inline ostream& operator<<(ostream &os, const btree_container<T> &b) {
inline std::ostream& operator<<(std::ostream &os, const btree_container<T> &b) {
b.dump(os);
return os;
}
@ -181,7 +180,7 @@ class btree_unique_container : public btree_container<Tree> {
}
// Insertion routines.
pair<iterator,bool> insert(const value_type &x) {
std::pair<iterator,bool> insert(const value_type &x) {
return this->tree_.insert_unique(x);
}
iterator insert(iterator position, const value_type &x) {
@ -230,7 +229,7 @@ class btree_map_container : public btree_unique_container<Tree> {
: key(k) {
}
value_type operator*() const {
return make_pair(key, data_type());
return std::make_pair(key, data_type());
}
const key_type &key;
};
@ -337,6 +336,5 @@ class btree_multi_container : public btree_container<Tree> {
};
} // namespace btree
} // namespace util
#endif // UTIL_BTREE_BTREE_CONTAINER_H__

View File

@ -1,4 +1,4 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Copyright 2007, 2012 Google Inc. All Rights Reserved.
// Author: jmacd@google.com (Josh MacDonald)
// Author: pmattis@google.com (Peter Mattis)
//
@ -18,16 +18,15 @@
#include <string>
#include <utility>
#include "util/btree/btree.h" // IWYU pragma: export
#include "util/btree/btree_container.h" // IWYU pragma: export
#include "btree.h"
#include "btree_container.h"
namespace util {
namespace btree {
// The btree_map class is needed mainly for it's constructors.
template <typename Key, typename Value,
typename Compare = less<Key>,
typename Alloc = std::allocator<pair<const Key, Value> >,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value> >,
int TargetNodeSize = 256>
class btree_map : public btree_map_container<
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
@ -71,8 +70,8 @@ inline void swap(btree_map<K, V, C, A, N> &x,
// The btree_multimap class is needed mainly for it's constructors.
template <typename Key, typename Value,
typename Compare = less<Key>,
typename Alloc = std::allocator<pair<const Key, Value> >,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value> >,
int TargetNodeSize = 256>
class btree_multimap : public btree_multi_container<
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
@ -117,6 +116,5 @@ inline void swap(btree_multimap<K, V, C, A, N> &x,
}
} // namespace btree
} // namespace util
#endif // UTIL_BTREE_BTREE_MAP_H__

View File

@ -14,15 +14,14 @@
#include <memory>
#include <string>
#include "util/btree/btree.h" // IWYU pragma: export
#include "util/btree/btree_container.h" // IWYU pragma: export
#include "btree.h"
#include "btree_container.h"
namespace util {
namespace btree {
// The btree_set class is needed mainly for it's constructors.
template <typename Key,
typename Compare = less<Key>,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<Key>,
int TargetNodeSize = 256>
class btree_set : public btree_unique_container<
@ -65,7 +64,7 @@ inline void swap(btree_set<K, C, A, N> &x, btree_set<K, C, A, N> &y) {
// The btree_multiset class is needed mainly for it's constructors.
template <typename Key,
typename Compare = less<Key>,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<Key>,
int TargetNodeSize = 256>
class btree_multiset : public btree_multi_container<
@ -108,6 +107,5 @@ inline void swap(btree_multiset<K, C, A, N> &x,
}
} // namespace btree
} // namespace util
#endif // UTIL_BTREE_BTREE_SET_H__

View File

@ -2,128 +2,120 @@
// Author: jmacd@google.com (Josh MacDonald)
// Author: pmattis@google.com (Peter Mattis)
#include "base/arena-inl.h"
#include "base/init_google.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "strings/stringpiece.h"
#include "testing/base/public/gunit.h"
#include "util/btree/btree_map.h"
#include "util/btree/btree_set.h"
#include "util/btree/btree_test.h"
#include "gtest/gtest.h"
#include "btree_map.h"
#include "btree_set.h"
#include "btree_test.h"
namespace util {
namespace btree {
namespace {
template <typename K, int N>
void SetTest() {
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
CHECK_EQ(sizeof(btree_set<K>), sizeof(void*));
BtreeTest<btree_set<K, less<K>, allocator<K>, N>, set<K> >();
BtreeArenaTest<btree_set<K, less<K>, ArenaAlloc, N> >();
typedef TestAllocator<K> TestAlloc;
ASSERT_EQ(sizeof(btree_set<K>), sizeof(void*));
BtreeTest<btree_set<K, std::less<K>, std::allocator<K>, N>, std::set<K> >();
BtreeAllocatorTest<btree_set<K, std::less<K>, TestAlloc, N> >();
}
template <typename K, int N>
void MapTest() {
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
CHECK_EQ(sizeof(btree_map<K, K>), sizeof(void*));
BtreeTest<btree_map<K, K, less<K>, allocator<K>, N>, map<K, K> >();
BtreeArenaTest<btree_map<K, K, less<K>, ArenaAlloc, N> >();
BtreeMapTest<btree_map<K, K, less<K>, allocator<K>, N> >();
typedef TestAllocator<K> TestAlloc;
ASSERT_EQ(sizeof(btree_map<K, K>), sizeof(void*));
BtreeTest<btree_map<K, K, std::less<K>, std::allocator<K>, N>, std::map<K, K> >();
BtreeAllocatorTest<btree_map<K, K, std::less<K>, TestAlloc, N> >();
BtreeMapTest<btree_map<K, K, std::less<K>, std::allocator<K>, N> >();
}
TEST(Btree, set_int32_32) { SetTest<int32, 32>(); }
TEST(Btree, set_int32_64) { SetTest<int32, 64>(); }
TEST(Btree, set_int32_128) { SetTest<int32, 128>(); }
TEST(Btree, set_int32_256) { SetTest<int32, 256>(); }
TEST(Btree, set_int64_256) { SetTest<int64, 256>(); }
TEST(Btree, set_string_256) { SetTest<string, 256>(); }
TEST(Btree, set_cord_256) { SetTest<Cord, 256>(); }
TEST(Btree, set_pair_256) { SetTest<pair<int, int>, 256>(); }
TEST(Btree, map_int32_256) { MapTest<int32, 256>(); }
TEST(Btree, map_int64_256) { MapTest<int64, 256>(); }
TEST(Btree, map_string_256) { MapTest<string, 256>(); }
TEST(Btree, map_cord_256) { MapTest<Cord, 256>(); }
TEST(Btree, map_pair_256) { MapTest<pair<int, int>, 256>(); }
TEST(Btree, set_int32_32) { SetTest<int32_t, 32>(); }
TEST(Btree, set_int32_64) { SetTest<int32_t, 64>(); }
TEST(Btree, set_int32_128) { SetTest<int32_t, 128>(); }
TEST(Btree, set_int32_256) { SetTest<int32_t, 256>(); }
TEST(Btree, set_int64_256) { SetTest<int64_t, 256>(); }
TEST(Btree, set_string_256) { SetTest<std::string, 256>(); }
TEST(Btree, set_pair_256) { SetTest<std::pair<int, int>, 256>(); }
TEST(Btree, map_int32_256) { MapTest<int32_t, 256>(); }
TEST(Btree, map_int64_256) { MapTest<int64_t, 256>(); }
TEST(Btree, map_string_256) { MapTest<std::string, 256>(); }
TEST(Btree, map_pair_256) { MapTest<std::pair<int, int>, 256>(); }
// Large-node tests
TEST(Btree, map_int32_1024) { MapTest<int32, 1024>(); }
TEST(Btree, map_int32_1032) { MapTest<int32, 1032>(); }
TEST(Btree, map_int32_1040) { MapTest<int32, 1040>(); }
TEST(Btree, map_int32_1048) { MapTest<int32, 1048>(); }
TEST(Btree, map_int32_1056) { MapTest<int32, 1056>(); }
TEST(Btree, map_int32_1024) { MapTest<int32_t, 1024>(); }
TEST(Btree, map_int32_1032) { MapTest<int32_t, 1032>(); }
TEST(Btree, map_int32_1040) { MapTest<int32_t, 1040>(); }
TEST(Btree, map_int32_1048) { MapTest<int32_t, 1048>(); }
TEST(Btree, map_int32_1056) { MapTest<int32_t, 1056>(); }
TEST(Btree, map_int32_2048) { MapTest<int32, 2048>(); }
TEST(Btree, map_int32_4096) { MapTest<int32, 4096>(); }
TEST(Btree, set_int32_1024) { SetTest<int32, 1024>(); }
TEST(Btree, set_int32_2048) { SetTest<int32, 2048>(); }
TEST(Btree, set_int32_4096) { SetTest<int32, 4096>(); }
TEST(Btree, map_string_1024) { MapTest<string, 1024>(); }
TEST(Btree, map_string_2048) { MapTest<string, 2048>(); }
TEST(Btree, map_string_4096) { MapTest<string, 4096>(); }
TEST(Btree, set_string_1024) { SetTest<string, 1024>(); }
TEST(Btree, set_string_2048) { SetTest<string, 2048>(); }
TEST(Btree, set_string_4096) { SetTest<string, 4096>(); }
TEST(Btree, map_int32_2048) { MapTest<int32_t, 2048>(); }
TEST(Btree, map_int32_4096) { MapTest<int32_t, 4096>(); }
TEST(Btree, set_int32_1024) { SetTest<int32_t, 1024>(); }
TEST(Btree, set_int32_2048) { SetTest<int32_t, 2048>(); }
TEST(Btree, set_int32_4096) { SetTest<int32_t, 4096>(); }
TEST(Btree, map_string_1024) { MapTest<std::string, 1024>(); }
TEST(Btree, map_string_2048) { MapTest<std::string, 2048>(); }
TEST(Btree, map_string_4096) { MapTest<std::string, 4096>(); }
TEST(Btree, set_string_1024) { SetTest<std::string, 1024>(); }
TEST(Btree, set_string_2048) { SetTest<std::string, 2048>(); }
TEST(Btree, set_string_4096) { SetTest<std::string, 4096>(); }
template <typename K, int N>
void MultiSetTest() {
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
CHECK_EQ(sizeof(btree_multiset<K>), sizeof(void*));
BtreeMultiTest<btree_multiset<K, less<K>, allocator<K>, N>,
multiset<K> >();
BtreeArenaTest<btree_multiset<K, less<K>, ArenaAlloc, N> >();
typedef TestAllocator<K> TestAlloc;
ASSERT_EQ(sizeof(btree_multiset<K>), sizeof(void*));
BtreeMultiTest<btree_multiset<K, std::less<K>, std::allocator<K>, N>,
std::multiset<K> >();
BtreeAllocatorTest<btree_multiset<K, std::less<K>, TestAlloc, N> >();
}
template <typename K, int N>
void MultiMapTest() {
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
CHECK_EQ(sizeof(btree_multimap<K, K>), sizeof(void*));
BtreeMultiTest<btree_multimap<K, K, less<K>, allocator<K>, N>,
multimap<K, K> >();
BtreeMultiMapTest<btree_multimap<K, K, less<K>, allocator<K>, N> >();
BtreeArenaTest<btree_multimap<K, K, less<K>, ArenaAlloc, N> >();
typedef TestAllocator<K> TestAlloc;
ASSERT_EQ(sizeof(btree_multimap<K, K>), sizeof(void*));
BtreeMultiTest<btree_multimap<K, K, std::less<K>, std::allocator<K>, N>,
std::multimap<K, K> >();
BtreeMultiMapTest<btree_multimap<K, K, std::less<K>, std::allocator<K>, N> >();
BtreeAllocatorTest<btree_multimap<K, K, std::less<K>, TestAlloc, N> >();
}
TEST(Btree, multiset_int32_256) { MultiSetTest<int32, 256>(); }
TEST(Btree, multiset_int64_256) { MultiSetTest<int64, 256>(); }
TEST(Btree, multiset_string_256) { MultiSetTest<string, 256>(); }
TEST(Btree, multiset_cord_256) { MultiSetTest<Cord, 256>(); }
TEST(Btree, multiset_pair_256) { MultiSetTest<pair<int, int>, 256>(); }
TEST(Btree, multimap_int32_256) { MultiMapTest<int32, 256>(); }
TEST(Btree, multimap_int64_256) { MultiMapTest<int64, 256>(); }
TEST(Btree, multimap_string_256) { MultiMapTest<string, 256>(); }
TEST(Btree, multimap_cord_256) { MultiMapTest<Cord, 256>(); }
TEST(Btree, multimap_pair_256) { MultiMapTest<pair<int, int>, 256>(); }
TEST(Btree, multiset_int32_256) { MultiSetTest<int32_t, 256>(); }
TEST(Btree, multiset_int64_256) { MultiSetTest<int64_t, 256>(); }
TEST(Btree, multiset_string_256) { MultiSetTest<std::string, 256>(); }
TEST(Btree, multiset_pair_256) { MultiSetTest<std::pair<int, int>, 256>(); }
TEST(Btree, multimap_int32_256) { MultiMapTest<int32_t, 256>(); }
TEST(Btree, multimap_int64_256) { MultiMapTest<int64_t, 256>(); }
TEST(Btree, multimap_string_256) { MultiMapTest<std::string, 256>(); }
TEST(Btree, multimap_pair_256) { MultiMapTest<std::pair<int, int>, 256>(); }
// Large-node tests
TEST(Btree, multimap_int32_1024) { MultiMapTest<int32, 1024>(); }
TEST(Btree, multimap_int32_2048) { MultiMapTest<int32, 2048>(); }
TEST(Btree, multimap_int32_4096) { MultiMapTest<int32, 4096>(); }
TEST(Btree, multiset_int32_1024) { MultiSetTest<int32, 1024>(); }
TEST(Btree, multiset_int32_2048) { MultiSetTest<int32, 2048>(); }
TEST(Btree, multiset_int32_4096) { MultiSetTest<int32, 4096>(); }
TEST(Btree, multimap_string_1024) { MultiMapTest<string, 1024>(); }
TEST(Btree, multimap_string_2048) { MultiMapTest<string, 2048>(); }
TEST(Btree, multimap_string_4096) { MultiMapTest<string, 4096>(); }
TEST(Btree, multiset_string_1024) { MultiSetTest<string, 1024>(); }
TEST(Btree, multiset_string_2048) { MultiSetTest<string, 2048>(); }
TEST(Btree, multiset_string_4096) { MultiSetTest<string, 4096>(); }
TEST(Btree, multimap_int32_1024) { MultiMapTest<int32_t, 1024>(); }
TEST(Btree, multimap_int32_2048) { MultiMapTest<int32_t, 2048>(); }
TEST(Btree, multimap_int32_4096) { MultiMapTest<int32_t, 4096>(); }
TEST(Btree, multiset_int32_1024) { MultiSetTest<int32_t, 1024>(); }
TEST(Btree, multiset_int32_2048) { MultiSetTest<int32_t, 2048>(); }
TEST(Btree, multiset_int32_4096) { MultiSetTest<int32_t, 4096>(); }
TEST(Btree, multimap_string_1024) { MultiMapTest<std::string, 1024>(); }
TEST(Btree, multimap_string_2048) { MultiMapTest<std::string, 2048>(); }
TEST(Btree, multimap_string_4096) { MultiMapTest<std::string, 4096>(); }
TEST(Btree, multiset_string_1024) { MultiSetTest<std::string, 1024>(); }
TEST(Btree, multiset_string_2048) { MultiSetTest<std::string, 2048>(); }
TEST(Btree, multiset_string_4096) { MultiSetTest<std::string, 4096>(); }
// Verify that swapping btrees swaps the key comparision functors.
struct SubstringLess {
SubstringLess() : n(2) {}
SubstringLess(int length)
SubstringLess(size_t length)
: n(length) {
}
bool operator()(const string &a, const string &b) const {
return StringPiece(a).substr(0, n) < StringPiece(b).substr(0, n);
bool operator()(const std::string &a, const std::string &b) const {
std::string as(a.data(), std::min(n, a.size()));
std::string bs(b.data(), std::min(n, b.size()));
return as < bs;
}
int n;
size_t n;
};
TEST(Btree, SwapKeyCompare) {
typedef btree_set<string, SubstringLess> SubstringSet;
typedef btree_set<std::string, SubstringLess> SubstringSet;
SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type());
SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type());
@ -147,7 +139,7 @@ TEST(Btree, SwapKeyCompare) {
TEST(Btree, UpperBoundRegression) {
// Regress a bug where upper_bound would default-construct a new key_compare
// instead of copying the existing one.
typedef btree_set<string, SubstringLess> SubstringSet;
typedef btree_set<std::string, SubstringLess> SubstringSet;
SubstringSet my_set(SubstringLess(3));
my_set.insert("aab");
my_set.insert("abb");
@ -164,25 +156,25 @@ TEST(Btree, UpperBoundRegression) {
TEST(Btree, IteratorIncrementBy) {
// Test that increment_by returns the same position as increment.
const int kSetSize = 2341;
btree_set<int32> my_set;
btree_set<int32_t> my_set;
for (int i = 0; i < kSetSize; ++i) {
my_set.insert(i);
}
{
// Simple increment vs. increment by.
btree_set<int32>::iterator a = my_set.begin();
btree_set<int32>::iterator b = my_set.begin();
btree_set<int32_t>::iterator a = my_set.begin();
btree_set<int32_t>::iterator b = my_set.begin();
a.increment();
b.increment_by(1);
EXPECT_EQ(*a, *b);
}
btree_set<int32>::iterator a = my_set.begin();
btree_set<int32_t>::iterator a = my_set.begin();
for (int i = 1; i < kSetSize; ++i) {
++a;
// increment_by
btree_set<int32>::iterator b = my_set.begin();
btree_set<int32_t>::iterator b = my_set.begin();
b.increment_by(i);
EXPECT_EQ(*a, *b) << ": i=" << i;
}
@ -190,11 +182,11 @@ TEST(Btree, IteratorIncrementBy) {
TEST(Btree, Comparison) {
const int kSetSize = 1201;
btree_set<int64> my_set;
btree_set<int64_t> my_set;
for (int i = 0; i < kSetSize; ++i) {
my_set.insert(i);
}
btree_set<int64> my_set_copy(my_set);
btree_set<int64_t> my_set_copy(my_set);
EXPECT_TRUE(my_set_copy == my_set);
EXPECT_TRUE(my_set == my_set_copy);
EXPECT_FALSE(my_set_copy != my_set);
@ -212,17 +204,17 @@ TEST(Btree, Comparison) {
EXPECT_TRUE(my_set_copy != my_set);
EXPECT_TRUE(my_set != my_set_copy);
btree_map<string, int64> my_map;
btree_map<std::string, int64_t> my_map;
for (int i = 0; i < kSetSize; ++i) {
my_map[string(i, 'a')] = i;
my_map[std::string(i, 'a')] = i;
}
btree_map<string, int64> my_map_copy(my_map);
btree_map<std::string, int64_t> my_map_copy(my_map);
EXPECT_TRUE(my_map_copy == my_map);
EXPECT_TRUE(my_map == my_map_copy);
EXPECT_FALSE(my_map_copy != my_map);
EXPECT_FALSE(my_map != my_map_copy);
++my_map_copy[string(7, 'a')];
++my_map_copy[std::string(7, 'a')];
EXPECT_FALSE(my_map_copy == my_map);
EXPECT_FALSE(my_map == my_map_copy);
EXPECT_TRUE(my_map_copy != my_map);
@ -235,7 +227,7 @@ TEST(Btree, Comparison) {
EXPECT_TRUE(my_map_copy != my_map);
EXPECT_TRUE(my_map != my_map_copy);
my_map.erase(string(kSetSize - 1, 'a'));
my_map.erase(std::string(kSetSize - 1, 'a'));
EXPECT_FALSE(my_map_copy == my_map);
EXPECT_FALSE(my_map == my_map_copy);
EXPECT_TRUE(my_map_copy != my_map);
@ -244,10 +236,3 @@ TEST(Btree, Comparison) {
} // namespace
} // namespace btree
} // namespace util
int main(int argc, char **argv) {
FLAGS_logtostderr = true;
InitGoogle(argv[0], &argc, &argv, true);
return RUN_ALL_TESTS();
}

View File

@ -8,6 +8,7 @@
#include <stdio.h>
#include <algorithm>
#include <functional>
#include <type_traits>
#include <iosfwd>
#include <map>
#include <set>
@ -16,53 +17,50 @@
#include <utility>
#include <vector>
#include "base/arena.h"
#include "base/commandlineflags.h"
#include "base/logging.h"
#include "base/type_traits.h"
#include "strings/cord.h"
#include "strings/util.h"
#include "testing/base/public/googletest.h"
#include "util/btree/btree_container.h"
#include "util/random/acmrandom.h"
#include "gtest/gtest.h"
#include "gflags/gflags.h"
#include "btree_container.h"
DECLARE_int32(test_values);
DECLARE_int32(benchmark_values);
namespace std {
// Provide operator<< support for pair<T, U>.
// Provide operator<< support for std::pair<T, U>.
template <typename T, typename U>
ostream& operator<<(ostream &os, const pair<T, U> &p) {
ostream& operator<<(ostream &os, const std::pair<T, U> &p) {
os << "(" << p.first << "," << p.second << ")";
return os;
}
// Provide pair equality testing that works as long as x.first is comparable to
// y.first and x.second is comparable to y.second. Needed in the test for
// comparing pair<T, U> to pair<const T, U>.
// comparing std::pair<T, U> to std::pair<const T, U>.
template <typename T, typename U, typename V, typename W>
bool operator==(const pair<T, U> &x, const pair<V, W> &y) {
bool operator==(const std::pair<T, U> &x, const std::pair<V, W> &y) {
return x.first == y.first && x.second == y.second;
}
} // namespace std
namespace base {
// Partial specialization of remove_const that propagates the removal through
// std::pair.
template <typename T, typename U>
struct remove_const<std::pair<T, U> > {
typedef std::pair<typename remove_const<T>::type,
typename remove_const<U>::type> type;
struct remove_const<pair<T, U> > {
typedef pair<typename remove_const<T>::type,
typename remove_const<U>::type> type;
};
} // namespace base
} // namespace std
namespace util {
namespace btree {
// Select the first member of a pair.
template <class _Pair>
struct select1st : public std::unary_function<_Pair, typename _Pair::first_type> {
const typename _Pair::first_type& operator()(const _Pair& __x) const {
return __x.first;
}
};
// Utility class to provide an accessor for a key given a value. The default
// behavior is to treat the value as a pair and return the first element.
template <typename K, typename V>
@ -70,6 +68,11 @@ struct KeyOfValue {
typedef select1st<V> type;
};
template <typename T>
struct identity {
inline const T& operator()(const T& t) const { return t; }
};
// Partial specialization of KeyOfValue class for when the key and value are
// the same type such as in set<> and btree_set<>.
template <typename K>
@ -77,6 +80,29 @@ struct KeyOfValue<K, K> {
typedef identity<K> type;
};
// Counts the number of occurances of "c" in a buffer.
inline ptrdiff_t strcount(const char* buf_begin, const char* buf_end, char c) {
if (buf_begin == NULL)
return 0;
if (buf_end <= buf_begin)
return 0;
ptrdiff_t num = 0;
for (const char* bp = buf_begin; bp != buf_end; bp++) {
if (*bp == c)
num++;
}
return num;
}
// for when the string is not null-terminated.
inline ptrdiff_t strcount(const char* buf, size_t len, char c) {
return strcount(buf, buf + len, c);
}
inline ptrdiff_t strcount(const std::string& buf, char c) {
return strcount(buf.c_str(), buf.size(), c);
}
// The base class for a sorted associative container checker. TreeType is the
// container type to check and CheckerType is the container type to check
// against. TreeType is expected to be btree_{set,map,multiset,multimap} and
@ -127,9 +153,9 @@ class base_checker {
IterType iter_check(
IterType tree_iter, CheckerIterType checker_iter) const {
if (tree_iter == tree_.end()) {
CHECK(checker_iter == checker_.end());
EXPECT_EQ(checker_iter, checker_.end());
} else {
CHECK_EQ(*tree_iter, *checker_iter);
EXPECT_EQ(*tree_iter, *checker_iter);
}
return tree_iter;
}
@ -137,9 +163,9 @@ class base_checker {
IterType riter_check(
IterType tree_iter, CheckerIterType checker_iter) const {
if (tree_iter == tree_.rend()) {
CHECK(checker_iter == checker_.rend());
EXPECT_EQ(checker_iter, checker_.rend());
} else {
CHECK_EQ(*tree_iter, *checker_iter);
EXPECT_EQ(*tree_iter, *checker_iter);
}
return tree_iter;
}
@ -147,17 +173,17 @@ class base_checker {
typename KeyOfValue<typename TreeType::key_type,
typename TreeType::value_type>::type key_of_value;
const key_type &key = key_of_value(x);
CHECK_EQ(*find(key), x);
EXPECT_EQ(*find(key), x);
lower_bound(key);
upper_bound(key);
equal_range(key);
count(key);
}
void erase_check(const key_type &key) {
CHECK(tree_.find(key) == const_tree_.end());
CHECK(const_tree_.find(key) == tree_.end());
CHECK(tree_.equal_range(key).first ==
const_tree_.equal_range(key).second);
EXPECT_TRUE(tree_.find(key) == const_tree_.end());
EXPECT_TRUE(const_tree_.find(key) == tree_.end());
EXPECT_TRUE(tree_.equal_range(key).first ==
const_tree_.equal_range(key).second);
}
// Lookup routines.
@ -173,20 +199,20 @@ class base_checker {
const_iterator upper_bound(const key_type &key) const {
return iter_check(tree_.upper_bound(key), checker_.upper_bound(key));
}
pair<iterator,iterator> equal_range(const key_type &key) {
pair<typename CheckerType::iterator,
std::pair<iterator,iterator> equal_range(const key_type &key) {
std::pair<typename CheckerType::iterator,
typename CheckerType::iterator> checker_res =
checker_.equal_range(key);
pair<iterator, iterator> tree_res = tree_.equal_range(key);
std::pair<iterator, iterator> tree_res = tree_.equal_range(key);
iter_check(tree_res.first, checker_res.first);
iter_check(tree_res.second, checker_res.second);
return tree_res;
}
pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
pair<typename CheckerType::const_iterator,
std::pair<const_iterator,const_iterator> equal_range(const key_type &key) const {
std::pair<typename CheckerType::const_iterator,
typename CheckerType::const_iterator> checker_res =
checker_.equal_range(key);
pair<const_iterator, const_iterator> tree_res = tree_.equal_range(key);
std::pair<const_iterator, const_iterator> tree_res = tree_.equal_range(key);
iter_check(tree_res.first, checker_res.first);
iter_check(tree_res.second, checker_res.second);
return tree_res;
@ -199,7 +225,7 @@ class base_checker {
}
size_type count(const key_type &key) const {
size_type res = checker_.count(key);
CHECK_EQ(res, tree_.count(key));
EXPECT_EQ(res, tree_.count(key));
return res;
}
@ -214,10 +240,10 @@ class base_checker {
int erase(const key_type &key) {
int size = tree_.size();
int res = checker_.erase(key);
CHECK_EQ(res, tree_.count(key));
CHECK_EQ(res, tree_.erase(key));
CHECK_EQ(tree_.count(key), 0);
CHECK_EQ(tree_.size(), size - res);
EXPECT_EQ(res, tree_.count(key));
EXPECT_EQ(res, tree_.erase(key));
EXPECT_EQ(tree_.count(key), 0);
EXPECT_EQ(tree_.size(), size - res);
erase_check(key);
return res;
}
@ -233,9 +259,9 @@ class base_checker {
++checker_next;
checker_.erase(checker_iter);
iter = tree_.erase(iter);
CHECK_EQ(tree_.size(), checker_.size());
CHECK_EQ(tree_.size(), size - 1);
CHECK_EQ(tree_.count(key), count - 1);
EXPECT_EQ(tree_.size(), checker_.size());
EXPECT_EQ(tree_.size(), size - 1);
EXPECT_EQ(tree_.count(key), count - 1);
if (count == 1) {
erase_check(key);
}
@ -258,8 +284,8 @@ class base_checker {
}
checker_.erase(checker_begin, checker_end);
tree_.erase(begin, end);
CHECK_EQ(tree_.size(), checker_.size());
CHECK_EQ(tree_.size(), size - count);
EXPECT_EQ(tree_.size(), checker_.size());
EXPECT_EQ(tree_.size(), size - count);
}
// Utility routines.
@ -274,7 +300,7 @@ class base_checker {
void verify() const {
tree_.verify();
CHECK_EQ(tree_.size(), checker_.size());
EXPECT_EQ(tree_.size(), checker_.size());
// Move through the forward iterators using increment.
typename CheckerType::const_iterator
@ -282,7 +308,7 @@ class base_checker {
const_iterator tree_iter(tree_.begin());
for (; tree_iter != tree_.end();
++tree_iter, ++checker_iter) {
CHECK_EQ(*tree_iter, *checker_iter);
EXPECT_EQ(*tree_iter, *checker_iter);
}
// Move through the forward iterators using decrement.
@ -291,8 +317,8 @@ class base_checker {
--tree_iter;
--checker_iter;
}
CHECK(tree_iter == tree_.begin());
CHECK(checker_iter == checker_.begin());
EXPECT_TRUE(tree_iter == tree_.begin());
EXPECT_TRUE(checker_iter == checker_.begin());
// Move through the reverse iterators using increment.
typename CheckerType::const_reverse_iterator
@ -300,7 +326,7 @@ class base_checker {
const_reverse_iterator tree_riter(tree_.rbegin());
for (; tree_riter != tree_.rend();
++tree_riter, ++checker_riter) {
CHECK_EQ(*tree_riter, *checker_riter);
EXPECT_EQ(*tree_riter, *checker_riter);
}
// Move through the reverse iterators using decrement.
@ -309,8 +335,8 @@ class base_checker {
--tree_riter;
--checker_riter;
}
CHECK(tree_riter == tree_.rbegin());
CHECK(checker_riter == checker_.rbegin());
EXPECT_EQ(tree_riter, tree_.rbegin());
EXPECT_EQ(checker_riter, checker_.rbegin());
}
// Access to the underlying btree.
@ -318,12 +344,12 @@ class base_checker {
// Size routines.
size_type size() const {
CHECK_EQ(tree_.size(), checker_.size());
EXPECT_EQ(tree_.size(), checker_.size());
return tree_.size();
}
size_type max_size() const { return tree_.max_size(); }
bool empty() const {
CHECK_EQ(tree_.empty(), checker_.empty());
EXPECT_EQ(tree_.empty(), checker_.empty());
return tree_.empty();
}
size_type height() const { return tree_.height(); }
@ -367,25 +393,25 @@ class unique_checker : public base_checker<TreeType, CheckerType> {
}
// Insertion routines.
pair<iterator,bool> insert(const value_type &x) {
std::pair<iterator,bool> insert(const value_type &x) {
int size = this->tree_.size();
pair<typename CheckerType::iterator,bool> checker_res =
std::pair<typename CheckerType::iterator,bool> checker_res =
this->checker_.insert(x);
pair<iterator,bool> tree_res = this->tree_.insert(x);
CHECK_EQ(*tree_res.first, *checker_res.first);
CHECK_EQ(tree_res.second, checker_res.second);
CHECK_EQ(this->tree_.size(), this->checker_.size());
CHECK_EQ(this->tree_.size(), size + tree_res.second);
std::pair<iterator,bool> tree_res = this->tree_.insert(x);
EXPECT_EQ(*tree_res.first, *checker_res.first);
EXPECT_EQ(tree_res.second, checker_res.second);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + tree_res.second);
return tree_res;
}
iterator insert(iterator position, const value_type &x) {
int size = this->tree_.size();
pair<typename CheckerType::iterator,bool> checker_res =
std::pair<typename CheckerType::iterator,bool> checker_res =
this->checker_.insert(x);
iterator tree_res = this->tree_.insert(position, x);
CHECK_EQ(*tree_res, *checker_res.first);
CHECK_EQ(this->tree_.size(), this->checker_.size());
CHECK_EQ(this->tree_.size(), size + checker_res.second);
EXPECT_EQ(*tree_res, *checker_res.first);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + checker_res.second);
return tree_res;
}
template <typename InputIterator>
@ -428,18 +454,18 @@ class multi_checker : public base_checker<TreeType, CheckerType> {
int size = this->tree_.size();
typename CheckerType::iterator checker_res = this->checker_.insert(x);
iterator tree_res = this->tree_.insert(x);
CHECK_EQ(*tree_res, *checker_res);
CHECK_EQ(this->tree_.size(), this->checker_.size());
CHECK_EQ(this->tree_.size(), size + 1);
EXPECT_EQ(*tree_res, *checker_res);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + 1);
return tree_res;
}
iterator insert(iterator position, const value_type &x) {
int size = this->tree_.size();
typename CheckerType::iterator checker_res = this->checker_.insert(x);
iterator tree_res = this->tree_.insert(position, x);
CHECK_EQ(*tree_res, *checker_res);
CHECK_EQ(this->tree_.size(), this->checker_.size());
CHECK_EQ(this->tree_.size(), size + 1);
EXPECT_EQ(*tree_res, *checker_res);
EXPECT_EQ(this->tree_.size(), this->checker_.size());
EXPECT_EQ(this->tree_.size(), size + 1);
return tree_res;
}
template <typename InputIterator>
@ -451,7 +477,7 @@ class multi_checker : public base_checker<TreeType, CheckerType> {
};
char* GenerateDigits(char buf[16], int val, int maxval) {
DCHECK_LE(val, maxval);
EXPECT_LE(val, maxval);
int p = 15;
buf[p--] = 0;
while (maxval > 0) {
@ -469,61 +495,48 @@ struct Generator {
: maxval(m) {
}
K operator()(int i) const {
DCHECK_LE(i, maxval);
EXPECT_LE(i, maxval);
return i;
}
};
template <>
struct Generator<string> {
struct Generator<std::string> {
int maxval;
Generator(int m)
: maxval(m) {
}
string operator()(int i) const {
std::string operator()(int i) const {
char buf[16];
return GenerateDigits(buf, i, maxval);
}
};
template <>
struct Generator<Cord> {
int maxval;
Generator(int m)
: maxval(m) {
}
Cord operator()(int i) const {
char buf[16];
return Cord(GenerateDigits(buf, i, maxval));
}
};
template <typename T, typename U>
struct Generator<pair<T, U> > {
Generator<typename base::remove_const<T>::type> tgen;
Generator<typename base::remove_const<U>::type> ugen;
struct Generator<std::pair<T, U> > {
Generator<typename std::remove_const<T>::type> tgen;
Generator<typename std::remove_const<U>::type> ugen;
Generator(int m)
: tgen(m),
ugen(m) {
}
pair<T, U> operator()(int i) const {
return make_pair(tgen(i), ugen(i));
std::pair<T, U> operator()(int i) const {
return std::make_pair(tgen(i), ugen(i));
}
};
// Generate values for our tests and benchmarks. Value range is [0, maxval].
const vector<int>& GenerateNumbers(int n, int maxval) {
static ACMRandom rand(FLAGS_test_random_seed);
static vector<int> values;
static set<int> unique_values;
const std::vector<int>& GenerateNumbers(int n, int maxval) {
static std::vector<int> values;
static std::set<int> unique_values;
if (values.size() < n) {
for (int i = values.size(); i < n; i++) {
int value;
do {
value = rand.Next() % (maxval + 1);
value = rand() % (maxval + 1);
} while (unique_values.find(value) != unique_values.end());
values.push_back(value);
@ -537,13 +550,13 @@ const vector<int>& GenerateNumbers(int n, int maxval) {
// Generates values in the range
// [0, 4 * min(FLAGS_benchmark_values, FLAGS_test_values)]
template <typename V>
vector<V> GenerateValues(int n) {
int two_times_max = 2 * max(FLAGS_benchmark_values, FLAGS_test_values);
std::vector<V> GenerateValues(int n) {
int two_times_max = 2 * std::max(FLAGS_benchmark_values, FLAGS_test_values);
int four_times_max = 2 * two_times_max;
DCHECK_LE(n, two_times_max);
const vector<int> &nums = GenerateNumbers(n, four_times_max);
EXPECT_LE(n, two_times_max);
const std::vector<int> &nums = GenerateNumbers(n, four_times_max);
Generator<V> gen(four_times_max);
vector<V> vec;
std::vector<V> vec;
for (int i = 0; i < n; i++) {
vec.push_back(gen(nums[i]));
@ -553,44 +566,44 @@ vector<V> GenerateValues(int n) {
}
template <typename K>
double ContainerInfo(const set<K> &s) {
double ContainerInfo(const std::set<K> &s) {
int sizeof_node = sizeof(std::_Rb_tree_node<K>);
int bytes_used = sizeof(s) + s.size() * sizeof_node;
double bytes_per_value = (double) bytes_used / s.size();
VLOG(1) << " size=" << s.size()
std::cout << " size=" << s.size()
<< " bytes-used=" << bytes_used
<< " bytes-per-value=" << bytes_per_value;
return bytes_per_value;
}
template <typename K>
double ContainerInfo(const multiset<K> &s) {
double ContainerInfo(const std::multiset<K> &s) {
int sizeof_node = sizeof(std::_Rb_tree_node<K>);
int bytes_used = sizeof(s) + s.size() * sizeof_node;
double bytes_per_value = (double) bytes_used / s.size();
VLOG(1) << " size=" << s.size()
std::cout << " size=" << s.size()
<< " bytes-used=" << bytes_used
<< " bytes-per-value=" << bytes_per_value;
return bytes_per_value;
}
template <typename K, typename V>
double ContainerInfo(const map<K, V> &m) {
int sizeof_node = sizeof(std::_Rb_tree_node<pair<K, V> >);
double ContainerInfo(const std::map<K, V> &m) {
int sizeof_node = sizeof(std::_Rb_tree_node<std::pair<K, V> >);
int bytes_used = sizeof(m) + m.size() * sizeof_node;
double bytes_per_value = (double) bytes_used / m.size();
VLOG(1) << " size=" << m.size()
std::cout << " size=" << m.size()
<< " bytes-used=" << bytes_used
<< " bytes-per-value=" << bytes_per_value;
return bytes_per_value;
}
template <typename K, typename V>
double ContainerInfo(const multimap<K, V> &m) {
int sizeof_node = sizeof(std::_Rb_tree_node<pair<K, V> >);
double ContainerInfo(const std::multimap<K, V> &m) {
int sizeof_node = sizeof(std::_Rb_tree_node<std::pair<K, V> >);
int bytes_used = sizeof(m) + m.size() * sizeof_node;
double bytes_per_value = (double) bytes_used / m.size();
VLOG(1) << " size=" << m.size()
std::cout << " size=" << m.size()
<< " bytes-used=" << bytes_used
<< " bytes-per-value=" << bytes_per_value;
return bytes_per_value;
@ -600,7 +613,7 @@ template <typename P>
double ContainerInfo(const btree_container<P> &b) {
double bytes_used = sizeof(b) + b.bytes_used();
double bytes_per_value = (double) bytes_used / b.size();
VLOG(1) << " size=" << b.size()
std::cout << " size=" << b.size()
<< " bytes-used=" << bytes_used
<< " bytes-per-value=" << bytes_per_value
<< " height=" << b.height()
@ -612,7 +625,7 @@ double ContainerInfo(const btree_container<P> &b) {
}
template <typename T, typename V>
void DoTest(const char *name, T *b, const vector<V> &values) {
void DoTest(const char *name, T *b, const std::vector<V> &values) {
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
T &mutable_b = *b;
@ -631,22 +644,22 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
// Test copy constructor.
T b_copy(const_b);
CHECK_EQ(b_copy.size(), const_b.size());
CHECK_LE(b_copy.height(), const_b.height());
CHECK_LE(b_copy.internal_nodes(), const_b.internal_nodes());
CHECK_LE(b_copy.leaf_nodes(), const_b.leaf_nodes());
EXPECT_EQ(b_copy.size(), const_b.size());
EXPECT_LE(b_copy.height(), const_b.height());
EXPECT_LE(b_copy.internal_nodes(), const_b.internal_nodes());
EXPECT_LE(b_copy.leaf_nodes(), const_b.leaf_nodes());
for (int i = 0; i < values.size(); ++i) {
CHECK_EQ(*b_copy.find(key_of_value(values[i])), values[i]);
EXPECT_EQ(*b_copy.find(key_of_value(values[i])), values[i]);
}
// Test range constructor.
T b_range(const_b.begin(), const_b.end());
CHECK_EQ(b_range.size(), const_b.size());
CHECK_LE(b_range.height(), const_b.height());
CHECK_LE(b_range.internal_nodes(), const_b.internal_nodes());
CHECK_LE(b_range.leaf_nodes(), const_b.leaf_nodes());
EXPECT_EQ(b_range.size(), const_b.size());
EXPECT_LE(b_range.height(), const_b.height());
EXPECT_LE(b_range.internal_nodes(), const_b.internal_nodes());
EXPECT_LE(b_range.leaf_nodes(), const_b.leaf_nodes());
for (int i = 0; i < values.size(); ++i) {
CHECK_EQ(*b_range.find(key_of_value(values[i])), values[i]);
EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]);
}
// Test range insertion for values that already exist.
@ -656,36 +669,36 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
// Test range insertion for new values.
b_range.clear();
b_range.insert(b_copy.begin(), b_copy.end());
CHECK_EQ(b_range.size(), b_copy.size());
CHECK_EQ(b_range.height(), b_copy.height());
CHECK_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
CHECK_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
EXPECT_EQ(b_range.size(), b_copy.size());
EXPECT_EQ(b_range.height(), b_copy.height());
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
for (int i = 0; i < values.size(); ++i) {
CHECK_EQ(*b_range.find(key_of_value(values[i])), values[i]);
EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]);
}
// Test assignment to self. Nothing should change.
b_range.operator=(b_range);
CHECK_EQ(b_range.size(), b_copy.size());
CHECK_EQ(b_range.height(), b_copy.height());
CHECK_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
CHECK_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
EXPECT_EQ(b_range.size(), b_copy.size());
EXPECT_EQ(b_range.height(), b_copy.height());
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
// Test assignment of new values.
b_range.clear();
b_range = b_copy;
CHECK_EQ(b_range.size(), b_copy.size());
CHECK_EQ(b_range.height(), b_copy.height());
CHECK_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
CHECK_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
EXPECT_EQ(b_range.size(), b_copy.size());
EXPECT_EQ(b_range.height(), b_copy.height());
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
// Test swap.
b_range.clear();
b_range.swap(b_copy);
CHECK_EQ(b_copy.size(), 0);
CHECK_EQ(b_range.size(), const_b.size());
EXPECT_EQ(b_copy.size(), 0);
EXPECT_EQ(b_range.size(), const_b.size());
for (int i = 0; i < values.size(); ++i) {
CHECK_EQ(*b_range.find(key_of_value(values[i])), values[i]);
EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]);
}
b_range.swap(b_copy);
@ -693,13 +706,13 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
for (int i = 0; i < values.size(); ++i) {
mutable_b.erase(key_of_value(values[i]));
// Erasing a non-existent key should have no effect.
CHECK_EQ(mutable_b.erase(key_of_value(values[i])), 0);
EXPECT_EQ(mutable_b.erase(key_of_value(values[i])), 0);
}
const_b.verify();
CHECK_EQ(const_b.internal_nodes(), 0);
CHECK_EQ(const_b.leaf_nodes(), 0);
CHECK_EQ(const_b.size(), 0);
EXPECT_EQ(const_b.internal_nodes(), 0);
EXPECT_EQ(const_b.leaf_nodes(), 0);
EXPECT_EQ(const_b.size(), 0);
// Test erase via iterators.
mutable_b = b_copy;
@ -708,9 +721,9 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
}
const_b.verify();
CHECK_EQ(const_b.internal_nodes(), 0);
CHECK_EQ(const_b.leaf_nodes(), 0);
CHECK_EQ(const_b.size(), 0);
EXPECT_EQ(const_b.internal_nodes(), 0);
EXPECT_EQ(const_b.leaf_nodes(), 0);
EXPECT_EQ(const_b.size(), 0);
// Test insert with hint.
for (int i = 0; i < values.size(); i++) {
@ -721,13 +734,13 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
// Test dumping of the btree to an ostream. There should be 1 line for each
// value.
ostringstream strm;
std::stringstream strm;
strm << mutable_b.tree();
CHECK_EQ(mutable_b.size(), strcount(strm.str(), '\n'));
EXPECT_EQ(mutable_b.size(), strcount(strm.str(), '\n'));
// Test range erase.
mutable_b.erase(mutable_b.begin(), mutable_b.end());
CHECK_EQ(mutable_b.size(), 0);
EXPECT_EQ(mutable_b.size(), 0);
const_b.verify();
// First half.
@ -735,7 +748,7 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
typename T::iterator mutable_iter_end = mutable_b.begin();
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end;
mutable_b.erase(mutable_b.begin(), mutable_iter_end);
CHECK_EQ(mutable_b.size(), values.size() - values.size() / 2);
EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2);
const_b.verify();
// Second half.
@ -743,7 +756,7 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
typename T::iterator mutable_iter_begin = mutable_b.begin();
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin;
mutable_b.erase(mutable_iter_begin, mutable_b.end());
CHECK_EQ(mutable_b.size(), values.size() / 2);
EXPECT_EQ(mutable_b.size(), values.size() / 2);
const_b.verify();
// Second quarter.
@ -753,7 +766,7 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
mutable_iter_end = mutable_iter_begin;
for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end;
mutable_b.erase(mutable_iter_begin, mutable_iter_end);
CHECK_EQ(mutable_b.size(), values.size() - values.size() / 4);
EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4);
const_b.verify();
mutable_b.clear();
@ -770,62 +783,62 @@ void ConstTest() {
// Insert a single value into the container and test looking it up.
value_type value = Generator<value_type>(2)(2);
mutable_b.insert(value);
CHECK(mutable_b.find(key_of_value(value)) != const_b.end());
CHECK(const_b.find(key_of_value(value)) != mutable_b.end());
CHECK_EQ(*const_b.lower_bound(key_of_value(value)), value);
CHECK(const_b.upper_bound(key_of_value(value)) == const_b.end());
CHECK_EQ(*const_b.equal_range(key_of_value(value)).first, value);
EXPECT_TRUE(mutable_b.find(key_of_value(value)) != const_b.end());
EXPECT_TRUE(const_b.find(key_of_value(value)) != mutable_b.end());
EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value);
EXPECT_TRUE(const_b.upper_bound(key_of_value(value)) == const_b.end());
EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value);
// We can only create a non-const iterator from a non-const container.
typename T::iterator mutable_iter(mutable_b.begin());
CHECK(mutable_iter == const_b.begin());
CHECK(mutable_iter != const_b.end());
CHECK(const_b.begin() == mutable_iter);
CHECK(const_b.end() != mutable_iter);
EXPECT_TRUE(mutable_iter == const_b.begin());
EXPECT_TRUE(mutable_iter != const_b.end());
EXPECT_TRUE(const_b.begin() == mutable_iter);
EXPECT_TRUE(const_b.end() != mutable_iter);
typename T::reverse_iterator mutable_riter(mutable_b.rbegin());
CHECK(mutable_riter == const_b.rbegin());
CHECK(mutable_riter != const_b.rend());
CHECK(const_b.rbegin() == mutable_riter);
CHECK(const_b.rend() != mutable_riter);
EXPECT_TRUE(mutable_riter == const_b.rbegin());
EXPECT_TRUE(mutable_riter != const_b.rend());
EXPECT_TRUE(const_b.rbegin() == mutable_riter);
EXPECT_TRUE(const_b.rend() != mutable_riter);
// We can create a const iterator from a non-const iterator.
typename T::const_iterator const_iter(mutable_iter);
CHECK(const_iter == mutable_b.begin());
CHECK(const_iter != mutable_b.end());
CHECK(mutable_b.begin() == const_iter);
CHECK(mutable_b.end() != const_iter);
EXPECT_TRUE(const_iter == mutable_b.begin());
EXPECT_TRUE(const_iter != mutable_b.end());
EXPECT_TRUE(mutable_b.begin() == const_iter);
EXPECT_TRUE(mutable_b.end() != const_iter);
typename T::const_reverse_iterator const_riter(mutable_riter);
CHECK(const_riter == mutable_b.rbegin());
CHECK(const_riter != mutable_b.rend());
CHECK(mutable_b.rbegin() == const_riter);
CHECK(mutable_b.rend() != const_riter);
EXPECT_EQ(const_riter, mutable_b.rbegin());
EXPECT_TRUE(const_riter != mutable_b.rend());
EXPECT_EQ(mutable_b.rbegin(), const_riter);
EXPECT_TRUE(mutable_b.rend() != const_riter);
// Make sure various methods can be invoked on a const container.
const_b.verify();
CHECK(!const_b.empty());
CHECK_EQ(const_b.size(), 1);
CHECK_GT(const_b.max_size(), 0);
CHECK_EQ(const_b.height(), 1);
CHECK_EQ(const_b.count(key_of_value(value)), 1);
CHECK_EQ(const_b.internal_nodes(), 0);
CHECK_EQ(const_b.leaf_nodes(), 1);
CHECK_EQ(const_b.nodes(), 1);
CHECK_GT(const_b.bytes_used(), 0);
CHECK_GT(const_b.fullness(), 0);
CHECK_GT(const_b.overhead(), 0);
EXPECT_FALSE(const_b.empty());
EXPECT_EQ(const_b.size(), 1);
EXPECT_GT(const_b.max_size(), 0);
EXPECT_EQ(const_b.height(), 1);
EXPECT_EQ(const_b.count(key_of_value(value)), 1);
EXPECT_EQ(const_b.internal_nodes(), 0);
EXPECT_EQ(const_b.leaf_nodes(), 1);
EXPECT_EQ(const_b.nodes(), 1);
EXPECT_GT(const_b.bytes_used(), 0);
EXPECT_GT(const_b.fullness(), 0);
EXPECT_GT(const_b.overhead(), 0);
}
template <typename T, typename C>
void BtreeTest() {
ConstTest<T>();
typedef typename base::remove_const<typename T::value_type>::type V;
vector<V> random_values = GenerateValues<V>(FLAGS_test_values);
typedef typename std::remove_const<typename T::value_type>::type V;
std::vector<V> random_values = GenerateValues<V>(FLAGS_test_values);
unique_checker<T, C> container;
// Test key insertion/deletion in sorted order.
vector<V> sorted_values(random_values);
std::vector<V> sorted_values(random_values);
sort(sorted_values.begin(), sorted_values.end());
DoTest("sorted: ", &container, sorted_values);
@ -841,13 +854,13 @@ template <typename T, typename C>
void BtreeMultiTest() {
ConstTest<T>();
typedef typename base::remove_const<typename T::value_type>::type V;
const vector<V>& random_values = GenerateValues<V>(FLAGS_test_values);
typedef typename std::remove_const<typename T::value_type>::type V;
const std::vector<V>& random_values = GenerateValues<V>(FLAGS_test_values);
multi_checker<T, C> container;
// Test keys in sorted order.
vector<V> sorted_values(random_values);
std::vector<V> sorted_values(random_values);
sort(sorted_values.begin(), sorted_values.end());
DoTest("sorted: ", &container, sorted_values);
@ -859,25 +872,64 @@ void BtreeMultiTest() {
DoTest("random: ", &container, random_values);
// Test keys in random order w/ duplicates.
vector<V> duplicate_values(random_values);
std::vector<V> duplicate_values(random_values);
duplicate_values.insert(
duplicate_values.end(), random_values.begin(), random_values.end());
DoTest("duplicates:", &container, duplicate_values);
// Test all identical keys.
vector<V> identical_values(100);
std::vector<V> identical_values(100);
fill(identical_values.begin(), identical_values.end(), Generator<V>(2)(2));
DoTest("identical: ", &container, identical_values);
}
template <typename T, typename Alloc = std::allocator<T> >
class TestAllocator : public Alloc {
public:
typedef typename Alloc::pointer pointer;
typedef typename Alloc::size_type size_type;
TestAllocator() : bytes_used_(NULL) { }
TestAllocator(int64_t *bytes_used) : bytes_used_(bytes_used) { }
// Constructor used for rebinding
template <class U>
TestAllocator(const TestAllocator<U>& x)
: Alloc(x),
bytes_used_(x.bytes_used()) {
}
pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0) {
EXPECT_TRUE(bytes_used_ != NULL);
*bytes_used_ += n * sizeof(T);
return Alloc::allocate(n, hint);
}
void deallocate(pointer p, size_type n) {
Alloc::deallocate(p, n);
EXPECT_TRUE(bytes_used_ != NULL);
*bytes_used_ -= n * sizeof(T);
}
// Rebind allows an allocator<T> to be used for a different type
template <class U> struct rebind {
typedef TestAllocator<U, typename Alloc::template rebind<U>::other> other;
};
int64_t* bytes_used() const { return bytes_used_; }
private:
int64_t *bytes_used_;
};
template <typename T>
void BtreeArenaTest() {
void BtreeAllocatorTest() {
typedef typename T::value_type value_type;
UnsafeArena arena1(1000);
UnsafeArena arena2(1000);
T b1(typename T::key_compare(), &arena1);
T b2(typename T::key_compare(), &arena2);
int64_t alloc1 = 0;
int64_t alloc2 = 0;
T b1(typename T::key_compare(), &alloc1);
T b2(typename T::key_compare(), &alloc2);
// This should swap the allocators!
swap(b1, b2);
@ -886,9 +938,9 @@ void BtreeArenaTest() {
b1.insert(Generator<value_type>(1000)(i));
}
// We should have allocated out of arena2!
CHECK_LE(b1.bytes_used(), arena2.status().bytes_allocated());
CHECK_GT(arena2.block_count(), arena1.block_count());
// We should have allocated out of alloc2!
EXPECT_LE(b1.bytes_used(), alloc2 + sizeof(b1));
EXPECT_GT(alloc2, alloc1);
}
template <typename T>
@ -906,15 +958,15 @@ void BtreeMapTest() {
value_type v = Generator<value_type>(1000)(i);
b[v.first] = v.second;
}
CHECK_EQ(b.size(), 1000);
EXPECT_EQ(b.size(), 1000);
// Test whether we can use the "->" operator on iterators and
// reverse_iterators. This stresses the btree_map_params::pair_pointer
// mechanism.
CHECK_EQ(b.begin()->first, Generator<value_type>(1000)(0).first);
CHECK_EQ(b.begin()->second, Generator<value_type>(1000)(0).second);
CHECK_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first);
CHECK_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second);
EXPECT_EQ(b.begin()->first, Generator<value_type>(1000)(0).first);
EXPECT_EQ(b.begin()->second, Generator<value_type>(1000)(0).second);
EXPECT_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first);
EXPECT_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second);
}
template <typename T>
@ -925,6 +977,5 @@ void BtreeMultiMapTest() {
}
} // namespace btree
} // namespace util
#endif // UTIL_BTREE_BTREE_TEST_H__

View File

@ -1,7 +1,7 @@
// Copyright 2007 Google Inc. All Rights Reserved.
// Author: pmattis@google.com (Peter Mattis)
#include "base/commandlineflags.h"
#include "gflags/gflags.h"
DEFINE_int32(test_values, 10000,
"The number of values to use for tests.");

View File

@ -21,11 +21,8 @@
#include <iosfwd>
#include <utility>
#include "base/integral_types.h"
#include "base/logging.h"
#include "util/btree/btree.h"
#include "btree.h"
namespace util {
namespace btree {
template <typename Tree, typename Iterator>
@ -77,7 +74,7 @@ class safe_btree_iterator {
}
Tree* tree() const { return tree_; }
int64 generation() const { return generation_; }
int64_t generation() const { return generation_; }
Iterator* mutable_iter() const {
if (generation_ != tree_->generation()) {
@ -114,13 +111,13 @@ class safe_btree_iterator {
// This reference value is potentially invalidated by any non-const
// method on the tree; it is NOT safe.
reference operator*() const {
DCHECK_GT(generation_, 0);
assert(generation_ > 0);
return iter().operator*();
}
// This pointer value is potentially invalidated by any non-const
// method on the tree; it is NOT safe.
pointer operator->() const {
DCHECK_GT(generation_, 0);
assert(generation_ > 0);
return iter().operator->();
}
@ -148,7 +145,7 @@ class safe_btree_iterator {
private:
// The generation of the tree when "iter" was updated.
mutable int64 generation_;
mutable int64_t generation_;
// The key the iterator points to.
mutable key_type key_;
// The underlying iterator.
@ -236,14 +233,14 @@ class safe_btree {
const_iterator upper_bound(const key_type &key) const {
return const_iterator(this, tree_.upper_bound(key));
}
pair<iterator, iterator> equal_range(const key_type &key) {
pair<tree_iterator, tree_iterator> p = tree_.equal_range(key);
return make_pair(iterator(this, p.first),
std::pair<iterator, iterator> equal_range(const key_type &key) {
std::pair<tree_iterator, tree_iterator> p = tree_.equal_range(key);
return std::make_pair(iterator(this, p.first),
iterator(this, p.second));
}
pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
pair<tree_const_iterator, tree_const_iterator> p = tree_.equal_range(key);
return make_pair(const_iterator(this, p.first),
std::pair<const_iterator, const_iterator> equal_range(const key_type &key) const {
std::pair<tree_const_iterator, tree_const_iterator> p = tree_.equal_range(key);
return std::make_pair(const_iterator(this, p.first),
const_iterator(this, p.second));
}
iterator find_unique(const key_type &key) {
@ -267,15 +264,15 @@ class safe_btree {
// Insertion routines.
template <typename ValuePointer>
pair<iterator, bool> insert_unique(const key_type &key, ValuePointer value) {
pair<tree_iterator, bool> p = tree_.insert_unique(key, value);
std::pair<iterator, bool> insert_unique(const key_type &key, ValuePointer value) {
std::pair<tree_iterator, bool> p = tree_.insert_unique(key, value);
generation_ += p.second;
return make_pair(iterator(this, p.first), p.second);
return std::make_pair(iterator(this, p.first), p.second);
}
pair<iterator, bool> insert_unique(const value_type &v) {
pair<tree_iterator, bool> p = tree_.insert_unique(v);
std::pair<iterator, bool> insert_unique(const value_type &v) {
std::pair<tree_iterator, bool> p = tree_.insert_unique(v);
generation_ += p.second;
return make_pair(iterator(this, p.first), p.second);
return std::make_pair(iterator(this, p.first), p.second);
}
iterator insert_unique(iterator position, const value_type &v) {
tree_iterator tree_pos = position.iter();
@ -351,13 +348,13 @@ class safe_btree {
++x.generation_;
tree_.swap(x.tree_);
}
void dump(ostream &os) const {
void dump(std::ostream &os) const {
tree_.dump(os);
}
void verify() const {
tree_.verify();
}
int64 generation() const {
int64_t generation() const {
return generation_;
}
key_compare key_comp() const { return tree_.key_comp(); }
@ -379,10 +376,9 @@ class safe_btree {
private:
btree_type tree_;
int64 generation_;
int64_t generation_;
};
} // namespace btree
} // namespace util
#endif // UTIL_BTREE_SAFE_BTREE_H__

View File

@ -22,17 +22,16 @@
#include <memory>
#include <utility>
#include "util/btree/btree_container.h"
#include "util/btree/btree_map.h"
#include "util/btree/safe_btree.h"
#include "btree_container.h"
#include "btree_map.h"
#include "safe_btree.h"
namespace util {
namespace btree {
// The safe_btree_map class is needed mainly for its constructors.
template <typename Key, typename Value,
typename Compare = less<Key>,
typename Alloc = std::allocator<pair<const Key, Value> >,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<std::pair<const Key, Value> >,
int TargetNodeSize = 256>
class safe_btree_map : public btree_map_container<
safe_btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
@ -75,6 +74,5 @@ inline void swap(safe_btree_map<K, V, C, A, N> &x,
}
} // namespace btree
} // namespace util
#endif // UTIL_BTREE_SAFE_BTREE_MAP_H__

View File

@ -22,16 +22,15 @@
#include <functional>
#include <memory>
#include "util/btree/btree_container.h"
#include "util/btree/btree_set.h"
#include "util/btree/safe_btree.h"
#include "btree_container.h"
#include "btree_set.h"
#include "safe_btree.h"
namespace util {
namespace btree {
// The safe_btree_set class is needed mainly for its constructors.
template <typename Key,
typename Compare = less<Key>,
typename Compare = std::less<Key>,
typename Alloc = std::allocator<Key>,
int TargetNodeSize = 256>
class safe_btree_set : public btree_unique_container<
@ -74,6 +73,5 @@ inline void swap(safe_btree_set<K, C, A, N> &x,
}
} // namespace btree
} // namespace util
#endif // UTIL_BTREE_SAFE_BTREE_SET_H__

View File

@ -11,58 +11,50 @@
#include <string>
#include <utility>
#include "base/arena-inl.h"
#include "base/init_google.h"
#include "base/integral_types.h"
#include "base/logging.h"
#include "strings/cord.h"
#include "testing/base/public/gunit.h"
#include "util/btree/btree_test.h"
#include "util/btree/safe_btree_map.h"
#include "util/btree/safe_btree_set.h"
#include "gtest/gtest.h"
#include "btree_test.h"
#include "safe_btree_map.h"
#include "safe_btree_set.h"
class UnsafeArena;
namespace util {
namespace btree {
namespace {
template <typename K, int N>
void SetTest() {
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
BtreeTest<safe_btree_set<K, less<K>, allocator<K>, N>, set<K> >();
BtreeArenaTest<safe_btree_set<K, less<K>, ArenaAlloc, N> >();
typedef TestAllocator<K> TestAlloc;
BtreeTest<safe_btree_set<K, std::less<K>, std::allocator<K>, N>, std::set<K> >();
BtreeAllocatorTest<safe_btree_set<K, std::less<K>, TestAlloc, N> >();
}
template <typename K, int N>
void MapTest() {
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
BtreeTest<safe_btree_map<K, K, less<K>, allocator<K>, N>, map<K, K> >();
BtreeArenaTest<safe_btree_map<K, K, less<K>, ArenaAlloc, N> >();
BtreeMapTest<safe_btree_map<K, K, less<K>, allocator<K>, N> >();
typedef TestAllocator<K> TestAlloc;
BtreeTest<safe_btree_map<K, K, std::less<K>, std::allocator<K>, N>, std::map<K, K> >();
BtreeAllocatorTest<safe_btree_map<K, K, std::less<K>, TestAlloc, N> >();
BtreeMapTest<safe_btree_map<K, K, std::less<K>, std::allocator<K>, N> >();
}
TEST(SafeBtree, set_int32_32) { SetTest<int32, 32>(); }
TEST(SafeBtree, set_int32_64) { SetTest<int32, 64>(); }
TEST(SafeBtree, set_int32_128) { SetTest<int32, 128>(); }
TEST(SafeBtree, set_int32_256) { SetTest<int32, 256>(); }
TEST(SafeBtree, set_int64_256) { SetTest<int64, 256>(); }
TEST(SafeBtree, set_string_256) { SetTest<string, 256>(); }
TEST(SafeBtree, set_cord_256) { SetTest<Cord, 256>(); }
TEST(SafeBtree, set_pair_256) { SetTest<pair<int, int>, 256>(); }
TEST(SafeBtree, map_int32_256) { MapTest<int32, 256>(); }
TEST(SafeBtree, map_int64_256) { MapTest<int64, 256>(); }
TEST(SafeBtree, map_string_256) { MapTest<string, 256>(); }
TEST(SafeBtree, map_cord_256) { MapTest<Cord, 256>(); }
TEST(SafeBtree, map_pair_256) { MapTest<pair<int, int>, 256>(); }
TEST(SafeBtree, set_int32_32) { SetTest<int32_t, 32>(); }
TEST(SafeBtree, set_int32_64) { SetTest<int32_t, 64>(); }
TEST(SafeBtree, set_int32_128) { SetTest<int32_t, 128>(); }
TEST(SafeBtree, set_int32_256) { SetTest<int32_t, 256>(); }
TEST(SafeBtree, set_int64_256) { SetTest<int64_t, 256>(); }
TEST(SafeBtree, set_string_256) { SetTest<std::string, 256>(); }
TEST(SafeBtree, set_pair_256) { SetTest<std::pair<int, int>, 256>(); }
TEST(SafeBtree, map_int32_256) { MapTest<int32_t, 256>(); }
TEST(SafeBtree, map_int64_256) { MapTest<int64_t, 256>(); }
TEST(SafeBtree, map_string_256) { MapTest<std::string, 256>(); }
TEST(SafeBtree, map_pair_256) { MapTest<std::pair<int, int>, 256>(); }
TEST(SafeBtree, Comparison) {
const int kSetSize = 1201;
safe_btree_set<int64> my_set;
safe_btree_set<int64_t> my_set;
for (int i = 0; i < kSetSize; ++i) {
my_set.insert(i);
}
safe_btree_set<int64> my_set_copy(my_set);
safe_btree_set<int64_t> my_set_copy(my_set);
EXPECT_TRUE(my_set_copy == my_set);
EXPECT_TRUE(my_set == my_set_copy);
EXPECT_FALSE(my_set_copy != my_set);
@ -80,17 +72,17 @@ TEST(SafeBtree, Comparison) {
EXPECT_TRUE(my_set_copy != my_set);
EXPECT_TRUE(my_set != my_set_copy);
safe_btree_map<string, int64> my_map;
safe_btree_map<std::string, int64_t> my_map;
for (int i = 0; i < kSetSize; ++i) {
my_map[string(i, 'a')] = i;
my_map[std::string(i, 'a')] = i;
}
safe_btree_map<string, int64> my_map_copy(my_map);
safe_btree_map<std::string, int64_t> my_map_copy(my_map);
EXPECT_TRUE(my_map_copy == my_map);
EXPECT_TRUE(my_map == my_map_copy);
EXPECT_FALSE(my_map_copy != my_map);
EXPECT_FALSE(my_map != my_map_copy);
++my_map_copy[string(7, 'a')];
++my_map_copy[std::string(7, 'a')];
EXPECT_FALSE(my_map_copy == my_map);
EXPECT_FALSE(my_map == my_map_copy);
EXPECT_TRUE(my_map_copy != my_map);
@ -103,7 +95,7 @@ TEST(SafeBtree, Comparison) {
EXPECT_TRUE(my_map_copy != my_map);
EXPECT_TRUE(my_map != my_map_copy);
my_map.erase(string(kSetSize - 1, 'a'));
my_map.erase(std::string(kSetSize - 1, 'a'));
EXPECT_FALSE(my_map_copy == my_map);
EXPECT_FALSE(my_map == my_map_copy);
EXPECT_TRUE(my_map_copy != my_map);
@ -112,10 +104,3 @@ TEST(SafeBtree, Comparison) {
} // namespace
} // namespace btree
} // namespace util
int main(int argc, char **argv) {
FLAGS_logtostderr = true;
InitGoogle(argv[0], &argc, &argv, true);
return RUN_ALL_TESTS();
}