Build outside of Google; add CMakeLists.txt, README
parent
9783752d62
commit
88853fbc9e
|
@ -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()
|
|
@ -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
381
btree.h
|
@ -35,11 +35,6 @@
|
||||||
//
|
//
|
||||||
// btree_bench --benchmarks=. 2>&1 | ./benchmarks.awk
|
// 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
|
// Run on pmattis-warp.nyc (4 X 2200 MHz CPUs); 2010/03/04-15:23:06
|
||||||
// Benchmark STL(ns) B-Tree(ns) @ <size>
|
// 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_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_fifo 398 596 -49.75% <256> [72.0, 44.0]
|
||||||
// BM_map_string_fwditer 243 113 +53.50% <256> [72.0, 55.8]
|
// 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__
|
#ifndef UTIL_BTREE_BTREE_H__
|
||||||
#define UTIL_BTREE_BTREE_H__
|
#define UTIL_BTREE_BTREE_H__
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator> // IWYU pragma: export // Clients can rely on this.
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <ostream> // IWYU pragma: export // Clients can rely on this.
|
#include <ostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "base/gdb-scripting.h"
|
#ifndef NDEBUG
|
||||||
#include "base/integral_types.h"
|
#define NDEBUG 1
|
||||||
#include "base/logging.h"
|
#endif
|
||||||
#include "base/macros.h"
|
|
||||||
#include "base/template_util.h"
|
|
||||||
#include "base/type_traits.h"
|
|
||||||
#include "strings/cord.h"
|
|
||||||
#include "strings/stringpiece.h"
|
|
||||||
|
|
||||||
// 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 {
|
namespace btree {
|
||||||
|
|
||||||
// Inside a btree method, if we just call swap(), it will choose the
|
// 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);
|
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
|
// 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:
|
// 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.
|
// btree_key_compare_to_tag.
|
||||||
template <typename Compare>
|
template <typename Compare>
|
||||||
struct btree_is_key_compare_to
|
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"
|
// 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 <>
|
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 {
|
: public btree_key_compare_to_tag {
|
||||||
btree_key_compare_to_adapter() {}
|
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(
|
btree_key_compare_to_adapter(
|
||||||
const btree_key_compare_to_adapter<less<string> >&) {}
|
const btree_key_compare_to_adapter<std::less<std::string> >&) {}
|
||||||
int operator()(const string &a, const string &b) const {
|
int operator()(const std::string &a, const std::string &b) const {
|
||||||
return a.compare(b);
|
return a.compare(b);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
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 {
|
: public btree_key_compare_to_tag {
|
||||||
btree_key_compare_to_adapter() {}
|
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(
|
btree_key_compare_to_adapter(
|
||||||
const btree_key_compare_to_adapter<greater<string> >&) {}
|
const btree_key_compare_to_adapter<std::greater<std::string> >&) {}
|
||||||
int operator()(const string &a, const string &b) const {
|
int operator()(const std::string &a, const std::string &b) const {
|
||||||
return b.compare(a);
|
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
|
// 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 functor. This specialization is used when we do not have a
|
||||||
// compare-to functor.
|
// 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
|
// If Compare is derived from btree_key_compare_to_tag then use it as the
|
||||||
// key_compare type. Otherwise, use btree_key_compare_to_adapter<> which will
|
// key_compare type. Otherwise, use btree_key_compare_to_adapter<> which will
|
||||||
// fall-back to Compare if we don't have an appropriate specialization.
|
// 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,
|
btree_is_key_compare_to<Compare>::value,
|
||||||
Compare, btree_key_compare_to_adapter<Compare> >::type key_compare;
|
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
|
// 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
|
// This is an integral type large enough to hold as many
|
||||||
// ValueSize-values as will fit a node of TargetNodeSize bytes.
|
// ValueSize-values as will fit a node of TargetNodeSize bytes.
|
||||||
typedef typename base::if_<
|
typedef typename if_<
|
||||||
(kNodeValueSpace / ValueSize) >= 256,
|
(kNodeValueSpace / ValueSize) >= 256,
|
||||||
uint16,
|
uint16_t,
|
||||||
uint8>::type node_count_type;
|
uint8_t>::type node_count_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A parameters structure for holding the type parameters for a btree_map.
|
// A parameters structure for holding the type parameters for a btree_map.
|
||||||
|
@ -358,8 +299,8 @@ struct btree_map_params
|
||||||
sizeof(Key) + sizeof(Data)> {
|
sizeof(Key) + sizeof(Data)> {
|
||||||
typedef Data data_type;
|
typedef Data data_type;
|
||||||
typedef Data mapped_type;
|
typedef Data mapped_type;
|
||||||
typedef pair<const Key, data_type> value_type;
|
typedef std::pair<const Key, data_type> value_type;
|
||||||
typedef pair<Key, data_type> mutable_value_type;
|
typedef std::pair<Key, data_type> mutable_value_type;
|
||||||
typedef value_type* pointer;
|
typedef value_type* pointer;
|
||||||
typedef const value_type* const_pointer;
|
typedef const value_type* const_pointer;
|
||||||
typedef value_type& reference;
|
typedef value_type& reference;
|
||||||
|
@ -382,8 +323,8 @@ template <typename Key, typename Compare, typename Alloc, int TargetNodeSize>
|
||||||
struct btree_set_params
|
struct btree_set_params
|
||||||
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize,
|
: public btree_common_params<Key, Compare, Alloc, TargetNodeSize,
|
||||||
sizeof(Key)> {
|
sizeof(Key)> {
|
||||||
typedef base::false_type data_type;
|
typedef std::false_type data_type;
|
||||||
typedef base::false_type mapped_type;
|
typedef std::false_type mapped_type;
|
||||||
typedef Key value_type;
|
typedef Key value_type;
|
||||||
typedef value_type mutable_value_type;
|
typedef value_type mutable_value_type;
|
||||||
typedef value_type* pointer;
|
typedef value_type* pointer;
|
||||||
|
@ -499,22 +440,22 @@ class btree_node {
|
||||||
key_type, self_type, key_compare> binary_search_compare_to_type;
|
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,
|
// If we have a valid key-compare-to type, use linear_search_compare_to,
|
||||||
// otherwise use linear_search_plain_compare.
|
// otherwise use linear_search_plain_compare.
|
||||||
typedef typename base::if_<
|
typedef typename if_<
|
||||||
Params::is_key_compare_to::value,
|
Params::is_key_compare_to::value,
|
||||||
linear_search_compare_to_type,
|
linear_search_compare_to_type,
|
||||||
linear_search_plain_compare_type>::type linear_search_type;
|
linear_search_plain_compare_type>::type linear_search_type;
|
||||||
// If we have a valid key-compare-to type, use binary_search_compare_to,
|
// If we have a valid key-compare-to type, use binary_search_compare_to,
|
||||||
// otherwise use binary_search_plain_compare.
|
// otherwise use binary_search_plain_compare.
|
||||||
typedef typename base::if_<
|
typedef typename if_<
|
||||||
Params::is_key_compare_to::value,
|
Params::is_key_compare_to::value,
|
||||||
binary_search_compare_to_type,
|
binary_search_compare_to_type,
|
||||||
binary_search_plain_compare_type>::type binary_search_type;
|
binary_search_plain_compare_type>::type binary_search_type;
|
||||||
// If the key is an integral or floating point type, use linear search which
|
// 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
|
// is faster than binary search for such types. Might be wise to also
|
||||||
// configure linear search based on node-size.
|
// configure linear search based on node-size.
|
||||||
typedef typename base::if_<
|
typedef typename if_<
|
||||||
base::is_integral<key_type>::value ||
|
std::is_integral<key_type>::value ||
|
||||||
base::is_floating_point<key_type>::value,
|
std::is_floating_point<key_type>::value,
|
||||||
linear_search_type, binary_search_type>::type search_type;
|
linear_search_type, binary_search_type>::type search_type;
|
||||||
|
|
||||||
struct base_fields {
|
struct base_fields {
|
||||||
|
@ -586,7 +527,7 @@ class btree_node {
|
||||||
// be a leaf.
|
// be a leaf.
|
||||||
bool is_root() const { return parent()->leaf(); }
|
bool is_root() const { return parent()->leaf(); }
|
||||||
void make_root() {
|
void make_root() {
|
||||||
DCHECK(parent()->is_root());
|
assert(parent()->is_root());
|
||||||
fields_.parent = fields_.parent->parent();
|
fields_.parent = fields_.parent->parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -739,7 +680,7 @@ class btree_node {
|
||||||
f->max_count = max_count;
|
f->max_count = max_count;
|
||||||
f->count = 0;
|
f->count = 0;
|
||||||
f->parent = parent;
|
f->parent = parent;
|
||||||
if (DEBUG_MODE) {
|
if (!NDEBUG) {
|
||||||
memset(&f->values, 0, max_count * sizeof(value_type));
|
memset(&f->values, 0, max_count * sizeof(value_type));
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
|
@ -747,7 +688,7 @@ class btree_node {
|
||||||
static btree_node* init_internal(internal_fields *f, btree_node *parent) {
|
static btree_node* init_internal(internal_fields *f, btree_node *parent) {
|
||||||
btree_node *n = init_leaf(f, parent, kNodeValues);
|
btree_node *n = init_leaf(f, parent, kNodeValues);
|
||||||
f->leaf = 0;
|
f->leaf = 0;
|
||||||
if (DEBUG_MODE) {
|
if (!NDEBUG) {
|
||||||
memset(f->children, 0, sizeof(f->children));
|
memset(f->children, 0, sizeof(f->children));
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
|
@ -779,7 +720,8 @@ class btree_node {
|
||||||
root_fields fields_;
|
root_fields fields_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(btree_node);
|
btree_node(const btree_node&);
|
||||||
|
void operator=(const btree_node&);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Node, typename Reference, typename Pointer>
|
template <typename Node, typename Reference, typename Pointer>
|
||||||
|
@ -790,7 +732,7 @@ struct btree_iterator {
|
||||||
typedef typename Node::params_type params_type;
|
typedef typename Node::params_type params_type;
|
||||||
|
|
||||||
typedef Node node_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 const Node const_node;
|
||||||
typedef typename params_type::value_type value_type;
|
typedef typename params_type::value_type value_type;
|
||||||
typedef typename params_type::pointer normal_pointer;
|
typedef typename params_type::pointer normal_pointer;
|
||||||
|
@ -800,7 +742,7 @@ struct btree_iterator {
|
||||||
|
|
||||||
typedef Pointer pointer;
|
typedef Pointer pointer;
|
||||||
typedef Reference reference;
|
typedef Reference reference;
|
||||||
typedef bidirectional_iterator_tag iterator_category;
|
typedef std::bidirectional_iterator_tag iterator_category;
|
||||||
|
|
||||||
typedef btree_iterator<
|
typedef btree_iterator<
|
||||||
normal_node, normal_reference, normal_pointer> 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.
|
// Dispatch helper class for using btree::internal_locate with plain compare.
|
||||||
struct btree_internal_locate_plain_compare {
|
struct btree_internal_locate_plain_compare {
|
||||||
template <typename K, typename T, typename Iter>
|
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);
|
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.
|
// Dispatch helper class for using btree::internal_locate with compare-to.
|
||||||
struct btree_internal_locate_compare_to {
|
struct btree_internal_locate_compare_to {
|
||||||
template <typename K, typename T, typename Iter>
|
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);
|
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_plain_compare;
|
||||||
friend class btree_internal_locate_compare_to;
|
friend class btree_internal_locate_compare_to;
|
||||||
typedef typename base::if_<
|
typedef typename if_<
|
||||||
is_key_compare_to::value,
|
is_key_compare_to::value,
|
||||||
btree_internal_locate_compare_to,
|
btree_internal_locate_compare_to,
|
||||||
btree_internal_locate_plain_compare>::type internal_locate_type;
|
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
|
// 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 returned pair is equal to lower_bound(key). The second member pair of
|
||||||
// the pair is equal to upper_bound(key).
|
// the pair is equal to upper_bound(key).
|
||||||
pair<iterator,iterator> equal_range(const key_type &key) {
|
std::pair<iterator,iterator> equal_range(const key_type &key) {
|
||||||
return make_pair(lower_bound(key), upper_bound(key));
|
return std::make_pair(lower_bound(key), upper_bound(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 make_pair(lower_bound(key), upper_bound(key));
|
return std::make_pair(lower_bound(key), upper_bound(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inserts a value into the btree only if it does not already exist. The
|
// 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
|
// is being inserted. Value is not dereferenced if the key already exists in
|
||||||
// the btree. See btree_map::operator[].
|
// the btree. See btree_map::operator[].
|
||||||
template <typename ValuePointer>
|
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
|
// Inserts a value into the btree only if it does not already exist. The
|
||||||
// boolean return value indicates whether insertion succeeded or failed.
|
// 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);
|
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
|
// Dump the btree to the specified ostream. Requires that operator<< is
|
||||||
// defined for Key and Value.
|
// defined for Key and Value.
|
||||||
void dump(ostream &os) const {
|
void dump(std::ostream &os) const {
|
||||||
if (root() != NULL) {
|
if (root() != NULL) {
|
||||||
internal_dump(os, root(), 0);
|
internal_dump(os, root(), 0);
|
||||||
}
|
}
|
||||||
|
@ -1185,7 +1127,7 @@ class btree : public Params::key_compare {
|
||||||
if (root()->leaf()) return root()->count();
|
if (root()->leaf()) return root()->count();
|
||||||
return root()->size();
|
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; }
|
bool empty() const { return root() == NULL; }
|
||||||
|
|
||||||
// The height of the btree. An empty tree will have height 0.
|
// 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) {
|
void delete_internal_node(node_type *node) {
|
||||||
node->destroy();
|
node->destroy();
|
||||||
DCHECK(node != root());
|
assert(node != root());
|
||||||
mutable_internal_allocator()->deallocate(
|
mutable_internal_allocator()->deallocate(
|
||||||
reinterpret_cast<char*>(node), sizeof(internal_fields));
|
reinterpret_cast<char*>(node), sizeof(internal_fields));
|
||||||
}
|
}
|
||||||
|
@ -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
|
// 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
|
// field of the pair. The compare_to specialization allows the caller to
|
||||||
// avoid a subsequent comparison to determine if an exact match was made,
|
// 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>
|
template <typename IterType>
|
||||||
pair<IterType, int> internal_locate(
|
std::pair<IterType, int> internal_locate(
|
||||||
const key_type &key, IterType iter) const;
|
const key_type &key, IterType iter) const;
|
||||||
template <typename IterType>
|
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;
|
const key_type &key, IterType iter) const;
|
||||||
template <typename IterType>
|
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;
|
const key_type &key, IterType iter) const;
|
||||||
|
|
||||||
// Internal routine which implements lower_bound().
|
// Internal routine which implements lower_bound().
|
||||||
|
@ -1403,7 +1345,7 @@ class btree : public Params::key_compare {
|
||||||
void internal_clear(node_type *node);
|
void internal_clear(node_type *node);
|
||||||
|
|
||||||
// Dumps a node and all of its children to the specified ostream.
|
// 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.
|
// Verifies the tree structure of node.
|
||||||
int internal_verify(const node_type *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_;
|
empty_base_handle<internal_allocator_type, node_type*> root_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// A never instantiated helper function that returns base::big_ if we have a
|
// A never instantiated helper function that returns big_ if we have a
|
||||||
// key-compare-to functor or if R is bool and base::small_ otherwise.
|
// key-compare-to functor or if R is bool and small_ otherwise.
|
||||||
template <typename R>
|
template <typename R>
|
||||||
static typename base::if_<
|
static typename if_<
|
||||||
base::if_<is_key_compare_to::value,
|
if_<is_key_compare_to::value,
|
||||||
base::type_equals_<R, int>,
|
std::is_same<R, int>,
|
||||||
base::type_equals_<R, bool> >::type::value,
|
std::is_same<R, bool> >::type::value,
|
||||||
base::big_, base::small_>::type key_compare_checker(R);
|
big_, small_>::type key_compare_checker(R);
|
||||||
|
|
||||||
// A never instantiated helper function that returns the key comparison
|
// A never instantiated helper function that returns the key comparison
|
||||||
// functor.
|
// functor.
|
||||||
|
@ -1445,10 +1387,10 @@ class btree : public Params::key_compare {
|
||||||
// is never actually invoked. The compiler will select which
|
// is never actually invoked. The compiler will select which
|
||||||
// key_compare_checker() to instantiate and then figure out the size of the
|
// 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
|
// 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(
|
COMPILE_ASSERT(
|
||||||
sizeof(key_compare_checker(key_compare_helper()(key_type(), key_type()))) ==
|
sizeof(key_compare_checker(key_compare_helper()(key_type(), key_type()))) ==
|
||||||
sizeof(base::big_),
|
sizeof(big_),
|
||||||
key_comparison_function_must_return_bool);
|
key_comparison_function_must_return_bool);
|
||||||
|
|
||||||
// Note: We insist on kTargetValues, which is computed from
|
// Note: We insist on kTargetValues, which is computed from
|
||||||
|
@ -1466,7 +1408,7 @@ class btree : public Params::key_compare {
|
||||||
// btree_node methods
|
// btree_node methods
|
||||||
template <typename P>
|
template <typename P>
|
||||||
inline void btree_node<P>::insert_value(int i, const value_type &x) {
|
inline void btree_node<P>::insert_value(int i, const value_type &x) {
|
||||||
DCHECK_LE(i, count());
|
assert(i <= count());
|
||||||
value_init(count(), x);
|
value_init(count(), x);
|
||||||
for (int j = count(); j > i; --j) {
|
for (int j = count(); j > i; --j) {
|
||||||
value_swap(j, this, j - 1);
|
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>
|
template <typename P>
|
||||||
inline void btree_node<P>::remove_value(int i) {
|
inline void btree_node<P>::remove_value(int i) {
|
||||||
if (!leaf()) {
|
if (!leaf()) {
|
||||||
DCHECK_EQ(child(i + 1)->count(), 0);
|
assert(child(i + 1)->count() == 0);
|
||||||
for (int j = i + 1; j < count(); ++j) {
|
for (int j = i + 1; j < count(); ++j) {
|
||||||
*mutable_child(j) = child(j + 1);
|
*mutable_child(j) = child(j + 1);
|
||||||
child(j)->set_position(j);
|
child(j)->set_position(j);
|
||||||
|
@ -1503,11 +1445,11 @@ inline void btree_node<P>::remove_value(int i) {
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
void btree_node<P>::rebalance_right_to_left(btree_node *src, int to_move) {
|
void btree_node<P>::rebalance_right_to_left(btree_node *src, int to_move) {
|
||||||
DCHECK_EQ(parent(), src->parent());
|
assert(parent() == src->parent());
|
||||||
DCHECK_EQ(position() + 1, src->position());
|
assert(position() + 1 == src->position());
|
||||||
DCHECK_GE(src->count(), count());
|
assert(src->count() >= count());
|
||||||
DCHECK_GE(to_move, 1);
|
assert(to_move >= 1);
|
||||||
DCHECK_LE(to_move, src->count());
|
assert(to_move <= src->count());
|
||||||
|
|
||||||
// Make room in the left node for the new values.
|
// Make room in the left node for the new values.
|
||||||
for (int i = 0; i < to_move; ++i) {
|
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));
|
set_child(1 + count() + i, src->child(i));
|
||||||
}
|
}
|
||||||
for (int i = 0; i <= src->count() - to_move; ++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->set_child(i, src->child(i + to_move));
|
||||||
*src->mutable_child(i + to_move) = NULL;
|
*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>
|
template <typename P>
|
||||||
void btree_node<P>::rebalance_left_to_right(btree_node *dest, int to_move) {
|
void btree_node<P>::rebalance_left_to_right(btree_node *dest, int to_move) {
|
||||||
DCHECK_EQ(parent(), dest->parent());
|
assert(parent() == dest->parent());
|
||||||
DCHECK_EQ(position() + 1, dest->position());
|
assert(position() + 1 == dest->position());
|
||||||
DCHECK_GE(count(), dest->count());
|
assert(count() >= dest->count());
|
||||||
DCHECK_GE(to_move, 1);
|
assert(to_move >= 1);
|
||||||
DCHECK_LE(to_move, count());
|
assert(to_move <= count());
|
||||||
|
|
||||||
// Make room in the right node for the new values.
|
// Make room in the right node for the new values.
|
||||||
for (int i = 0; i < to_move; ++i) {
|
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>
|
template <typename P>
|
||||||
void btree_node<P>::split(btree_node *dest, int insert_position) {
|
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
|
// 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
|
// 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);
|
dest->set_count(count() / 2);
|
||||||
}
|
}
|
||||||
set_count(count() - dest->count());
|
set_count(count() - dest->count());
|
||||||
DCHECK_GE(count(), 1);
|
assert(count() >= 1);
|
||||||
|
|
||||||
// Move values from the left sibling to the right sibling.
|
// Move values from the left sibling to the right sibling.
|
||||||
for (int i = 0; i < dest->count(); ++i) {
|
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()) {
|
if (!leaf()) {
|
||||||
for (int i = 0; i <= dest->count(); ++i) {
|
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));
|
dest->set_child(i, child(count() + i + 1));
|
||||||
*mutable_child(count() + i + 1) = NULL;
|
*mutable_child(count() + i + 1) = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1636,8 +1578,8 @@ void btree_node<P>::split(btree_node *dest, int insert_position) {
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
void btree_node<P>::merge(btree_node *src) {
|
void btree_node<P>::merge(btree_node *src) {
|
||||||
DCHECK_EQ(parent(), src->parent());
|
assert(parent() == src->parent());
|
||||||
DCHECK_EQ(position() + 1, src->position());
|
assert(position() + 1 == src->position());
|
||||||
|
|
||||||
// Move the delimiting value to the left node.
|
// Move the delimiting value to the left node.
|
||||||
value_init(count());
|
value_init(count());
|
||||||
|
@ -1668,7 +1610,7 @@ void btree_node<P>::merge(btree_node *src) {
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
void btree_node<P>::swap(btree_node *x) {
|
void btree_node<P>::swap(btree_node *x) {
|
||||||
DCHECK_EQ(leaf(), x->leaf());
|
assert(leaf() == x->leaf());
|
||||||
|
|
||||||
// Swap the values.
|
// Swap the values.
|
||||||
for (int i = count(); i < x->count(); ++i) {
|
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) {
|
for (int i = x->count(); i < count(); ++i) {
|
||||||
x->value_init(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) {
|
for (int i = 0; i < n; ++i) {
|
||||||
value_swap(i, x, 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>
|
template <typename N, typename R, typename P>
|
||||||
void btree_iterator<N, R, P>::increment_slow() {
|
void btree_iterator<N, R, P>::increment_slow() {
|
||||||
if (node->leaf()) {
|
if (node->leaf()) {
|
||||||
DCHECK_GE(position, node->count());
|
assert(position >= node->count());
|
||||||
self_type save(*this);
|
self_type save(*this);
|
||||||
while (position == node->count() && !node->is_root()) {
|
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();
|
position = node->position();
|
||||||
node = node->parent();
|
node = node->parent();
|
||||||
}
|
}
|
||||||
|
@ -1721,7 +1663,7 @@ void btree_iterator<N, R, P>::increment_slow() {
|
||||||
*this = save;
|
*this = save;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DCHECK_LT(position, node->count());
|
assert(position < node->count());
|
||||||
node = node->child(position + 1);
|
node = node->child(position + 1);
|
||||||
while (!node->leaf()) {
|
while (!node->leaf()) {
|
||||||
node = node->child(0);
|
node = node->child(0);
|
||||||
|
@ -1735,7 +1677,7 @@ void btree_iterator<N, R, P>::increment_by(int count) {
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
if (node->leaf()) {
|
if (node->leaf()) {
|
||||||
int rest = node->count() - position;
|
int rest = node->count() - position;
|
||||||
position += min(rest, count);
|
position += std::min(rest, count);
|
||||||
count = count - rest;
|
count = count - rest;
|
||||||
if (position < node->count()) {
|
if (position < node->count()) {
|
||||||
return;
|
return;
|
||||||
|
@ -1750,10 +1692,10 @@ void btree_iterator<N, R, P>::increment_by(int count) {
|
||||||
template <typename N, typename R, typename P>
|
template <typename N, typename R, typename P>
|
||||||
void btree_iterator<N, R, P>::decrement_slow() {
|
void btree_iterator<N, R, P>::decrement_slow() {
|
||||||
if (node->leaf()) {
|
if (node->leaf()) {
|
||||||
DCHECK_LE(position, -1);
|
assert(position <= -1);
|
||||||
self_type save(*this);
|
self_type save(*this);
|
||||||
while (position < 0 && !node->is_root()) {
|
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;
|
position = node->position() - 1;
|
||||||
node = node->parent();
|
node = node->parent();
|
||||||
}
|
}
|
||||||
|
@ -1761,7 +1703,7 @@ void btree_iterator<N, R, P>::decrement_slow() {
|
||||||
*this = save;
|
*this = save;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DCHECK_GE(position, 0);
|
assert(position >= 0);
|
||||||
node = node->child(position);
|
node = node->child(position);
|
||||||
while (!node->leaf()) {
|
while (!node->leaf()) {
|
||||||
node = node->child(node->count());
|
node = node->child(node->count());
|
||||||
|
@ -1786,26 +1728,26 @@ btree<P>::btree(const self_type &x)
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P> template <typename ValuePointer>
|
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) {
|
btree<P>::insert_unique(const key_type &key, ValuePointer value) {
|
||||||
if (empty()) {
|
if (empty()) {
|
||||||
*mutable_root() = new_leaf_root_node(1);
|
*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;
|
iterator &iter = res.first;
|
||||||
if (res.second == kExactMatch) {
|
if (res.second == kExactMatch) {
|
||||||
// The key already exists in the tree, do nothing.
|
// 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) {
|
} else if (!res.second) {
|
||||||
iterator last = internal_last(iter);
|
iterator last = internal_last(iter);
|
||||||
if (last.node && !compare_keys(key, last.key())) {
|
if (last.node && !compare_keys(key, last.key())) {
|
||||||
// The key already exists in the tree, do nothing.
|
// 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>
|
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
|
// 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.
|
// value of our left child. This is easy, we just decrement iter.
|
||||||
iterator tmp_iter(iter--);
|
iterator tmp_iter(iter--);
|
||||||
DCHECK(iter.node->leaf());
|
assert(iter.node->leaf());
|
||||||
DCHECK(!compare_keys(tmp_iter.key(), iter.key()));
|
assert(!compare_keys(tmp_iter.key(), iter.key()));
|
||||||
iter.node->value_swap(iter.position, tmp_iter.node, tmp_iter.position);
|
iter.node->value_swap(iter.position, tmp_iter.node, tmp_iter.position);
|
||||||
internal_delete = true;
|
internal_delete = true;
|
||||||
--*mutable_size();
|
--*mutable_size();
|
||||||
|
@ -2010,22 +1952,22 @@ void btree<P>::clear() {
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
void btree<P>::swap(self_type &x) {
|
void btree<P>::swap(self_type &x) {
|
||||||
::swap(static_cast<key_compare&>(*this), static_cast<key_compare&>(x));
|
std::swap(static_cast<key_compare&>(*this), static_cast<key_compare&>(x));
|
||||||
::swap(root_, x.root_);
|
std::swap(root_, x.root_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
void btree<P>::verify() const {
|
void btree<P>::verify() const {
|
||||||
if (root() != NULL) {
|
if (root() != NULL) {
|
||||||
CHECK_EQ(size(), internal_verify(root(), NULL, NULL));
|
assert(size() == internal_verify(root(), NULL, NULL));
|
||||||
CHECK_EQ(leftmost(), (++const_iterator(root(), -1)).node);
|
assert(leftmost() == (++const_iterator(root(), -1)).node);
|
||||||
CHECK_EQ(rightmost(), (--const_iterator(root(), root()->count())).node);
|
assert(rightmost() == (--const_iterator(root(), root()->count())).node);
|
||||||
CHECK(leftmost()->leaf());
|
assert(leftmost()->leaf());
|
||||||
CHECK(rightmost()->leaf());
|
assert(rightmost()->leaf());
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(size(), 0);
|
assert(size() == 0);
|
||||||
CHECK(leftmost() == NULL);
|
assert(leftmost() == NULL);
|
||||||
CHECK(rightmost() == NULL);
|
assert(rightmost() == NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2033,7 +1975,7 @@ template <typename P>
|
||||||
void btree<P>::rebalance_or_split(iterator *iter) {
|
void btree<P>::rebalance_or_split(iterator *iter) {
|
||||||
node_type *&node = iter->node;
|
node_type *&node = iter->node;
|
||||||
int &insert_position = iter->position;
|
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.
|
// First try to make room on the node by rebalancing.
|
||||||
node_type *parent = node->parent();
|
node_type *parent = node->parent();
|
||||||
|
@ -2047,20 +1989,20 @@ void btree<P>::rebalance_or_split(iterator *iter) {
|
||||||
// fill up the left node.
|
// fill up the left node.
|
||||||
int to_move = (left->max_count() - left->count()) /
|
int to_move = (left->max_count() - left->count()) /
|
||||||
(1 + (insert_position < left->max_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) ||
|
if (((insert_position - to_move) >= 0) ||
|
||||||
((left->count() + to_move) < left->max_count())) {
|
((left->count() + to_move) < left->max_count())) {
|
||||||
left->rebalance_right_to_left(node, to_move);
|
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;
|
insert_position = insert_position - to_move;
|
||||||
if (insert_position < 0) {
|
if (insert_position < 0) {
|
||||||
insert_position = insert_position + left->count() + 1;
|
insert_position = insert_position + left->count() + 1;
|
||||||
node = left;
|
node = left;
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK_LT(node->count(), node->max_count());
|
assert(node->count() < node->max_count());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2075,7 +2017,7 @@ void btree<P>::rebalance_or_split(iterator *iter) {
|
||||||
// to fill up the right node.
|
// to fill up the right node.
|
||||||
int to_move = (right->max_count() - right->count()) /
|
int to_move = (right->max_count() - right->count()) /
|
||||||
(1 + (insert_position > 0));
|
(1 + (insert_position > 0));
|
||||||
to_move = max(1, to_move);
|
to_move = std::max(1, to_move);
|
||||||
|
|
||||||
if ((insert_position <= (node->count() - to_move)) ||
|
if ((insert_position <= (node->count() - to_move)) ||
|
||||||
((right->count() + to_move) < right->max_count())) {
|
((right->count() + to_move) < right->max_count())) {
|
||||||
|
@ -2086,7 +2028,7 @@ void btree<P>::rebalance_or_split(iterator *iter) {
|
||||||
node = right;
|
node = right;
|
||||||
}
|
}
|
||||||
|
|
||||||
DCHECK_LT(node->count(), node->max_count());
|
assert(node->count() < node->max_count());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2106,7 +2048,7 @@ void btree<P>::rebalance_or_split(iterator *iter) {
|
||||||
parent = new_internal_root_node();
|
parent = new_internal_root_node();
|
||||||
parent->set_child(0, root());
|
parent->set_child(0, root());
|
||||||
*mutable_root() = parent;
|
*mutable_root() = parent;
|
||||||
DCHECK(*mutable_rightmost() == parent->child(0));
|
assert(*mutable_rightmost() == parent->child(0));
|
||||||
} else {
|
} else {
|
||||||
// The root node is an internal node. We do not want to create a new root
|
// 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
|
// 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->node->count() == 0) ||
|
||||||
(iter->position > 0))) {
|
(iter->position > 0))) {
|
||||||
int to_move = (right->count() - iter->node->count()) / 2;
|
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);
|
iter->node->rebalance_right_to_left(right, to_move);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2194,7 +2136,7 @@ bool btree<P>::try_merge_or_rebalance(iterator *iter) {
|
||||||
((iter->node->count() == 0) ||
|
((iter->node->count() == 0) ||
|
||||||
(iter->position < iter->node->count()))) {
|
(iter->position < iter->node->count()))) {
|
||||||
int to_move = (left->count() - iter->node->count()) / 2;
|
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);
|
left->rebalance_left_to_right(iter->node, to_move);
|
||||||
iter->position += to_move;
|
iter->position += to_move;
|
||||||
return false;
|
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.
|
// Deleted the last item on the root node, shrink the height of the tree.
|
||||||
if (root()->leaf()) {
|
if (root()->leaf()) {
|
||||||
DCHECK_EQ(size(), 0);
|
assert(size() == 0);
|
||||||
delete_leaf_node(root());
|
delete_leaf_node(root());
|
||||||
*mutable_root() = NULL;
|
*mutable_root() = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2256,9 +2198,9 @@ btree<P>::internal_insert(iterator iter, const value_type &v) {
|
||||||
if (iter.node->max_count() < kNodeValues) {
|
if (iter.node->max_count() < kNodeValues) {
|
||||||
// Insertion into the root where the root is smaller that the full node
|
// Insertion into the root where the root is smaller that the full node
|
||||||
// size. Simply grow the size of the root node.
|
// size. Simply grow the size of the root node.
|
||||||
DCHECK(iter.node == root());
|
assert(iter.node == root());
|
||||||
iter.node = new_leaf_root_node(
|
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());
|
iter.node->swap(root());
|
||||||
delete_leaf_node(root());
|
delete_leaf_node(root());
|
||||||
*mutable_root() = iter.node;
|
*mutable_root() = iter.node;
|
||||||
|
@ -2274,13 +2216,13 @@ btree<P>::internal_insert(iterator iter, const value_type &v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P> template <typename IterType>
|
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 {
|
const key_type &key, IterType iter) const {
|
||||||
return internal_locate_type::dispatch(key, *this, iter);
|
return internal_locate_type::dispatch(key, *this, iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P> template <typename IterType>
|
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 {
|
const key_type &key, IterType iter) const {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
iter.position = iter.node->lower_bound(key, key_comp());
|
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);
|
iter.node = iter.node->child(iter.position);
|
||||||
}
|
}
|
||||||
return make_pair(iter, 0);
|
return std::make_pair(iter, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P> template <typename IterType>
|
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 {
|
const key_type &key, IterType iter) const {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int res = iter.node->lower_bound(key, key_comp());
|
int res = iter.node->lower_bound(key, key_comp());
|
||||||
iter.position = res & kMatchMask;
|
iter.position = res & kMatchMask;
|
||||||
if (res & kExactMatch) {
|
if (res & kExactMatch) {
|
||||||
return make_pair(iter, static_cast<int>(kExactMatch));
|
return std::make_pair(iter, static_cast<int>(kExactMatch));
|
||||||
}
|
}
|
||||||
if (iter.node->leaf()) {
|
if (iter.node->leaf()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
iter.node = iter.node->child(iter.position);
|
iter.node = iter.node->child(iter.position);
|
||||||
}
|
}
|
||||||
return make_pair(iter, -kExactMatch);
|
return std::make_pair(iter, -kExactMatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename P> template <typename IterType>
|
template <typename P> template <typename IterType>
|
||||||
|
@ -2346,7 +2288,7 @@ template <typename P> template <typename IterType>
|
||||||
IterType btree<P>::internal_find_unique(
|
IterType btree<P>::internal_find_unique(
|
||||||
const key_type &key, IterType iter) const {
|
const key_type &key, IterType iter) const {
|
||||||
if (iter.node) {
|
if (iter.node) {
|
||||||
pair<IterType, int> res = internal_locate(key, iter);
|
std::pair<IterType, int> res = internal_locate(key, iter);
|
||||||
if (res.second == kExactMatch) {
|
if (res.second == kExactMatch) {
|
||||||
return res.first;
|
return res.first;
|
||||||
}
|
}
|
||||||
|
@ -2393,7 +2335,7 @@ void btree<P>::internal_clear(node_type *node) {
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
void btree<P>::internal_dump(
|
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) {
|
for (int i = 0; i < node->count(); ++i) {
|
||||||
if (!node->leaf()) {
|
if (!node->leaf()) {
|
||||||
internal_dump(os, node->child(i), level + 1);
|
internal_dump(os, node->child(i), level + 1);
|
||||||
|
@ -2411,23 +2353,23 @@ void btree<P>::internal_dump(
|
||||||
template <typename P>
|
template <typename P>
|
||||||
int btree<P>::internal_verify(
|
int btree<P>::internal_verify(
|
||||||
const node_type *node, const key_type *lo, const key_type *hi) const {
|
const node_type *node, const key_type *lo, const key_type *hi) const {
|
||||||
CHECK_GT(node->count(), 0);
|
assert(node->count() > 0);
|
||||||
CHECK_LE(node->count(), node->max_count());
|
assert(node->count() <= node->max_count());
|
||||||
if (lo) {
|
if (lo) {
|
||||||
CHECK(!compare_keys(node->key(0), *lo));
|
assert(!compare_keys(node->key(0), *lo));
|
||||||
}
|
}
|
||||||
if (hi) {
|
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) {
|
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();
|
int count = node->count();
|
||||||
if (!node->leaf()) {
|
if (!node->leaf()) {
|
||||||
for (int i = 0; i <= node->count(); ++i) {
|
for (int i = 0; i <= node->count(); ++i) {
|
||||||
CHECK(node->child(i) != NULL);
|
assert(node->child(i) != NULL);
|
||||||
CHECK_EQ(node->child(i)->parent(), node);
|
assert(node->child(i)->parent() == node);
|
||||||
CHECK_EQ(node->child(i)->position(), i);
|
assert(node->child(i)->position() == i);
|
||||||
count += internal_verify(
|
count += internal_verify(
|
||||||
node->child(i),
|
node->child(i),
|
||||||
(i == 0) ? lo : &node->key(i - 1),
|
(i == 0) ? lo : &node->key(i - 1),
|
||||||
|
@ -2438,8 +2380,5 @@ int btree<P>::internal_verify(
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
DEFINE_GDB_AUTO_SCRIPT("util/btree/btree_printer.py")
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_BTREE_H__
|
#endif // UTIL_BTREE_BTREE_H__
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
DECLARE_int32(benchmark_max_iters);
|
DECLARE_int32(benchmark_max_iters);
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -480,7 +479,6 @@ MY_BENCHMARK(multimap_cord);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
FLAGS_logtostderr = true;
|
FLAGS_logtostderr = true;
|
||||||
|
|
|
@ -8,9 +8,8 @@
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "util/btree/btree.h" // IWYU pragma: export
|
#include "btree.h"
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
|
|
||||||
// A common base class for btree_set, btree_map, btree_multiset and
|
// 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 {
|
const_iterator upper_bound(const key_type &key) const {
|
||||||
return tree_.upper_bound(key);
|
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);
|
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);
|
return tree_.equal_range(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ class btree_container {
|
||||||
void swap(self_type &x) {
|
void swap(self_type &x) {
|
||||||
tree_.swap(x.tree_);
|
tree_.swap(x.tree_);
|
||||||
}
|
}
|
||||||
void dump(ostream &os) const {
|
void dump(std::ostream &os) const {
|
||||||
tree_.dump(os);
|
tree_.dump(os);
|
||||||
}
|
}
|
||||||
void verify() const {
|
void verify() const {
|
||||||
|
@ -128,7 +127,7 @@ class btree_container {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
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);
|
b.dump(os);
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +180,7 @@ class btree_unique_container : public btree_container<Tree> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertion routines.
|
// 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);
|
return this->tree_.insert_unique(x);
|
||||||
}
|
}
|
||||||
iterator insert(iterator position, const value_type &x) {
|
iterator insert(iterator position, const value_type &x) {
|
||||||
|
@ -230,7 +229,7 @@ class btree_map_container : public btree_unique_container<Tree> {
|
||||||
: key(k) {
|
: key(k) {
|
||||||
}
|
}
|
||||||
value_type operator*() const {
|
value_type operator*() const {
|
||||||
return make_pair(key, data_type());
|
return std::make_pair(key, data_type());
|
||||||
}
|
}
|
||||||
const key_type &key;
|
const key_type &key;
|
||||||
};
|
};
|
||||||
|
@ -337,6 +336,5 @@ class btree_multi_container : public btree_container<Tree> {
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_BTREE_CONTAINER_H__
|
#endif // UTIL_BTREE_BTREE_CONTAINER_H__
|
||||||
|
|
16
btree_map.h
16
btree_map.h
|
@ -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: jmacd@google.com (Josh MacDonald)
|
||||||
// Author: pmattis@google.com (Peter Mattis)
|
// Author: pmattis@google.com (Peter Mattis)
|
||||||
//
|
//
|
||||||
|
@ -18,16 +18,15 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "util/btree/btree.h" // IWYU pragma: export
|
#include "btree.h"
|
||||||
#include "util/btree/btree_container.h" // IWYU pragma: export
|
#include "btree_container.h"
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
|
|
||||||
// The btree_map class is needed mainly for it's constructors.
|
// The btree_map class is needed mainly for it's constructors.
|
||||||
template <typename Key, typename Value,
|
template <typename Key, typename Value,
|
||||||
typename Compare = less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<pair<const Key, Value> >,
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
int TargetNodeSize = 256>
|
int TargetNodeSize = 256>
|
||||||
class btree_map : public btree_map_container<
|
class btree_map : public btree_map_container<
|
||||||
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
btree<btree_map_params<Key, Value, Compare, Alloc, 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.
|
// The btree_multimap class is needed mainly for it's constructors.
|
||||||
template <typename Key, typename Value,
|
template <typename Key, typename Value,
|
||||||
typename Compare = less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<pair<const Key, Value> >,
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
int TargetNodeSize = 256>
|
int TargetNodeSize = 256>
|
||||||
class btree_multimap : public btree_multi_container<
|
class btree_multimap : public btree_multi_container<
|
||||||
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
||||||
|
@ -117,6 +116,5 @@ inline void swap(btree_multimap<K, V, C, A, N> &x,
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_BTREE_MAP_H__
|
#endif // UTIL_BTREE_BTREE_MAP_H__
|
||||||
|
|
10
btree_set.h
10
btree_set.h
|
@ -14,15 +14,14 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "util/btree/btree.h" // IWYU pragma: export
|
#include "btree.h"
|
||||||
#include "util/btree/btree_container.h" // IWYU pragma: export
|
#include "btree_container.h"
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
|
|
||||||
// The btree_set class is needed mainly for it's constructors.
|
// The btree_set class is needed mainly for it's constructors.
|
||||||
template <typename Key,
|
template <typename Key,
|
||||||
typename Compare = less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<Key>,
|
typename Alloc = std::allocator<Key>,
|
||||||
int TargetNodeSize = 256>
|
int TargetNodeSize = 256>
|
||||||
class btree_set : public btree_unique_container<
|
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.
|
// The btree_multiset class is needed mainly for it's constructors.
|
||||||
template <typename Key,
|
template <typename Key,
|
||||||
typename Compare = less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<Key>,
|
typename Alloc = std::allocator<Key>,
|
||||||
int TargetNodeSize = 256>
|
int TargetNodeSize = 256>
|
||||||
class btree_multiset : public btree_multi_container<
|
class btree_multiset : public btree_multi_container<
|
||||||
|
@ -108,6 +107,5 @@ inline void swap(btree_multiset<K, C, A, N> &x,
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_BTREE_SET_H__
|
#endif // UTIL_BTREE_BTREE_SET_H__
|
||||||
|
|
197
btree_test.cc
197
btree_test.cc
|
@ -2,128 +2,120 @@
|
||||||
// Author: jmacd@google.com (Josh MacDonald)
|
// Author: jmacd@google.com (Josh MacDonald)
|
||||||
// Author: pmattis@google.com (Peter Mattis)
|
// Author: pmattis@google.com (Peter Mattis)
|
||||||
|
|
||||||
#include "base/arena-inl.h"
|
#include "gtest/gtest.h"
|
||||||
#include "base/init_google.h"
|
#include "btree_map.h"
|
||||||
#include "base/integral_types.h"
|
#include "btree_set.h"
|
||||||
#include "base/logging.h"
|
#include "btree_test.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"
|
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <typename K, int N>
|
template <typename K, int N>
|
||||||
void SetTest() {
|
void SetTest() {
|
||||||
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
|
typedef TestAllocator<K> TestAlloc;
|
||||||
CHECK_EQ(sizeof(btree_set<K>), sizeof(void*));
|
ASSERT_EQ(sizeof(btree_set<K>), sizeof(void*));
|
||||||
BtreeTest<btree_set<K, less<K>, allocator<K>, N>, set<K> >();
|
BtreeTest<btree_set<K, std::less<K>, std::allocator<K>, N>, std::set<K> >();
|
||||||
BtreeArenaTest<btree_set<K, less<K>, ArenaAlloc, N> >();
|
BtreeAllocatorTest<btree_set<K, std::less<K>, TestAlloc, N> >();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, int N>
|
template <typename K, int N>
|
||||||
void MapTest() {
|
void MapTest() {
|
||||||
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
|
typedef TestAllocator<K> TestAlloc;
|
||||||
CHECK_EQ(sizeof(btree_map<K, K>), sizeof(void*));
|
ASSERT_EQ(sizeof(btree_map<K, K>), sizeof(void*));
|
||||||
BtreeTest<btree_map<K, K, less<K>, allocator<K>, N>, map<K, K> >();
|
BtreeTest<btree_map<K, K, std::less<K>, std::allocator<K>, N>, std::map<K, K> >();
|
||||||
BtreeArenaTest<btree_map<K, K, less<K>, ArenaAlloc, N> >();
|
BtreeAllocatorTest<btree_map<K, K, std::less<K>, TestAlloc, N> >();
|
||||||
BtreeMapTest<btree_map<K, K, less<K>, allocator<K>, 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_32) { SetTest<int32_t, 32>(); }
|
||||||
TEST(Btree, set_int32_64) { SetTest<int32, 64>(); }
|
TEST(Btree, set_int32_64) { SetTest<int32_t, 64>(); }
|
||||||
TEST(Btree, set_int32_128) { SetTest<int32, 128>(); }
|
TEST(Btree, set_int32_128) { SetTest<int32_t, 128>(); }
|
||||||
TEST(Btree, set_int32_256) { SetTest<int32, 256>(); }
|
TEST(Btree, set_int32_256) { SetTest<int32_t, 256>(); }
|
||||||
TEST(Btree, set_int64_256) { SetTest<int64, 256>(); }
|
TEST(Btree, set_int64_256) { SetTest<int64_t, 256>(); }
|
||||||
TEST(Btree, set_string_256) { SetTest<string, 256>(); }
|
TEST(Btree, set_string_256) { SetTest<std::string, 256>(); }
|
||||||
TEST(Btree, set_cord_256) { SetTest<Cord, 256>(); }
|
TEST(Btree, set_pair_256) { SetTest<std::pair<int, int>, 256>(); }
|
||||||
TEST(Btree, set_pair_256) { SetTest<pair<int, int>, 256>(); }
|
TEST(Btree, map_int32_256) { MapTest<int32_t, 256>(); }
|
||||||
TEST(Btree, map_int32_256) { MapTest<int32, 256>(); }
|
TEST(Btree, map_int64_256) { MapTest<int64_t, 256>(); }
|
||||||
TEST(Btree, map_int64_256) { MapTest<int64, 256>(); }
|
TEST(Btree, map_string_256) { MapTest<std::string, 256>(); }
|
||||||
TEST(Btree, map_string_256) { MapTest<string, 256>(); }
|
TEST(Btree, map_pair_256) { MapTest<std::pair<int, int>, 256>(); }
|
||||||
TEST(Btree, map_cord_256) { MapTest<Cord, 256>(); }
|
|
||||||
TEST(Btree, map_pair_256) { MapTest<pair<int, int>, 256>(); }
|
|
||||||
|
|
||||||
// Large-node tests
|
// Large-node tests
|
||||||
TEST(Btree, map_int32_1024) { MapTest<int32, 1024>(); }
|
TEST(Btree, map_int32_1024) { MapTest<int32_t, 1024>(); }
|
||||||
TEST(Btree, map_int32_1032) { MapTest<int32, 1032>(); }
|
TEST(Btree, map_int32_1032) { MapTest<int32_t, 1032>(); }
|
||||||
TEST(Btree, map_int32_1040) { MapTest<int32, 1040>(); }
|
TEST(Btree, map_int32_1040) { MapTest<int32_t, 1040>(); }
|
||||||
TEST(Btree, map_int32_1048) { MapTest<int32, 1048>(); }
|
TEST(Btree, map_int32_1048) { MapTest<int32_t, 1048>(); }
|
||||||
TEST(Btree, map_int32_1056) { MapTest<int32, 1056>(); }
|
TEST(Btree, map_int32_1056) { MapTest<int32_t, 1056>(); }
|
||||||
|
|
||||||
TEST(Btree, map_int32_2048) { MapTest<int32, 2048>(); }
|
TEST(Btree, map_int32_2048) { MapTest<int32_t, 2048>(); }
|
||||||
TEST(Btree, map_int32_4096) { MapTest<int32, 4096>(); }
|
TEST(Btree, map_int32_4096) { MapTest<int32_t, 4096>(); }
|
||||||
TEST(Btree, set_int32_1024) { SetTest<int32, 1024>(); }
|
TEST(Btree, set_int32_1024) { SetTest<int32_t, 1024>(); }
|
||||||
TEST(Btree, set_int32_2048) { SetTest<int32, 2048>(); }
|
TEST(Btree, set_int32_2048) { SetTest<int32_t, 2048>(); }
|
||||||
TEST(Btree, set_int32_4096) { SetTest<int32, 4096>(); }
|
TEST(Btree, set_int32_4096) { SetTest<int32_t, 4096>(); }
|
||||||
TEST(Btree, map_string_1024) { MapTest<string, 1024>(); }
|
TEST(Btree, map_string_1024) { MapTest<std::string, 1024>(); }
|
||||||
TEST(Btree, map_string_2048) { MapTest<string, 2048>(); }
|
TEST(Btree, map_string_2048) { MapTest<std::string, 2048>(); }
|
||||||
TEST(Btree, map_string_4096) { MapTest<string, 4096>(); }
|
TEST(Btree, map_string_4096) { MapTest<std::string, 4096>(); }
|
||||||
TEST(Btree, set_string_1024) { SetTest<string, 1024>(); }
|
TEST(Btree, set_string_1024) { SetTest<std::string, 1024>(); }
|
||||||
TEST(Btree, set_string_2048) { SetTest<string, 2048>(); }
|
TEST(Btree, set_string_2048) { SetTest<std::string, 2048>(); }
|
||||||
TEST(Btree, set_string_4096) { SetTest<string, 4096>(); }
|
TEST(Btree, set_string_4096) { SetTest<std::string, 4096>(); }
|
||||||
|
|
||||||
template <typename K, int N>
|
template <typename K, int N>
|
||||||
void MultiSetTest() {
|
void MultiSetTest() {
|
||||||
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
|
typedef TestAllocator<K> TestAlloc;
|
||||||
CHECK_EQ(sizeof(btree_multiset<K>), sizeof(void*));
|
ASSERT_EQ(sizeof(btree_multiset<K>), sizeof(void*));
|
||||||
BtreeMultiTest<btree_multiset<K, less<K>, allocator<K>, N>,
|
BtreeMultiTest<btree_multiset<K, std::less<K>, std::allocator<K>, N>,
|
||||||
multiset<K> >();
|
std::multiset<K> >();
|
||||||
BtreeArenaTest<btree_multiset<K, less<K>, ArenaAlloc, N> >();
|
BtreeAllocatorTest<btree_multiset<K, std::less<K>, TestAlloc, N> >();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, int N>
|
template <typename K, int N>
|
||||||
void MultiMapTest() {
|
void MultiMapTest() {
|
||||||
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
|
typedef TestAllocator<K> TestAlloc;
|
||||||
CHECK_EQ(sizeof(btree_multimap<K, K>), sizeof(void*));
|
ASSERT_EQ(sizeof(btree_multimap<K, K>), sizeof(void*));
|
||||||
BtreeMultiTest<btree_multimap<K, K, less<K>, allocator<K>, N>,
|
BtreeMultiTest<btree_multimap<K, K, std::less<K>, std::allocator<K>, N>,
|
||||||
multimap<K, K> >();
|
std::multimap<K, K> >();
|
||||||
BtreeMultiMapTest<btree_multimap<K, K, less<K>, allocator<K>, N> >();
|
BtreeMultiMapTest<btree_multimap<K, K, std::less<K>, std::allocator<K>, N> >();
|
||||||
BtreeArenaTest<btree_multimap<K, K, less<K>, ArenaAlloc, N> >();
|
BtreeAllocatorTest<btree_multimap<K, K, std::less<K>, TestAlloc, N> >();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(Btree, multiset_int32_256) { MultiSetTest<int32, 256>(); }
|
TEST(Btree, multiset_int32_256) { MultiSetTest<int32_t, 256>(); }
|
||||||
TEST(Btree, multiset_int64_256) { MultiSetTest<int64, 256>(); }
|
TEST(Btree, multiset_int64_256) { MultiSetTest<int64_t, 256>(); }
|
||||||
TEST(Btree, multiset_string_256) { MultiSetTest<string, 256>(); }
|
TEST(Btree, multiset_string_256) { MultiSetTest<std::string, 256>(); }
|
||||||
TEST(Btree, multiset_cord_256) { MultiSetTest<Cord, 256>(); }
|
TEST(Btree, multiset_pair_256) { MultiSetTest<std::pair<int, int>, 256>(); }
|
||||||
TEST(Btree, multiset_pair_256) { MultiSetTest<pair<int, int>, 256>(); }
|
TEST(Btree, multimap_int32_256) { MultiMapTest<int32_t, 256>(); }
|
||||||
TEST(Btree, multimap_int32_256) { MultiMapTest<int32, 256>(); }
|
TEST(Btree, multimap_int64_256) { MultiMapTest<int64_t, 256>(); }
|
||||||
TEST(Btree, multimap_int64_256) { MultiMapTest<int64, 256>(); }
|
TEST(Btree, multimap_string_256) { MultiMapTest<std::string, 256>(); }
|
||||||
TEST(Btree, multimap_string_256) { MultiMapTest<string, 256>(); }
|
TEST(Btree, multimap_pair_256) { MultiMapTest<std::pair<int, int>, 256>(); }
|
||||||
TEST(Btree, multimap_cord_256) { MultiMapTest<Cord, 256>(); }
|
|
||||||
TEST(Btree, multimap_pair_256) { MultiMapTest<pair<int, int>, 256>(); }
|
|
||||||
|
|
||||||
// Large-node tests
|
// Large-node tests
|
||||||
TEST(Btree, multimap_int32_1024) { MultiMapTest<int32, 1024>(); }
|
TEST(Btree, multimap_int32_1024) { MultiMapTest<int32_t, 1024>(); }
|
||||||
TEST(Btree, multimap_int32_2048) { MultiMapTest<int32, 2048>(); }
|
TEST(Btree, multimap_int32_2048) { MultiMapTest<int32_t, 2048>(); }
|
||||||
TEST(Btree, multimap_int32_4096) { MultiMapTest<int32, 4096>(); }
|
TEST(Btree, multimap_int32_4096) { MultiMapTest<int32_t, 4096>(); }
|
||||||
TEST(Btree, multiset_int32_1024) { MultiSetTest<int32, 1024>(); }
|
TEST(Btree, multiset_int32_1024) { MultiSetTest<int32_t, 1024>(); }
|
||||||
TEST(Btree, multiset_int32_2048) { MultiSetTest<int32, 2048>(); }
|
TEST(Btree, multiset_int32_2048) { MultiSetTest<int32_t, 2048>(); }
|
||||||
TEST(Btree, multiset_int32_4096) { MultiSetTest<int32, 4096>(); }
|
TEST(Btree, multiset_int32_4096) { MultiSetTest<int32_t, 4096>(); }
|
||||||
TEST(Btree, multimap_string_1024) { MultiMapTest<string, 1024>(); }
|
TEST(Btree, multimap_string_1024) { MultiMapTest<std::string, 1024>(); }
|
||||||
TEST(Btree, multimap_string_2048) { MultiMapTest<string, 2048>(); }
|
TEST(Btree, multimap_string_2048) { MultiMapTest<std::string, 2048>(); }
|
||||||
TEST(Btree, multimap_string_4096) { MultiMapTest<string, 4096>(); }
|
TEST(Btree, multimap_string_4096) { MultiMapTest<std::string, 4096>(); }
|
||||||
TEST(Btree, multiset_string_1024) { MultiSetTest<string, 1024>(); }
|
TEST(Btree, multiset_string_1024) { MultiSetTest<std::string, 1024>(); }
|
||||||
TEST(Btree, multiset_string_2048) { MultiSetTest<string, 2048>(); }
|
TEST(Btree, multiset_string_2048) { MultiSetTest<std::string, 2048>(); }
|
||||||
TEST(Btree, multiset_string_4096) { MultiSetTest<string, 4096>(); }
|
TEST(Btree, multiset_string_4096) { MultiSetTest<std::string, 4096>(); }
|
||||||
|
|
||||||
// Verify that swapping btrees swaps the key comparision functors.
|
// Verify that swapping btrees swaps the key comparision functors.
|
||||||
struct SubstringLess {
|
struct SubstringLess {
|
||||||
SubstringLess() : n(2) {}
|
SubstringLess() : n(2) {}
|
||||||
SubstringLess(int length)
|
SubstringLess(size_t length)
|
||||||
: n(length) {
|
: n(length) {
|
||||||
}
|
}
|
||||||
bool operator()(const string &a, const string &b) const {
|
bool operator()(const std::string &a, const std::string &b) const {
|
||||||
return StringPiece(a).substr(0, n) < StringPiece(b).substr(0, n);
|
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) {
|
TEST(Btree, SwapKeyCompare) {
|
||||||
typedef btree_set<string, SubstringLess> SubstringSet;
|
typedef btree_set<std::string, SubstringLess> SubstringSet;
|
||||||
SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type());
|
SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type());
|
||||||
SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type());
|
SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type());
|
||||||
|
|
||||||
|
@ -147,7 +139,7 @@ TEST(Btree, SwapKeyCompare) {
|
||||||
TEST(Btree, UpperBoundRegression) {
|
TEST(Btree, UpperBoundRegression) {
|
||||||
// Regress a bug where upper_bound would default-construct a new key_compare
|
// Regress a bug where upper_bound would default-construct a new key_compare
|
||||||
// instead of copying the existing one.
|
// instead of copying the existing one.
|
||||||
typedef btree_set<string, SubstringLess> SubstringSet;
|
typedef btree_set<std::string, SubstringLess> SubstringSet;
|
||||||
SubstringSet my_set(SubstringLess(3));
|
SubstringSet my_set(SubstringLess(3));
|
||||||
my_set.insert("aab");
|
my_set.insert("aab");
|
||||||
my_set.insert("abb");
|
my_set.insert("abb");
|
||||||
|
@ -164,25 +156,25 @@ TEST(Btree, UpperBoundRegression) {
|
||||||
TEST(Btree, IteratorIncrementBy) {
|
TEST(Btree, IteratorIncrementBy) {
|
||||||
// Test that increment_by returns the same position as increment.
|
// Test that increment_by returns the same position as increment.
|
||||||
const int kSetSize = 2341;
|
const int kSetSize = 2341;
|
||||||
btree_set<int32> my_set;
|
btree_set<int32_t> my_set;
|
||||||
for (int i = 0; i < kSetSize; ++i) {
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
my_set.insert(i);
|
my_set.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
// Simple increment vs. increment by.
|
// Simple increment vs. increment by.
|
||||||
btree_set<int32>::iterator a = my_set.begin();
|
btree_set<int32_t>::iterator a = my_set.begin();
|
||||||
btree_set<int32>::iterator b = my_set.begin();
|
btree_set<int32_t>::iterator b = my_set.begin();
|
||||||
a.increment();
|
a.increment();
|
||||||
b.increment_by(1);
|
b.increment_by(1);
|
||||||
EXPECT_EQ(*a, *b);
|
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) {
|
for (int i = 1; i < kSetSize; ++i) {
|
||||||
++a;
|
++a;
|
||||||
// increment_by
|
// increment_by
|
||||||
btree_set<int32>::iterator b = my_set.begin();
|
btree_set<int32_t>::iterator b = my_set.begin();
|
||||||
b.increment_by(i);
|
b.increment_by(i);
|
||||||
EXPECT_EQ(*a, *b) << ": i=" << i;
|
EXPECT_EQ(*a, *b) << ": i=" << i;
|
||||||
}
|
}
|
||||||
|
@ -190,11 +182,11 @@ TEST(Btree, IteratorIncrementBy) {
|
||||||
|
|
||||||
TEST(Btree, Comparison) {
|
TEST(Btree, Comparison) {
|
||||||
const int kSetSize = 1201;
|
const int kSetSize = 1201;
|
||||||
btree_set<int64> my_set;
|
btree_set<int64_t> my_set;
|
||||||
for (int i = 0; i < kSetSize; ++i) {
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
my_set.insert(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_copy == my_set);
|
||||||
EXPECT_TRUE(my_set == my_set_copy);
|
EXPECT_TRUE(my_set == my_set_copy);
|
||||||
EXPECT_FALSE(my_set_copy != my_set);
|
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_copy != my_set);
|
||||||
EXPECT_TRUE(my_set != my_set_copy);
|
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) {
|
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_copy == my_map);
|
||||||
EXPECT_TRUE(my_map == my_map_copy);
|
EXPECT_TRUE(my_map == my_map_copy);
|
||||||
EXPECT_FALSE(my_map_copy != my_map);
|
EXPECT_FALSE(my_map_copy != my_map);
|
||||||
EXPECT_FALSE(my_map != my_map_copy);
|
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_copy == my_map);
|
||||||
EXPECT_FALSE(my_map == my_map_copy);
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
EXPECT_TRUE(my_map_copy != my_map);
|
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_copy != my_map);
|
||||||
EXPECT_TRUE(my_map != my_map_copy);
|
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_copy == my_map);
|
||||||
EXPECT_FALSE(my_map == my_map_copy);
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
EXPECT_TRUE(my_map_copy != my_map);
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
@ -244,10 +236,3 @@ TEST(Btree, Comparison) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
FLAGS_logtostderr = true;
|
|
||||||
InitGoogle(argv[0], &argc, &argv, true);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
||||||
|
|
469
btree_test.h
469
btree_test.h
|
@ -8,6 +8,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -16,53 +17,50 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/arena.h"
|
#include "gtest/gtest.h"
|
||||||
#include "base/commandlineflags.h"
|
#include "gflags/gflags.h"
|
||||||
#include "base/logging.h"
|
#include "btree_container.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"
|
|
||||||
|
|
||||||
DECLARE_int32(test_values);
|
DECLARE_int32(test_values);
|
||||||
DECLARE_int32(benchmark_values);
|
DECLARE_int32(benchmark_values);
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
// Provide operator<< support for pair<T, U>.
|
// Provide operator<< support for std::pair<T, U>.
|
||||||
template <typename T, typename 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 << ")";
|
os << "(" << p.first << "," << p.second << ")";
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide pair equality testing that works as long as x.first is comparable to
|
// 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
|
// 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>
|
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;
|
return x.first == y.first && x.second == y.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace std
|
|
||||||
|
|
||||||
namespace base {
|
|
||||||
|
|
||||||
// Partial specialization of remove_const that propagates the removal through
|
// Partial specialization of remove_const that propagates the removal through
|
||||||
// std::pair.
|
// std::pair.
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
struct remove_const<std::pair<T, U> > {
|
struct remove_const<pair<T, U> > {
|
||||||
typedef std::pair<typename remove_const<T>::type,
|
typedef pair<typename remove_const<T>::type,
|
||||||
typename remove_const<U>::type> type;
|
typename remove_const<U>::type> type;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace base
|
} // namespace std
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
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
|
// 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.
|
// behavior is to treat the value as a pair and return the first element.
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
|
@ -70,6 +68,11 @@ struct KeyOfValue {
|
||||||
typedef select1st<V> type;
|
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
|
// Partial specialization of KeyOfValue class for when the key and value are
|
||||||
// the same type such as in set<> and btree_set<>.
|
// the same type such as in set<> and btree_set<>.
|
||||||
template <typename K>
|
template <typename K>
|
||||||
|
@ -77,6 +80,29 @@ struct KeyOfValue<K, K> {
|
||||||
typedef identity<K> type;
|
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
|
// The base class for a sorted associative container checker. TreeType is the
|
||||||
// container type to check and CheckerType is the container type to check
|
// container type to check and CheckerType is the container type to check
|
||||||
// against. TreeType is expected to be btree_{set,map,multiset,multimap} and
|
// against. TreeType is expected to be btree_{set,map,multiset,multimap} and
|
||||||
|
@ -127,9 +153,9 @@ class base_checker {
|
||||||
IterType iter_check(
|
IterType iter_check(
|
||||||
IterType tree_iter, CheckerIterType checker_iter) const {
|
IterType tree_iter, CheckerIterType checker_iter) const {
|
||||||
if (tree_iter == tree_.end()) {
|
if (tree_iter == tree_.end()) {
|
||||||
CHECK(checker_iter == checker_.end());
|
EXPECT_EQ(checker_iter, checker_.end());
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(*tree_iter, *checker_iter);
|
EXPECT_EQ(*tree_iter, *checker_iter);
|
||||||
}
|
}
|
||||||
return tree_iter;
|
return tree_iter;
|
||||||
}
|
}
|
||||||
|
@ -137,9 +163,9 @@ class base_checker {
|
||||||
IterType riter_check(
|
IterType riter_check(
|
||||||
IterType tree_iter, CheckerIterType checker_iter) const {
|
IterType tree_iter, CheckerIterType checker_iter) const {
|
||||||
if (tree_iter == tree_.rend()) {
|
if (tree_iter == tree_.rend()) {
|
||||||
CHECK(checker_iter == checker_.rend());
|
EXPECT_EQ(checker_iter, checker_.rend());
|
||||||
} else {
|
} else {
|
||||||
CHECK_EQ(*tree_iter, *checker_iter);
|
EXPECT_EQ(*tree_iter, *checker_iter);
|
||||||
}
|
}
|
||||||
return tree_iter;
|
return tree_iter;
|
||||||
}
|
}
|
||||||
|
@ -147,17 +173,17 @@ class base_checker {
|
||||||
typename KeyOfValue<typename TreeType::key_type,
|
typename KeyOfValue<typename TreeType::key_type,
|
||||||
typename TreeType::value_type>::type key_of_value;
|
typename TreeType::value_type>::type key_of_value;
|
||||||
const key_type &key = key_of_value(x);
|
const key_type &key = key_of_value(x);
|
||||||
CHECK_EQ(*find(key), x);
|
EXPECT_EQ(*find(key), x);
|
||||||
lower_bound(key);
|
lower_bound(key);
|
||||||
upper_bound(key);
|
upper_bound(key);
|
||||||
equal_range(key);
|
equal_range(key);
|
||||||
count(key);
|
count(key);
|
||||||
}
|
}
|
||||||
void erase_check(const key_type &key) {
|
void erase_check(const key_type &key) {
|
||||||
CHECK(tree_.find(key) == const_tree_.end());
|
EXPECT_TRUE(tree_.find(key) == const_tree_.end());
|
||||||
CHECK(const_tree_.find(key) == tree_.end());
|
EXPECT_TRUE(const_tree_.find(key) == tree_.end());
|
||||||
CHECK(tree_.equal_range(key).first ==
|
EXPECT_TRUE(tree_.equal_range(key).first ==
|
||||||
const_tree_.equal_range(key).second);
|
const_tree_.equal_range(key).second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup routines.
|
// Lookup routines.
|
||||||
|
@ -173,20 +199,20 @@ class base_checker {
|
||||||
const_iterator upper_bound(const key_type &key) const {
|
const_iterator upper_bound(const key_type &key) const {
|
||||||
return iter_check(tree_.upper_bound(key), checker_.upper_bound(key));
|
return iter_check(tree_.upper_bound(key), checker_.upper_bound(key));
|
||||||
}
|
}
|
||||||
pair<iterator,iterator> equal_range(const key_type &key) {
|
std::pair<iterator,iterator> equal_range(const key_type &key) {
|
||||||
pair<typename CheckerType::iterator,
|
std::pair<typename CheckerType::iterator,
|
||||||
typename CheckerType::iterator> checker_res =
|
typename CheckerType::iterator> checker_res =
|
||||||
checker_.equal_range(key);
|
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.first, checker_res.first);
|
||||||
iter_check(tree_res.second, checker_res.second);
|
iter_check(tree_res.second, checker_res.second);
|
||||||
return tree_res;
|
return tree_res;
|
||||||
}
|
}
|
||||||
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 {
|
||||||
pair<typename CheckerType::const_iterator,
|
std::pair<typename CheckerType::const_iterator,
|
||||||
typename CheckerType::const_iterator> checker_res =
|
typename CheckerType::const_iterator> checker_res =
|
||||||
checker_.equal_range(key);
|
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.first, checker_res.first);
|
||||||
iter_check(tree_res.second, checker_res.second);
|
iter_check(tree_res.second, checker_res.second);
|
||||||
return tree_res;
|
return tree_res;
|
||||||
|
@ -199,7 +225,7 @@ class base_checker {
|
||||||
}
|
}
|
||||||
size_type count(const key_type &key) const {
|
size_type count(const key_type &key) const {
|
||||||
size_type res = checker_.count(key);
|
size_type res = checker_.count(key);
|
||||||
CHECK_EQ(res, tree_.count(key));
|
EXPECT_EQ(res, tree_.count(key));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,10 +240,10 @@ class base_checker {
|
||||||
int erase(const key_type &key) {
|
int erase(const key_type &key) {
|
||||||
int size = tree_.size();
|
int size = tree_.size();
|
||||||
int res = checker_.erase(key);
|
int res = checker_.erase(key);
|
||||||
CHECK_EQ(res, tree_.count(key));
|
EXPECT_EQ(res, tree_.count(key));
|
||||||
CHECK_EQ(res, tree_.erase(key));
|
EXPECT_EQ(res, tree_.erase(key));
|
||||||
CHECK_EQ(tree_.count(key), 0);
|
EXPECT_EQ(tree_.count(key), 0);
|
||||||
CHECK_EQ(tree_.size(), size - res);
|
EXPECT_EQ(tree_.size(), size - res);
|
||||||
erase_check(key);
|
erase_check(key);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -233,9 +259,9 @@ class base_checker {
|
||||||
++checker_next;
|
++checker_next;
|
||||||
checker_.erase(checker_iter);
|
checker_.erase(checker_iter);
|
||||||
iter = tree_.erase(iter);
|
iter = tree_.erase(iter);
|
||||||
CHECK_EQ(tree_.size(), checker_.size());
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
CHECK_EQ(tree_.size(), size - 1);
|
EXPECT_EQ(tree_.size(), size - 1);
|
||||||
CHECK_EQ(tree_.count(key), count - 1);
|
EXPECT_EQ(tree_.count(key), count - 1);
|
||||||
if (count == 1) {
|
if (count == 1) {
|
||||||
erase_check(key);
|
erase_check(key);
|
||||||
}
|
}
|
||||||
|
@ -258,8 +284,8 @@ class base_checker {
|
||||||
}
|
}
|
||||||
checker_.erase(checker_begin, checker_end);
|
checker_.erase(checker_begin, checker_end);
|
||||||
tree_.erase(begin, end);
|
tree_.erase(begin, end);
|
||||||
CHECK_EQ(tree_.size(), checker_.size());
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
CHECK_EQ(tree_.size(), size - count);
|
EXPECT_EQ(tree_.size(), size - count);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility routines.
|
// Utility routines.
|
||||||
|
@ -274,7 +300,7 @@ class base_checker {
|
||||||
|
|
||||||
void verify() const {
|
void verify() const {
|
||||||
tree_.verify();
|
tree_.verify();
|
||||||
CHECK_EQ(tree_.size(), checker_.size());
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
|
|
||||||
// Move through the forward iterators using increment.
|
// Move through the forward iterators using increment.
|
||||||
typename CheckerType::const_iterator
|
typename CheckerType::const_iterator
|
||||||
|
@ -282,7 +308,7 @@ class base_checker {
|
||||||
const_iterator tree_iter(tree_.begin());
|
const_iterator tree_iter(tree_.begin());
|
||||||
for (; tree_iter != tree_.end();
|
for (; tree_iter != tree_.end();
|
||||||
++tree_iter, ++checker_iter) {
|
++tree_iter, ++checker_iter) {
|
||||||
CHECK_EQ(*tree_iter, *checker_iter);
|
EXPECT_EQ(*tree_iter, *checker_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move through the forward iterators using decrement.
|
// Move through the forward iterators using decrement.
|
||||||
|
@ -291,8 +317,8 @@ class base_checker {
|
||||||
--tree_iter;
|
--tree_iter;
|
||||||
--checker_iter;
|
--checker_iter;
|
||||||
}
|
}
|
||||||
CHECK(tree_iter == tree_.begin());
|
EXPECT_TRUE(tree_iter == tree_.begin());
|
||||||
CHECK(checker_iter == checker_.begin());
|
EXPECT_TRUE(checker_iter == checker_.begin());
|
||||||
|
|
||||||
// Move through the reverse iterators using increment.
|
// Move through the reverse iterators using increment.
|
||||||
typename CheckerType::const_reverse_iterator
|
typename CheckerType::const_reverse_iterator
|
||||||
|
@ -300,7 +326,7 @@ class base_checker {
|
||||||
const_reverse_iterator tree_riter(tree_.rbegin());
|
const_reverse_iterator tree_riter(tree_.rbegin());
|
||||||
for (; tree_riter != tree_.rend();
|
for (; tree_riter != tree_.rend();
|
||||||
++tree_riter, ++checker_riter) {
|
++tree_riter, ++checker_riter) {
|
||||||
CHECK_EQ(*tree_riter, *checker_riter);
|
EXPECT_EQ(*tree_riter, *checker_riter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move through the reverse iterators using decrement.
|
// Move through the reverse iterators using decrement.
|
||||||
|
@ -309,8 +335,8 @@ class base_checker {
|
||||||
--tree_riter;
|
--tree_riter;
|
||||||
--checker_riter;
|
--checker_riter;
|
||||||
}
|
}
|
||||||
CHECK(tree_riter == tree_.rbegin());
|
EXPECT_EQ(tree_riter, tree_.rbegin());
|
||||||
CHECK(checker_riter == checker_.rbegin());
|
EXPECT_EQ(checker_riter, checker_.rbegin());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access to the underlying btree.
|
// Access to the underlying btree.
|
||||||
|
@ -318,12 +344,12 @@ class base_checker {
|
||||||
|
|
||||||
// Size routines.
|
// Size routines.
|
||||||
size_type size() const {
|
size_type size() const {
|
||||||
CHECK_EQ(tree_.size(), checker_.size());
|
EXPECT_EQ(tree_.size(), checker_.size());
|
||||||
return tree_.size();
|
return tree_.size();
|
||||||
}
|
}
|
||||||
size_type max_size() const { return tree_.max_size(); }
|
size_type max_size() const { return tree_.max_size(); }
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
CHECK_EQ(tree_.empty(), checker_.empty());
|
EXPECT_EQ(tree_.empty(), checker_.empty());
|
||||||
return tree_.empty();
|
return tree_.empty();
|
||||||
}
|
}
|
||||||
size_type height() const { return tree_.height(); }
|
size_type height() const { return tree_.height(); }
|
||||||
|
@ -367,25 +393,25 @@ class unique_checker : public base_checker<TreeType, CheckerType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insertion routines.
|
// Insertion routines.
|
||||||
pair<iterator,bool> insert(const value_type &x) {
|
std::pair<iterator,bool> insert(const value_type &x) {
|
||||||
int size = this->tree_.size();
|
int size = this->tree_.size();
|
||||||
pair<typename CheckerType::iterator,bool> checker_res =
|
std::pair<typename CheckerType::iterator,bool> checker_res =
|
||||||
this->checker_.insert(x);
|
this->checker_.insert(x);
|
||||||
pair<iterator,bool> tree_res = this->tree_.insert(x);
|
std::pair<iterator,bool> tree_res = this->tree_.insert(x);
|
||||||
CHECK_EQ(*tree_res.first, *checker_res.first);
|
EXPECT_EQ(*tree_res.first, *checker_res.first);
|
||||||
CHECK_EQ(tree_res.second, checker_res.second);
|
EXPECT_EQ(tree_res.second, checker_res.second);
|
||||||
CHECK_EQ(this->tree_.size(), this->checker_.size());
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
CHECK_EQ(this->tree_.size(), size + tree_res.second);
|
EXPECT_EQ(this->tree_.size(), size + tree_res.second);
|
||||||
return tree_res;
|
return tree_res;
|
||||||
}
|
}
|
||||||
iterator insert(iterator position, const value_type &x) {
|
iterator insert(iterator position, const value_type &x) {
|
||||||
int size = this->tree_.size();
|
int size = this->tree_.size();
|
||||||
pair<typename CheckerType::iterator,bool> checker_res =
|
std::pair<typename CheckerType::iterator,bool> checker_res =
|
||||||
this->checker_.insert(x);
|
this->checker_.insert(x);
|
||||||
iterator tree_res = this->tree_.insert(position, x);
|
iterator tree_res = this->tree_.insert(position, x);
|
||||||
CHECK_EQ(*tree_res, *checker_res.first);
|
EXPECT_EQ(*tree_res, *checker_res.first);
|
||||||
CHECK_EQ(this->tree_.size(), this->checker_.size());
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
CHECK_EQ(this->tree_.size(), size + checker_res.second);
|
EXPECT_EQ(this->tree_.size(), size + checker_res.second);
|
||||||
return tree_res;
|
return tree_res;
|
||||||
}
|
}
|
||||||
template <typename InputIterator>
|
template <typename InputIterator>
|
||||||
|
@ -428,18 +454,18 @@ class multi_checker : public base_checker<TreeType, CheckerType> {
|
||||||
int size = this->tree_.size();
|
int size = this->tree_.size();
|
||||||
typename CheckerType::iterator checker_res = this->checker_.insert(x);
|
typename CheckerType::iterator checker_res = this->checker_.insert(x);
|
||||||
iterator tree_res = this->tree_.insert(x);
|
iterator tree_res = this->tree_.insert(x);
|
||||||
CHECK_EQ(*tree_res, *checker_res);
|
EXPECT_EQ(*tree_res, *checker_res);
|
||||||
CHECK_EQ(this->tree_.size(), this->checker_.size());
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
CHECK_EQ(this->tree_.size(), size + 1);
|
EXPECT_EQ(this->tree_.size(), size + 1);
|
||||||
return tree_res;
|
return tree_res;
|
||||||
}
|
}
|
||||||
iterator insert(iterator position, const value_type &x) {
|
iterator insert(iterator position, const value_type &x) {
|
||||||
int size = this->tree_.size();
|
int size = this->tree_.size();
|
||||||
typename CheckerType::iterator checker_res = this->checker_.insert(x);
|
typename CheckerType::iterator checker_res = this->checker_.insert(x);
|
||||||
iterator tree_res = this->tree_.insert(position, x);
|
iterator tree_res = this->tree_.insert(position, x);
|
||||||
CHECK_EQ(*tree_res, *checker_res);
|
EXPECT_EQ(*tree_res, *checker_res);
|
||||||
CHECK_EQ(this->tree_.size(), this->checker_.size());
|
EXPECT_EQ(this->tree_.size(), this->checker_.size());
|
||||||
CHECK_EQ(this->tree_.size(), size + 1);
|
EXPECT_EQ(this->tree_.size(), size + 1);
|
||||||
return tree_res;
|
return tree_res;
|
||||||
}
|
}
|
||||||
template <typename InputIterator>
|
template <typename InputIterator>
|
||||||
|
@ -451,7 +477,7 @@ class multi_checker : public base_checker<TreeType, CheckerType> {
|
||||||
};
|
};
|
||||||
|
|
||||||
char* GenerateDigits(char buf[16], int val, int maxval) {
|
char* GenerateDigits(char buf[16], int val, int maxval) {
|
||||||
DCHECK_LE(val, maxval);
|
EXPECT_LE(val, maxval);
|
||||||
int p = 15;
|
int p = 15;
|
||||||
buf[p--] = 0;
|
buf[p--] = 0;
|
||||||
while (maxval > 0) {
|
while (maxval > 0) {
|
||||||
|
@ -469,61 +495,48 @@ struct Generator {
|
||||||
: maxval(m) {
|
: maxval(m) {
|
||||||
}
|
}
|
||||||
K operator()(int i) const {
|
K operator()(int i) const {
|
||||||
DCHECK_LE(i, maxval);
|
EXPECT_LE(i, maxval);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct Generator<string> {
|
struct Generator<std::string> {
|
||||||
int maxval;
|
int maxval;
|
||||||
Generator(int m)
|
Generator(int m)
|
||||||
: maxval(m) {
|
: maxval(m) {
|
||||||
}
|
}
|
||||||
string operator()(int i) const {
|
std::string operator()(int i) const {
|
||||||
char buf[16];
|
char buf[16];
|
||||||
return GenerateDigits(buf, i, maxval);
|
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>
|
template <typename T, typename U>
|
||||||
struct Generator<pair<T, U> > {
|
struct Generator<std::pair<T, U> > {
|
||||||
Generator<typename base::remove_const<T>::type> tgen;
|
Generator<typename std::remove_const<T>::type> tgen;
|
||||||
Generator<typename base::remove_const<U>::type> ugen;
|
Generator<typename std::remove_const<U>::type> ugen;
|
||||||
|
|
||||||
Generator(int m)
|
Generator(int m)
|
||||||
: tgen(m),
|
: tgen(m),
|
||||||
ugen(m) {
|
ugen(m) {
|
||||||
}
|
}
|
||||||
pair<T, U> operator()(int i) const {
|
std::pair<T, U> operator()(int i) const {
|
||||||
return make_pair(tgen(i), ugen(i));
|
return std::make_pair(tgen(i), ugen(i));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate values for our tests and benchmarks. Value range is [0, maxval].
|
// Generate values for our tests and benchmarks. Value range is [0, maxval].
|
||||||
const vector<int>& GenerateNumbers(int n, int maxval) {
|
const std::vector<int>& GenerateNumbers(int n, int maxval) {
|
||||||
static ACMRandom rand(FLAGS_test_random_seed);
|
static std::vector<int> values;
|
||||||
static vector<int> values;
|
static std::set<int> unique_values;
|
||||||
static set<int> unique_values;
|
|
||||||
|
|
||||||
if (values.size() < n) {
|
if (values.size() < n) {
|
||||||
|
|
||||||
for (int i = values.size(); i < n; i++) {
|
for (int i = values.size(); i < n; i++) {
|
||||||
int value;
|
int value;
|
||||||
do {
|
do {
|
||||||
value = rand.Next() % (maxval + 1);
|
value = rand() % (maxval + 1);
|
||||||
} while (unique_values.find(value) != unique_values.end());
|
} while (unique_values.find(value) != unique_values.end());
|
||||||
|
|
||||||
values.push_back(value);
|
values.push_back(value);
|
||||||
|
@ -537,13 +550,13 @@ const vector<int>& GenerateNumbers(int n, int maxval) {
|
||||||
// Generates values in the range
|
// Generates values in the range
|
||||||
// [0, 4 * min(FLAGS_benchmark_values, FLAGS_test_values)]
|
// [0, 4 * min(FLAGS_benchmark_values, FLAGS_test_values)]
|
||||||
template <typename V>
|
template <typename V>
|
||||||
vector<V> GenerateValues(int n) {
|
std::vector<V> GenerateValues(int n) {
|
||||||
int two_times_max = 2 * max(FLAGS_benchmark_values, FLAGS_test_values);
|
int two_times_max = 2 * std::max(FLAGS_benchmark_values, FLAGS_test_values);
|
||||||
int four_times_max = 2 * two_times_max;
|
int four_times_max = 2 * two_times_max;
|
||||||
DCHECK_LE(n, two_times_max);
|
EXPECT_LE(n, two_times_max);
|
||||||
const vector<int> &nums = GenerateNumbers(n, four_times_max);
|
const std::vector<int> &nums = GenerateNumbers(n, four_times_max);
|
||||||
Generator<V> gen(four_times_max);
|
Generator<V> gen(four_times_max);
|
||||||
vector<V> vec;
|
std::vector<V> vec;
|
||||||
|
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
vec.push_back(gen(nums[i]));
|
vec.push_back(gen(nums[i]));
|
||||||
|
@ -553,44 +566,44 @@ vector<V> GenerateValues(int n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K>
|
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 sizeof_node = sizeof(std::_Rb_tree_node<K>);
|
||||||
int bytes_used = sizeof(s) + s.size() * sizeof_node;
|
int bytes_used = sizeof(s) + s.size() * sizeof_node;
|
||||||
double bytes_per_value = (double) bytes_used / s.size();
|
double bytes_per_value = (double) bytes_used / s.size();
|
||||||
VLOG(1) << " size=" << s.size()
|
std::cout << " size=" << s.size()
|
||||||
<< " bytes-used=" << bytes_used
|
<< " bytes-used=" << bytes_used
|
||||||
<< " bytes-per-value=" << bytes_per_value;
|
<< " bytes-per-value=" << bytes_per_value;
|
||||||
return bytes_per_value;
|
return bytes_per_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K>
|
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 sizeof_node = sizeof(std::_Rb_tree_node<K>);
|
||||||
int bytes_used = sizeof(s) + s.size() * sizeof_node;
|
int bytes_used = sizeof(s) + s.size() * sizeof_node;
|
||||||
double bytes_per_value = (double) bytes_used / s.size();
|
double bytes_per_value = (double) bytes_used / s.size();
|
||||||
VLOG(1) << " size=" << s.size()
|
std::cout << " size=" << s.size()
|
||||||
<< " bytes-used=" << bytes_used
|
<< " bytes-used=" << bytes_used
|
||||||
<< " bytes-per-value=" << bytes_per_value;
|
<< " bytes-per-value=" << bytes_per_value;
|
||||||
return bytes_per_value;
|
return bytes_per_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
double ContainerInfo(const map<K, V> &m) {
|
double ContainerInfo(const std::map<K, V> &m) {
|
||||||
int sizeof_node = sizeof(std::_Rb_tree_node<pair<K, V> >);
|
int sizeof_node = sizeof(std::_Rb_tree_node<std::pair<K, V> >);
|
||||||
int bytes_used = sizeof(m) + m.size() * sizeof_node;
|
int bytes_used = sizeof(m) + m.size() * sizeof_node;
|
||||||
double bytes_per_value = (double) bytes_used / m.size();
|
double bytes_per_value = (double) bytes_used / m.size();
|
||||||
VLOG(1) << " size=" << m.size()
|
std::cout << " size=" << m.size()
|
||||||
<< " bytes-used=" << bytes_used
|
<< " bytes-used=" << bytes_used
|
||||||
<< " bytes-per-value=" << bytes_per_value;
|
<< " bytes-per-value=" << bytes_per_value;
|
||||||
return bytes_per_value;
|
return bytes_per_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
double ContainerInfo(const multimap<K, V> &m) {
|
double ContainerInfo(const std::multimap<K, V> &m) {
|
||||||
int sizeof_node = sizeof(std::_Rb_tree_node<pair<K, V> >);
|
int sizeof_node = sizeof(std::_Rb_tree_node<std::pair<K, V> >);
|
||||||
int bytes_used = sizeof(m) + m.size() * sizeof_node;
|
int bytes_used = sizeof(m) + m.size() * sizeof_node;
|
||||||
double bytes_per_value = (double) bytes_used / m.size();
|
double bytes_per_value = (double) bytes_used / m.size();
|
||||||
VLOG(1) << " size=" << m.size()
|
std::cout << " size=" << m.size()
|
||||||
<< " bytes-used=" << bytes_used
|
<< " bytes-used=" << bytes_used
|
||||||
<< " bytes-per-value=" << bytes_per_value;
|
<< " bytes-per-value=" << bytes_per_value;
|
||||||
return bytes_per_value;
|
return bytes_per_value;
|
||||||
|
@ -600,7 +613,7 @@ template <typename P>
|
||||||
double ContainerInfo(const btree_container<P> &b) {
|
double ContainerInfo(const btree_container<P> &b) {
|
||||||
double bytes_used = sizeof(b) + b.bytes_used();
|
double bytes_used = sizeof(b) + b.bytes_used();
|
||||||
double bytes_per_value = (double) bytes_used / b.size();
|
double bytes_per_value = (double) bytes_used / b.size();
|
||||||
VLOG(1) << " size=" << b.size()
|
std::cout << " size=" << b.size()
|
||||||
<< " bytes-used=" << bytes_used
|
<< " bytes-used=" << bytes_used
|
||||||
<< " bytes-per-value=" << bytes_per_value
|
<< " bytes-per-value=" << bytes_per_value
|
||||||
<< " height=" << b.height()
|
<< " height=" << b.height()
|
||||||
|
@ -612,7 +625,7 @@ double ContainerInfo(const btree_container<P> &b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename V>
|
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;
|
typename KeyOfValue<typename T::key_type, V>::type key_of_value;
|
||||||
|
|
||||||
T &mutable_b = *b;
|
T &mutable_b = *b;
|
||||||
|
@ -631,22 +644,22 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
|
||||||
|
|
||||||
// Test copy constructor.
|
// Test copy constructor.
|
||||||
T b_copy(const_b);
|
T b_copy(const_b);
|
||||||
CHECK_EQ(b_copy.size(), const_b.size());
|
EXPECT_EQ(b_copy.size(), const_b.size());
|
||||||
CHECK_LE(b_copy.height(), const_b.height());
|
EXPECT_LE(b_copy.height(), const_b.height());
|
||||||
CHECK_LE(b_copy.internal_nodes(), const_b.internal_nodes());
|
EXPECT_LE(b_copy.internal_nodes(), const_b.internal_nodes());
|
||||||
CHECK_LE(b_copy.leaf_nodes(), const_b.leaf_nodes());
|
EXPECT_LE(b_copy.leaf_nodes(), const_b.leaf_nodes());
|
||||||
for (int i = 0; i < values.size(); ++i) {
|
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.
|
// Test range constructor.
|
||||||
T b_range(const_b.begin(), const_b.end());
|
T b_range(const_b.begin(), const_b.end());
|
||||||
CHECK_EQ(b_range.size(), const_b.size());
|
EXPECT_EQ(b_range.size(), const_b.size());
|
||||||
CHECK_LE(b_range.height(), const_b.height());
|
EXPECT_LE(b_range.height(), const_b.height());
|
||||||
CHECK_LE(b_range.internal_nodes(), const_b.internal_nodes());
|
EXPECT_LE(b_range.internal_nodes(), const_b.internal_nodes());
|
||||||
CHECK_LE(b_range.leaf_nodes(), const_b.leaf_nodes());
|
EXPECT_LE(b_range.leaf_nodes(), const_b.leaf_nodes());
|
||||||
for (int i = 0; i < values.size(); ++i) {
|
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.
|
// 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.
|
// Test range insertion for new values.
|
||||||
b_range.clear();
|
b_range.clear();
|
||||||
b_range.insert(b_copy.begin(), b_copy.end());
|
b_range.insert(b_copy.begin(), b_copy.end());
|
||||||
CHECK_EQ(b_range.size(), b_copy.size());
|
EXPECT_EQ(b_range.size(), b_copy.size());
|
||||||
CHECK_EQ(b_range.height(), b_copy.height());
|
EXPECT_EQ(b_range.height(), b_copy.height());
|
||||||
CHECK_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
||||||
CHECK_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
||||||
for (int i = 0; i < values.size(); ++i) {
|
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.
|
// Test assignment to self. Nothing should change.
|
||||||
b_range.operator=(b_range);
|
b_range.operator=(b_range);
|
||||||
CHECK_EQ(b_range.size(), b_copy.size());
|
EXPECT_EQ(b_range.size(), b_copy.size());
|
||||||
CHECK_EQ(b_range.height(), b_copy.height());
|
EXPECT_EQ(b_range.height(), b_copy.height());
|
||||||
CHECK_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
||||||
CHECK_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
||||||
|
|
||||||
// Test assignment of new values.
|
// Test assignment of new values.
|
||||||
b_range.clear();
|
b_range.clear();
|
||||||
b_range = b_copy;
|
b_range = b_copy;
|
||||||
CHECK_EQ(b_range.size(), b_copy.size());
|
EXPECT_EQ(b_range.size(), b_copy.size());
|
||||||
CHECK_EQ(b_range.height(), b_copy.height());
|
EXPECT_EQ(b_range.height(), b_copy.height());
|
||||||
CHECK_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes());
|
||||||
CHECK_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes());
|
||||||
|
|
||||||
// Test swap.
|
// Test swap.
|
||||||
b_range.clear();
|
b_range.clear();
|
||||||
b_range.swap(b_copy);
|
b_range.swap(b_copy);
|
||||||
CHECK_EQ(b_copy.size(), 0);
|
EXPECT_EQ(b_copy.size(), 0);
|
||||||
CHECK_EQ(b_range.size(), const_b.size());
|
EXPECT_EQ(b_range.size(), const_b.size());
|
||||||
for (int i = 0; i < values.size(); ++i) {
|
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);
|
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) {
|
for (int i = 0; i < values.size(); ++i) {
|
||||||
mutable_b.erase(key_of_value(values[i]));
|
mutable_b.erase(key_of_value(values[i]));
|
||||||
// Erasing a non-existent key should have no effect.
|
// 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();
|
const_b.verify();
|
||||||
CHECK_EQ(const_b.internal_nodes(), 0);
|
EXPECT_EQ(const_b.internal_nodes(), 0);
|
||||||
CHECK_EQ(const_b.leaf_nodes(), 0);
|
EXPECT_EQ(const_b.leaf_nodes(), 0);
|
||||||
CHECK_EQ(const_b.size(), 0);
|
EXPECT_EQ(const_b.size(), 0);
|
||||||
|
|
||||||
// Test erase via iterators.
|
// Test erase via iterators.
|
||||||
mutable_b = b_copy;
|
mutable_b = b_copy;
|
||||||
|
@ -708,9 +721,9 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const_b.verify();
|
const_b.verify();
|
||||||
CHECK_EQ(const_b.internal_nodes(), 0);
|
EXPECT_EQ(const_b.internal_nodes(), 0);
|
||||||
CHECK_EQ(const_b.leaf_nodes(), 0);
|
EXPECT_EQ(const_b.leaf_nodes(), 0);
|
||||||
CHECK_EQ(const_b.size(), 0);
|
EXPECT_EQ(const_b.size(), 0);
|
||||||
|
|
||||||
// Test insert with hint.
|
// Test insert with hint.
|
||||||
for (int i = 0; i < values.size(); i++) {
|
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
|
// Test dumping of the btree to an ostream. There should be 1 line for each
|
||||||
// value.
|
// value.
|
||||||
ostringstream strm;
|
std::stringstream strm;
|
||||||
strm << mutable_b.tree();
|
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.
|
// Test range erase.
|
||||||
mutable_b.erase(mutable_b.begin(), mutable_b.end());
|
mutable_b.erase(mutable_b.begin(), mutable_b.end());
|
||||||
CHECK_EQ(mutable_b.size(), 0);
|
EXPECT_EQ(mutable_b.size(), 0);
|
||||||
const_b.verify();
|
const_b.verify();
|
||||||
|
|
||||||
// First half.
|
// 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();
|
typename T::iterator mutable_iter_end = mutable_b.begin();
|
||||||
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end;
|
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end;
|
||||||
mutable_b.erase(mutable_b.begin(), 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();
|
const_b.verify();
|
||||||
|
|
||||||
// Second half.
|
// 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();
|
typename T::iterator mutable_iter_begin = mutable_b.begin();
|
||||||
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin;
|
for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin;
|
||||||
mutable_b.erase(mutable_iter_begin, mutable_b.end());
|
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();
|
const_b.verify();
|
||||||
|
|
||||||
// Second quarter.
|
// Second quarter.
|
||||||
|
@ -753,7 +766,7 @@ void DoTest(const char *name, T *b, const vector<V> &values) {
|
||||||
mutable_iter_end = mutable_iter_begin;
|
mutable_iter_end = mutable_iter_begin;
|
||||||
for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end;
|
for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end;
|
||||||
mutable_b.erase(mutable_iter_begin, 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();
|
const_b.verify();
|
||||||
|
|
||||||
mutable_b.clear();
|
mutable_b.clear();
|
||||||
|
@ -770,62 +783,62 @@ void ConstTest() {
|
||||||
// Insert a single value into the container and test looking it up.
|
// Insert a single value into the container and test looking it up.
|
||||||
value_type value = Generator<value_type>(2)(2);
|
value_type value = Generator<value_type>(2)(2);
|
||||||
mutable_b.insert(value);
|
mutable_b.insert(value);
|
||||||
CHECK(mutable_b.find(key_of_value(value)) != const_b.end());
|
EXPECT_TRUE(mutable_b.find(key_of_value(value)) != const_b.end());
|
||||||
CHECK(const_b.find(key_of_value(value)) != mutable_b.end());
|
EXPECT_TRUE(const_b.find(key_of_value(value)) != mutable_b.end());
|
||||||
CHECK_EQ(*const_b.lower_bound(key_of_value(value)), value);
|
EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value);
|
||||||
CHECK(const_b.upper_bound(key_of_value(value)) == const_b.end());
|
EXPECT_TRUE(const_b.upper_bound(key_of_value(value)) == const_b.end());
|
||||||
CHECK_EQ(*const_b.equal_range(key_of_value(value)).first, value);
|
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.
|
// We can only create a non-const iterator from a non-const container.
|
||||||
typename T::iterator mutable_iter(mutable_b.begin());
|
typename T::iterator mutable_iter(mutable_b.begin());
|
||||||
CHECK(mutable_iter == const_b.begin());
|
EXPECT_TRUE(mutable_iter == const_b.begin());
|
||||||
CHECK(mutable_iter != const_b.end());
|
EXPECT_TRUE(mutable_iter != const_b.end());
|
||||||
CHECK(const_b.begin() == mutable_iter);
|
EXPECT_TRUE(const_b.begin() == mutable_iter);
|
||||||
CHECK(const_b.end() != mutable_iter);
|
EXPECT_TRUE(const_b.end() != mutable_iter);
|
||||||
typename T::reverse_iterator mutable_riter(mutable_b.rbegin());
|
typename T::reverse_iterator mutable_riter(mutable_b.rbegin());
|
||||||
CHECK(mutable_riter == const_b.rbegin());
|
EXPECT_TRUE(mutable_riter == const_b.rbegin());
|
||||||
CHECK(mutable_riter != const_b.rend());
|
EXPECT_TRUE(mutable_riter != const_b.rend());
|
||||||
CHECK(const_b.rbegin() == mutable_riter);
|
EXPECT_TRUE(const_b.rbegin() == mutable_riter);
|
||||||
CHECK(const_b.rend() != mutable_riter);
|
EXPECT_TRUE(const_b.rend() != mutable_riter);
|
||||||
|
|
||||||
// We can create a const iterator from a non-const iterator.
|
// We can create a const iterator from a non-const iterator.
|
||||||
typename T::const_iterator const_iter(mutable_iter);
|
typename T::const_iterator const_iter(mutable_iter);
|
||||||
CHECK(const_iter == mutable_b.begin());
|
EXPECT_TRUE(const_iter == mutable_b.begin());
|
||||||
CHECK(const_iter != mutable_b.end());
|
EXPECT_TRUE(const_iter != mutable_b.end());
|
||||||
CHECK(mutable_b.begin() == const_iter);
|
EXPECT_TRUE(mutable_b.begin() == const_iter);
|
||||||
CHECK(mutable_b.end() != const_iter);
|
EXPECT_TRUE(mutable_b.end() != const_iter);
|
||||||
typename T::const_reverse_iterator const_riter(mutable_riter);
|
typename T::const_reverse_iterator const_riter(mutable_riter);
|
||||||
CHECK(const_riter == mutable_b.rbegin());
|
EXPECT_EQ(const_riter, mutable_b.rbegin());
|
||||||
CHECK(const_riter != mutable_b.rend());
|
EXPECT_TRUE(const_riter != mutable_b.rend());
|
||||||
CHECK(mutable_b.rbegin() == const_riter);
|
EXPECT_EQ(mutable_b.rbegin(), const_riter);
|
||||||
CHECK(mutable_b.rend() != const_riter);
|
EXPECT_TRUE(mutable_b.rend() != const_riter);
|
||||||
|
|
||||||
// Make sure various methods can be invoked on a const container.
|
// Make sure various methods can be invoked on a const container.
|
||||||
const_b.verify();
|
const_b.verify();
|
||||||
CHECK(!const_b.empty());
|
EXPECT_FALSE(const_b.empty());
|
||||||
CHECK_EQ(const_b.size(), 1);
|
EXPECT_EQ(const_b.size(), 1);
|
||||||
CHECK_GT(const_b.max_size(), 0);
|
EXPECT_GT(const_b.max_size(), 0);
|
||||||
CHECK_EQ(const_b.height(), 1);
|
EXPECT_EQ(const_b.height(), 1);
|
||||||
CHECK_EQ(const_b.count(key_of_value(value)), 1);
|
EXPECT_EQ(const_b.count(key_of_value(value)), 1);
|
||||||
CHECK_EQ(const_b.internal_nodes(), 0);
|
EXPECT_EQ(const_b.internal_nodes(), 0);
|
||||||
CHECK_EQ(const_b.leaf_nodes(), 1);
|
EXPECT_EQ(const_b.leaf_nodes(), 1);
|
||||||
CHECK_EQ(const_b.nodes(), 1);
|
EXPECT_EQ(const_b.nodes(), 1);
|
||||||
CHECK_GT(const_b.bytes_used(), 0);
|
EXPECT_GT(const_b.bytes_used(), 0);
|
||||||
CHECK_GT(const_b.fullness(), 0);
|
EXPECT_GT(const_b.fullness(), 0);
|
||||||
CHECK_GT(const_b.overhead(), 0);
|
EXPECT_GT(const_b.overhead(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename C>
|
template <typename T, typename C>
|
||||||
void BtreeTest() {
|
void BtreeTest() {
|
||||||
ConstTest<T>();
|
ConstTest<T>();
|
||||||
|
|
||||||
typedef typename base::remove_const<typename T::value_type>::type V;
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
vector<V> random_values = GenerateValues<V>(FLAGS_test_values);
|
std::vector<V> random_values = GenerateValues<V>(FLAGS_test_values);
|
||||||
|
|
||||||
unique_checker<T, C> container;
|
unique_checker<T, C> container;
|
||||||
|
|
||||||
// Test key insertion/deletion in sorted order.
|
// 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());
|
sort(sorted_values.begin(), sorted_values.end());
|
||||||
DoTest("sorted: ", &container, sorted_values);
|
DoTest("sorted: ", &container, sorted_values);
|
||||||
|
|
||||||
|
@ -841,13 +854,13 @@ template <typename T, typename C>
|
||||||
void BtreeMultiTest() {
|
void BtreeMultiTest() {
|
||||||
ConstTest<T>();
|
ConstTest<T>();
|
||||||
|
|
||||||
typedef typename base::remove_const<typename T::value_type>::type V;
|
typedef typename std::remove_const<typename T::value_type>::type V;
|
||||||
const vector<V>& random_values = GenerateValues<V>(FLAGS_test_values);
|
const std::vector<V>& random_values = GenerateValues<V>(FLAGS_test_values);
|
||||||
|
|
||||||
multi_checker<T, C> container;
|
multi_checker<T, C> container;
|
||||||
|
|
||||||
// Test keys in sorted order.
|
// 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());
|
sort(sorted_values.begin(), sorted_values.end());
|
||||||
DoTest("sorted: ", &container, sorted_values);
|
DoTest("sorted: ", &container, sorted_values);
|
||||||
|
|
||||||
|
@ -859,25 +872,64 @@ void BtreeMultiTest() {
|
||||||
DoTest("random: ", &container, random_values);
|
DoTest("random: ", &container, random_values);
|
||||||
|
|
||||||
// Test keys in random order w/ duplicates.
|
// 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.insert(
|
||||||
duplicate_values.end(), random_values.begin(), random_values.end());
|
duplicate_values.end(), random_values.begin(), random_values.end());
|
||||||
DoTest("duplicates:", &container, duplicate_values);
|
DoTest("duplicates:", &container, duplicate_values);
|
||||||
|
|
||||||
// Test all identical keys.
|
// 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));
|
fill(identical_values.begin(), identical_values.end(), Generator<V>(2)(2));
|
||||||
DoTest("identical: ", &container, identical_values);
|
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>
|
template <typename T>
|
||||||
void BtreeArenaTest() {
|
void BtreeAllocatorTest() {
|
||||||
typedef typename T::value_type value_type;
|
typedef typename T::value_type value_type;
|
||||||
|
|
||||||
UnsafeArena arena1(1000);
|
int64_t alloc1 = 0;
|
||||||
UnsafeArena arena2(1000);
|
int64_t alloc2 = 0;
|
||||||
T b1(typename T::key_compare(), &arena1);
|
T b1(typename T::key_compare(), &alloc1);
|
||||||
T b2(typename T::key_compare(), &arena2);
|
T b2(typename T::key_compare(), &alloc2);
|
||||||
|
|
||||||
// This should swap the allocators!
|
// This should swap the allocators!
|
||||||
swap(b1, b2);
|
swap(b1, b2);
|
||||||
|
@ -886,9 +938,9 @@ void BtreeArenaTest() {
|
||||||
b1.insert(Generator<value_type>(1000)(i));
|
b1.insert(Generator<value_type>(1000)(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should have allocated out of arena2!
|
// We should have allocated out of alloc2!
|
||||||
CHECK_LE(b1.bytes_used(), arena2.status().bytes_allocated());
|
EXPECT_LE(b1.bytes_used(), alloc2 + sizeof(b1));
|
||||||
CHECK_GT(arena2.block_count(), arena1.block_count());
|
EXPECT_GT(alloc2, alloc1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -906,15 +958,15 @@ void BtreeMapTest() {
|
||||||
value_type v = Generator<value_type>(1000)(i);
|
value_type v = Generator<value_type>(1000)(i);
|
||||||
b[v.first] = v.second;
|
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
|
// Test whether we can use the "->" operator on iterators and
|
||||||
// reverse_iterators. This stresses the btree_map_params::pair_pointer
|
// reverse_iterators. This stresses the btree_map_params::pair_pointer
|
||||||
// mechanism.
|
// mechanism.
|
||||||
CHECK_EQ(b.begin()->first, Generator<value_type>(1000)(0).first);
|
EXPECT_EQ(b.begin()->first, Generator<value_type>(1000)(0).first);
|
||||||
CHECK_EQ(b.begin()->second, Generator<value_type>(1000)(0).second);
|
EXPECT_EQ(b.begin()->second, Generator<value_type>(1000)(0).second);
|
||||||
CHECK_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first);
|
EXPECT_EQ(b.rbegin()->first, Generator<value_type>(1000)(999).first);
|
||||||
CHECK_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second);
|
EXPECT_EQ(b.rbegin()->second, Generator<value_type>(1000)(999).second);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -925,6 +977,5 @@ void BtreeMultiMapTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_BTREE_TEST_H__
|
#endif // UTIL_BTREE_BTREE_TEST_H__
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2007 Google Inc. All Rights Reserved.
|
// Copyright 2007 Google Inc. All Rights Reserved.
|
||||||
// Author: pmattis@google.com (Peter Mattis)
|
// Author: pmattis@google.com (Peter Mattis)
|
||||||
|
|
||||||
#include "base/commandlineflags.h"
|
#include "gflags/gflags.h"
|
||||||
|
|
||||||
DEFINE_int32(test_values, 10000,
|
DEFINE_int32(test_values, 10000,
|
||||||
"The number of values to use for tests.");
|
"The number of values to use for tests.");
|
||||||
|
|
44
safe_btree.h
44
safe_btree.h
|
@ -21,11 +21,8 @@
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "base/integral_types.h"
|
#include "btree.h"
|
||||||
#include "base/logging.h"
|
|
||||||
#include "util/btree/btree.h"
|
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
|
|
||||||
template <typename Tree, typename Iterator>
|
template <typename Tree, typename Iterator>
|
||||||
|
@ -77,7 +74,7 @@ class safe_btree_iterator {
|
||||||
}
|
}
|
||||||
|
|
||||||
Tree* tree() const { return tree_; }
|
Tree* tree() const { return tree_; }
|
||||||
int64 generation() const { return generation_; }
|
int64_t generation() const { return generation_; }
|
||||||
|
|
||||||
Iterator* mutable_iter() const {
|
Iterator* mutable_iter() const {
|
||||||
if (generation_ != tree_->generation()) {
|
if (generation_ != tree_->generation()) {
|
||||||
|
@ -114,13 +111,13 @@ class safe_btree_iterator {
|
||||||
// This reference value is potentially invalidated by any non-const
|
// This reference value is potentially invalidated by any non-const
|
||||||
// method on the tree; it is NOT safe.
|
// method on the tree; it is NOT safe.
|
||||||
reference operator*() const {
|
reference operator*() const {
|
||||||
DCHECK_GT(generation_, 0);
|
assert(generation_ > 0);
|
||||||
return iter().operator*();
|
return iter().operator*();
|
||||||
}
|
}
|
||||||
// This pointer value is potentially invalidated by any non-const
|
// This pointer value is potentially invalidated by any non-const
|
||||||
// method on the tree; it is NOT safe.
|
// method on the tree; it is NOT safe.
|
||||||
pointer operator->() const {
|
pointer operator->() const {
|
||||||
DCHECK_GT(generation_, 0);
|
assert(generation_ > 0);
|
||||||
return iter().operator->();
|
return iter().operator->();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +145,7 @@ class safe_btree_iterator {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The generation of the tree when "iter" was updated.
|
// The generation of the tree when "iter" was updated.
|
||||||
mutable int64 generation_;
|
mutable int64_t generation_;
|
||||||
// The key the iterator points to.
|
// The key the iterator points to.
|
||||||
mutable key_type key_;
|
mutable key_type key_;
|
||||||
// The underlying iterator.
|
// The underlying iterator.
|
||||||
|
@ -236,14 +233,14 @@ class safe_btree {
|
||||||
const_iterator upper_bound(const key_type &key) const {
|
const_iterator upper_bound(const key_type &key) const {
|
||||||
return const_iterator(this, tree_.upper_bound(key));
|
return const_iterator(this, tree_.upper_bound(key));
|
||||||
}
|
}
|
||||||
pair<iterator, iterator> equal_range(const key_type &key) {
|
std::pair<iterator, iterator> equal_range(const key_type &key) {
|
||||||
pair<tree_iterator, tree_iterator> p = tree_.equal_range(key);
|
std::pair<tree_iterator, tree_iterator> p = tree_.equal_range(key);
|
||||||
return make_pair(iterator(this, p.first),
|
return std::make_pair(iterator(this, p.first),
|
||||||
iterator(this, p.second));
|
iterator(this, p.second));
|
||||||
}
|
}
|
||||||
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 {
|
||||||
pair<tree_const_iterator, tree_const_iterator> p = tree_.equal_range(key);
|
std::pair<tree_const_iterator, tree_const_iterator> p = tree_.equal_range(key);
|
||||||
return make_pair(const_iterator(this, p.first),
|
return std::make_pair(const_iterator(this, p.first),
|
||||||
const_iterator(this, p.second));
|
const_iterator(this, p.second));
|
||||||
}
|
}
|
||||||
iterator find_unique(const key_type &key) {
|
iterator find_unique(const key_type &key) {
|
||||||
|
@ -267,15 +264,15 @@ class safe_btree {
|
||||||
|
|
||||||
// Insertion routines.
|
// Insertion routines.
|
||||||
template <typename ValuePointer>
|
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) {
|
||||||
pair<tree_iterator, bool> p = tree_.insert_unique(key, value);
|
std::pair<tree_iterator, bool> p = tree_.insert_unique(key, value);
|
||||||
generation_ += p.second;
|
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) {
|
std::pair<iterator, bool> insert_unique(const value_type &v) {
|
||||||
pair<tree_iterator, bool> p = tree_.insert_unique(v);
|
std::pair<tree_iterator, bool> p = tree_.insert_unique(v);
|
||||||
generation_ += p.second;
|
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) {
|
iterator insert_unique(iterator position, const value_type &v) {
|
||||||
tree_iterator tree_pos = position.iter();
|
tree_iterator tree_pos = position.iter();
|
||||||
|
@ -351,13 +348,13 @@ class safe_btree {
|
||||||
++x.generation_;
|
++x.generation_;
|
||||||
tree_.swap(x.tree_);
|
tree_.swap(x.tree_);
|
||||||
}
|
}
|
||||||
void dump(ostream &os) const {
|
void dump(std::ostream &os) const {
|
||||||
tree_.dump(os);
|
tree_.dump(os);
|
||||||
}
|
}
|
||||||
void verify() const {
|
void verify() const {
|
||||||
tree_.verify();
|
tree_.verify();
|
||||||
}
|
}
|
||||||
int64 generation() const {
|
int64_t generation() const {
|
||||||
return generation_;
|
return generation_;
|
||||||
}
|
}
|
||||||
key_compare key_comp() const { return tree_.key_comp(); }
|
key_compare key_comp() const { return tree_.key_comp(); }
|
||||||
|
@ -379,10 +376,9 @@ class safe_btree {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
btree_type tree_;
|
btree_type tree_;
|
||||||
int64 generation_;
|
int64_t generation_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_SAFE_BTREE_H__
|
#endif // UTIL_BTREE_SAFE_BTREE_H__
|
||||||
|
|
|
@ -22,17 +22,16 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "util/btree/btree_container.h"
|
#include "btree_container.h"
|
||||||
#include "util/btree/btree_map.h"
|
#include "btree_map.h"
|
||||||
#include "util/btree/safe_btree.h"
|
#include "safe_btree.h"
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
|
|
||||||
// The safe_btree_map class is needed mainly for its constructors.
|
// The safe_btree_map class is needed mainly for its constructors.
|
||||||
template <typename Key, typename Value,
|
template <typename Key, typename Value,
|
||||||
typename Compare = less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<pair<const Key, Value> >,
|
typename Alloc = std::allocator<std::pair<const Key, Value> >,
|
||||||
int TargetNodeSize = 256>
|
int TargetNodeSize = 256>
|
||||||
class safe_btree_map : public btree_map_container<
|
class safe_btree_map : public btree_map_container<
|
||||||
safe_btree<btree_map_params<Key, Value, Compare, Alloc, TargetNodeSize> > > {
|
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 btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_SAFE_BTREE_MAP_H__
|
#endif // UTIL_BTREE_SAFE_BTREE_MAP_H__
|
||||||
|
|
|
@ -22,16 +22,15 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "util/btree/btree_container.h"
|
#include "btree_container.h"
|
||||||
#include "util/btree/btree_set.h"
|
#include "btree_set.h"
|
||||||
#include "util/btree/safe_btree.h"
|
#include "safe_btree.h"
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
|
|
||||||
// The safe_btree_set class is needed mainly for its constructors.
|
// The safe_btree_set class is needed mainly for its constructors.
|
||||||
template <typename Key,
|
template <typename Key,
|
||||||
typename Compare = less<Key>,
|
typename Compare = std::less<Key>,
|
||||||
typename Alloc = std::allocator<Key>,
|
typename Alloc = std::allocator<Key>,
|
||||||
int TargetNodeSize = 256>
|
int TargetNodeSize = 256>
|
||||||
class safe_btree_set : public btree_unique_container<
|
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 btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
#endif // UTIL_BTREE_SAFE_BTREE_SET_H__
|
#endif // UTIL_BTREE_SAFE_BTREE_SET_H__
|
||||||
|
|
|
@ -11,58 +11,50 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "base/arena-inl.h"
|
#include "gtest/gtest.h"
|
||||||
#include "base/init_google.h"
|
#include "btree_test.h"
|
||||||
#include "base/integral_types.h"
|
#include "safe_btree_map.h"
|
||||||
#include "base/logging.h"
|
#include "safe_btree_set.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"
|
|
||||||
|
|
||||||
class UnsafeArena;
|
class UnsafeArena;
|
||||||
|
|
||||||
namespace util {
|
|
||||||
namespace btree {
|
namespace btree {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <typename K, int N>
|
template <typename K, int N>
|
||||||
void SetTest() {
|
void SetTest() {
|
||||||
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
|
typedef TestAllocator<K> TestAlloc;
|
||||||
BtreeTest<safe_btree_set<K, less<K>, allocator<K>, N>, set<K> >();
|
BtreeTest<safe_btree_set<K, std::less<K>, std::allocator<K>, N>, std::set<K> >();
|
||||||
BtreeArenaTest<safe_btree_set<K, less<K>, ArenaAlloc, N> >();
|
BtreeAllocatorTest<safe_btree_set<K, std::less<K>, TestAlloc, N> >();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, int N>
|
template <typename K, int N>
|
||||||
void MapTest() {
|
void MapTest() {
|
||||||
typedef ArenaAllocator<K, UnsafeArena> ArenaAlloc;
|
typedef TestAllocator<K> TestAlloc;
|
||||||
BtreeTest<safe_btree_map<K, K, less<K>, allocator<K>, N>, map<K, K> >();
|
BtreeTest<safe_btree_map<K, K, std::less<K>, std::allocator<K>, N>, std::map<K, K> >();
|
||||||
BtreeArenaTest<safe_btree_map<K, K, less<K>, ArenaAlloc, N> >();
|
BtreeAllocatorTest<safe_btree_map<K, K, std::less<K>, TestAlloc, N> >();
|
||||||
BtreeMapTest<safe_btree_map<K, K, less<K>, allocator<K>, 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_32) { SetTest<int32_t, 32>(); }
|
||||||
TEST(SafeBtree, set_int32_64) { SetTest<int32, 64>(); }
|
TEST(SafeBtree, set_int32_64) { SetTest<int32_t, 64>(); }
|
||||||
TEST(SafeBtree, set_int32_128) { SetTest<int32, 128>(); }
|
TEST(SafeBtree, set_int32_128) { SetTest<int32_t, 128>(); }
|
||||||
TEST(SafeBtree, set_int32_256) { SetTest<int32, 256>(); }
|
TEST(SafeBtree, set_int32_256) { SetTest<int32_t, 256>(); }
|
||||||
TEST(SafeBtree, set_int64_256) { SetTest<int64, 256>(); }
|
TEST(SafeBtree, set_int64_256) { SetTest<int64_t, 256>(); }
|
||||||
TEST(SafeBtree, set_string_256) { SetTest<string, 256>(); }
|
TEST(SafeBtree, set_string_256) { SetTest<std::string, 256>(); }
|
||||||
TEST(SafeBtree, set_cord_256) { SetTest<Cord, 256>(); }
|
TEST(SafeBtree, set_pair_256) { SetTest<std::pair<int, int>, 256>(); }
|
||||||
TEST(SafeBtree, set_pair_256) { SetTest<pair<int, int>, 256>(); }
|
TEST(SafeBtree, map_int32_256) { MapTest<int32_t, 256>(); }
|
||||||
TEST(SafeBtree, map_int32_256) { MapTest<int32, 256>(); }
|
TEST(SafeBtree, map_int64_256) { MapTest<int64_t, 256>(); }
|
||||||
TEST(SafeBtree, map_int64_256) { MapTest<int64, 256>(); }
|
TEST(SafeBtree, map_string_256) { MapTest<std::string, 256>(); }
|
||||||
TEST(SafeBtree, map_string_256) { MapTest<string, 256>(); }
|
TEST(SafeBtree, map_pair_256) { MapTest<std::pair<int, int>, 256>(); }
|
||||||
TEST(SafeBtree, map_cord_256) { MapTest<Cord, 256>(); }
|
|
||||||
TEST(SafeBtree, map_pair_256) { MapTest<pair<int, int>, 256>(); }
|
|
||||||
|
|
||||||
TEST(SafeBtree, Comparison) {
|
TEST(SafeBtree, Comparison) {
|
||||||
const int kSetSize = 1201;
|
const int kSetSize = 1201;
|
||||||
safe_btree_set<int64> my_set;
|
safe_btree_set<int64_t> my_set;
|
||||||
for (int i = 0; i < kSetSize; ++i) {
|
for (int i = 0; i < kSetSize; ++i) {
|
||||||
my_set.insert(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_copy == my_set);
|
||||||
EXPECT_TRUE(my_set == my_set_copy);
|
EXPECT_TRUE(my_set == my_set_copy);
|
||||||
EXPECT_FALSE(my_set_copy != my_set);
|
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_copy != my_set);
|
||||||
EXPECT_TRUE(my_set != my_set_copy);
|
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) {
|
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_copy == my_map);
|
||||||
EXPECT_TRUE(my_map == my_map_copy);
|
EXPECT_TRUE(my_map == my_map_copy);
|
||||||
EXPECT_FALSE(my_map_copy != my_map);
|
EXPECT_FALSE(my_map_copy != my_map);
|
||||||
EXPECT_FALSE(my_map != my_map_copy);
|
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_copy == my_map);
|
||||||
EXPECT_FALSE(my_map == my_map_copy);
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
EXPECT_TRUE(my_map_copy != my_map);
|
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_copy != my_map);
|
||||||
EXPECT_TRUE(my_map != my_map_copy);
|
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_copy == my_map);
|
||||||
EXPECT_FALSE(my_map == my_map_copy);
|
EXPECT_FALSE(my_map == my_map_copy);
|
||||||
EXPECT_TRUE(my_map_copy != my_map);
|
EXPECT_TRUE(my_map_copy != my_map);
|
||||||
|
@ -112,10 +104,3 @@ TEST(SafeBtree, Comparison) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace btree
|
} // namespace btree
|
||||||
} // namespace util
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
FLAGS_logtostderr = true;
|
|
||||||
InitGoogle(argv[0], &argc, &argv, true);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue