├── CMakeLists.txt ├── COPYING ├── Makefile ├── README ├── btree.h ├── btree_bench.cc ├── btree_container.h ├── btree_map.h ├── btree_set.h ├── btree_test.cc ├── btree_test.h ├── btree_test_flags.cc ├── safe_btree.h ├── safe_btree_map.h ├── safe_btree_set.h └── safe_btree_test.cc /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Google Inc. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | cmake_minimum_required(VERSION 2.6) 16 | 17 | project(cppbtree CXX) 18 | 19 | option(build_tests "Build B-tree tests" OFF) 20 | add_definitions(-std=c++11) 21 | set(CMAKE_CXX_FLAGS "-g -O2") 22 | 23 | # CMake doesn't have a way to pure template library, 24 | # add_library(cppbtree btree.h btree_map.h btree_set.h 25 | # safe_btree.h safe_btree_map.h safe_btree_set.h) 26 | # set_target_properties(cppbtree PROPERTIES LINKER_LANGUAGE CXX) 27 | 28 | if(build_tests) 29 | enable_testing() 30 | include_directories($ENV{GTEST_ROOT}/include) 31 | link_directories($ENV{GTEST_ROOT}) 32 | add_executable(btree_test btree_test.cc btree_test_flags.cc) 33 | add_executable(safe_btree_test safe_btree_test.cc btree_test_flags.cc) 34 | add_executable(btree_bench btree_bench.cc btree_test_flags.cc) 35 | target_link_libraries(btree_test gtest_main gtest gflags) 36 | target_link_libraries(safe_btree_test gtest_main gtest gflags) 37 | target_link_libraries(btree_bench gflags gtest) 38 | endif() 39 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # CMAKE generated file: DO NOT EDIT! 2 | # Generated by "Unix Makefiles" Generator, CMake Version 2.8 3 | 4 | # Default target executed when no arguments are given to make. 5 | default_target: all 6 | .PHONY : default_target 7 | 8 | #============================================================================= 9 | # Special targets provided by cmake. 10 | 11 | # Disable implicit rules so canonical targets will work. 12 | .SUFFIXES: 13 | 14 | # Remove some rules from gmake that .SUFFIXES does not remove. 15 | SUFFIXES = 16 | 17 | .SUFFIXES: .hpux_make_needs_suffix_list 18 | 19 | # Suppress display of executed commands. 20 | $(VERBOSE).SILENT: 21 | 22 | # A target that is always out of date. 23 | cmake_force: 24 | .PHONY : cmake_force 25 | 26 | #============================================================================= 27 | # Set environment variables for the build. 28 | 29 | # The shell in which to execute make rules. 30 | SHELL = /bin/sh 31 | 32 | # The CMake executable. 33 | CMAKE_COMMAND = "/Applications/CMake 2.8-8.app/Contents/bin/cmake" 34 | 35 | # The command to remove a file. 36 | RM = "/Applications/CMake 2.8-8.app/Contents/bin/cmake" -E remove -f 37 | 38 | # The program to use to edit the cache. 39 | CMAKE_EDIT_COMMAND = "/Applications/CMake 2.8-8.app/Contents/bin/ccmake" 40 | 41 | # The top-level source directory on which CMake was run. 42 | CMAKE_SOURCE_DIR = /Users/jmacd/src/cpp-btree 43 | 44 | # The top-level build directory on which CMake was run. 45 | CMAKE_BINARY_DIR = /Users/jmacd/src/cpp-btree 46 | 47 | #============================================================================= 48 | # Targets provided globally by CMake. 49 | 50 | # Special rule for the target edit_cache 51 | edit_cache: 52 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." 53 | "/Applications/CMake 2.8-8.app/Contents/bin/ccmake" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) 54 | .PHONY : edit_cache 55 | 56 | # Special rule for the target edit_cache 57 | edit_cache/fast: edit_cache 58 | .PHONY : edit_cache/fast 59 | 60 | # Special rule for the target rebuild_cache 61 | rebuild_cache: 62 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." 63 | "/Applications/CMake 2.8-8.app/Contents/bin/cmake" -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) 64 | .PHONY : rebuild_cache 65 | 66 | # Special rule for the target rebuild_cache 67 | rebuild_cache/fast: rebuild_cache 68 | .PHONY : rebuild_cache/fast 69 | 70 | # Special rule for the target test 71 | test: 72 | @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..." 73 | "/Applications/CMake 2.8-8.app/Contents/bin/ctest" --force-new-ctest-process $(ARGS) 74 | .PHONY : test 75 | 76 | # Special rule for the target test 77 | test/fast: test 78 | .PHONY : test/fast 79 | 80 | # The main all target 81 | all: cmake_check_build_system 82 | $(CMAKE_COMMAND) -E cmake_progress_start /Users/jmacd/src/cpp-btree/CMakeFiles /Users/jmacd/src/cpp-btree/CMakeFiles/progress.marks 83 | $(MAKE) -f CMakeFiles/Makefile2 all 84 | $(CMAKE_COMMAND) -E cmake_progress_start /Users/jmacd/src/cpp-btree/CMakeFiles 0 85 | .PHONY : all 86 | 87 | # The main clean target 88 | clean: 89 | $(MAKE) -f CMakeFiles/Makefile2 clean 90 | .PHONY : clean 91 | 92 | # The main clean target 93 | clean/fast: clean 94 | .PHONY : clean/fast 95 | 96 | # Prepare targets for installation. 97 | preinstall: all 98 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 99 | .PHONY : preinstall 100 | 101 | # Prepare targets for installation. 102 | preinstall/fast: 103 | $(MAKE) -f CMakeFiles/Makefile2 preinstall 104 | .PHONY : preinstall/fast 105 | 106 | # clear depends 107 | depend: 108 | $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 109 | .PHONY : depend 110 | 111 | #============================================================================= 112 | # Target rules for targets named btree_bench 113 | 114 | # Build rule for target. 115 | btree_bench: cmake_check_build_system 116 | $(MAKE) -f CMakeFiles/Makefile2 btree_bench 117 | .PHONY : btree_bench 118 | 119 | # fast build rule for target. 120 | btree_bench/fast: 121 | $(MAKE) -f CMakeFiles/btree_bench.dir/build.make CMakeFiles/btree_bench.dir/build 122 | .PHONY : btree_bench/fast 123 | 124 | #============================================================================= 125 | # Target rules for targets named btree_test 126 | 127 | # Build rule for target. 128 | btree_test: cmake_check_build_system 129 | $(MAKE) -f CMakeFiles/Makefile2 btree_test 130 | .PHONY : btree_test 131 | 132 | # fast build rule for target. 133 | btree_test/fast: 134 | $(MAKE) -f CMakeFiles/btree_test.dir/build.make CMakeFiles/btree_test.dir/build 135 | .PHONY : btree_test/fast 136 | 137 | #============================================================================= 138 | # Target rules for targets named safe_btree_test 139 | 140 | # Build rule for target. 141 | safe_btree_test: cmake_check_build_system 142 | $(MAKE) -f CMakeFiles/Makefile2 safe_btree_test 143 | .PHONY : safe_btree_test 144 | 145 | # fast build rule for target. 146 | safe_btree_test/fast: 147 | $(MAKE) -f CMakeFiles/safe_btree_test.dir/build.make CMakeFiles/safe_btree_test.dir/build 148 | .PHONY : safe_btree_test/fast 149 | 150 | btree_bench.o: btree_bench.cc.o 151 | .PHONY : btree_bench.o 152 | 153 | # target to build an object file 154 | btree_bench.cc.o: 155 | $(MAKE) -f CMakeFiles/btree_bench.dir/build.make CMakeFiles/btree_bench.dir/btree_bench.cc.o 156 | .PHONY : btree_bench.cc.o 157 | 158 | btree_bench.i: btree_bench.cc.i 159 | .PHONY : btree_bench.i 160 | 161 | # target to preprocess a source file 162 | btree_bench.cc.i: 163 | $(MAKE) -f CMakeFiles/btree_bench.dir/build.make CMakeFiles/btree_bench.dir/btree_bench.cc.i 164 | .PHONY : btree_bench.cc.i 165 | 166 | btree_bench.s: btree_bench.cc.s 167 | .PHONY : btree_bench.s 168 | 169 | # target to generate assembly for a file 170 | btree_bench.cc.s: 171 | $(MAKE) -f CMakeFiles/btree_bench.dir/build.make CMakeFiles/btree_bench.dir/btree_bench.cc.s 172 | .PHONY : btree_bench.cc.s 173 | 174 | btree_test.o: btree_test.cc.o 175 | .PHONY : btree_test.o 176 | 177 | # target to build an object file 178 | btree_test.cc.o: 179 | $(MAKE) -f CMakeFiles/btree_test.dir/build.make CMakeFiles/btree_test.dir/btree_test.cc.o 180 | .PHONY : btree_test.cc.o 181 | 182 | btree_test.i: btree_test.cc.i 183 | .PHONY : btree_test.i 184 | 185 | # target to preprocess a source file 186 | btree_test.cc.i: 187 | $(MAKE) -f CMakeFiles/btree_test.dir/build.make CMakeFiles/btree_test.dir/btree_test.cc.i 188 | .PHONY : btree_test.cc.i 189 | 190 | btree_test.s: btree_test.cc.s 191 | .PHONY : btree_test.s 192 | 193 | # target to generate assembly for a file 194 | btree_test.cc.s: 195 | $(MAKE) -f CMakeFiles/btree_test.dir/build.make CMakeFiles/btree_test.dir/btree_test.cc.s 196 | .PHONY : btree_test.cc.s 197 | 198 | btree_test_flags.o: btree_test_flags.cc.o 199 | .PHONY : btree_test_flags.o 200 | 201 | # target to build an object file 202 | btree_test_flags.cc.o: 203 | $(MAKE) -f CMakeFiles/btree_bench.dir/build.make CMakeFiles/btree_bench.dir/btree_test_flags.cc.o 204 | $(MAKE) -f CMakeFiles/btree_test.dir/build.make CMakeFiles/btree_test.dir/btree_test_flags.cc.o 205 | $(MAKE) -f CMakeFiles/safe_btree_test.dir/build.make CMakeFiles/safe_btree_test.dir/btree_test_flags.cc.o 206 | .PHONY : btree_test_flags.cc.o 207 | 208 | btree_test_flags.i: btree_test_flags.cc.i 209 | .PHONY : btree_test_flags.i 210 | 211 | # target to preprocess a source file 212 | btree_test_flags.cc.i: 213 | $(MAKE) -f CMakeFiles/btree_bench.dir/build.make CMakeFiles/btree_bench.dir/btree_test_flags.cc.i 214 | $(MAKE) -f CMakeFiles/btree_test.dir/build.make CMakeFiles/btree_test.dir/btree_test_flags.cc.i 215 | $(MAKE) -f CMakeFiles/safe_btree_test.dir/build.make CMakeFiles/safe_btree_test.dir/btree_test_flags.cc.i 216 | .PHONY : btree_test_flags.cc.i 217 | 218 | btree_test_flags.s: btree_test_flags.cc.s 219 | .PHONY : btree_test_flags.s 220 | 221 | # target to generate assembly for a file 222 | btree_test_flags.cc.s: 223 | $(MAKE) -f CMakeFiles/btree_bench.dir/build.make CMakeFiles/btree_bench.dir/btree_test_flags.cc.s 224 | $(MAKE) -f CMakeFiles/btree_test.dir/build.make CMakeFiles/btree_test.dir/btree_test_flags.cc.s 225 | $(MAKE) -f CMakeFiles/safe_btree_test.dir/build.make CMakeFiles/safe_btree_test.dir/btree_test_flags.cc.s 226 | .PHONY : btree_test_flags.cc.s 227 | 228 | safe_btree_test.o: safe_btree_test.cc.o 229 | .PHONY : safe_btree_test.o 230 | 231 | # target to build an object file 232 | safe_btree_test.cc.o: 233 | $(MAKE) -f CMakeFiles/safe_btree_test.dir/build.make CMakeFiles/safe_btree_test.dir/safe_btree_test.cc.o 234 | .PHONY : safe_btree_test.cc.o 235 | 236 | safe_btree_test.i: safe_btree_test.cc.i 237 | .PHONY : safe_btree_test.i 238 | 239 | # target to preprocess a source file 240 | safe_btree_test.cc.i: 241 | $(MAKE) -f CMakeFiles/safe_btree_test.dir/build.make CMakeFiles/safe_btree_test.dir/safe_btree_test.cc.i 242 | .PHONY : safe_btree_test.cc.i 243 | 244 | safe_btree_test.s: safe_btree_test.cc.s 245 | .PHONY : safe_btree_test.s 246 | 247 | # target to generate assembly for a file 248 | safe_btree_test.cc.s: 249 | $(MAKE) -f CMakeFiles/safe_btree_test.dir/build.make CMakeFiles/safe_btree_test.dir/safe_btree_test.cc.s 250 | .PHONY : safe_btree_test.cc.s 251 | 252 | # Help Target 253 | help: 254 | @echo "The following are some of the valid targets for this Makefile:" 255 | @echo "... all (the default if no target is provided)" 256 | @echo "... clean" 257 | @echo "... depend" 258 | @echo "... btree_bench" 259 | @echo "... btree_test" 260 | @echo "... edit_cache" 261 | @echo "... rebuild_cache" 262 | @echo "... safe_btree_test" 263 | @echo "... test" 264 | @echo "... btree_bench.o" 265 | @echo "... btree_bench.i" 266 | @echo "... btree_bench.s" 267 | @echo "... btree_test.o" 268 | @echo "... btree_test.i" 269 | @echo "... btree_test.s" 270 | @echo "... btree_test_flags.o" 271 | @echo "... btree_test_flags.i" 272 | @echo "... btree_test_flags.s" 273 | @echo "... safe_btree_test.o" 274 | @echo "... safe_btree_test.i" 275 | @echo "... safe_btree_test.s" 276 | .PHONY : help 277 | 278 | 279 | 280 | #============================================================================= 281 | # Special targets to cleanup operation of make. 282 | 283 | # Special rule to run CMake to check the build system integrity. 284 | # No rule that depends on this can have commands that come from listfiles 285 | # because they might be regenerated. 286 | cmake_check_build_system: 287 | $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 288 | .PHONY : cmake_check_build_system 289 | 290 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This library is a C++ template library and, as such, there is no 2 | library to build and install. Copy the .h files and use them! 3 | 4 | See http://code.google.com/p/cpp-btree/wiki/UsageInstructions for 5 | details. 6 | 7 | ---- 8 | 9 | To build and run the provided tests, however, you will need to install 10 | CMake, the Google C++ Test framework, and the Google flags package. 11 | 12 | Download and install CMake from http://www.cmake.org 13 | 14 | Download and build the GoogleTest framework from http://code.google.com/p/googletest 15 | 16 | Download and install gflags from https://code.google.com/p/gflags 17 | 18 | export GTEST_ROOT=/path/for/gtest-x.y 19 | 20 | cmake . -Dbuild_tests=ON 21 | -------------------------------------------------------------------------------- /btree.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // A btree implementation of the STL set and map interfaces. A btree is both 16 | // smaller and faster than STL set/map. The red-black tree implementation of 17 | // STL set/map has an overhead of 3 pointers (left, right and parent) plus the 18 | // node color information for each stored value. So a set consumes 20 19 | // bytes for each value stored. This btree implementation stores multiple 20 | // values on fixed size nodes (usually 256 bytes) and doesn't store child 21 | // pointers for leaf nodes. The result is that a btree_set may use much 22 | // less memory per stored value. For the random insertion benchmark in 23 | // btree_test.cc, a btree_set with node-size of 256 uses 4.9 bytes per 24 | // stored value. 25 | // 26 | // The packing of multiple values on to each node of a btree has another effect 27 | // besides better space utilization: better cache locality due to fewer cache 28 | // lines being accessed. Better cache locality translates into faster 29 | // operations. 30 | // 31 | // CAVEATS 32 | // 33 | // Insertions and deletions on a btree can cause splitting, merging or 34 | // rebalancing of btree nodes. And even without these operations, insertions 35 | // and deletions on a btree will move values around within a node. In both 36 | // cases, the result is that insertions and deletions can invalidate iterators 37 | // pointing to values other than the one being inserted/deleted. This is 38 | // notably different from STL set/map which takes care to not invalidate 39 | // iterators on insert/erase except, of course, for iterators pointing to the 40 | // value being erased. A partial workaround when erasing is available: 41 | // erase() returns an iterator pointing to the item just after the one that was 42 | // erased (or end() if none exists). See also safe_btree. 43 | 44 | // PERFORMANCE 45 | // 46 | // btree_bench --benchmarks=. 2>&1 | ./benchmarks.awk 47 | // 48 | // Run on pmattis-warp.nyc (4 X 2200 MHz CPUs); 2010/03/04-15:23:06 49 | // Benchmark STL(ns) B-Tree(ns) @ 50 | // -------------------------------------------------------- 51 | // BM_set_int32_insert 1516 608 +59.89% <256> [40.0, 5.2] 52 | // BM_set_int32_lookup 1160 414 +64.31% <256> [40.0, 5.2] 53 | // BM_set_int32_fulllookup 960 410 +57.29% <256> [40.0, 4.4] 54 | // BM_set_int32_delete 1741 528 +69.67% <256> [40.0, 5.2] 55 | // BM_set_int32_queueaddrem 3078 1046 +66.02% <256> [40.0, 5.5] 56 | // BM_set_int32_mixedaddrem 3600 1384 +61.56% <256> [40.0, 5.3] 57 | // BM_set_int32_fifo 227 113 +50.22% <256> [40.0, 4.4] 58 | // BM_set_int32_fwditer 158 26 +83.54% <256> [40.0, 5.2] 59 | // BM_map_int32_insert 1551 636 +58.99% <256> [48.0, 10.5] 60 | // BM_map_int32_lookup 1200 508 +57.67% <256> [48.0, 10.5] 61 | // BM_map_int32_fulllookup 989 487 +50.76% <256> [48.0, 8.8] 62 | // BM_map_int32_delete 1794 628 +64.99% <256> [48.0, 10.5] 63 | // BM_map_int32_queueaddrem 3189 1266 +60.30% <256> [48.0, 11.6] 64 | // BM_map_int32_mixedaddrem 3822 1623 +57.54% <256> [48.0, 10.9] 65 | // BM_map_int32_fifo 151 134 +11.26% <256> [48.0, 8.8] 66 | // BM_map_int32_fwditer 161 32 +80.12% <256> [48.0, 10.5] 67 | // BM_set_int64_insert 1546 636 +58.86% <256> [40.0, 10.5] 68 | // BM_set_int64_lookup 1200 512 +57.33% <256> [40.0, 10.5] 69 | // BM_set_int64_fulllookup 971 487 +49.85% <256> [40.0, 8.8] 70 | // BM_set_int64_delete 1745 616 +64.70% <256> [40.0, 10.5] 71 | // BM_set_int64_queueaddrem 3163 1195 +62.22% <256> [40.0, 11.6] 72 | // BM_set_int64_mixedaddrem 3760 1564 +58.40% <256> [40.0, 10.9] 73 | // BM_set_int64_fifo 146 103 +29.45% <256> [40.0, 8.8] 74 | // BM_set_int64_fwditer 162 31 +80.86% <256> [40.0, 10.5] 75 | // BM_map_int64_insert 1551 720 +53.58% <256> [48.0, 20.7] 76 | // BM_map_int64_lookup 1214 612 +49.59% <256> [48.0, 20.7] 77 | // BM_map_int64_fulllookup 994 592 +40.44% <256> [48.0, 17.2] 78 | // BM_map_int64_delete 1778 764 +57.03% <256> [48.0, 20.7] 79 | // BM_map_int64_queueaddrem 3189 1547 +51.49% <256> [48.0, 20.9] 80 | // BM_map_int64_mixedaddrem 3779 1887 +50.07% <256> [48.0, 21.6] 81 | // BM_map_int64_fifo 147 145 +1.36% <256> [48.0, 17.2] 82 | // BM_map_int64_fwditer 162 41 +74.69% <256> [48.0, 20.7] 83 | // BM_set_string_insert 1989 1966 +1.16% <256> [64.0, 44.5] 84 | // BM_set_string_lookup 1709 1600 +6.38% <256> [64.0, 44.5] 85 | // BM_set_string_fulllookup 1573 1529 +2.80% <256> [64.0, 35.4] 86 | // BM_set_string_delete 2520 1920 +23.81% <256> [64.0, 44.5] 87 | // BM_set_string_queueaddrem 4706 4309 +8.44% <256> [64.0, 48.3] 88 | // BM_set_string_mixedaddrem 5080 4654 +8.39% <256> [64.0, 46.7] 89 | // BM_set_string_fifo 318 512 -61.01% <256> [64.0, 35.4] 90 | // BM_set_string_fwditer 182 93 +48.90% <256> [64.0, 44.5] 91 | // BM_map_string_insert 2600 2227 +14.35% <256> [72.0, 55.8] 92 | // BM_map_string_lookup 2068 1730 +16.34% <256> [72.0, 55.8] 93 | // BM_map_string_fulllookup 1859 1618 +12.96% <256> [72.0, 44.0] 94 | // BM_map_string_delete 3168 2080 +34.34% <256> [72.0, 55.8] 95 | // BM_map_string_queueaddrem 5840 4701 +19.50% <256> [72.0, 59.4] 96 | // BM_map_string_mixedaddrem 6400 5200 +18.75% <256> [72.0, 57.8] 97 | // BM_map_string_fifo 398 596 -49.75% <256> [72.0, 44.0] 98 | // BM_map_string_fwditer 243 113 +53.50% <256> [72.0, 55.8] 99 | 100 | #ifndef UTIL_BTREE_BTREE_H__ 101 | #define UTIL_BTREE_BTREE_H__ 102 | 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include 117 | 118 | #ifndef NDEBUG 119 | #define NDEBUG 1 120 | #endif 121 | 122 | namespace btree { 123 | 124 | // Inside a btree method, if we just call swap(), it will choose the 125 | // btree::swap method, which we don't want. And we can't say ::swap 126 | // because then MSVC won't pickup any std::swap() implementations. We 127 | // can't just use std::swap() directly because then we don't get the 128 | // specialization for types outside the std namespace. So the solution 129 | // is to have a special swap helper function whose name doesn't 130 | // collide with other swap functions defined by the btree classes. 131 | template 132 | inline void btree_swap_helper(T &a, T &b) { 133 | using std::swap; 134 | swap(a, b); 135 | } 136 | 137 | // A template helper used to select A or B based on a condition. 138 | template 139 | struct if_{ 140 | typedef A type; 141 | }; 142 | 143 | template 144 | struct if_ { 145 | typedef B type; 146 | }; 147 | 148 | // Types small_ and big_ are promise that sizeof(small_) < sizeof(big_) 149 | typedef char small_; 150 | 151 | struct big_ { 152 | char dummy[2]; 153 | }; 154 | 155 | // A compile-time assertion. 156 | template 157 | struct CompileAssert { 158 | }; 159 | 160 | #define COMPILE_ASSERT(expr, msg) \ 161 | typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] 162 | 163 | // A helper type used to indicate that a key-compare-to functor has been 164 | // provided. A user can specify a key-compare-to functor by doing: 165 | // 166 | // struct MyStringComparer 167 | // : public util::btree::btree_key_compare_to_tag { 168 | // int operator()(const string &a, const string &b) const { 169 | // return a.compare(b); 170 | // } 171 | // }; 172 | // 173 | // Note that the return type is an int and not a bool. There is a 174 | // COMPILE_ASSERT which enforces this return type. 175 | struct btree_key_compare_to_tag { 176 | }; 177 | 178 | // A helper class that indicates if the Compare parameter is derived from 179 | // btree_key_compare_to_tag. 180 | template 181 | struct btree_is_key_compare_to 182 | : public std::is_convertible { 183 | }; 184 | 185 | // A helper class to convert a boolean comparison into a three-way 186 | // "compare-to" comparison that returns a negative value to indicate 187 | // less-than, zero to indicate equality and a positive value to 188 | // indicate greater-than. This helper class is specialized for 189 | // less and greater. The btree_key_compare_to_adapter 190 | // class is provided so that btree users automatically get the more 191 | // efficient compare-to code when using common google string types 192 | // with common comparison functors. 193 | template 194 | struct btree_key_compare_to_adapter : Compare { 195 | btree_key_compare_to_adapter() { } 196 | btree_key_compare_to_adapter(const Compare &c) : Compare(c) { } 197 | btree_key_compare_to_adapter(const btree_key_compare_to_adapter &c) 198 | : Compare(c) { 199 | } 200 | }; 201 | 202 | template <> 203 | struct btree_key_compare_to_adapter > 204 | : public btree_key_compare_to_tag { 205 | btree_key_compare_to_adapter() {} 206 | btree_key_compare_to_adapter(const std::less&) {} 207 | btree_key_compare_to_adapter( 208 | const btree_key_compare_to_adapter >&) {} 209 | int operator()(const std::string &a, const std::string &b) const { 210 | return a.compare(b); 211 | } 212 | }; 213 | 214 | template <> 215 | struct btree_key_compare_to_adapter > 216 | : public btree_key_compare_to_tag { 217 | btree_key_compare_to_adapter() {} 218 | btree_key_compare_to_adapter(const std::greater&) {} 219 | btree_key_compare_to_adapter( 220 | const btree_key_compare_to_adapter >&) {} 221 | int operator()(const std::string &a, const std::string &b) const { 222 | return b.compare(a); 223 | } 224 | }; 225 | 226 | // A helper class that allows a compare-to functor to behave like a plain 227 | // compare functor. This specialization is used when we do not have a 228 | // compare-to functor. 229 | template 230 | struct btree_key_comparer { 231 | btree_key_comparer() {} 232 | btree_key_comparer(Compare c) : comp(c) {} 233 | static bool bool_compare(const Compare &comp, const Key &x, const Key &y) { 234 | return comp(x, y); 235 | } 236 | bool operator()(const Key &x, const Key &y) const { 237 | return bool_compare(comp, x, y); 238 | } 239 | Compare comp; 240 | }; 241 | 242 | // A specialization of btree_key_comparer when a compare-to functor is 243 | // present. We need a plain (boolean) comparison in some parts of the btree 244 | // code, such as insert-with-hint. 245 | template 246 | struct btree_key_comparer { 247 | btree_key_comparer() {} 248 | btree_key_comparer(Compare c) : comp(c) {} 249 | static bool bool_compare(const Compare &comp, const Key &x, const Key &y) { 250 | return comp(x, y) < 0; 251 | } 252 | bool operator()(const Key &x, const Key &y) const { 253 | return bool_compare(comp, x, y); 254 | } 255 | Compare comp; 256 | }; 257 | 258 | // A helper function to compare to keys using the specified compare 259 | // functor. This dispatches to the appropriate btree_key_comparer comparison, 260 | // depending on whether we have a compare-to functor or not (which depends on 261 | // whether Compare is derived from btree_key_compare_to_tag). 262 | template 263 | static bool btree_compare_keys( 264 | const Compare &comp, const Key &x, const Key &y) { 265 | typedef btree_key_comparer::value> key_comparer; 267 | return key_comparer::bool_compare(comp, x, y); 268 | } 269 | 270 | template 272 | struct btree_common_params { 273 | // If Compare is derived from btree_key_compare_to_tag then use it as the 274 | // key_compare type. Otherwise, use btree_key_compare_to_adapter<> which will 275 | // fall-back to Compare if we don't have an appropriate specialization. 276 | typedef typename if_< 277 | btree_is_key_compare_to::value, 278 | Compare, btree_key_compare_to_adapter >::type key_compare; 279 | // A type which indicates if we have a key-compare-to functor or a plain old 280 | // key-compare functor. 281 | typedef btree_is_key_compare_to is_key_compare_to; 282 | 283 | typedef Alloc allocator_type; 284 | typedef Key key_type; 285 | typedef ssize_t size_type; 286 | typedef ptrdiff_t difference_type; 287 | 288 | enum { 289 | kTargetNodeSize = TargetNodeSize, 290 | 291 | // Available space for values. This is largest for leaf nodes, 292 | // which has overhead no fewer than two pointers. 293 | kNodeValueSpace = TargetNodeSize - 2 * sizeof(void*), 294 | }; 295 | 296 | // This is an integral type large enough to hold as many 297 | // ValueSize-values as will fit a node of TargetNodeSize bytes. 298 | typedef typename if_< 299 | (kNodeValueSpace / ValueSize) >= 256, 300 | uint16_t, 301 | uint8_t>::type node_count_type; 302 | }; 303 | 304 | // A parameters structure for holding the type parameters for a btree_map. 305 | template 307 | struct btree_map_params 308 | : public btree_common_params { 310 | typedef Data data_type; 311 | typedef Data mapped_type; 312 | typedef std::pair value_type; 313 | typedef std::pair mutable_value_type; 314 | typedef value_type* pointer; 315 | typedef const value_type* const_pointer; 316 | typedef value_type& reference; 317 | typedef const value_type& const_reference; 318 | 319 | enum { 320 | kValueSize = sizeof(Key) + sizeof(data_type), 321 | }; 322 | 323 | static const Key& key(const value_type &x) { return x.first; } 324 | static const Key& key(const mutable_value_type &x) { return x.first; } 325 | static void swap(mutable_value_type *a, mutable_value_type *b) { 326 | btree_swap_helper(a->first, b->first); 327 | btree_swap_helper(a->second, b->second); 328 | } 329 | }; 330 | 331 | // A parameters structure for holding the type parameters for a btree_set. 332 | template 333 | struct btree_set_params 334 | : public btree_common_params { 336 | typedef std::false_type data_type; 337 | typedef std::false_type mapped_type; 338 | typedef Key value_type; 339 | typedef value_type mutable_value_type; 340 | typedef value_type* pointer; 341 | typedef const value_type* const_pointer; 342 | typedef value_type& reference; 343 | typedef const value_type& const_reference; 344 | 345 | enum { 346 | kValueSize = sizeof(Key), 347 | }; 348 | 349 | static const Key& key(const value_type &x) { return x; } 350 | static void swap(mutable_value_type *a, mutable_value_type *b) { 351 | btree_swap_helper(*a, *b); 352 | } 353 | }; 354 | 355 | // An adapter class that converts a lower-bound compare into an upper-bound 356 | // compare. 357 | template 358 | struct btree_upper_bound_adapter : public Compare { 359 | btree_upper_bound_adapter(Compare c) : Compare(c) {} 360 | bool operator()(const Key &a, const Key &b) const { 361 | return !static_cast(*this)(b, a); 362 | } 363 | }; 364 | 365 | template 366 | struct btree_upper_bound_compare_to_adapter : public CompareTo { 367 | btree_upper_bound_compare_to_adapter(CompareTo c) : CompareTo(c) {} 368 | int operator()(const Key &a, const Key &b) const { 369 | return static_cast(*this)(b, a); 370 | } 371 | }; 372 | 373 | // Dispatch helper class for using linear search with plain compare. 374 | template 375 | struct btree_linear_search_plain_compare { 376 | static int lower_bound(const K &k, const N &n, Compare comp) { 377 | return n.linear_search_plain_compare(k, 0, n.count(), comp); 378 | } 379 | static int upper_bound(const K &k, const N &n, Compare comp) { 380 | typedef btree_upper_bound_adapter upper_compare; 381 | return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp)); 382 | } 383 | }; 384 | 385 | // Dispatch helper class for using linear search with compare-to 386 | template 387 | struct btree_linear_search_compare_to { 388 | static int lower_bound(const K &k, const N &n, CompareTo comp) { 389 | return n.linear_search_compare_to(k, 0, n.count(), comp); 390 | } 391 | static int upper_bound(const K &k, const N &n, CompareTo comp) { 392 | typedef btree_upper_bound_adapter > upper_compare; 394 | return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp)); 395 | } 396 | }; 397 | 398 | // Dispatch helper class for using binary search with plain compare. 399 | template 400 | struct btree_binary_search_plain_compare { 401 | static int lower_bound(const K &k, const N &n, Compare comp) { 402 | return n.binary_search_plain_compare(k, 0, n.count(), comp); 403 | } 404 | static int upper_bound(const K &k, const N &n, Compare comp) { 405 | typedef btree_upper_bound_adapter upper_compare; 406 | return n.binary_search_plain_compare(k, 0, n.count(), upper_compare(comp)); 407 | } 408 | }; 409 | 410 | // Dispatch helper class for using binary search with compare-to. 411 | template 412 | struct btree_binary_search_compare_to { 413 | static int lower_bound(const K &k, const N &n, CompareTo comp) { 414 | return n.binary_search_compare_to(k, 0, n.count(), CompareTo()); 415 | } 416 | static int upper_bound(const K &k, const N &n, CompareTo comp) { 417 | typedef btree_upper_bound_adapter > upper_compare; 419 | return n.linear_search_plain_compare(k, 0, n.count(), upper_compare(comp)); 420 | } 421 | }; 422 | 423 | // A node in the btree holding. The same node type is used for both internal 424 | // and leaf nodes in the btree, though the nodes are allocated in such a way 425 | // that the children array is only valid in internal nodes. 426 | template 427 | class btree_node { 428 | public: 429 | typedef Params params_type; 430 | typedef btree_node self_type; 431 | typedef typename Params::key_type key_type; 432 | typedef typename Params::data_type data_type; 433 | typedef typename Params::value_type value_type; 434 | typedef typename Params::mutable_value_type mutable_value_type; 435 | typedef typename Params::pointer pointer; 436 | typedef typename Params::const_pointer const_pointer; 437 | typedef typename Params::reference reference; 438 | typedef typename Params::const_reference const_reference; 439 | typedef typename Params::key_compare key_compare; 440 | typedef typename Params::size_type size_type; 441 | typedef typename Params::difference_type difference_type; 442 | // Typedefs for the various types of node searches. 443 | typedef btree_linear_search_plain_compare< 444 | key_type, self_type, key_compare> linear_search_plain_compare_type; 445 | typedef btree_linear_search_compare_to< 446 | key_type, self_type, key_compare> linear_search_compare_to_type; 447 | typedef btree_binary_search_plain_compare< 448 | key_type, self_type, key_compare> binary_search_plain_compare_type; 449 | typedef btree_binary_search_compare_to< 450 | key_type, self_type, key_compare> binary_search_compare_to_type; 451 | // If we have a valid key-compare-to type, use linear_search_compare_to, 452 | // otherwise use linear_search_plain_compare. 453 | typedef typename if_< 454 | Params::is_key_compare_to::value, 455 | linear_search_compare_to_type, 456 | linear_search_plain_compare_type>::type linear_search_type; 457 | // If we have a valid key-compare-to type, use binary_search_compare_to, 458 | // otherwise use binary_search_plain_compare. 459 | typedef typename if_< 460 | Params::is_key_compare_to::value, 461 | binary_search_compare_to_type, 462 | binary_search_plain_compare_type>::type binary_search_type; 463 | // If the key is an integral or floating point type, use linear search which 464 | // is faster than binary search for such types. Might be wise to also 465 | // configure linear search based on node-size. 466 | typedef typename if_< 467 | std::is_integral::value || 468 | std::is_floating_point::value, 469 | linear_search_type, binary_search_type>::type search_type; 470 | 471 | struct base_fields { 472 | typedef typename Params::node_count_type field_type; 473 | 474 | // A boolean indicating whether the node is a leaf or not. 475 | bool leaf; 476 | // The position of the node in the node's parent. 477 | field_type position; 478 | // The maximum number of values the node can hold. 479 | field_type max_count; 480 | // The count of the number of values in the node. 481 | field_type count; 482 | // A pointer to the node's parent. 483 | btree_node *parent; 484 | }; 485 | 486 | enum { 487 | kValueSize = params_type::kValueSize, 488 | kTargetNodeSize = params_type::kTargetNodeSize, 489 | 490 | // Compute how many values we can fit onto a leaf node. 491 | kNodeTargetValues = (kTargetNodeSize - sizeof(base_fields)) / kValueSize, 492 | // We need a minimum of 3 values per internal node in order to perform 493 | // splitting (1 value for the two nodes involved in the split and 1 value 494 | // propagated to the parent as the delimiter for the split). 495 | kNodeValues = kNodeTargetValues >= 3 ? kNodeTargetValues : 3, 496 | 497 | kExactMatch = 1 << 30, 498 | kMatchMask = kExactMatch - 1, 499 | }; 500 | 501 | struct leaf_fields : public base_fields { 502 | // The array of values. Only the first count of these values have been 503 | // constructed and are valid. 504 | mutable_value_type values[kNodeValues]; 505 | }; 506 | 507 | struct internal_fields : public leaf_fields { 508 | // The array of child pointers. The keys in children_[i] are all less than 509 | // key(i). The keys in children_[i + 1] are all greater than key(i). There 510 | // are always count + 1 children. 511 | btree_node *children[kNodeValues + 1]; 512 | }; 513 | 514 | struct root_fields : public internal_fields { 515 | btree_node *rightmost; 516 | size_type size; 517 | }; 518 | 519 | public: 520 | // Getter/setter for whether this is a leaf node or not. This value doesn't 521 | // change after the node is created. 522 | bool leaf() const { return fields_.leaf; } 523 | 524 | // Getter for the position of this node in its parent. 525 | int position() const { return fields_.position; } 526 | void set_position(int v) { fields_.position = v; } 527 | 528 | // Getter/setter for the number of values stored in this node. 529 | int count() const { return fields_.count; } 530 | void set_count(int v) { fields_.count = v; } 531 | int max_count() const { return fields_.max_count; } 532 | 533 | // Getter for the parent of this node. 534 | btree_node* parent() const { return fields_.parent; } 535 | // Getter for whether the node is the root of the tree. The parent of the 536 | // root of the tree is the leftmost node in the tree which is guaranteed to 537 | // be a leaf. 538 | bool is_root() const { return parent()->leaf(); } 539 | void make_root() { 540 | assert(parent()->is_root()); 541 | fields_.parent = fields_.parent->parent(); 542 | } 543 | 544 | // Getter for the rightmost root node field. Only valid on the root node. 545 | btree_node* rightmost() const { return fields_.rightmost; } 546 | btree_node** mutable_rightmost() { return &fields_.rightmost; } 547 | 548 | // Getter for the size root node field. Only valid on the root node. 549 | size_type size() const { return fields_.size; } 550 | size_type* mutable_size() { return &fields_.size; } 551 | 552 | // Getters for the key/value at position i in the node. 553 | const key_type& key(int i) const { 554 | return params_type::key(fields_.values[i]); 555 | } 556 | reference value(int i) { 557 | return reinterpret_cast(fields_.values[i]); 558 | } 559 | const_reference value(int i) const { 560 | return reinterpret_cast(fields_.values[i]); 561 | } 562 | mutable_value_type* mutable_value(int i) { 563 | return &fields_.values[i]; 564 | } 565 | 566 | // Swap value i in this node with value j in node x. 567 | void value_swap(int i, btree_node *x, int j) { 568 | params_type::swap(mutable_value(i), x->mutable_value(j)); 569 | } 570 | 571 | // Getters/setter for the child at position i in the node. 572 | btree_node* child(int i) const { return fields_.children[i]; } 573 | btree_node** mutable_child(int i) { return &fields_.children[i]; } 574 | void set_child(int i, btree_node *c) { 575 | *mutable_child(i) = c; 576 | c->fields_.parent = this; 577 | c->fields_.position = i; 578 | } 579 | 580 | // Returns the position of the first value whose key is not less than k. 581 | template 582 | int lower_bound(const key_type &k, const Compare &comp) const { 583 | return search_type::lower_bound(k, *this, comp); 584 | } 585 | // Returns the position of the first value whose key is greater than k. 586 | template 587 | int upper_bound(const key_type &k, const Compare &comp) const { 588 | return search_type::upper_bound(k, *this, comp); 589 | } 590 | 591 | // Returns the position of the first value whose key is not less than k using 592 | // linear search performed using plain compare. 593 | template 594 | int linear_search_plain_compare( 595 | const key_type &k, int s, int e, const Compare &comp) const { 596 | while (s < e) { 597 | if (!btree_compare_keys(comp, key(s), k)) { 598 | break; 599 | } 600 | ++s; 601 | } 602 | return s; 603 | } 604 | 605 | // Returns the position of the first value whose key is not less than k using 606 | // linear search performed using compare-to. 607 | template 608 | int linear_search_compare_to( 609 | const key_type &k, int s, int e, const Compare &comp) const { 610 | while (s < e) { 611 | int c = comp(key(s), k); 612 | if (c == 0) { 613 | return s | kExactMatch; 614 | } else if (c > 0) { 615 | break; 616 | } 617 | ++s; 618 | } 619 | return s; 620 | } 621 | 622 | // Returns the position of the first value whose key is not less than k using 623 | // binary search performed using plain compare. 624 | template 625 | int binary_search_plain_compare( 626 | const key_type &k, int s, int e, const Compare &comp) const { 627 | while (s != e) { 628 | int mid = (s + e) / 2; 629 | if (btree_compare_keys(comp, key(mid), k)) { 630 | s = mid + 1; 631 | } else { 632 | e = mid; 633 | } 634 | } 635 | return s; 636 | } 637 | 638 | // Returns the position of the first value whose key is not less than k using 639 | // binary search performed using compare-to. 640 | template 641 | int binary_search_compare_to( 642 | const key_type &k, int s, int e, const CompareTo &comp) const { 643 | while (s != e) { 644 | int mid = (s + e) / 2; 645 | int c = comp(key(mid), k); 646 | if (c < 0) { 647 | s = mid + 1; 648 | } else if (c > 0) { 649 | e = mid; 650 | } else { 651 | // Need to return the first value whose key is not less than k, which 652 | // requires continuing the binary search. Note that we are guaranteed 653 | // that the result is an exact match because if "key(mid-1) < k" the 654 | // call to binary_search_compare_to() will return "mid". 655 | s = binary_search_compare_to(k, s, mid, comp); 656 | return s | kExactMatch; 657 | } 658 | } 659 | return s; 660 | } 661 | 662 | // Inserts the value x at position i, shifting all existing values and 663 | // children at positions >= i to the right by 1. 664 | void insert_value(int i, const value_type &x); 665 | 666 | // Removes the value at position i, shifting all existing values and children 667 | // at positions > i to the left by 1. 668 | void remove_value(int i); 669 | 670 | // Rebalances a node with its right sibling. 671 | void rebalance_right_to_left(btree_node *sibling, int to_move); 672 | void rebalance_left_to_right(btree_node *sibling, int to_move); 673 | 674 | // Splits a node, moving a portion of the node's values to its right sibling. 675 | void split(btree_node *sibling, int insert_position); 676 | 677 | // Merges a node with its right sibling, moving all of the values and the 678 | // delimiting key in the parent node onto itself. 679 | void merge(btree_node *sibling); 680 | 681 | // Swap the contents of "this" and "src". 682 | void swap(btree_node *src); 683 | 684 | // Node allocation/deletion routines. 685 | static btree_node* init_leaf( 686 | leaf_fields *f, btree_node *parent, int max_count) { 687 | btree_node *n = reinterpret_cast(f); 688 | f->leaf = 1; 689 | f->position = 0; 690 | f->max_count = max_count; 691 | f->count = 0; 692 | f->parent = parent; 693 | if (!NDEBUG) { 694 | memset(&f->values, 0, max_count * sizeof(value_type)); 695 | } 696 | return n; 697 | } 698 | static btree_node* init_internal(internal_fields *f, btree_node *parent) { 699 | btree_node *n = init_leaf(f, parent, kNodeValues); 700 | f->leaf = 0; 701 | if (!NDEBUG) { 702 | memset(f->children, 0, sizeof(f->children)); 703 | } 704 | return n; 705 | } 706 | static btree_node* init_root(root_fields *f, btree_node *parent) { 707 | btree_node *n = init_internal(f, parent); 708 | f->rightmost = parent; 709 | f->size = parent->count(); 710 | return n; 711 | } 712 | void destroy() { 713 | for (int i = 0; i < count(); ++i) { 714 | value_destroy(i); 715 | } 716 | } 717 | 718 | private: 719 | void value_init(int i) { 720 | new (&fields_.values[i]) mutable_value_type; 721 | } 722 | void value_init(int i, const value_type &x) { 723 | new (&fields_.values[i]) mutable_value_type(x); 724 | } 725 | void value_destroy(int i) { 726 | fields_.values[i].~mutable_value_type(); 727 | } 728 | 729 | private: 730 | root_fields fields_; 731 | 732 | private: 733 | btree_node(const btree_node&); 734 | void operator=(const btree_node&); 735 | }; 736 | 737 | template 738 | struct btree_iterator { 739 | typedef typename Node::key_type key_type; 740 | typedef typename Node::size_type size_type; 741 | typedef typename Node::difference_type difference_type; 742 | typedef typename Node::params_type params_type; 743 | 744 | typedef Node node_type; 745 | typedef typename std::remove_const::type normal_node; 746 | typedef const Node const_node; 747 | typedef typename params_type::value_type value_type; 748 | typedef typename params_type::pointer normal_pointer; 749 | typedef typename params_type::reference normal_reference; 750 | typedef typename params_type::const_pointer const_pointer; 751 | typedef typename params_type::const_reference const_reference; 752 | 753 | typedef Pointer pointer; 754 | typedef Reference reference; 755 | typedef std::bidirectional_iterator_tag iterator_category; 756 | 757 | typedef btree_iterator< 758 | normal_node, normal_reference, normal_pointer> iterator; 759 | typedef btree_iterator< 760 | const_node, const_reference, const_pointer> const_iterator; 761 | typedef btree_iterator self_type; 762 | 763 | btree_iterator() 764 | : node(NULL), 765 | position(-1) { 766 | } 767 | btree_iterator(Node *n, int p) 768 | : node(n), 769 | position(p) { 770 | } 771 | btree_iterator(const iterator &x) 772 | : node(x.node), 773 | position(x.position) { 774 | } 775 | 776 | // Increment/decrement the iterator. 777 | void increment() { 778 | if (node->leaf() && ++position < node->count()) { 779 | return; 780 | } 781 | increment_slow(); 782 | } 783 | void increment_by(int count); 784 | void increment_slow(); 785 | 786 | void decrement() { 787 | if (node->leaf() && --position >= 0) { 788 | return; 789 | } 790 | decrement_slow(); 791 | } 792 | void decrement_slow(); 793 | 794 | bool operator==(const const_iterator &x) const { 795 | return node == x.node && position == x.position; 796 | } 797 | bool operator!=(const const_iterator &x) const { 798 | return node != x.node || position != x.position; 799 | } 800 | 801 | // Accessors for the key/value the iterator is pointing at. 802 | const key_type& key() const { 803 | return node->key(position); 804 | } 805 | reference operator*() const { 806 | return node->value(position); 807 | } 808 | pointer operator->() const { 809 | return &node->value(position); 810 | } 811 | 812 | self_type& operator++() { 813 | increment(); 814 | return *this; 815 | } 816 | self_type& operator--() { 817 | decrement(); 818 | return *this; 819 | } 820 | self_type operator++(int) { 821 | self_type tmp = *this; 822 | ++*this; 823 | return tmp; 824 | } 825 | self_type operator--(int) { 826 | self_type tmp = *this; 827 | --*this; 828 | return tmp; 829 | } 830 | 831 | // The node in the tree the iterator is pointing at. 832 | Node *node; 833 | // The position within the node of the tree the iterator is pointing at. 834 | int position; 835 | }; 836 | 837 | // Dispatch helper class for using btree::internal_locate with plain compare. 838 | struct btree_internal_locate_plain_compare { 839 | template 840 | static std::pair dispatch(const K &k, const T &t, Iter iter) { 841 | return t.internal_locate_plain_compare(k, iter); 842 | } 843 | }; 844 | 845 | // Dispatch helper class for using btree::internal_locate with compare-to. 846 | struct btree_internal_locate_compare_to { 847 | template 848 | static std::pair dispatch(const K &k, const T &t, Iter iter) { 849 | return t.internal_locate_compare_to(k, iter); 850 | } 851 | }; 852 | 853 | template 854 | class btree : public Params::key_compare { 855 | typedef btree self_type; 856 | typedef btree_node node_type; 857 | typedef typename node_type::base_fields base_fields; 858 | typedef typename node_type::leaf_fields leaf_fields; 859 | typedef typename node_type::internal_fields internal_fields; 860 | typedef typename node_type::root_fields root_fields; 861 | typedef typename Params::is_key_compare_to is_key_compare_to; 862 | 863 | friend class btree_internal_locate_plain_compare; 864 | friend class btree_internal_locate_compare_to; 865 | typedef typename if_< 866 | is_key_compare_to::value, 867 | btree_internal_locate_compare_to, 868 | btree_internal_locate_plain_compare>::type internal_locate_type; 869 | 870 | enum { 871 | kNodeValues = node_type::kNodeValues, 872 | kMinNodeValues = kNodeValues / 2, 873 | kValueSize = node_type::kValueSize, 874 | kExactMatch = node_type::kExactMatch, 875 | kMatchMask = node_type::kMatchMask, 876 | }; 877 | 878 | // A helper class to get the empty base class optimization for 0-size 879 | // allocators. Base is internal_allocator_type. 880 | // (e.g. empty_base_handle). If Base is 881 | // 0-size, the compiler doesn't have to reserve any space for it and 882 | // sizeof(empty_base_handle) will simply be sizeof(Data). Google [empty base 883 | // class optimization] for more details. 884 | template 885 | struct empty_base_handle : public Base { 886 | empty_base_handle(const Base &b, const Data &d) 887 | : Base(b), 888 | data(d) { 889 | } 890 | Data data; 891 | }; 892 | 893 | struct node_stats { 894 | node_stats(ssize_t l, ssize_t i) 895 | : leaf_nodes(l), 896 | internal_nodes(i) { 897 | } 898 | 899 | node_stats& operator+=(const node_stats &x) { 900 | leaf_nodes += x.leaf_nodes; 901 | internal_nodes += x.internal_nodes; 902 | return *this; 903 | } 904 | 905 | ssize_t leaf_nodes; 906 | ssize_t internal_nodes; 907 | }; 908 | 909 | public: 910 | typedef Params params_type; 911 | typedef typename Params::key_type key_type; 912 | typedef typename Params::data_type data_type; 913 | typedef typename Params::mapped_type mapped_type; 914 | typedef typename Params::value_type value_type; 915 | typedef typename Params::key_compare key_compare; 916 | typedef typename Params::pointer pointer; 917 | typedef typename Params::const_pointer const_pointer; 918 | typedef typename Params::reference reference; 919 | typedef typename Params::const_reference const_reference; 920 | typedef typename Params::size_type size_type; 921 | typedef typename Params::difference_type difference_type; 922 | typedef btree_iterator iterator; 923 | typedef typename iterator::const_iterator const_iterator; 924 | typedef std::reverse_iterator const_reverse_iterator; 925 | typedef std::reverse_iterator reverse_iterator; 926 | 927 | typedef typename Params::allocator_type allocator_type; 928 | typedef typename allocator_type::template rebind::other 929 | internal_allocator_type; 930 | 931 | public: 932 | // Default constructor. 933 | btree(const key_compare &comp, const allocator_type &alloc); 934 | 935 | // Copy constructor. 936 | btree(const self_type &x); 937 | 938 | // Destructor. 939 | ~btree() { 940 | clear(); 941 | } 942 | 943 | // Iterator routines. 944 | iterator begin() { 945 | return iterator(leftmost(), 0); 946 | } 947 | const_iterator begin() const { 948 | return const_iterator(leftmost(), 0); 949 | } 950 | iterator end() { 951 | return iterator(rightmost(), rightmost() ? rightmost()->count() : 0); 952 | } 953 | const_iterator end() const { 954 | return const_iterator(rightmost(), rightmost() ? rightmost()->count() : 0); 955 | } 956 | reverse_iterator rbegin() { 957 | return reverse_iterator(end()); 958 | } 959 | const_reverse_iterator rbegin() const { 960 | return const_reverse_iterator(end()); 961 | } 962 | reverse_iterator rend() { 963 | return reverse_iterator(begin()); 964 | } 965 | const_reverse_iterator rend() const { 966 | return const_reverse_iterator(begin()); 967 | } 968 | 969 | // Finds the first element whose key is not less than key. 970 | iterator lower_bound(const key_type &key) { 971 | return internal_end( 972 | internal_lower_bound(key, iterator(root(), 0))); 973 | } 974 | const_iterator lower_bound(const key_type &key) const { 975 | return internal_end( 976 | internal_lower_bound(key, const_iterator(root(), 0))); 977 | } 978 | 979 | // Finds the first element whose key is greater than key. 980 | iterator upper_bound(const key_type &key) { 981 | return internal_end( 982 | internal_upper_bound(key, iterator(root(), 0))); 983 | } 984 | const_iterator upper_bound(const key_type &key) const { 985 | return internal_end( 986 | internal_upper_bound(key, const_iterator(root(), 0))); 987 | } 988 | 989 | // Finds the range of values which compare equal to key. The first member of 990 | // the returned pair is equal to lower_bound(key). The second member pair of 991 | // the pair is equal to upper_bound(key). 992 | std::pair equal_range(const key_type &key) { 993 | return std::make_pair(lower_bound(key), upper_bound(key)); 994 | } 995 | std::pair equal_range(const key_type &key) const { 996 | return std::make_pair(lower_bound(key), upper_bound(key)); 997 | } 998 | 999 | // Inserts a value into the btree only if it does not already exist. The 1000 | // boolean return value indicates whether insertion succeeded or failed. The 1001 | // ValuePointer type is used to avoid instatiating the value unless the key 1002 | // is being inserted. Value is not dereferenced if the key already exists in 1003 | // the btree. See btree_map::operator[]. 1004 | template 1005 | std::pair insert_unique(const key_type &key, ValuePointer value); 1006 | 1007 | // Inserts a value into the btree only if it does not already exist. The 1008 | // boolean return value indicates whether insertion succeeded or failed. 1009 | std::pair insert_unique(const value_type &v) { 1010 | return insert_unique(params_type::key(v), &v); 1011 | } 1012 | 1013 | // Insert with hint. Check to see if the value should be placed immediately 1014 | // before position in the tree. If it does, then the insertion will take 1015 | // amortized constant time. If not, the insertion will take amortized 1016 | // logarithmic time as if a call to insert_unique(v) were made. 1017 | iterator insert_unique(iterator position, const value_type &v); 1018 | 1019 | // Insert a range of values into the btree. 1020 | template 1021 | void insert_unique(InputIterator b, InputIterator e); 1022 | 1023 | // Inserts a value into the btree. The ValuePointer type is used to avoid 1024 | // instatiating the value unless the key is being inserted. Value is not 1025 | // dereferenced if the key already exists in the btree. See 1026 | // btree_map::operator[]. 1027 | template 1028 | iterator insert_multi(const key_type &key, ValuePointer value); 1029 | 1030 | // Inserts a value into the btree. 1031 | iterator insert_multi(const value_type &v) { 1032 | return insert_multi(params_type::key(v), &v); 1033 | } 1034 | 1035 | // Insert with hint. Check to see if the value should be placed immediately 1036 | // before position in the tree. If it does, then the insertion will take 1037 | // amortized constant time. If not, the insertion will take amortized 1038 | // logarithmic time as if a call to insert_multi(v) were made. 1039 | iterator insert_multi(iterator position, const value_type &v); 1040 | 1041 | // Insert a range of values into the btree. 1042 | template 1043 | void insert_multi(InputIterator b, InputIterator e); 1044 | 1045 | void assign(const self_type &x); 1046 | 1047 | // Erase the specified iterator from the btree. The iterator must be valid 1048 | // (i.e. not equal to end()). Return an iterator pointing to the node after 1049 | // the one that was erased (or end() if none exists). 1050 | iterator erase(iterator iter); 1051 | 1052 | // Erases range. Returns the number of keys erased. 1053 | int erase(iterator begin, iterator end); 1054 | 1055 | // Erases the specified key from the btree. Returns 1 if an element was 1056 | // erased and 0 otherwise. 1057 | int erase_unique(const key_type &key); 1058 | 1059 | // Erases all of the entries matching the specified key from the 1060 | // btree. Returns the number of elements erased. 1061 | int erase_multi(const key_type &key); 1062 | 1063 | // Finds the iterator corresponding to a key or returns end() if the key is 1064 | // not present. 1065 | iterator find_unique(const key_type &key) { 1066 | return internal_end( 1067 | internal_find_unique(key, iterator(root(), 0))); 1068 | } 1069 | const_iterator find_unique(const key_type &key) const { 1070 | return internal_end( 1071 | internal_find_unique(key, const_iterator(root(), 0))); 1072 | } 1073 | iterator find_multi(const key_type &key) { 1074 | return internal_end( 1075 | internal_find_multi(key, iterator(root(), 0))); 1076 | } 1077 | const_iterator find_multi(const key_type &key) const { 1078 | return internal_end( 1079 | internal_find_multi(key, const_iterator(root(), 0))); 1080 | } 1081 | 1082 | // Returns a count of the number of times the key appears in the btree. 1083 | size_type count_unique(const key_type &key) const { 1084 | const_iterator begin = internal_find_unique( 1085 | key, const_iterator(root(), 0)); 1086 | if (!begin.node) { 1087 | // The key doesn't exist in the tree. 1088 | return 0; 1089 | } 1090 | return 1; 1091 | } 1092 | // Returns a count of the number of times the key appears in the btree. 1093 | size_type count_multi(const key_type &key) const { 1094 | return distance(lower_bound(key), upper_bound(key)); 1095 | } 1096 | 1097 | // Clear the btree, deleting all of the values it contains. 1098 | void clear(); 1099 | 1100 | // Swap the contents of *this and x. 1101 | void swap(self_type &x); 1102 | 1103 | // Assign the contents of x to *this. 1104 | self_type& operator=(const self_type &x) { 1105 | if (&x == this) { 1106 | // Don't copy onto ourselves. 1107 | return *this; 1108 | } 1109 | assign(x); 1110 | return *this; 1111 | } 1112 | 1113 | key_compare* mutable_key_comp() { 1114 | return this; 1115 | } 1116 | const key_compare& key_comp() const { 1117 | return *this; 1118 | } 1119 | bool compare_keys(const key_type &x, const key_type &y) const { 1120 | return btree_compare_keys(key_comp(), x, y); 1121 | } 1122 | 1123 | // Dump the btree to the specified ostream. Requires that operator<< is 1124 | // defined for Key and Value. 1125 | void dump(std::ostream &os) const { 1126 | if (root() != NULL) { 1127 | internal_dump(os, root(), 0); 1128 | } 1129 | } 1130 | 1131 | // Verifies the structure of the btree. 1132 | void verify() const; 1133 | 1134 | // Size routines. Note that empty() is slightly faster than doing size()==0. 1135 | size_type size() const { 1136 | if (empty()) return 0; 1137 | if (root()->leaf()) return root()->count(); 1138 | return root()->size(); 1139 | } 1140 | size_type max_size() const { return std::numeric_limits::max(); } 1141 | bool empty() const { return root() == NULL; } 1142 | 1143 | // The height of the btree. An empty tree will have height 0. 1144 | size_type height() const { 1145 | size_type h = 0; 1146 | if (root()) { 1147 | // Count the length of the chain from the leftmost node up to the 1148 | // root. We actually count from the root back around to the level below 1149 | // the root, but the calculation is the same because of the circularity 1150 | // of that traversal. 1151 | const node_type *n = root(); 1152 | do { 1153 | ++h; 1154 | n = n->parent(); 1155 | } while (n != root()); 1156 | } 1157 | return h; 1158 | } 1159 | 1160 | // The number of internal, leaf and total nodes used by the btree. 1161 | size_type leaf_nodes() const { 1162 | return internal_stats(root()).leaf_nodes; 1163 | } 1164 | size_type internal_nodes() const { 1165 | return internal_stats(root()).internal_nodes; 1166 | } 1167 | size_type nodes() const { 1168 | node_stats stats = internal_stats(root()); 1169 | return stats.leaf_nodes + stats.internal_nodes; 1170 | } 1171 | 1172 | // The total number of bytes used by the btree. 1173 | size_type bytes_used() const { 1174 | node_stats stats = internal_stats(root()); 1175 | if (stats.leaf_nodes == 1 && stats.internal_nodes == 0) { 1176 | return sizeof(*this) + 1177 | sizeof(base_fields) + root()->max_count() * sizeof(value_type); 1178 | } else { 1179 | return sizeof(*this) + 1180 | sizeof(root_fields) - sizeof(internal_fields) + 1181 | stats.leaf_nodes * sizeof(leaf_fields) + 1182 | stats.internal_nodes * sizeof(internal_fields); 1183 | } 1184 | } 1185 | 1186 | // The average number of bytes used per value stored in the btree. 1187 | static double average_bytes_per_value() { 1188 | // Returns the number of bytes per value on a leaf node that is 75% 1189 | // full. Experimentally, this matches up nicely with the computed number of 1190 | // bytes per value in trees that had their values inserted in random order. 1191 | return sizeof(leaf_fields) / (kNodeValues * 0.75); 1192 | } 1193 | 1194 | // The fullness of the btree. Computed as the number of elements in the btree 1195 | // divided by the maximum number of elements a tree with the current number 1196 | // of nodes could hold. A value of 1 indicates perfect space 1197 | // utilization. Smaller values indicate space wastage. 1198 | double fullness() const { 1199 | return double(size()) / (nodes() * kNodeValues); 1200 | } 1201 | // The overhead of the btree structure in bytes per node. Computed as the 1202 | // total number of bytes used by the btree minus the number of bytes used for 1203 | // storing elements divided by the number of elements. 1204 | double overhead() const { 1205 | if (empty()) { 1206 | return 0.0; 1207 | } 1208 | return (bytes_used() - size() * kValueSize) / double(size()); 1209 | } 1210 | 1211 | private: 1212 | // Internal accessor routines. 1213 | node_type* root() { return root_.data; } 1214 | const node_type* root() const { return root_.data; } 1215 | node_type** mutable_root() { return &root_.data; } 1216 | 1217 | // The rightmost node is stored in the root node. 1218 | node_type* rightmost() { 1219 | return (!root() || root()->leaf()) ? root() : root()->rightmost(); 1220 | } 1221 | const node_type* rightmost() const { 1222 | return (!root() || root()->leaf()) ? root() : root()->rightmost(); 1223 | } 1224 | node_type** mutable_rightmost() { return root()->mutable_rightmost(); } 1225 | 1226 | // The leftmost node is stored as the parent of the root node. 1227 | node_type* leftmost() { return root() ? root()->parent() : NULL; } 1228 | const node_type* leftmost() const { return root() ? root()->parent() : NULL; } 1229 | 1230 | // The size of the tree is stored in the root node. 1231 | size_type* mutable_size() { return root()->mutable_size(); } 1232 | 1233 | // Allocator routines. 1234 | internal_allocator_type* mutable_internal_allocator() { 1235 | return static_cast(&root_); 1236 | } 1237 | const internal_allocator_type& internal_allocator() const { 1238 | return *static_cast(&root_); 1239 | } 1240 | 1241 | // Node creation/deletion routines. 1242 | node_type* new_internal_node(node_type *parent) { 1243 | internal_fields *p = reinterpret_cast( 1244 | mutable_internal_allocator()->allocate(sizeof(internal_fields))); 1245 | return node_type::init_internal(p, parent); 1246 | } 1247 | node_type* new_internal_root_node() { 1248 | root_fields *p = reinterpret_cast( 1249 | mutable_internal_allocator()->allocate(sizeof(root_fields))); 1250 | return node_type::init_root(p, root()->parent()); 1251 | } 1252 | node_type* new_leaf_node(node_type *parent) { 1253 | leaf_fields *p = reinterpret_cast( 1254 | mutable_internal_allocator()->allocate(sizeof(leaf_fields))); 1255 | return node_type::init_leaf(p, parent, kNodeValues); 1256 | } 1257 | node_type* new_leaf_root_node(int max_count) { 1258 | leaf_fields *p = reinterpret_cast( 1259 | mutable_internal_allocator()->allocate( 1260 | sizeof(base_fields) + max_count * sizeof(value_type))); 1261 | return node_type::init_leaf(p, reinterpret_cast(p), max_count); 1262 | } 1263 | void delete_internal_node(node_type *node) { 1264 | node->destroy(); 1265 | assert(node != root()); 1266 | mutable_internal_allocator()->deallocate( 1267 | reinterpret_cast(node), sizeof(internal_fields)); 1268 | } 1269 | void delete_internal_root_node() { 1270 | root()->destroy(); 1271 | mutable_internal_allocator()->deallocate( 1272 | reinterpret_cast(root()), sizeof(root_fields)); 1273 | } 1274 | void delete_leaf_node(node_type *node) { 1275 | node->destroy(); 1276 | mutable_internal_allocator()->deallocate( 1277 | reinterpret_cast(node), 1278 | sizeof(base_fields) + node->max_count() * sizeof(value_type)); 1279 | } 1280 | 1281 | // Rebalances or splits the node iter points to. 1282 | void rebalance_or_split(iterator *iter); 1283 | 1284 | // Merges the values of left, right and the delimiting key on their parent 1285 | // onto left, removing the delimiting key and deleting right. 1286 | void merge_nodes(node_type *left, node_type *right); 1287 | 1288 | // Tries to merge node with its left or right sibling, and failing that, 1289 | // rebalance with its left or right sibling. Returns true if a merge 1290 | // occurred, at which point it is no longer valid to access node. Returns 1291 | // false if no merging took place. 1292 | bool try_merge_or_rebalance(iterator *iter); 1293 | 1294 | // Tries to shrink the height of the tree by 1. 1295 | void try_shrink(); 1296 | 1297 | iterator internal_end(iterator iter) { 1298 | return iter.node ? iter : end(); 1299 | } 1300 | const_iterator internal_end(const_iterator iter) const { 1301 | return iter.node ? iter : end(); 1302 | } 1303 | 1304 | // Inserts a value into the btree immediately before iter. Requires that 1305 | // key(v) <= iter.key() and (--iter).key() <= key(v). 1306 | iterator internal_insert(iterator iter, const value_type &v); 1307 | 1308 | // Returns an iterator pointing to the first value >= the value "iter" is 1309 | // pointing at. Note that "iter" might be pointing to an invalid location as 1310 | // iter.position == iter.node->count(). This routine simply moves iter up in 1311 | // the tree to a valid location. 1312 | template 1313 | static IterType internal_last(IterType iter); 1314 | 1315 | // Returns an iterator pointing to the leaf position at which key would 1316 | // reside in the tree. We provide 2 versions of internal_locate. The first 1317 | // version (internal_locate_plain_compare) always returns 0 for the second 1318 | // field of the pair. The second version (internal_locate_compare_to) is for 1319 | // the key-compare-to specialization and returns either kExactMatch (if the 1320 | // key was found in the tree) or -kExactMatch (if it wasn't) in the second 1321 | // field of the pair. The compare_to specialization allows the caller to 1322 | // avoid a subsequent comparison to determine if an exact match was made, 1323 | // speeding up string keys. 1324 | template 1325 | std::pair internal_locate( 1326 | const key_type &key, IterType iter) const; 1327 | template 1328 | std::pair internal_locate_plain_compare( 1329 | const key_type &key, IterType iter) const; 1330 | template 1331 | std::pair internal_locate_compare_to( 1332 | const key_type &key, IterType iter) const; 1333 | 1334 | // Internal routine which implements lower_bound(). 1335 | template 1336 | IterType internal_lower_bound( 1337 | const key_type &key, IterType iter) const; 1338 | 1339 | // Internal routine which implements upper_bound(). 1340 | template 1341 | IterType internal_upper_bound( 1342 | const key_type &key, IterType iter) const; 1343 | 1344 | // Internal routine which implements find_unique(). 1345 | template 1346 | IterType internal_find_unique( 1347 | const key_type &key, IterType iter) const; 1348 | 1349 | // Internal routine which implements find_multi(). 1350 | template 1351 | IterType internal_find_multi( 1352 | const key_type &key, IterType iter) const; 1353 | 1354 | // Deletes a node and all of its children. 1355 | void internal_clear(node_type *node); 1356 | 1357 | // Dumps a node and all of its children to the specified ostream. 1358 | void internal_dump(std::ostream &os, const node_type *node, int level) const; 1359 | 1360 | // Verifies the tree structure of node. 1361 | int internal_verify(const node_type *node, 1362 | const key_type *lo, const key_type *hi) const; 1363 | 1364 | node_stats internal_stats(const node_type *node) const { 1365 | if (!node) { 1366 | return node_stats(0, 0); 1367 | } 1368 | if (node->leaf()) { 1369 | return node_stats(1, 0); 1370 | } 1371 | node_stats res(0, 1); 1372 | for (int i = 0; i <= node->count(); ++i) { 1373 | res += internal_stats(node->child(i)); 1374 | } 1375 | return res; 1376 | } 1377 | 1378 | private: 1379 | empty_base_handle root_; 1380 | 1381 | private: 1382 | // A never instantiated helper function that returns big_ if we have a 1383 | // key-compare-to functor or if R is bool and small_ otherwise. 1384 | template 1385 | static typename if_< 1386 | if_, 1388 | std::is_same >::type::value, 1389 | big_, small_>::type key_compare_checker(R); 1390 | 1391 | // A never instantiated helper function that returns the key comparison 1392 | // functor. 1393 | static key_compare key_compare_helper(); 1394 | 1395 | // Verify that key_compare returns a bool. This is similar to the way 1396 | // is_convertible in base/type_traits.h works. Note that key_compare_checker 1397 | // is never actually invoked. The compiler will select which 1398 | // key_compare_checker() to instantiate and then figure out the size of the 1399 | // return type of key_compare_checker() at compile time which we then check 1400 | // against the sizeof of big_. 1401 | COMPILE_ASSERT( 1402 | sizeof(key_compare_checker(key_compare_helper()(key_type(), key_type()))) == 1403 | sizeof(big_), 1404 | key_comparison_function_must_return_bool); 1405 | 1406 | // Note: We insist on kTargetValues, which is computed from 1407 | // Params::kTargetNodeSize, must fit the base_fields::field_type. 1408 | COMPILE_ASSERT(kNodeValues < 1409 | (1 << (8 * sizeof(typename base_fields::field_type))), 1410 | target_node_size_too_large); 1411 | 1412 | // Test the assumption made in setting kNodeValueSpace. 1413 | COMPILE_ASSERT(sizeof(base_fields) >= 2 * sizeof(void*), 1414 | node_space_assumption_incorrect); 1415 | }; 1416 | 1417 | //// 1418 | // btree_node methods 1419 | template 1420 | inline void btree_node

::insert_value(int i, const value_type &x) { 1421 | assert(i <= count()); 1422 | value_init(count(), x); 1423 | for (int j = count(); j > i; --j) { 1424 | value_swap(j, this, j - 1); 1425 | } 1426 | set_count(count() + 1); 1427 | 1428 | if (!leaf()) { 1429 | ++i; 1430 | for (int j = count(); j > i; --j) { 1431 | *mutable_child(j) = child(j - 1); 1432 | child(j)->set_position(j); 1433 | } 1434 | *mutable_child(i) = NULL; 1435 | } 1436 | } 1437 | 1438 | template 1439 | inline void btree_node

::remove_value(int i) { 1440 | if (!leaf()) { 1441 | assert(child(i + 1)->count() == 0); 1442 | for (int j = i + 1; j < count(); ++j) { 1443 | *mutable_child(j) = child(j + 1); 1444 | child(j)->set_position(j); 1445 | } 1446 | *mutable_child(count()) = NULL; 1447 | } 1448 | 1449 | set_count(count() - 1); 1450 | for (; i < count(); ++i) { 1451 | value_swap(i, this, i + 1); 1452 | } 1453 | value_destroy(i); 1454 | } 1455 | 1456 | template 1457 | void btree_node

::rebalance_right_to_left(btree_node *src, int to_move) { 1458 | assert(parent() == src->parent()); 1459 | assert(position() + 1 == src->position()); 1460 | assert(src->count() >= count()); 1461 | assert(to_move >= 1); 1462 | assert(to_move <= src->count()); 1463 | 1464 | // Make room in the left node for the new values. 1465 | for (int i = 0; i < to_move; ++i) { 1466 | value_init(i + count()); 1467 | } 1468 | 1469 | // Move the delimiting value to the left node and the new delimiting value 1470 | // from the right node. 1471 | value_swap(count(), parent(), position()); 1472 | parent()->value_swap(position(), src, to_move - 1); 1473 | 1474 | // Move the values from the right to the left node. 1475 | for (int i = 1; i < to_move; ++i) { 1476 | value_swap(count() + i, src, i - 1); 1477 | } 1478 | // Shift the values in the right node to their correct position. 1479 | for (int i = to_move; i < src->count(); ++i) { 1480 | src->value_swap(i - to_move, src, i); 1481 | } 1482 | for (int i = 1; i <= to_move; ++i) { 1483 | src->value_destroy(src->count() - i); 1484 | } 1485 | 1486 | if (!leaf()) { 1487 | // Move the child pointers from the right to the left node. 1488 | for (int i = 0; i < to_move; ++i) { 1489 | set_child(1 + count() + i, src->child(i)); 1490 | } 1491 | for (int i = 0; i <= src->count() - to_move; ++i) { 1492 | assert(i + to_move <= src->max_count()); 1493 | src->set_child(i, src->child(i + to_move)); 1494 | *src->mutable_child(i + to_move) = NULL; 1495 | } 1496 | } 1497 | 1498 | // Fixup the counts on the src and dest nodes. 1499 | set_count(count() + to_move); 1500 | src->set_count(src->count() - to_move); 1501 | } 1502 | 1503 | template 1504 | void btree_node

::rebalance_left_to_right(btree_node *dest, int to_move) { 1505 | assert(parent() == dest->parent()); 1506 | assert(position() + 1 == dest->position()); 1507 | assert(count() >= dest->count()); 1508 | assert(to_move >= 1); 1509 | assert(to_move <= count()); 1510 | 1511 | // Make room in the right node for the new values. 1512 | for (int i = 0; i < to_move; ++i) { 1513 | dest->value_init(i + dest->count()); 1514 | } 1515 | for (int i = dest->count() - 1; i >= 0; --i) { 1516 | dest->value_swap(i, dest, i + to_move); 1517 | } 1518 | 1519 | // Move the delimiting value to the right node and the new delimiting value 1520 | // from the left node. 1521 | dest->value_swap(to_move - 1, parent(), position()); 1522 | parent()->value_swap(position(), this, count() - to_move); 1523 | value_destroy(count() - to_move); 1524 | 1525 | // Move the values from the left to the right node. 1526 | for (int i = 1; i < to_move; ++i) { 1527 | value_swap(count() - to_move + i, dest, i - 1); 1528 | value_destroy(count() - to_move + i); 1529 | } 1530 | 1531 | if (!leaf()) { 1532 | // Move the child pointers from the left to the right node. 1533 | for (int i = dest->count(); i >= 0; --i) { 1534 | dest->set_child(i + to_move, dest->child(i)); 1535 | *dest->mutable_child(i) = NULL; 1536 | } 1537 | for (int i = 1; i <= to_move; ++i) { 1538 | dest->set_child(i - 1, child(count() - to_move + i)); 1539 | *mutable_child(count() - to_move + i) = NULL; 1540 | } 1541 | } 1542 | 1543 | // Fixup the counts on the src and dest nodes. 1544 | set_count(count() - to_move); 1545 | dest->set_count(dest->count() + to_move); 1546 | } 1547 | 1548 | template 1549 | void btree_node

::split(btree_node *dest, int insert_position) { 1550 | assert(dest->count() == 0); 1551 | 1552 | // We bias the split based on the position being inserted. If we're 1553 | // inserting at the beginning of the left node then bias the split to put 1554 | // more values on the right node. If we're inserting at the end of the 1555 | // right node then bias the split to put more values on the left node. 1556 | if (insert_position == 0) { 1557 | dest->set_count(count() - 1); 1558 | } else if (insert_position == max_count()) { 1559 | dest->set_count(0); 1560 | } else { 1561 | dest->set_count(count() / 2); 1562 | } 1563 | set_count(count() - dest->count()); 1564 | assert(count() >= 1); 1565 | 1566 | // Move values from the left sibling to the right sibling. 1567 | for (int i = 0; i < dest->count(); ++i) { 1568 | dest->value_init(i); 1569 | value_swap(count() + i, dest, i); 1570 | value_destroy(count() + i); 1571 | } 1572 | 1573 | // The split key is the largest value in the left sibling. 1574 | set_count(count() - 1); 1575 | parent()->insert_value(position(), value_type()); 1576 | value_swap(count(), parent(), position()); 1577 | value_destroy(count()); 1578 | parent()->set_child(position() + 1, dest); 1579 | 1580 | if (!leaf()) { 1581 | for (int i = 0; i <= dest->count(); ++i) { 1582 | assert(child(count() + i + 1) != NULL); 1583 | dest->set_child(i, child(count() + i + 1)); 1584 | *mutable_child(count() + i + 1) = NULL; 1585 | } 1586 | } 1587 | } 1588 | 1589 | template 1590 | void btree_node

::merge(btree_node *src) { 1591 | assert(parent() == src->parent()); 1592 | assert(position() + 1 == src->position()); 1593 | 1594 | // Move the delimiting value to the left node. 1595 | value_init(count()); 1596 | value_swap(count(), parent(), position()); 1597 | 1598 | // Move the values from the right to the left node. 1599 | for (int i = 0; i < src->count(); ++i) { 1600 | value_init(1 + count() + i); 1601 | value_swap(1 + count() + i, src, i); 1602 | src->value_destroy(i); 1603 | } 1604 | 1605 | if (!leaf()) { 1606 | // Move the child pointers from the right to the left node. 1607 | for (int i = 0; i <= src->count(); ++i) { 1608 | set_child(1 + count() + i, src->child(i)); 1609 | *src->mutable_child(i) = NULL; 1610 | } 1611 | } 1612 | 1613 | // Fixup the counts on the src and dest nodes. 1614 | set_count(1 + count() + src->count()); 1615 | src->set_count(0); 1616 | 1617 | // Remove the value on the parent node. 1618 | parent()->remove_value(position()); 1619 | } 1620 | 1621 | template 1622 | void btree_node

::swap(btree_node *x) { 1623 | assert(leaf() == x->leaf()); 1624 | 1625 | // Swap the values. 1626 | for (int i = count(); i < x->count(); ++i) { 1627 | value_init(i); 1628 | } 1629 | for (int i = x->count(); i < count(); ++i) { 1630 | x->value_init(i); 1631 | } 1632 | int n = std::max(count(), x->count()); 1633 | for (int i = 0; i < n; ++i) { 1634 | value_swap(i, x, i); 1635 | } 1636 | for (int i = count(); i < x->count(); ++i) { 1637 | x->value_destroy(i); 1638 | } 1639 | for (int i = x->count(); i < count(); ++i) { 1640 | value_destroy(i); 1641 | } 1642 | 1643 | if (!leaf()) { 1644 | // Swap the child pointers. 1645 | for (int i = 0; i <= n; ++i) { 1646 | btree_swap_helper(*mutable_child(i), *x->mutable_child(i)); 1647 | } 1648 | for (int i = 0; i <= count(); ++i) { 1649 | x->child(i)->fields_.parent = x; 1650 | } 1651 | for (int i = 0; i <= x->count(); ++i) { 1652 | child(i)->fields_.parent = this; 1653 | } 1654 | } 1655 | 1656 | // Swap the counts. 1657 | btree_swap_helper(fields_.count, x->fields_.count); 1658 | } 1659 | 1660 | //// 1661 | // btree_iterator methods 1662 | template 1663 | void btree_iterator::increment_slow() { 1664 | if (node->leaf()) { 1665 | assert(position >= node->count()); 1666 | self_type save(*this); 1667 | while (position == node->count() && !node->is_root()) { 1668 | assert(node->parent()->child(node->position()) == node); 1669 | position = node->position(); 1670 | node = node->parent(); 1671 | } 1672 | if (position == node->count()) { 1673 | *this = save; 1674 | } 1675 | } else { 1676 | assert(position < node->count()); 1677 | node = node->child(position + 1); 1678 | while (!node->leaf()) { 1679 | node = node->child(0); 1680 | } 1681 | position = 0; 1682 | } 1683 | } 1684 | 1685 | template 1686 | void btree_iterator::increment_by(int count) { 1687 | while (count > 0) { 1688 | if (node->leaf()) { 1689 | int rest = node->count() - position; 1690 | position += std::min(rest, count); 1691 | count = count - rest; 1692 | if (position < node->count()) { 1693 | return; 1694 | } 1695 | } else { 1696 | --count; 1697 | } 1698 | increment_slow(); 1699 | } 1700 | } 1701 | 1702 | template 1703 | void btree_iterator::decrement_slow() { 1704 | if (node->leaf()) { 1705 | assert(position <= -1); 1706 | self_type save(*this); 1707 | while (position < 0 && !node->is_root()) { 1708 | assert(node->parent()->child(node->position()) == node); 1709 | position = node->position() - 1; 1710 | node = node->parent(); 1711 | } 1712 | if (position < 0) { 1713 | *this = save; 1714 | } 1715 | } else { 1716 | assert(position >= 0); 1717 | node = node->child(position); 1718 | while (!node->leaf()) { 1719 | node = node->child(node->count()); 1720 | } 1721 | position = node->count() - 1; 1722 | } 1723 | } 1724 | 1725 | //// 1726 | // btree methods 1727 | template 1728 | btree

::btree(const key_compare &comp, const allocator_type &alloc) 1729 | : key_compare(comp), 1730 | root_(alloc, NULL) { 1731 | } 1732 | 1733 | template 1734 | btree

::btree(const self_type &x) 1735 | : key_compare(x.key_comp()), 1736 | root_(x.internal_allocator(), NULL) { 1737 | assign(x); 1738 | } 1739 | 1740 | template template 1741 | std::pair::iterator, bool> 1742 | btree

::insert_unique(const key_type &key, ValuePointer value) { 1743 | if (empty()) { 1744 | *mutable_root() = new_leaf_root_node(1); 1745 | } 1746 | 1747 | std::pair res = internal_locate(key, iterator(root(), 0)); 1748 | iterator &iter = res.first; 1749 | if (res.second == kExactMatch) { 1750 | // The key already exists in the tree, do nothing. 1751 | return std::make_pair(internal_last(iter), false); 1752 | } else if (!res.second) { 1753 | iterator last = internal_last(iter); 1754 | if (last.node && !compare_keys(key, last.key())) { 1755 | // The key already exists in the tree, do nothing. 1756 | return std::make_pair(last, false); 1757 | } 1758 | } 1759 | 1760 | return std::make_pair(internal_insert(iter, *value), true); 1761 | } 1762 | 1763 | template 1764 | inline typename btree

::iterator 1765 | btree

::insert_unique(iterator position, const value_type &v) { 1766 | if (!empty()) { 1767 | const key_type &key = params_type::key(v); 1768 | if (position == end() || compare_keys(key, position.key())) { 1769 | iterator prev = position; 1770 | if (position == begin() || compare_keys((--prev).key(), key)) { 1771 | // prev.key() < key < position.key() 1772 | return internal_insert(position, v); 1773 | } 1774 | } else if (compare_keys(position.key(), key)) { 1775 | iterator next = position; 1776 | ++next; 1777 | if (next == end() || compare_keys(key, next.key())) { 1778 | // position.key() < key < next.key() 1779 | return internal_insert(next, v); 1780 | } 1781 | } else { 1782 | // position.key() == key 1783 | return position; 1784 | } 1785 | } 1786 | return insert_unique(v).first; 1787 | } 1788 | 1789 | template template 1790 | void btree

::insert_unique(InputIterator b, InputIterator e) { 1791 | for (; b != e; ++b) { 1792 | insert_unique(end(), *b); 1793 | } 1794 | } 1795 | 1796 | template template 1797 | typename btree

::iterator 1798 | btree

::insert_multi(const key_type &key, ValuePointer value) { 1799 | if (empty()) { 1800 | *mutable_root() = new_leaf_root_node(1); 1801 | } 1802 | 1803 | iterator iter = internal_upper_bound(key, iterator(root(), 0)); 1804 | if (!iter.node) { 1805 | iter = end(); 1806 | } 1807 | return internal_insert(iter, *value); 1808 | } 1809 | 1810 | template 1811 | typename btree

::iterator 1812 | btree

::insert_multi(iterator position, const value_type &v) { 1813 | if (!empty()) { 1814 | const key_type &key = params_type::key(v); 1815 | if (position == end() || !compare_keys(position.key(), key)) { 1816 | iterator prev = position; 1817 | if (position == begin() || !compare_keys(key, (--prev).key())) { 1818 | // prev.key() <= key <= position.key() 1819 | return internal_insert(position, v); 1820 | } 1821 | } else { 1822 | iterator next = position; 1823 | ++next; 1824 | if (next == end() || !compare_keys(next.key(), key)) { 1825 | // position.key() < key <= next.key() 1826 | return internal_insert(next, v); 1827 | } 1828 | } 1829 | } 1830 | return insert_multi(v); 1831 | } 1832 | 1833 | template template 1834 | void btree

::insert_multi(InputIterator b, InputIterator e) { 1835 | for (; b != e; ++b) { 1836 | insert_multi(end(), *b); 1837 | } 1838 | } 1839 | 1840 | template 1841 | void btree

::assign(const self_type &x) { 1842 | clear(); 1843 | 1844 | *mutable_key_comp() = x.key_comp(); 1845 | *mutable_internal_allocator() = x.internal_allocator(); 1846 | 1847 | // Assignment can avoid key comparisons because we know the order of the 1848 | // values is the same order we'll store them in. 1849 | for (const_iterator iter = x.begin(); iter != x.end(); ++iter) { 1850 | if (empty()) { 1851 | insert_multi(*iter); 1852 | } else { 1853 | // If the btree is not empty, we can just insert the new value at the end 1854 | // of the tree! 1855 | internal_insert(end(), *iter); 1856 | } 1857 | } 1858 | } 1859 | 1860 | template 1861 | typename btree

::iterator btree

::erase(iterator iter) { 1862 | bool internal_delete = false; 1863 | if (!iter.node->leaf()) { 1864 | // Deletion of a value on an internal node. Swap the key with the largest 1865 | // value of our left child. This is easy, we just decrement iter. 1866 | iterator tmp_iter(iter--); 1867 | assert(iter.node->leaf()); 1868 | assert(!compare_keys(tmp_iter.key(), iter.key())); 1869 | iter.node->value_swap(iter.position, tmp_iter.node, tmp_iter.position); 1870 | internal_delete = true; 1871 | --*mutable_size(); 1872 | } else if (!root()->leaf()) { 1873 | --*mutable_size(); 1874 | } 1875 | 1876 | // Delete the key from the leaf. 1877 | iter.node->remove_value(iter.position); 1878 | 1879 | // We want to return the next value after the one we just erased. If we 1880 | // erased from an internal node (internal_delete == true), then the next 1881 | // value is ++(++iter). If we erased from a leaf node (internal_delete == 1882 | // false) then the next value is ++iter. Note that ++iter may point to an 1883 | // internal node and the value in the internal node may move to a leaf node 1884 | // (iter.node) when rebalancing is performed at the leaf level. 1885 | 1886 | // Merge/rebalance as we walk back up the tree. 1887 | iterator res(iter); 1888 | for (;;) { 1889 | if (iter.node == root()) { 1890 | try_shrink(); 1891 | if (empty()) { 1892 | return end(); 1893 | } 1894 | break; 1895 | } 1896 | if (iter.node->count() >= kMinNodeValues) { 1897 | break; 1898 | } 1899 | bool merged = try_merge_or_rebalance(&iter); 1900 | if (iter.node->leaf()) { 1901 | res = iter; 1902 | } 1903 | if (!merged) { 1904 | break; 1905 | } 1906 | iter.node = iter.node->parent(); 1907 | } 1908 | 1909 | // Adjust our return value. If we're pointing at the end of a node, advance 1910 | // the iterator. 1911 | if (res.position == res.node->count()) { 1912 | res.position = res.node->count() - 1; 1913 | ++res; 1914 | } 1915 | // If we erased from an internal node, advance the iterator. 1916 | if (internal_delete) { 1917 | ++res; 1918 | } 1919 | return res; 1920 | } 1921 | 1922 | template 1923 | int btree

::erase(iterator begin, iterator end) { 1924 | int count = distance(begin, end); 1925 | for (int i = 0; i < count; i++) { 1926 | begin = erase(begin); 1927 | } 1928 | return count; 1929 | } 1930 | 1931 | template 1932 | int btree

::erase_unique(const key_type &key) { 1933 | iterator iter = internal_find_unique(key, iterator(root(), 0)); 1934 | if (!iter.node) { 1935 | // The key doesn't exist in the tree, return nothing done. 1936 | return 0; 1937 | } 1938 | erase(iter); 1939 | return 1; 1940 | } 1941 | 1942 | template 1943 | int btree

::erase_multi(const key_type &key) { 1944 | iterator begin = internal_lower_bound(key, iterator(root(), 0)); 1945 | if (!begin.node) { 1946 | // The key doesn't exist in the tree, return nothing done. 1947 | return 0; 1948 | } 1949 | // Delete all of the keys between begin and upper_bound(key). 1950 | iterator end = internal_end( 1951 | internal_upper_bound(key, iterator(root(), 0))); 1952 | return erase(begin, end); 1953 | } 1954 | 1955 | template 1956 | void btree

::clear() { 1957 | if (root() != NULL) { 1958 | internal_clear(root()); 1959 | } 1960 | *mutable_root() = NULL; 1961 | } 1962 | 1963 | template 1964 | void btree

::swap(self_type &x) { 1965 | std::swap(static_cast(*this), static_cast(x)); 1966 | std::swap(root_, x.root_); 1967 | } 1968 | 1969 | template 1970 | void btree

::verify() const { 1971 | if (root() != NULL) { 1972 | assert(size() == internal_verify(root(), NULL, NULL)); 1973 | assert(leftmost() == (++const_iterator(root(), -1)).node); 1974 | assert(rightmost() == (--const_iterator(root(), root()->count())).node); 1975 | assert(leftmost()->leaf()); 1976 | assert(rightmost()->leaf()); 1977 | } else { 1978 | assert(size() == 0); 1979 | assert(leftmost() == NULL); 1980 | assert(rightmost() == NULL); 1981 | } 1982 | } 1983 | 1984 | template 1985 | void btree

::rebalance_or_split(iterator *iter) { 1986 | node_type *&node = iter->node; 1987 | int &insert_position = iter->position; 1988 | assert(node->count() == node->max_count()); 1989 | 1990 | // First try to make room on the node by rebalancing. 1991 | node_type *parent = node->parent(); 1992 | if (node != root()) { 1993 | if (node->position() > 0) { 1994 | // Try rebalancing with our left sibling. 1995 | node_type *left = parent->child(node->position() - 1); 1996 | if (left->count() < left->max_count()) { 1997 | // We bias rebalancing based on the position being inserted. If we're 1998 | // inserting at the end of the right node then we bias rebalancing to 1999 | // fill up the left node. 2000 | int to_move = (left->max_count() - left->count()) / 2001 | (1 + (insert_position < left->max_count())); 2002 | to_move = std::max(1, to_move); 2003 | 2004 | if (((insert_position - to_move) >= 0) || 2005 | ((left->count() + to_move) < left->max_count())) { 2006 | left->rebalance_right_to_left(node, to_move); 2007 | 2008 | assert(node->max_count() - node->count() == to_move); 2009 | insert_position = insert_position - to_move; 2010 | if (insert_position < 0) { 2011 | insert_position = insert_position + left->count() + 1; 2012 | node = left; 2013 | } 2014 | 2015 | assert(node->count() < node->max_count()); 2016 | return; 2017 | } 2018 | } 2019 | } 2020 | 2021 | if (node->position() < parent->count()) { 2022 | // Try rebalancing with our right sibling. 2023 | node_type *right = parent->child(node->position() + 1); 2024 | if (right->count() < right->max_count()) { 2025 | // We bias rebalancing based on the position being inserted. If we're 2026 | // inserting at the beginning of the left node then we bias rebalancing 2027 | // to fill up the right node. 2028 | int to_move = (right->max_count() - right->count()) / 2029 | (1 + (insert_position > 0)); 2030 | to_move = std::max(1, to_move); 2031 | 2032 | if ((insert_position <= (node->count() - to_move)) || 2033 | ((right->count() + to_move) < right->max_count())) { 2034 | node->rebalance_left_to_right(right, to_move); 2035 | 2036 | if (insert_position > node->count()) { 2037 | insert_position = insert_position - node->count() - 1; 2038 | node = right; 2039 | } 2040 | 2041 | assert(node->count() < node->max_count()); 2042 | return; 2043 | } 2044 | } 2045 | } 2046 | 2047 | // Rebalancing failed, make sure there is room on the parent node for a new 2048 | // value. 2049 | if (parent->count() == parent->max_count()) { 2050 | iterator parent_iter(node->parent(), node->position()); 2051 | rebalance_or_split(&parent_iter); 2052 | } 2053 | } else { 2054 | // Rebalancing not possible because this is the root node. 2055 | if (root()->leaf()) { 2056 | // The root node is currently a leaf node: create a new root node and set 2057 | // the current root node as the child of the new root. 2058 | parent = new_internal_root_node(); 2059 | parent->set_child(0, root()); 2060 | *mutable_root() = parent; 2061 | assert(*mutable_rightmost() == parent->child(0)); 2062 | } else { 2063 | // The root node is an internal node. We do not want to create a new root 2064 | // node because the root node is special and holds the size of the tree 2065 | // and a pointer to the rightmost node. So we create a new internal node 2066 | // and move all of the items on the current root into the new node. 2067 | parent = new_internal_node(parent); 2068 | parent->set_child(0, parent); 2069 | parent->swap(root()); 2070 | node = parent; 2071 | } 2072 | } 2073 | 2074 | // Split the node. 2075 | node_type *split_node; 2076 | if (node->leaf()) { 2077 | split_node = new_leaf_node(parent); 2078 | node->split(split_node, insert_position); 2079 | if (rightmost() == node) { 2080 | *mutable_rightmost() = split_node; 2081 | } 2082 | } else { 2083 | split_node = new_internal_node(parent); 2084 | node->split(split_node, insert_position); 2085 | } 2086 | 2087 | if (insert_position > node->count()) { 2088 | insert_position = insert_position - node->count() - 1; 2089 | node = split_node; 2090 | } 2091 | } 2092 | 2093 | template 2094 | void btree

::merge_nodes(node_type *left, node_type *right) { 2095 | left->merge(right); 2096 | if (right->leaf()) { 2097 | if (rightmost() == right) { 2098 | *mutable_rightmost() = left; 2099 | } 2100 | delete_leaf_node(right); 2101 | } else { 2102 | delete_internal_node(right); 2103 | } 2104 | } 2105 | 2106 | template 2107 | bool btree

::try_merge_or_rebalance(iterator *iter) { 2108 | node_type *parent = iter->node->parent(); 2109 | if (iter->node->position() > 0) { 2110 | // Try merging with our left sibling. 2111 | node_type *left = parent->child(iter->node->position() - 1); 2112 | if ((1 + left->count() + iter->node->count()) <= left->max_count()) { 2113 | iter->position += 1 + left->count(); 2114 | merge_nodes(left, iter->node); 2115 | iter->node = left; 2116 | return true; 2117 | } 2118 | } 2119 | if (iter->node->position() < parent->count()) { 2120 | // Try merging with our right sibling. 2121 | node_type *right = parent->child(iter->node->position() + 1); 2122 | if ((1 + iter->node->count() + right->count()) <= right->max_count()) { 2123 | merge_nodes(iter->node, right); 2124 | return true; 2125 | } 2126 | // Try rebalancing with our right sibling. We don't perform rebalancing if 2127 | // we deleted the first element from iter->node and the node is not 2128 | // empty. This is a small optimization for the common pattern of deleting 2129 | // from the front of the tree. 2130 | if ((right->count() > kMinNodeValues) && 2131 | ((iter->node->count() == 0) || 2132 | (iter->position > 0))) { 2133 | int to_move = (right->count() - iter->node->count()) / 2; 2134 | to_move = std::min(to_move, right->count() - 1); 2135 | iter->node->rebalance_right_to_left(right, to_move); 2136 | return false; 2137 | } 2138 | } 2139 | if (iter->node->position() > 0) { 2140 | // Try rebalancing with our left sibling. We don't perform rebalancing if 2141 | // we deleted the last element from iter->node and the node is not 2142 | // empty. This is a small optimization for the common pattern of deleting 2143 | // from the back of the tree. 2144 | node_type *left = parent->child(iter->node->position() - 1); 2145 | if ((left->count() > kMinNodeValues) && 2146 | ((iter->node->count() == 0) || 2147 | (iter->position < iter->node->count()))) { 2148 | int to_move = (left->count() - iter->node->count()) / 2; 2149 | to_move = std::min(to_move, left->count() - 1); 2150 | left->rebalance_left_to_right(iter->node, to_move); 2151 | iter->position += to_move; 2152 | return false; 2153 | } 2154 | } 2155 | return false; 2156 | } 2157 | 2158 | template 2159 | void btree

::try_shrink() { 2160 | if (root()->count() > 0) { 2161 | return; 2162 | } 2163 | // Deleted the last item on the root node, shrink the height of the tree. 2164 | if (root()->leaf()) { 2165 | assert(size() == 0); 2166 | delete_leaf_node(root()); 2167 | *mutable_root() = NULL; 2168 | } else { 2169 | node_type *child = root()->child(0); 2170 | if (child->leaf()) { 2171 | // The child is a leaf node so simply make it the root node in the tree. 2172 | child->make_root(); 2173 | delete_internal_root_node(); 2174 | *mutable_root() = child; 2175 | } else { 2176 | // The child is an internal node. We want to keep the existing root node 2177 | // so we move all of the values from the child node into the existing 2178 | // (empty) root node. 2179 | child->swap(root()); 2180 | delete_internal_node(child); 2181 | } 2182 | } 2183 | } 2184 | 2185 | template template 2186 | inline IterType btree

::internal_last(IterType iter) { 2187 | while (iter.node && iter.position == iter.node->count()) { 2188 | iter.position = iter.node->position(); 2189 | iter.node = iter.node->parent(); 2190 | if (iter.node->leaf()) { 2191 | iter.node = NULL; 2192 | } 2193 | } 2194 | return iter; 2195 | } 2196 | 2197 | template 2198 | inline typename btree

::iterator 2199 | btree

::internal_insert(iterator iter, const value_type &v) { 2200 | if (!iter.node->leaf()) { 2201 | // We can't insert on an internal node. Instead, we'll insert after the 2202 | // previous value which is guaranteed to be on a leaf node. 2203 | --iter; 2204 | ++iter.position; 2205 | } 2206 | if (iter.node->count() == iter.node->max_count()) { 2207 | // Make room in the leaf for the new item. 2208 | if (iter.node->max_count() < kNodeValues) { 2209 | // Insertion into the root where the root is smaller that the full node 2210 | // size. Simply grow the size of the root node. 2211 | assert(iter.node == root()); 2212 | iter.node = new_leaf_root_node( 2213 | std::min(kNodeValues, 2 * iter.node->max_count())); 2214 | iter.node->swap(root()); 2215 | delete_leaf_node(root()); 2216 | *mutable_root() = iter.node; 2217 | } else { 2218 | rebalance_or_split(&iter); 2219 | ++*mutable_size(); 2220 | } 2221 | } else if (!root()->leaf()) { 2222 | ++*mutable_size(); 2223 | } 2224 | iter.node->insert_value(iter.position, v); 2225 | return iter; 2226 | } 2227 | 2228 | template template 2229 | inline std::pair btree

::internal_locate( 2230 | const key_type &key, IterType iter) const { 2231 | return internal_locate_type::dispatch(key, *this, iter); 2232 | } 2233 | 2234 | template template 2235 | inline std::pair btree

::internal_locate_plain_compare( 2236 | const key_type &key, IterType iter) const { 2237 | for (;;) { 2238 | iter.position = iter.node->lower_bound(key, key_comp()); 2239 | if (iter.node->leaf()) { 2240 | break; 2241 | } 2242 | iter.node = iter.node->child(iter.position); 2243 | } 2244 | return std::make_pair(iter, 0); 2245 | } 2246 | 2247 | template template 2248 | inline std::pair btree

::internal_locate_compare_to( 2249 | const key_type &key, IterType iter) const { 2250 | for (;;) { 2251 | int res = iter.node->lower_bound(key, key_comp()); 2252 | iter.position = res & kMatchMask; 2253 | if (res & kExactMatch) { 2254 | return std::make_pair(iter, static_cast(kExactMatch)); 2255 | } 2256 | if (iter.node->leaf()) { 2257 | break; 2258 | } 2259 | iter.node = iter.node->child(iter.position); 2260 | } 2261 | return std::make_pair(iter, -kExactMatch); 2262 | } 2263 | 2264 | template template 2265 | IterType btree

::internal_lower_bound( 2266 | const key_type &key, IterType iter) const { 2267 | if (iter.node) { 2268 | for (;;) { 2269 | iter.position = 2270 | iter.node->lower_bound(key, key_comp()) & kMatchMask; 2271 | if (iter.node->leaf()) { 2272 | break; 2273 | } 2274 | iter.node = iter.node->child(iter.position); 2275 | } 2276 | iter = internal_last(iter); 2277 | } 2278 | return iter; 2279 | } 2280 | 2281 | template template 2282 | IterType btree

::internal_upper_bound( 2283 | const key_type &key, IterType iter) const { 2284 | if (iter.node) { 2285 | for (;;) { 2286 | iter.position = iter.node->upper_bound(key, key_comp()); 2287 | if (iter.node->leaf()) { 2288 | break; 2289 | } 2290 | iter.node = iter.node->child(iter.position); 2291 | } 2292 | iter = internal_last(iter); 2293 | } 2294 | return iter; 2295 | } 2296 | 2297 | template template 2298 | IterType btree

::internal_find_unique( 2299 | const key_type &key, IterType iter) const { 2300 | if (iter.node) { 2301 | std::pair res = internal_locate(key, iter); 2302 | if (res.second == kExactMatch) { 2303 | return res.first; 2304 | } 2305 | if (!res.second) { 2306 | iter = internal_last(res.first); 2307 | if (iter.node && !compare_keys(key, iter.key())) { 2308 | return iter; 2309 | } 2310 | } 2311 | } 2312 | return IterType(NULL, 0); 2313 | } 2314 | 2315 | template template 2316 | IterType btree

::internal_find_multi( 2317 | const key_type &key, IterType iter) const { 2318 | if (iter.node) { 2319 | iter = internal_lower_bound(key, iter); 2320 | if (iter.node) { 2321 | iter = internal_last(iter); 2322 | if (iter.node && !compare_keys(key, iter.key())) { 2323 | return iter; 2324 | } 2325 | } 2326 | } 2327 | return IterType(NULL, 0); 2328 | } 2329 | 2330 | template 2331 | void btree

::internal_clear(node_type *node) { 2332 | if (!node->leaf()) { 2333 | for (int i = 0; i <= node->count(); ++i) { 2334 | internal_clear(node->child(i)); 2335 | } 2336 | if (node == root()) { 2337 | delete_internal_root_node(); 2338 | } else { 2339 | delete_internal_node(node); 2340 | } 2341 | } else { 2342 | delete_leaf_node(node); 2343 | } 2344 | } 2345 | 2346 | template 2347 | void btree

::internal_dump( 2348 | std::ostream &os, const node_type *node, int level) const { 2349 | for (int i = 0; i < node->count(); ++i) { 2350 | if (!node->leaf()) { 2351 | internal_dump(os, node->child(i), level + 1); 2352 | } 2353 | for (int j = 0; j < level; ++j) { 2354 | os << " "; 2355 | } 2356 | os << node->key(i) << " [" << level << "]\n"; 2357 | } 2358 | if (!node->leaf()) { 2359 | internal_dump(os, node->child(node->count()), level + 1); 2360 | } 2361 | } 2362 | 2363 | template 2364 | int btree

::internal_verify( 2365 | const node_type *node, const key_type *lo, const key_type *hi) const { 2366 | assert(node->count() > 0); 2367 | assert(node->count() <= node->max_count()); 2368 | if (lo) { 2369 | assert(!compare_keys(node->key(0), *lo)); 2370 | } 2371 | if (hi) { 2372 | assert(!compare_keys(*hi, node->key(node->count() - 1))); 2373 | } 2374 | for (int i = 1; i < node->count(); ++i) { 2375 | assert(!compare_keys(node->key(i), node->key(i - 1))); 2376 | } 2377 | int count = node->count(); 2378 | if (!node->leaf()) { 2379 | for (int i = 0; i <= node->count(); ++i) { 2380 | assert(node->child(i) != NULL); 2381 | assert(node->child(i)->parent() == node); 2382 | assert(node->child(i)->position() == i); 2383 | count += internal_verify( 2384 | node->child(i), 2385 | (i == 0) ? lo : &node->key(i - 1), 2386 | (i == node->count()) ? hi : &node->key(i)); 2387 | } 2388 | } 2389 | return count; 2390 | } 2391 | 2392 | } // namespace btree 2393 | 2394 | #endif // UTIL_BTREE_BTREE_H__ 2395 | -------------------------------------------------------------------------------- /btree_bench.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "gflags/gflags.h" 27 | #include "btree_map.h" 28 | #include "btree_set.h" 29 | #include "btree_test.h" 30 | 31 | DEFINE_int32(test_random_seed, 123456789, "Seed for srand()"); 32 | DEFINE_int32(benchmark_max_iters, 10000000, "Maximum test iterations"); 33 | DEFINE_int32(benchmark_min_iters, 100, "Minimum test iterations"); 34 | DEFINE_int32(benchmark_target_seconds, 1, 35 | "Attempt to benchmark for this many seconds"); 36 | 37 | using std::allocator; 38 | using std::less; 39 | using std::map; 40 | using std::max; 41 | using std::min; 42 | using std::multimap; 43 | using std::multiset; 44 | using std::set; 45 | using std::string; 46 | using std::vector; 47 | 48 | namespace btree { 49 | namespace { 50 | 51 | struct RandGen { 52 | typedef ptrdiff_t result_type; 53 | RandGen(result_type seed) { 54 | srand(seed); 55 | } 56 | result_type operator()(result_type l) { 57 | return rand() % l; 58 | } 59 | }; 60 | 61 | struct BenchmarkRun { 62 | BenchmarkRun(const char *name, void (*func)(int)); 63 | void Run(); 64 | void Stop(); 65 | void Start(); 66 | void Reset(); 67 | 68 | BenchmarkRun *next_benchmark; 69 | const char *benchmark_name; 70 | void (*benchmark_func)(int); 71 | int64_t accum_micros; 72 | int64_t last_started; 73 | }; 74 | 75 | BenchmarkRun *first_benchmark; 76 | BenchmarkRun *current_benchmark; 77 | 78 | int64_t get_micros () { 79 | timeval tv; 80 | gettimeofday(&tv, NULL); 81 | return tv.tv_sec * 1000000 + tv.tv_usec; 82 | } 83 | 84 | BenchmarkRun::BenchmarkRun(const char *name, void (*func)(int)) 85 | : next_benchmark(first_benchmark), 86 | benchmark_name(name), 87 | benchmark_func(func), 88 | accum_micros(0), 89 | last_started(0) { 90 | first_benchmark = this; 91 | } 92 | 93 | #define BTREE_BENCHMARK(name) \ 94 | BTREE_BENCHMARK2(#name, name, __COUNTER__) 95 | #define BTREE_BENCHMARK2(name, func, counter) \ 96 | BTREE_BENCHMARK3(name, func, counter) 97 | #define BTREE_BENCHMARK3(name, func, counter) \ 98 | BenchmarkRun bench ## counter (name, func) 99 | 100 | void StopBenchmarkTiming() { 101 | current_benchmark->Stop(); 102 | } 103 | 104 | void StartBenchmarkTiming() { 105 | current_benchmark->Start(); 106 | } 107 | 108 | void RunBenchmarks() { 109 | for (BenchmarkRun *bench = first_benchmark; bench; 110 | bench = bench->next_benchmark) { 111 | bench->Run(); 112 | } 113 | } 114 | 115 | void BenchmarkRun::Start() { 116 | assert(!last_started); 117 | last_started = get_micros(); 118 | } 119 | 120 | void BenchmarkRun::Stop() { 121 | if (last_started == 0) { 122 | return; 123 | } 124 | accum_micros += get_micros() - last_started; 125 | last_started = 0; 126 | } 127 | 128 | void BenchmarkRun::Reset() { 129 | last_started = 0; 130 | accum_micros = 0; 131 | } 132 | 133 | void BenchmarkRun::Run() { 134 | assert(current_benchmark == NULL); 135 | current_benchmark = this; 136 | int iters = FLAGS_benchmark_min_iters; 137 | for (;;) { 138 | Reset(); 139 | Start(); 140 | benchmark_func(iters); 141 | Stop(); 142 | if (accum_micros > FLAGS_benchmark_target_seconds * 1000000 || 143 | iters >= FLAGS_benchmark_max_iters) { 144 | break; 145 | } else if (accum_micros == 0) { 146 | iters *= 100; 147 | } else { 148 | int64_t target_micros = FLAGS_benchmark_target_seconds * 1000000; 149 | iters = target_micros * iters / accum_micros; 150 | } 151 | iters = min(iters, FLAGS_benchmark_max_iters); 152 | } 153 | fprintf(stdout, "%s\t%qu\t%qu\n", 154 | benchmark_name, 155 | accum_micros * 1000 / iters, 156 | iters); 157 | current_benchmark = NULL; 158 | } 159 | 160 | // Used to avoid compiler optimizations for these benchmarks. 161 | template 162 | void sink(const T& t0) { 163 | volatile T t = t0; 164 | } 165 | 166 | // Benchmark insertion of values into a container. 167 | template 168 | void BM_Insert(int n) { 169 | typedef typename std::remove_const::type V; 170 | typename KeyOfValue::type key_of_value; 171 | 172 | // Disable timing while we perform some initialization. 173 | StopBenchmarkTiming(); 174 | 175 | T container; 176 | vector values = GenerateValues(FLAGS_benchmark_values); 177 | for (int i = 0; i < values.size(); i++) { 178 | container.insert(values[i]); 179 | } 180 | 181 | for (int i = 0; i < n; ) { 182 | // Remove and re-insert 10% of the keys 183 | int m = min(n - i, FLAGS_benchmark_values / 10); 184 | 185 | for (int j = i; j < i + m; j++) { 186 | int x = j % FLAGS_benchmark_values; 187 | container.erase(key_of_value(values[x])); 188 | } 189 | 190 | StartBenchmarkTiming(); 191 | 192 | for (int j = i; j < i + m; j++) { 193 | int x = j % FLAGS_benchmark_values; 194 | container.insert(values[x]); 195 | } 196 | 197 | StopBenchmarkTiming(); 198 | 199 | i += m; 200 | } 201 | } 202 | 203 | // Benchmark lookup of values in a container. 204 | template 205 | void BM_Lookup(int n) { 206 | typedef typename std::remove_const::type V; 207 | typename KeyOfValue::type key_of_value; 208 | 209 | // Disable timing while we perform some initialization. 210 | StopBenchmarkTiming(); 211 | 212 | T container; 213 | vector values = GenerateValues(FLAGS_benchmark_values); 214 | 215 | for (int i = 0; i < values.size(); i++) { 216 | container.insert(values[i]); 217 | } 218 | 219 | V r = V(); 220 | 221 | StartBenchmarkTiming(); 222 | 223 | for (int i = 0; i < n; i++) { 224 | int m = i % values.size(); 225 | r = *container.find(key_of_value(values[m])); 226 | } 227 | 228 | StopBenchmarkTiming(); 229 | 230 | sink(r); // Keep compiler from optimizing away r. 231 | } 232 | 233 | // Benchmark lookup of values in a full container, meaning that values 234 | // are inserted in-order to take advantage of biased insertion, which 235 | // yields a full tree. 236 | template 237 | void BM_FullLookup(int n) { 238 | typedef typename std::remove_const::type V; 239 | typename KeyOfValue::type key_of_value; 240 | 241 | // Disable timing while we perform some initialization. 242 | StopBenchmarkTiming(); 243 | 244 | T container; 245 | vector values = GenerateValues(FLAGS_benchmark_values); 246 | vector sorted(values); 247 | sort(sorted.begin(), sorted.end()); 248 | 249 | for (int i = 0; i < sorted.size(); i++) { 250 | container.insert(sorted[i]); 251 | } 252 | 253 | V r = V(); 254 | 255 | StartBenchmarkTiming(); 256 | 257 | for (int i = 0; i < n; i++) { 258 | int m = i % values.size(); 259 | r = *container.find(key_of_value(values[m])); 260 | } 261 | 262 | StopBenchmarkTiming(); 263 | 264 | sink(r); // Keep compiler from optimizing away r. 265 | } 266 | 267 | // Benchmark deletion of values from a container. 268 | template 269 | void BM_Delete(int n) { 270 | typedef typename std::remove_const::type V; 271 | typename KeyOfValue::type key_of_value; 272 | 273 | // Disable timing while we perform some initialization. 274 | StopBenchmarkTiming(); 275 | 276 | T container; 277 | vector values = GenerateValues(FLAGS_benchmark_values); 278 | for (int i = 0; i < values.size(); i++) { 279 | container.insert(values[i]); 280 | } 281 | 282 | for (int i = 0; i < n; ) { 283 | // Remove and re-insert 10% of the keys 284 | int m = min(n - i, FLAGS_benchmark_values / 10); 285 | 286 | StartBenchmarkTiming(); 287 | 288 | for (int j = i; j < i + m; j++) { 289 | int x = j % FLAGS_benchmark_values; 290 | container.erase(key_of_value(values[x])); 291 | } 292 | 293 | StopBenchmarkTiming(); 294 | 295 | for (int j = i; j < i + m; j++) { 296 | int x = j % FLAGS_benchmark_values; 297 | container.insert(values[x]); 298 | } 299 | 300 | i += m; 301 | } 302 | } 303 | 304 | // Benchmark steady-state insert (into first half of range) and remove 305 | // (from second second half of range), treating the container 306 | // approximately like a queue with log-time access for all elements. 307 | // This benchmark does not test the case where insertion and removal 308 | // happen in the same region of the tree. This benchmark counts two 309 | // value constructors. 310 | template 311 | void BM_QueueAddRem(int n) { 312 | typedef typename std::remove_const::type V; 313 | typename KeyOfValue::type key_of_value; 314 | 315 | // Disable timing while we perform some initialization. 316 | StopBenchmarkTiming(); 317 | assert(FLAGS_benchmark_values % 2 == 0); 318 | 319 | T container; 320 | 321 | const int half = FLAGS_benchmark_values / 2; 322 | vector remove_keys(half); 323 | vector add_keys(half); 324 | 325 | for (int i = 0; i < half; i++) { 326 | remove_keys[i] = i; 327 | add_keys[i] = i; 328 | } 329 | 330 | RandGen rand(FLAGS_test_random_seed); 331 | 332 | random_shuffle(remove_keys.begin(), remove_keys.end(), rand); 333 | random_shuffle(add_keys.begin(), add_keys.end(), rand); 334 | 335 | Generator g(FLAGS_benchmark_values + FLAGS_benchmark_max_iters); 336 | 337 | for (int i = 0; i < half; i++) { 338 | container.insert(g(add_keys[i])); 339 | container.insert(g(half + remove_keys[i])); 340 | } 341 | 342 | // There are three parts each of size "half": 343 | // 1 is being deleted from [offset - half, offset) 344 | // 2 is standing [offset, offset + half) 345 | // 3 is being inserted into [offset + half, offset + 2 * half) 346 | int offset = 0; 347 | 348 | StartBenchmarkTiming(); 349 | 350 | for (int i = 0; i < n; i++) { 351 | int idx = i % half; 352 | 353 | if (idx == 0) { 354 | StopBenchmarkTiming(); 355 | random_shuffle(remove_keys.begin(), remove_keys.end(), rand); 356 | random_shuffle(add_keys.begin(), add_keys.end(), rand); 357 | offset += half; 358 | StartBenchmarkTiming(); 359 | } 360 | 361 | int e = container.erase(key_of_value(g(offset - half + remove_keys[idx]))); 362 | assert(e == 1); 363 | container.insert(g(offset + half + add_keys[idx])); 364 | } 365 | 366 | StopBenchmarkTiming(); 367 | } 368 | 369 | // Mixed insertion and deletion in the same range using pre-constructed values. 370 | template 371 | void BM_MixedAddRem(int n) { 372 | typedef typename std::remove_const::type V; 373 | typename KeyOfValue::type key_of_value; 374 | 375 | // Disable timing while we perform some initialization. 376 | StopBenchmarkTiming(); 377 | assert(FLAGS_benchmark_values % 2 == 0); 378 | 379 | T container; 380 | RandGen rand(FLAGS_test_random_seed); 381 | 382 | vector values = GenerateValues(FLAGS_benchmark_values * 2); 383 | 384 | // Create two random shuffles 385 | vector remove_keys(FLAGS_benchmark_values); 386 | vector add_keys(FLAGS_benchmark_values); 387 | 388 | // Insert the first half of the values (already in random order) 389 | for (int i = 0; i < FLAGS_benchmark_values; i++) { 390 | container.insert(values[i]); 391 | 392 | // remove_keys and add_keys will be swapped before each round, 393 | // therefore fill add_keys here w/ the keys being inserted, so 394 | // they'll be the first to be removed. 395 | remove_keys[i] = i + FLAGS_benchmark_values; 396 | add_keys[i] = i; 397 | } 398 | 399 | StartBenchmarkTiming(); 400 | 401 | for (int i = 0; i < n; i++) { 402 | int idx = i % FLAGS_benchmark_values; 403 | 404 | if (idx == 0) { 405 | StopBenchmarkTiming(); 406 | remove_keys.swap(add_keys); 407 | random_shuffle(remove_keys.begin(), remove_keys.end(), rand); 408 | random_shuffle(add_keys.begin(), add_keys.end(), rand); 409 | StartBenchmarkTiming(); 410 | } 411 | 412 | int e = container.erase(key_of_value(values[remove_keys[idx]])); 413 | assert(e == 1); 414 | container.insert(values[add_keys[idx]]); 415 | } 416 | 417 | StopBenchmarkTiming(); 418 | } 419 | 420 | // Insertion at end, removal from the beginning. This benchmark 421 | // counts two value constructors. 422 | template 423 | void BM_Fifo(int n) { 424 | typedef typename std::remove_const::type V; 425 | 426 | // Disable timing while we perform some initialization. 427 | StopBenchmarkTiming(); 428 | 429 | T container; 430 | Generator g(FLAGS_benchmark_values + FLAGS_benchmark_max_iters); 431 | 432 | for (int i = 0; i < FLAGS_benchmark_values; i++) { 433 | container.insert(g(i)); 434 | } 435 | 436 | StartBenchmarkTiming(); 437 | 438 | for (int i = 0; i < n; i++) { 439 | container.erase(container.begin()); 440 | container.insert(container.end(), g(i + FLAGS_benchmark_values)); 441 | } 442 | 443 | StopBenchmarkTiming(); 444 | } 445 | 446 | // Iteration (forward) through the tree 447 | template 448 | void BM_FwdIter(int n) { 449 | typedef typename std::remove_const::type V; 450 | 451 | // Disable timing while we perform some initialization. 452 | StopBenchmarkTiming(); 453 | 454 | T container; 455 | vector values = GenerateValues(FLAGS_benchmark_values); 456 | 457 | for (int i = 0; i < FLAGS_benchmark_values; i++) { 458 | container.insert(values[i]); 459 | } 460 | 461 | typename T::iterator iter; 462 | 463 | V r = V(); 464 | 465 | StartBenchmarkTiming(); 466 | 467 | for (int i = 0; i < n; i++) { 468 | int idx = i % FLAGS_benchmark_values; 469 | 470 | if (idx == 0) { 471 | iter = container.begin(); 472 | } 473 | r = *iter; 474 | ++iter; 475 | } 476 | 477 | StopBenchmarkTiming(); 478 | 479 | sink(r); // Keep compiler from optimizing away r. 480 | } 481 | 482 | typedef set stl_set_int32; 483 | typedef set stl_set_int64; 484 | typedef set stl_set_string; 485 | 486 | typedef map stl_map_int32; 487 | typedef map stl_map_int64; 488 | typedef map stl_map_string; 489 | 490 | typedef multiset stl_multiset_int32; 491 | typedef multiset stl_multiset_int64; 492 | typedef multiset stl_multiset_string; 493 | 494 | typedef multimap stl_multimap_int32; 495 | typedef multimap stl_multimap_int64; 496 | typedef multimap stl_multimap_string; 497 | 498 | #define MY_BENCHMARK_TYPES2(value, name, size) \ 499 | typedef btree ## _set, allocator, size> \ 500 | btree ## _ ## size ## _set_ ## name; \ 501 | typedef btree ## _map, allocator, size> \ 502 | btree ## _ ## size ## _map_ ## name; \ 503 | typedef btree ## _multiset, allocator, size> \ 504 | btree ## _ ## size ## _multiset_ ## name; \ 505 | typedef btree ## _multimap, allocator, size> \ 506 | btree ## _ ## size ## _multimap_ ## name 507 | 508 | #define MY_BENCHMARK_TYPES(value, name) \ 509 | MY_BENCHMARK_TYPES2(value, name, 128); \ 510 | MY_BENCHMARK_TYPES2(value, name, 160); \ 511 | MY_BENCHMARK_TYPES2(value, name, 192); \ 512 | MY_BENCHMARK_TYPES2(value, name, 224); \ 513 | MY_BENCHMARK_TYPES2(value, name, 256); \ 514 | MY_BENCHMARK_TYPES2(value, name, 288); \ 515 | MY_BENCHMARK_TYPES2(value, name, 320); \ 516 | MY_BENCHMARK_TYPES2(value, name, 352); \ 517 | MY_BENCHMARK_TYPES2(value, name, 384); \ 518 | MY_BENCHMARK_TYPES2(value, name, 416); \ 519 | MY_BENCHMARK_TYPES2(value, name, 448); \ 520 | MY_BENCHMARK_TYPES2(value, name, 480); \ 521 | MY_BENCHMARK_TYPES2(value, name, 512); \ 522 | MY_BENCHMARK_TYPES2(value, name, 1024); \ 523 | MY_BENCHMARK_TYPES2(value, name, 1536); \ 524 | MY_BENCHMARK_TYPES2(value, name, 2048) 525 | 526 | MY_BENCHMARK_TYPES(int32_t, int32); 527 | MY_BENCHMARK_TYPES(int64_t, int64); 528 | MY_BENCHMARK_TYPES(string, string); 529 | 530 | #define MY_BENCHMARK4(type, name, func) \ 531 | void BM_ ## type ## _ ## name(int n) { BM_ ## func (n); } \ 532 | BTREE_BENCHMARK(BM_ ## type ## _ ## name) 533 | 534 | // Define NODESIZE_TESTING when running btree_perf.py. 535 | 536 | #ifdef NODESIZE_TESTING 537 | #define MY_BENCHMARK3(tree, type, name, func) \ 538 | MY_BENCHMARK4(tree ## _128_ ## type, name, func); \ 539 | MY_BENCHMARK4(tree ## _160_ ## type, name, func); \ 540 | MY_BENCHMARK4(tree ## _192_ ## type, name, func); \ 541 | MY_BENCHMARK4(tree ## _224_ ## type, name, func); \ 542 | MY_BENCHMARK4(tree ## _256_ ## type, name, func); \ 543 | MY_BENCHMARK4(tree ## _288_ ## type, name, func); \ 544 | MY_BENCHMARK4(tree ## _320_ ## type, name, func); \ 545 | MY_BENCHMARK4(tree ## _352_ ## type, name, func); \ 546 | MY_BENCHMARK4(tree ## _384_ ## type, name, func); \ 547 | MY_BENCHMARK4(tree ## _416_ ## type, name, func); \ 548 | MY_BENCHMARK4(tree ## _448_ ## type, name, func); \ 549 | MY_BENCHMARK4(tree ## _480_ ## type, name, func); \ 550 | MY_BENCHMARK4(tree ## _512_ ## type, name, func); \ 551 | MY_BENCHMARK4(tree ## _1024_ ## type, name, func); \ 552 | MY_BENCHMARK4(tree ## _1536_ ## type, name, func); \ 553 | MY_BENCHMARK4(tree ## _2048_ ## type, name, func) 554 | #else 555 | #define MY_BENCHMARK3(tree, type, name, func) \ 556 | MY_BENCHMARK4(tree ## _256_ ## type, name, func); \ 557 | MY_BENCHMARK4(tree ## _2048_ ## type, name, func) 558 | #endif 559 | 560 | #define MY_BENCHMARK2(type, name, func) \ 561 | MY_BENCHMARK4(stl_ ## type, name, func); \ 562 | MY_BENCHMARK3(btree, type, name, func) 563 | 564 | #define MY_BENCHMARK(type) \ 565 | MY_BENCHMARK2(type, insert, Insert); \ 566 | MY_BENCHMARK2(type, lookup, Lookup); \ 567 | MY_BENCHMARK2(type, fulllookup, FullLookup); \ 568 | MY_BENCHMARK2(type, delete, Delete); \ 569 | MY_BENCHMARK2(type, queueaddrem, QueueAddRem); \ 570 | MY_BENCHMARK2(type, mixedaddrem, MixedAddRem); \ 571 | MY_BENCHMARK2(type, fifo, Fifo); \ 572 | MY_BENCHMARK2(type, fwditer, FwdIter) 573 | 574 | MY_BENCHMARK(set_int32); 575 | MY_BENCHMARK(map_int32); 576 | MY_BENCHMARK(set_int64); 577 | MY_BENCHMARK(map_int64); 578 | MY_BENCHMARK(set_string); 579 | MY_BENCHMARK(map_string); 580 | 581 | MY_BENCHMARK(multiset_int32); 582 | MY_BENCHMARK(multimap_int32); 583 | MY_BENCHMARK(multiset_int64); 584 | MY_BENCHMARK(multimap_int64); 585 | MY_BENCHMARK(multiset_string); 586 | MY_BENCHMARK(multimap_string); 587 | 588 | } // namespace 589 | } // namespace btree 590 | 591 | int main(int argc, char **argv) { 592 | btree::RunBenchmarks(); 593 | return 0; 594 | } 595 | -------------------------------------------------------------------------------- /btree_container.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef UTIL_BTREE_BTREE_CONTAINER_H__ 16 | #define UTIL_BTREE_BTREE_CONTAINER_H__ 17 | 18 | #include 19 | #include 20 | 21 | #include "btree.h" 22 | 23 | namespace btree { 24 | 25 | // A common base class for btree_set, btree_map, btree_multiset and 26 | // btree_multimap. 27 | template 28 | class btree_container { 29 | typedef btree_container self_type; 30 | 31 | public: 32 | typedef typename Tree::params_type params_type; 33 | typedef typename Tree::key_type key_type; 34 | typedef typename Tree::value_type value_type; 35 | typedef typename Tree::key_compare key_compare; 36 | typedef typename Tree::allocator_type allocator_type; 37 | typedef typename Tree::pointer pointer; 38 | typedef typename Tree::const_pointer const_pointer; 39 | typedef typename Tree::reference reference; 40 | typedef typename Tree::const_reference const_reference; 41 | typedef typename Tree::size_type size_type; 42 | typedef typename Tree::difference_type difference_type; 43 | typedef typename Tree::iterator iterator; 44 | typedef typename Tree::const_iterator const_iterator; 45 | typedef typename Tree::reverse_iterator reverse_iterator; 46 | typedef typename Tree::const_reverse_iterator const_reverse_iterator; 47 | 48 | public: 49 | // Default constructor. 50 | btree_container(const key_compare &comp, const allocator_type &alloc) 51 | : tree_(comp, alloc) { 52 | } 53 | 54 | // Copy constructor. 55 | btree_container(const self_type &x) 56 | : tree_(x.tree_) { 57 | } 58 | 59 | // Iterator routines. 60 | iterator begin() { return tree_.begin(); } 61 | const_iterator begin() const { return tree_.begin(); } 62 | iterator end() { return tree_.end(); } 63 | const_iterator end() const { return tree_.end(); } 64 | reverse_iterator rbegin() { return tree_.rbegin(); } 65 | const_reverse_iterator rbegin() const { return tree_.rbegin(); } 66 | reverse_iterator rend() { return tree_.rend(); } 67 | const_reverse_iterator rend() const { return tree_.rend(); } 68 | 69 | // Lookup routines. 70 | iterator lower_bound(const key_type &key) { 71 | return tree_.lower_bound(key); 72 | } 73 | const_iterator lower_bound(const key_type &key) const { 74 | return tree_.lower_bound(key); 75 | } 76 | iterator upper_bound(const key_type &key) { 77 | return tree_.upper_bound(key); 78 | } 79 | const_iterator upper_bound(const key_type &key) const { 80 | return tree_.upper_bound(key); 81 | } 82 | std::pair equal_range(const key_type &key) { 83 | return tree_.equal_range(key); 84 | } 85 | std::pair equal_range(const key_type &key) const { 86 | return tree_.equal_range(key); 87 | } 88 | 89 | // Utility routines. 90 | void clear() { 91 | tree_.clear(); 92 | } 93 | void swap(self_type &x) { 94 | tree_.swap(x.tree_); 95 | } 96 | void dump(std::ostream &os) const { 97 | tree_.dump(os); 98 | } 99 | void verify() const { 100 | tree_.verify(); 101 | } 102 | 103 | // Size routines. 104 | size_type size() const { return tree_.size(); } 105 | size_type max_size() const { return tree_.max_size(); } 106 | bool empty() const { return tree_.empty(); } 107 | size_type height() const { return tree_.height(); } 108 | size_type internal_nodes() const { return tree_.internal_nodes(); } 109 | size_type leaf_nodes() const { return tree_.leaf_nodes(); } 110 | size_type nodes() const { return tree_.nodes(); } 111 | size_type bytes_used() const { return tree_.bytes_used(); } 112 | static double average_bytes_per_value() { 113 | return Tree::average_bytes_per_value(); 114 | } 115 | double fullness() const { return tree_.fullness(); } 116 | double overhead() const { return tree_.overhead(); } 117 | 118 | bool operator==(const self_type& x) const { 119 | if (size() != x.size()) { 120 | return false; 121 | } 122 | for (const_iterator i = begin(), xi = x.begin(); i != end(); ++i, ++xi) { 123 | if (*i != *xi) { 124 | return false; 125 | } 126 | } 127 | return true; 128 | } 129 | 130 | bool operator!=(const self_type& other) const { 131 | return !operator==(other); 132 | } 133 | 134 | 135 | protected: 136 | Tree tree_; 137 | }; 138 | 139 | template 140 | inline std::ostream& operator<<(std::ostream &os, const btree_container &b) { 141 | b.dump(os); 142 | return os; 143 | } 144 | 145 | // A common base class for btree_set and safe_btree_set. 146 | template 147 | class btree_unique_container : public btree_container { 148 | typedef btree_unique_container self_type; 149 | typedef btree_container super_type; 150 | 151 | public: 152 | typedef typename Tree::key_type key_type; 153 | typedef typename Tree::value_type value_type; 154 | typedef typename Tree::size_type size_type; 155 | typedef typename Tree::key_compare key_compare; 156 | typedef typename Tree::allocator_type allocator_type; 157 | typedef typename Tree::iterator iterator; 158 | typedef typename Tree::const_iterator const_iterator; 159 | 160 | public: 161 | // Default constructor. 162 | btree_unique_container(const key_compare &comp = key_compare(), 163 | const allocator_type &alloc = allocator_type()) 164 | : super_type(comp, alloc) { 165 | } 166 | 167 | // Copy constructor. 168 | btree_unique_container(const self_type &x) 169 | : super_type(x) { 170 | } 171 | 172 | // Range constructor. 173 | template 174 | btree_unique_container(InputIterator b, InputIterator e, 175 | const key_compare &comp = key_compare(), 176 | const allocator_type &alloc = allocator_type()) 177 | : super_type(comp, alloc) { 178 | insert(b, e); 179 | } 180 | 181 | // Lookup routines. 182 | iterator find(const key_type &key) { 183 | return this->tree_.find_unique(key); 184 | } 185 | const_iterator find(const key_type &key) const { 186 | return this->tree_.find_unique(key); 187 | } 188 | size_type count(const key_type &key) const { 189 | return this->tree_.count_unique(key); 190 | } 191 | 192 | // Insertion routines. 193 | std::pair insert(const value_type &x) { 194 | return this->tree_.insert_unique(x); 195 | } 196 | iterator insert(iterator position, const value_type &x) { 197 | return this->tree_.insert_unique(position, x); 198 | } 199 | template 200 | void insert(InputIterator b, InputIterator e) { 201 | this->tree_.insert_unique(b, e); 202 | } 203 | 204 | // Deletion routines. 205 | int erase(const key_type &key) { 206 | return this->tree_.erase_unique(key); 207 | } 208 | // Erase the specified iterator from the btree. The iterator must be valid 209 | // (i.e. not equal to end()). Return an iterator pointing to the node after 210 | // the one that was erased (or end() if none exists). 211 | iterator erase(const iterator &iter) { 212 | return this->tree_.erase(iter); 213 | } 214 | void erase(const iterator &first, const iterator &last) { 215 | this->tree_.erase(first, last); 216 | } 217 | }; 218 | 219 | // A common base class for btree_map and safe_btree_map. 220 | template 221 | class btree_map_container : public btree_unique_container { 222 | typedef btree_map_container self_type; 223 | typedef btree_unique_container super_type; 224 | 225 | public: 226 | typedef typename Tree::key_type key_type; 227 | typedef typename Tree::data_type data_type; 228 | typedef typename Tree::value_type value_type; 229 | typedef typename Tree::mapped_type mapped_type; 230 | typedef typename Tree::key_compare key_compare; 231 | typedef typename Tree::allocator_type allocator_type; 232 | 233 | private: 234 | // A pointer-like object which only generates its value when 235 | // dereferenced. Used by operator[] to avoid constructing an empty data_type 236 | // if the key already exists in the map. 237 | struct generate_value { 238 | generate_value(const key_type &k) 239 | : key(k) { 240 | } 241 | value_type operator*() const { 242 | return std::make_pair(key, data_type()); 243 | } 244 | const key_type &key; 245 | }; 246 | 247 | public: 248 | // Default constructor. 249 | btree_map_container(const key_compare &comp = key_compare(), 250 | const allocator_type &alloc = allocator_type()) 251 | : super_type(comp, alloc) { 252 | } 253 | 254 | // Copy constructor. 255 | btree_map_container(const self_type &x) 256 | : super_type(x) { 257 | } 258 | 259 | // Range constructor. 260 | template 261 | btree_map_container(InputIterator b, InputIterator e, 262 | const key_compare &comp = key_compare(), 263 | const allocator_type &alloc = allocator_type()) 264 | : super_type(b, e, comp, alloc) { 265 | } 266 | 267 | // Insertion routines. 268 | data_type& operator[](const key_type &key) { 269 | return this->tree_.insert_unique(key, generate_value(key)).first->second; 270 | } 271 | }; 272 | 273 | // A common base class for btree_multiset and btree_multimap. 274 | template 275 | class btree_multi_container : public btree_container { 276 | typedef btree_multi_container self_type; 277 | typedef btree_container super_type; 278 | 279 | public: 280 | typedef typename Tree::key_type key_type; 281 | typedef typename Tree::value_type value_type; 282 | typedef typename Tree::size_type size_type; 283 | typedef typename Tree::key_compare key_compare; 284 | typedef typename Tree::allocator_type allocator_type; 285 | typedef typename Tree::iterator iterator; 286 | typedef typename Tree::const_iterator const_iterator; 287 | 288 | public: 289 | // Default constructor. 290 | btree_multi_container(const key_compare &comp = key_compare(), 291 | const allocator_type &alloc = allocator_type()) 292 | : super_type(comp, alloc) { 293 | } 294 | 295 | // Copy constructor. 296 | btree_multi_container(const self_type &x) 297 | : super_type(x) { 298 | } 299 | 300 | // Range constructor. 301 | template 302 | btree_multi_container(InputIterator b, InputIterator e, 303 | const key_compare &comp = key_compare(), 304 | const allocator_type &alloc = allocator_type()) 305 | : super_type(comp, alloc) { 306 | insert(b, e); 307 | } 308 | 309 | // Lookup routines. 310 | iterator find(const key_type &key) { 311 | return this->tree_.find_multi(key); 312 | } 313 | const_iterator find(const key_type &key) const { 314 | return this->tree_.find_multi(key); 315 | } 316 | size_type count(const key_type &key) const { 317 | return this->tree_.count_multi(key); 318 | } 319 | 320 | // Insertion routines. 321 | iterator insert(const value_type &x) { 322 | return this->tree_.insert_multi(x); 323 | } 324 | iterator insert(iterator position, const value_type &x) { 325 | return this->tree_.insert_multi(position, x); 326 | } 327 | template 328 | void insert(InputIterator b, InputIterator e) { 329 | this->tree_.insert_multi(b, e); 330 | } 331 | 332 | // Deletion routines. 333 | int erase(const key_type &key) { 334 | return this->tree_.erase_multi(key); 335 | } 336 | // Erase the specified iterator from the btree. The iterator must be valid 337 | // (i.e. not equal to end()). Return an iterator pointing to the node after 338 | // the one that was erased (or end() if none exists). 339 | iterator erase(const iterator &iter) { 340 | return this->tree_.erase(iter); 341 | } 342 | void erase(const iterator &first, const iterator &last) { 343 | this->tree_.erase(first, last); 344 | } 345 | }; 346 | 347 | } // namespace btree 348 | 349 | #endif // UTIL_BTREE_BTREE_CONTAINER_H__ 350 | -------------------------------------------------------------------------------- /btree_map.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // A btree_map<> implements the STL unique sorted associative container 16 | // interface and the pair associative container interface (a.k.a map<>) using a 17 | // btree. A btree_multimap<> implements the STL multiple sorted associative 18 | // container interface and the pair associtive container interface (a.k.a 19 | // multimap<>) using a btree. See btree.h for details of the btree 20 | // implementation and caveats. 21 | 22 | #ifndef UTIL_BTREE_BTREE_MAP_H__ 23 | #define UTIL_BTREE_BTREE_MAP_H__ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "btree.h" 32 | #include "btree_container.h" 33 | 34 | namespace btree { 35 | 36 | // The btree_map class is needed mainly for its constructors. 37 | template , 39 | typename Alloc = std::allocator >, 40 | int TargetNodeSize = 256> 41 | class btree_map : public btree_map_container< 42 | btree > > { 43 | 44 | typedef btree_map self_type; 45 | typedef btree_map_params< 46 | Key, Value, Compare, Alloc, TargetNodeSize> params_type; 47 | typedef btree btree_type; 48 | typedef btree_map_container super_type; 49 | 50 | public: 51 | typedef typename btree_type::key_compare key_compare; 52 | typedef typename btree_type::allocator_type allocator_type; 53 | 54 | public: 55 | // Default constructor. 56 | btree_map(const key_compare &comp = key_compare(), 57 | const allocator_type &alloc = allocator_type()) 58 | : super_type(comp, alloc) { 59 | } 60 | 61 | // Copy constructor. 62 | btree_map(const self_type &x) 63 | : super_type(x) { 64 | } 65 | 66 | // Range constructor. 67 | template 68 | btree_map(InputIterator b, InputIterator e, 69 | const key_compare &comp = key_compare(), 70 | const allocator_type &alloc = allocator_type()) 71 | : super_type(b, e, comp, alloc) { 72 | } 73 | }; 74 | 75 | template 76 | inline void swap(btree_map &x, 77 | btree_map &y) { 78 | x.swap(y); 79 | } 80 | 81 | // The btree_multimap class is needed mainly for its constructors. 82 | template , 84 | typename Alloc = std::allocator >, 85 | int TargetNodeSize = 256> 86 | class btree_multimap : public btree_multi_container< 87 | btree > > { 88 | 89 | typedef btree_multimap self_type; 90 | typedef btree_map_params< 91 | Key, Value, Compare, Alloc, TargetNodeSize> params_type; 92 | typedef btree btree_type; 93 | typedef btree_multi_container super_type; 94 | 95 | public: 96 | typedef typename btree_type::key_compare key_compare; 97 | typedef typename btree_type::allocator_type allocator_type; 98 | typedef typename btree_type::data_type data_type; 99 | typedef typename btree_type::mapped_type mapped_type; 100 | 101 | public: 102 | // Default constructor. 103 | btree_multimap(const key_compare &comp = key_compare(), 104 | const allocator_type &alloc = allocator_type()) 105 | : super_type(comp, alloc) { 106 | } 107 | 108 | // Copy constructor. 109 | btree_multimap(const self_type &x) 110 | : super_type(x) { 111 | } 112 | 113 | // Range constructor. 114 | template 115 | btree_multimap(InputIterator b, InputIterator e, 116 | const key_compare &comp = key_compare(), 117 | const allocator_type &alloc = allocator_type()) 118 | : super_type(b, e, comp, alloc) { 119 | } 120 | }; 121 | 122 | template 123 | inline void swap(btree_multimap &x, 124 | btree_multimap &y) { 125 | x.swap(y); 126 | } 127 | 128 | } // namespace btree 129 | 130 | #endif // UTIL_BTREE_BTREE_MAP_H__ 131 | -------------------------------------------------------------------------------- /btree_set.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // A btree_set<> implements the STL unique sorted associative container 16 | // interface (a.k.a set<>) using a btree. A btree_multiset<> implements the STL 17 | // multiple sorted associative container interface (a.k.a multiset<>) using a 18 | // btree. See btree.h for details of the btree implementation and caveats. 19 | 20 | #ifndef UTIL_BTREE_BTREE_SET_H__ 21 | #define UTIL_BTREE_BTREE_SET_H__ 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "btree.h" 28 | #include "btree_container.h" 29 | 30 | namespace btree { 31 | 32 | // The btree_set class is needed mainly for its constructors. 33 | template , 35 | typename Alloc = std::allocator, 36 | int TargetNodeSize = 256> 37 | class btree_set : public btree_unique_container< 38 | btree > > { 39 | 40 | typedef btree_set self_type; 41 | typedef btree_set_params params_type; 42 | typedef btree btree_type; 43 | typedef btree_unique_container super_type; 44 | 45 | public: 46 | typedef typename btree_type::key_compare key_compare; 47 | typedef typename btree_type::allocator_type allocator_type; 48 | 49 | public: 50 | // Default constructor. 51 | btree_set(const key_compare &comp = key_compare(), 52 | const allocator_type &alloc = allocator_type()) 53 | : super_type(comp, alloc) { 54 | } 55 | 56 | // Copy constructor. 57 | btree_set(const self_type &x) 58 | : super_type(x) { 59 | } 60 | 61 | // Range constructor. 62 | template 63 | btree_set(InputIterator b, InputIterator e, 64 | const key_compare &comp = key_compare(), 65 | const allocator_type &alloc = allocator_type()) 66 | : super_type(b, e, comp, alloc) { 67 | } 68 | }; 69 | 70 | template 71 | inline void swap(btree_set &x, btree_set &y) { 72 | x.swap(y); 73 | } 74 | 75 | // The btree_multiset class is needed mainly for its constructors. 76 | template , 78 | typename Alloc = std::allocator, 79 | int TargetNodeSize = 256> 80 | class btree_multiset : public btree_multi_container< 81 | btree > > { 82 | 83 | typedef btree_multiset self_type; 84 | typedef btree_set_params params_type; 85 | typedef btree btree_type; 86 | typedef btree_multi_container super_type; 87 | 88 | public: 89 | typedef typename btree_type::key_compare key_compare; 90 | typedef typename btree_type::allocator_type allocator_type; 91 | 92 | public: 93 | // Default constructor. 94 | btree_multiset(const key_compare &comp = key_compare(), 95 | const allocator_type &alloc = allocator_type()) 96 | : super_type(comp, alloc) { 97 | } 98 | 99 | // Copy constructor. 100 | btree_multiset(const self_type &x) 101 | : super_type(x) { 102 | } 103 | 104 | // Range constructor. 105 | template 106 | btree_multiset(InputIterator b, InputIterator e, 107 | const key_compare &comp = key_compare(), 108 | const allocator_type &alloc = allocator_type()) 109 | : super_type(b, e, comp, alloc) { 110 | } 111 | }; 112 | 113 | template 114 | inline void swap(btree_multiset &x, 115 | btree_multiset &y) { 116 | x.swap(y); 117 | } 118 | 119 | } // namespace btree 120 | 121 | #endif // UTIL_BTREE_BTREE_SET_H__ 122 | -------------------------------------------------------------------------------- /btree_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gtest/gtest.h" 16 | #include "btree_map.h" 17 | #include "btree_set.h" 18 | #include "btree_test.h" 19 | 20 | namespace btree { 21 | namespace { 22 | 23 | template 24 | void SetTest() { 25 | typedef TestAllocator TestAlloc; 26 | ASSERT_EQ(sizeof(btree_set), sizeof(void*)); 27 | BtreeTest, std::allocator, N>, std::set >(); 28 | BtreeAllocatorTest, TestAlloc, N> >(); 29 | } 30 | 31 | template 32 | void MapTest() { 33 | typedef TestAllocator TestAlloc; 34 | ASSERT_EQ(sizeof(btree_map), sizeof(void*)); 35 | BtreeTest, std::allocator, N>, std::map >(); 36 | BtreeAllocatorTest, TestAlloc, N> >(); 37 | BtreeMapTest, std::allocator, N> >(); 38 | } 39 | 40 | TEST(Btree, set_int32_32) { SetTest(); } 41 | TEST(Btree, set_int32_64) { SetTest(); } 42 | TEST(Btree, set_int32_128) { SetTest(); } 43 | TEST(Btree, set_int32_256) { SetTest(); } 44 | TEST(Btree, set_int64_256) { SetTest(); } 45 | TEST(Btree, set_string_256) { SetTest(); } 46 | TEST(Btree, set_pair_256) { SetTest, 256>(); } 47 | TEST(Btree, map_int32_256) { MapTest(); } 48 | TEST(Btree, map_int64_256) { MapTest(); } 49 | TEST(Btree, map_string_256) { MapTest(); } 50 | TEST(Btree, map_pair_256) { MapTest, 256>(); } 51 | 52 | // Large-node tests 53 | TEST(Btree, map_int32_1024) { MapTest(); } 54 | TEST(Btree, map_int32_1032) { MapTest(); } 55 | TEST(Btree, map_int32_1040) { MapTest(); } 56 | TEST(Btree, map_int32_1048) { MapTest(); } 57 | TEST(Btree, map_int32_1056) { MapTest(); } 58 | 59 | TEST(Btree, map_int32_2048) { MapTest(); } 60 | TEST(Btree, map_int32_4096) { MapTest(); } 61 | TEST(Btree, set_int32_1024) { SetTest(); } 62 | TEST(Btree, set_int32_2048) { SetTest(); } 63 | TEST(Btree, set_int32_4096) { SetTest(); } 64 | TEST(Btree, map_string_1024) { MapTest(); } 65 | TEST(Btree, map_string_2048) { MapTest(); } 66 | TEST(Btree, map_string_4096) { MapTest(); } 67 | TEST(Btree, set_string_1024) { SetTest(); } 68 | TEST(Btree, set_string_2048) { SetTest(); } 69 | TEST(Btree, set_string_4096) { SetTest(); } 70 | 71 | template 72 | void MultiSetTest() { 73 | typedef TestAllocator TestAlloc; 74 | ASSERT_EQ(sizeof(btree_multiset), sizeof(void*)); 75 | BtreeMultiTest, std::allocator, N>, 76 | std::multiset >(); 77 | BtreeAllocatorTest, TestAlloc, N> >(); 78 | } 79 | 80 | template 81 | void MultiMapTest() { 82 | typedef TestAllocator TestAlloc; 83 | ASSERT_EQ(sizeof(btree_multimap), sizeof(void*)); 84 | BtreeMultiTest, std::allocator, N>, 85 | std::multimap >(); 86 | BtreeMultiMapTest, std::allocator, N> >(); 87 | BtreeAllocatorTest, TestAlloc, N> >(); 88 | } 89 | 90 | TEST(Btree, multiset_int32_256) { MultiSetTest(); } 91 | TEST(Btree, multiset_int64_256) { MultiSetTest(); } 92 | TEST(Btree, multiset_string_256) { MultiSetTest(); } 93 | TEST(Btree, multiset_pair_256) { MultiSetTest, 256>(); } 94 | TEST(Btree, multimap_int32_256) { MultiMapTest(); } 95 | TEST(Btree, multimap_int64_256) { MultiMapTest(); } 96 | TEST(Btree, multimap_string_256) { MultiMapTest(); } 97 | TEST(Btree, multimap_pair_256) { MultiMapTest, 256>(); } 98 | 99 | // Large-node tests 100 | TEST(Btree, multimap_int32_1024) { MultiMapTest(); } 101 | TEST(Btree, multimap_int32_2048) { MultiMapTest(); } 102 | TEST(Btree, multimap_int32_4096) { MultiMapTest(); } 103 | TEST(Btree, multiset_int32_1024) { MultiSetTest(); } 104 | TEST(Btree, multiset_int32_2048) { MultiSetTest(); } 105 | TEST(Btree, multiset_int32_4096) { MultiSetTest(); } 106 | TEST(Btree, multimap_string_1024) { MultiMapTest(); } 107 | TEST(Btree, multimap_string_2048) { MultiMapTest(); } 108 | TEST(Btree, multimap_string_4096) { MultiMapTest(); } 109 | TEST(Btree, multiset_string_1024) { MultiSetTest(); } 110 | TEST(Btree, multiset_string_2048) { MultiSetTest(); } 111 | TEST(Btree, multiset_string_4096) { MultiSetTest(); } 112 | 113 | // Verify that swapping btrees swaps the key comparision functors. 114 | struct SubstringLess { 115 | SubstringLess() : n(2) {} 116 | SubstringLess(size_t length) 117 | : n(length) { 118 | } 119 | bool operator()(const std::string &a, const std::string &b) const { 120 | std::string as(a.data(), std::min(n, a.size())); 121 | std::string bs(b.data(), std::min(n, b.size())); 122 | return as < bs; 123 | } 124 | size_t n; 125 | }; 126 | 127 | TEST(Btree, SwapKeyCompare) { 128 | typedef btree_set SubstringSet; 129 | SubstringSet s1(SubstringLess(1), SubstringSet::allocator_type()); 130 | SubstringSet s2(SubstringLess(2), SubstringSet::allocator_type()); 131 | 132 | ASSERT_TRUE(s1.insert("a").second); 133 | ASSERT_FALSE(s1.insert("aa").second); 134 | 135 | ASSERT_TRUE(s2.insert("a").second); 136 | ASSERT_TRUE(s2.insert("aa").second); 137 | ASSERT_FALSE(s2.insert("aaa").second); 138 | 139 | swap(s1, s2); 140 | 141 | ASSERT_TRUE(s1.insert("b").second); 142 | ASSERT_TRUE(s1.insert("bb").second); 143 | ASSERT_FALSE(s1.insert("bbb").second); 144 | 145 | ASSERT_TRUE(s2.insert("b").second); 146 | ASSERT_FALSE(s2.insert("bb").second); 147 | } 148 | 149 | TEST(Btree, UpperBoundRegression) { 150 | // Regress a bug where upper_bound would default-construct a new key_compare 151 | // instead of copying the existing one. 152 | typedef btree_set SubstringSet; 153 | SubstringSet my_set(SubstringLess(3)); 154 | my_set.insert("aab"); 155 | my_set.insert("abb"); 156 | // We call upper_bound("aaa"). If this correctly uses the length 3 157 | // comparator, aaa < aab < abb, so we should get aab as the result. 158 | // If it instead uses the default-constructed length 2 comparator, 159 | // aa == aa < ab, so we'll get abb as our result. 160 | SubstringSet::iterator it = my_set.upper_bound("aaa"); 161 | ASSERT_TRUE(it != my_set.end()); 162 | EXPECT_EQ("aab", *it); 163 | } 164 | 165 | 166 | TEST(Btree, IteratorIncrementBy) { 167 | // Test that increment_by returns the same position as increment. 168 | const int kSetSize = 2341; 169 | btree_set my_set; 170 | for (int i = 0; i < kSetSize; ++i) { 171 | my_set.insert(i); 172 | } 173 | 174 | { 175 | // Simple increment vs. increment by. 176 | btree_set::iterator a = my_set.begin(); 177 | btree_set::iterator b = my_set.begin(); 178 | a.increment(); 179 | b.increment_by(1); 180 | EXPECT_EQ(*a, *b); 181 | } 182 | 183 | btree_set::iterator a = my_set.begin(); 184 | for (int i = 1; i < kSetSize; ++i) { 185 | ++a; 186 | // increment_by 187 | btree_set::iterator b = my_set.begin(); 188 | b.increment_by(i); 189 | EXPECT_EQ(*a, *b) << ": i=" << i; 190 | } 191 | } 192 | 193 | TEST(Btree, Comparison) { 194 | const int kSetSize = 1201; 195 | btree_set my_set; 196 | for (int i = 0; i < kSetSize; ++i) { 197 | my_set.insert(i); 198 | } 199 | btree_set my_set_copy(my_set); 200 | EXPECT_TRUE(my_set_copy == my_set); 201 | EXPECT_TRUE(my_set == my_set_copy); 202 | EXPECT_FALSE(my_set_copy != my_set); 203 | EXPECT_FALSE(my_set != my_set_copy); 204 | 205 | my_set.insert(kSetSize); 206 | EXPECT_FALSE(my_set_copy == my_set); 207 | EXPECT_FALSE(my_set == my_set_copy); 208 | EXPECT_TRUE(my_set_copy != my_set); 209 | EXPECT_TRUE(my_set != my_set_copy); 210 | 211 | my_set.erase(kSetSize - 1); 212 | EXPECT_FALSE(my_set_copy == my_set); 213 | EXPECT_FALSE(my_set == my_set_copy); 214 | EXPECT_TRUE(my_set_copy != my_set); 215 | EXPECT_TRUE(my_set != my_set_copy); 216 | 217 | btree_map my_map; 218 | for (int i = 0; i < kSetSize; ++i) { 219 | my_map[std::string(i, 'a')] = i; 220 | } 221 | btree_map my_map_copy(my_map); 222 | EXPECT_TRUE(my_map_copy == my_map); 223 | EXPECT_TRUE(my_map == my_map_copy); 224 | EXPECT_FALSE(my_map_copy != my_map); 225 | EXPECT_FALSE(my_map != my_map_copy); 226 | 227 | ++my_map_copy[std::string(7, 'a')]; 228 | EXPECT_FALSE(my_map_copy == my_map); 229 | EXPECT_FALSE(my_map == my_map_copy); 230 | EXPECT_TRUE(my_map_copy != my_map); 231 | EXPECT_TRUE(my_map != my_map_copy); 232 | 233 | my_map_copy = my_map; 234 | my_map["hello"] = kSetSize; 235 | EXPECT_FALSE(my_map_copy == my_map); 236 | EXPECT_FALSE(my_map == my_map_copy); 237 | EXPECT_TRUE(my_map_copy != my_map); 238 | EXPECT_TRUE(my_map != my_map_copy); 239 | 240 | my_map.erase(std::string(kSetSize - 1, 'a')); 241 | EXPECT_FALSE(my_map_copy == my_map); 242 | EXPECT_FALSE(my_map == my_map_copy); 243 | EXPECT_TRUE(my_map_copy != my_map); 244 | EXPECT_TRUE(my_map != my_map_copy); 245 | } 246 | 247 | TEST(Btree, RangeCtorSanity) { 248 | typedef btree_set, std::allocator, 256> test_set; 249 | typedef btree_map, std::allocator, 256> 250 | test_map; 251 | typedef btree_multiset, std::allocator, 256> 252 | test_mset; 253 | typedef btree_multimap, std::allocator, 256> 254 | test_mmap; 255 | std::vector ivec; 256 | ivec.push_back(1); 257 | std::map imap; 258 | imap.insert(std::make_pair(1, 2)); 259 | test_mset tmset(ivec.begin(), ivec.end()); 260 | test_mmap tmmap(imap.begin(), imap.end()); 261 | test_set tset(ivec.begin(), ivec.end()); 262 | test_map tmap(imap.begin(), imap.end()); 263 | EXPECT_EQ(1, tmset.size()); 264 | EXPECT_EQ(1, tmmap.size()); 265 | EXPECT_EQ(1, tset.size()); 266 | EXPECT_EQ(1, tmap.size()); 267 | } 268 | 269 | } // namespace 270 | } // namespace btree 271 | -------------------------------------------------------------------------------- /btree_test.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef UTIL_BTREE_BTREE_TEST_H__ 16 | #define UTIL_BTREE_BTREE_TEST_H__ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "gtest/gtest.h" 31 | #include "gflags/gflags.h" 32 | #include "btree_container.h" 33 | 34 | DECLARE_int32(test_values); 35 | DECLARE_int32(benchmark_values); 36 | 37 | namespace std { 38 | 39 | // Provide operator<< support for std::pair. 40 | template 41 | ostream& operator<<(ostream &os, const std::pair &p) { 42 | os << "(" << p.first << "," << p.second << ")"; 43 | return os; 44 | } 45 | 46 | // Provide pair equality testing that works as long as x.first is comparable to 47 | // y.first and x.second is comparable to y.second. Needed in the test for 48 | // comparing std::pair to std::pair. 49 | template 50 | bool operator==(const std::pair &x, const std::pair &y) { 51 | return x.first == y.first && x.second == y.second; 52 | } 53 | 54 | // Partial specialization of remove_const that propagates the removal through 55 | // std::pair. 56 | template 57 | struct remove_const > { 58 | typedef pair::type, 59 | typename remove_const::type> type; 60 | }; 61 | 62 | } // namespace std 63 | 64 | namespace btree { 65 | 66 | // Select the first member of a pair. 67 | template 68 | struct select1st : public std::unary_function<_Pair, typename _Pair::first_type> { 69 | const typename _Pair::first_type& operator()(const _Pair& __x) const { 70 | return __x.first; 71 | } 72 | }; 73 | 74 | // Utility class to provide an accessor for a key given a value. The default 75 | // behavior is to treat the value as a pair and return the first element. 76 | template 77 | struct KeyOfValue { 78 | typedef select1st type; 79 | }; 80 | 81 | template 82 | struct identity { 83 | inline const T& operator()(const T& t) const { return t; } 84 | }; 85 | 86 | // Partial specialization of KeyOfValue class for when the key and value are 87 | // the same type such as in set<> and btree_set<>. 88 | template 89 | struct KeyOfValue { 90 | typedef identity type; 91 | }; 92 | 93 | // Counts the number of occurances of "c" in a buffer. 94 | inline ptrdiff_t strcount(const char* buf_begin, const char* buf_end, char c) { 95 | if (buf_begin == NULL) 96 | return 0; 97 | if (buf_end <= buf_begin) 98 | return 0; 99 | ptrdiff_t num = 0; 100 | for (const char* bp = buf_begin; bp != buf_end; bp++) { 101 | if (*bp == c) 102 | num++; 103 | } 104 | return num; 105 | } 106 | 107 | // for when the string is not null-terminated. 108 | inline ptrdiff_t strcount(const char* buf, size_t len, char c) { 109 | return strcount(buf, buf + len, c); 110 | } 111 | 112 | inline ptrdiff_t strcount(const std::string& buf, char c) { 113 | return strcount(buf.c_str(), buf.size(), c); 114 | } 115 | 116 | // The base class for a sorted associative container checker. TreeType is the 117 | // container type to check and CheckerType is the container type to check 118 | // against. TreeType is expected to be btree_{set,map,multiset,multimap} and 119 | // CheckerType is expected to be {set,map,multiset,multimap}. 120 | template 121 | class base_checker { 122 | typedef base_checker self_type; 123 | 124 | public: 125 | typedef typename TreeType::key_type key_type; 126 | typedef typename TreeType::value_type value_type; 127 | typedef typename TreeType::key_compare key_compare; 128 | typedef typename TreeType::pointer pointer; 129 | typedef typename TreeType::const_pointer const_pointer; 130 | typedef typename TreeType::reference reference; 131 | typedef typename TreeType::const_reference const_reference; 132 | typedef typename TreeType::size_type size_type; 133 | typedef typename TreeType::difference_type difference_type; 134 | typedef typename TreeType::iterator iterator; 135 | typedef typename TreeType::const_iterator const_iterator; 136 | typedef typename TreeType::reverse_iterator reverse_iterator; 137 | typedef typename TreeType::const_reverse_iterator const_reverse_iterator; 138 | 139 | public: 140 | // Default constructor. 141 | base_checker() 142 | : const_tree_(tree_) { 143 | } 144 | // Copy constructor. 145 | base_checker(const self_type &x) 146 | : tree_(x.tree_), 147 | const_tree_(tree_), 148 | checker_(x.checker_) { 149 | } 150 | // Range constructor. 151 | template 152 | base_checker(InputIterator b, InputIterator e) 153 | : tree_(b, e), 154 | const_tree_(tree_), 155 | checker_(b, e) { 156 | } 157 | 158 | // Iterator routines. 159 | iterator begin() { return tree_.begin(); } 160 | const_iterator begin() const { return tree_.begin(); } 161 | iterator end() { return tree_.end(); } 162 | const_iterator end() const { return tree_.end(); } 163 | reverse_iterator rbegin() { return tree_.rbegin(); } 164 | const_reverse_iterator rbegin() const { return tree_.rbegin(); } 165 | reverse_iterator rend() { return tree_.rend(); } 166 | const_reverse_iterator rend() const { return tree_.rend(); } 167 | 168 | // Helper routines. 169 | template 170 | IterType iter_check( 171 | IterType tree_iter, CheckerIterType checker_iter) const { 172 | if (tree_iter == tree_.end()) { 173 | EXPECT_EQ(checker_iter, checker_.end()); 174 | } else { 175 | EXPECT_EQ(*tree_iter, *checker_iter); 176 | } 177 | return tree_iter; 178 | } 179 | template 180 | IterType riter_check( 181 | IterType tree_iter, CheckerIterType checker_iter) const { 182 | if (tree_iter == tree_.rend()) { 183 | EXPECT_EQ(checker_iter, checker_.rend()); 184 | } else { 185 | EXPECT_EQ(*tree_iter, *checker_iter); 186 | } 187 | return tree_iter; 188 | } 189 | void value_check(const value_type &x) { 190 | typename KeyOfValue::type key_of_value; 192 | const key_type &key = key_of_value(x); 193 | EXPECT_EQ(*find(key), x); 194 | lower_bound(key); 195 | upper_bound(key); 196 | equal_range(key); 197 | count(key); 198 | } 199 | void erase_check(const key_type &key) { 200 | EXPECT_TRUE(tree_.find(key) == const_tree_.end()); 201 | EXPECT_TRUE(const_tree_.find(key) == tree_.end()); 202 | EXPECT_TRUE(tree_.equal_range(key).first == 203 | const_tree_.equal_range(key).second); 204 | } 205 | 206 | // Lookup routines. 207 | iterator lower_bound(const key_type &key) { 208 | return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); 209 | } 210 | const_iterator lower_bound(const key_type &key) const { 211 | return iter_check(tree_.lower_bound(key), checker_.lower_bound(key)); 212 | } 213 | iterator upper_bound(const key_type &key) { 214 | return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); 215 | } 216 | const_iterator upper_bound(const key_type &key) const { 217 | return iter_check(tree_.upper_bound(key), checker_.upper_bound(key)); 218 | } 219 | std::pair equal_range(const key_type &key) { 220 | std::pair checker_res = 222 | checker_.equal_range(key); 223 | std::pair tree_res = tree_.equal_range(key); 224 | iter_check(tree_res.first, checker_res.first); 225 | iter_check(tree_res.second, checker_res.second); 226 | return tree_res; 227 | } 228 | std::pair equal_range(const key_type &key) const { 229 | std::pair checker_res = 231 | checker_.equal_range(key); 232 | std::pair tree_res = tree_.equal_range(key); 233 | iter_check(tree_res.first, checker_res.first); 234 | iter_check(tree_res.second, checker_res.second); 235 | return tree_res; 236 | } 237 | iterator find(const key_type &key) { 238 | return iter_check(tree_.find(key), checker_.find(key)); 239 | } 240 | const_iterator find(const key_type &key) const { 241 | return iter_check(tree_.find(key), checker_.find(key)); 242 | } 243 | size_type count(const key_type &key) const { 244 | size_type res = checker_.count(key); 245 | EXPECT_EQ(res, tree_.count(key)); 246 | return res; 247 | } 248 | 249 | // Assignment operator. 250 | self_type& operator=(const self_type &x) { 251 | tree_ = x.tree_; 252 | checker_ = x.checker_; 253 | return *this; 254 | } 255 | 256 | // Deletion routines. 257 | int erase(const key_type &key) { 258 | int size = tree_.size(); 259 | int res = checker_.erase(key); 260 | EXPECT_EQ(res, tree_.count(key)); 261 | EXPECT_EQ(res, tree_.erase(key)); 262 | EXPECT_EQ(tree_.count(key), 0); 263 | EXPECT_EQ(tree_.size(), size - res); 264 | erase_check(key); 265 | return res; 266 | } 267 | iterator erase(iterator iter) { 268 | key_type key = iter.key(); 269 | int size = tree_.size(); 270 | int count = tree_.count(key); 271 | typename CheckerType::iterator checker_iter = checker_.find(key); 272 | for (iterator tmp(tree_.find(key)); tmp != iter; ++tmp) { 273 | ++checker_iter; 274 | } 275 | typename CheckerType::iterator checker_next = checker_iter; 276 | ++checker_next; 277 | checker_.erase(checker_iter); 278 | iter = tree_.erase(iter); 279 | EXPECT_EQ(tree_.size(), checker_.size()); 280 | EXPECT_EQ(tree_.size(), size - 1); 281 | EXPECT_EQ(tree_.count(key), count - 1); 282 | if (count == 1) { 283 | erase_check(key); 284 | } 285 | return iter_check(iter, checker_next); 286 | } 287 | 288 | void erase(iterator begin, iterator end) { 289 | int size = tree_.size(); 290 | int count = distance(begin, end); 291 | typename CheckerType::iterator checker_begin = checker_.find(begin.key()); 292 | for (iterator tmp(tree_.find(begin.key())); tmp != begin; ++tmp) { 293 | ++checker_begin; 294 | } 295 | typename CheckerType::iterator checker_end = 296 | end == tree_.end() ? checker_.end() : checker_.find(end.key()); 297 | if (end != tree_.end()) { 298 | for (iterator tmp(tree_.find(end.key())); tmp != end; ++tmp) { 299 | ++checker_end; 300 | } 301 | } 302 | checker_.erase(checker_begin, checker_end); 303 | tree_.erase(begin, end); 304 | EXPECT_EQ(tree_.size(), checker_.size()); 305 | EXPECT_EQ(tree_.size(), size - count); 306 | } 307 | 308 | // Utility routines. 309 | void clear() { 310 | tree_.clear(); 311 | checker_.clear(); 312 | } 313 | void swap(self_type &x) { 314 | tree_.swap(x.tree_); 315 | checker_.swap(x.checker_); 316 | } 317 | 318 | void verify() const { 319 | tree_.verify(); 320 | EXPECT_EQ(tree_.size(), checker_.size()); 321 | 322 | // Move through the forward iterators using increment. 323 | typename CheckerType::const_iterator 324 | checker_iter(checker_.begin()); 325 | const_iterator tree_iter(tree_.begin()); 326 | for (; tree_iter != tree_.end(); 327 | ++tree_iter, ++checker_iter) { 328 | EXPECT_EQ(*tree_iter, *checker_iter); 329 | } 330 | 331 | // Move through the forward iterators using decrement. 332 | for (int n = tree_.size() - 1; n >= 0; --n) { 333 | iter_check(tree_iter, checker_iter); 334 | --tree_iter; 335 | --checker_iter; 336 | } 337 | EXPECT_TRUE(tree_iter == tree_.begin()); 338 | EXPECT_TRUE(checker_iter == checker_.begin()); 339 | 340 | // Move through the reverse iterators using increment. 341 | typename CheckerType::const_reverse_iterator 342 | checker_riter(checker_.rbegin()); 343 | const_reverse_iterator tree_riter(tree_.rbegin()); 344 | for (; tree_riter != tree_.rend(); 345 | ++tree_riter, ++checker_riter) { 346 | EXPECT_EQ(*tree_riter, *checker_riter); 347 | } 348 | 349 | // Move through the reverse iterators using decrement. 350 | for (int n = tree_.size() - 1; n >= 0; --n) { 351 | riter_check(tree_riter, checker_riter); 352 | --tree_riter; 353 | --checker_riter; 354 | } 355 | EXPECT_EQ(tree_riter, tree_.rbegin()); 356 | EXPECT_EQ(checker_riter, checker_.rbegin()); 357 | } 358 | 359 | // Access to the underlying btree. 360 | const TreeType& tree() const { return tree_; } 361 | 362 | // Size routines. 363 | size_type size() const { 364 | EXPECT_EQ(tree_.size(), checker_.size()); 365 | return tree_.size(); 366 | } 367 | size_type max_size() const { return tree_.max_size(); } 368 | bool empty() const { 369 | EXPECT_EQ(tree_.empty(), checker_.empty()); 370 | return tree_.empty(); 371 | } 372 | size_type height() const { return tree_.height(); } 373 | size_type internal_nodes() const { return tree_.internal_nodes(); } 374 | size_type leaf_nodes() const { return tree_.leaf_nodes(); } 375 | size_type nodes() const { return tree_.nodes(); } 376 | size_type bytes_used() const { return tree_.bytes_used(); } 377 | double fullness() const { return tree_.fullness(); } 378 | double overhead() const { return tree_.overhead(); } 379 | 380 | protected: 381 | TreeType tree_; 382 | const TreeType &const_tree_; 383 | CheckerType checker_; 384 | }; 385 | 386 | // A checker for unique sorted associative containers. TreeType is expected to 387 | // be btree_{set,map} and CheckerType is expected to be {set,map}. 388 | template 389 | class unique_checker : public base_checker { 390 | typedef base_checker super_type; 391 | typedef unique_checker self_type; 392 | 393 | public: 394 | typedef typename super_type::iterator iterator; 395 | typedef typename super_type::value_type value_type; 396 | 397 | public: 398 | // Default constructor. 399 | unique_checker() 400 | : super_type() { 401 | } 402 | // Copy constructor. 403 | unique_checker(const self_type &x) 404 | : super_type(x) { 405 | } 406 | // Range constructor. 407 | template 408 | unique_checker(InputIterator b, InputIterator e) 409 | : super_type(b, e) { 410 | } 411 | 412 | // Insertion routines. 413 | std::pair insert(const value_type &x) { 414 | int size = this->tree_.size(); 415 | std::pair checker_res = 416 | this->checker_.insert(x); 417 | std::pair tree_res = this->tree_.insert(x); 418 | EXPECT_EQ(*tree_res.first, *checker_res.first); 419 | EXPECT_EQ(tree_res.second, checker_res.second); 420 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); 421 | EXPECT_EQ(this->tree_.size(), size + tree_res.second); 422 | return tree_res; 423 | } 424 | iterator insert(iterator position, const value_type &x) { 425 | int size = this->tree_.size(); 426 | std::pair checker_res = 427 | this->checker_.insert(x); 428 | iterator tree_res = this->tree_.insert(position, x); 429 | EXPECT_EQ(*tree_res, *checker_res.first); 430 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); 431 | EXPECT_EQ(this->tree_.size(), size + checker_res.second); 432 | return tree_res; 433 | } 434 | template 435 | void insert(InputIterator b, InputIterator e) { 436 | for (; b != e; ++b) { 437 | insert(*b); 438 | } 439 | } 440 | }; 441 | 442 | // A checker for multiple sorted associative containers. TreeType is expected 443 | // to be btree_{multiset,multimap} and CheckerType is expected to be 444 | // {multiset,multimap}. 445 | template 446 | class multi_checker : public base_checker { 447 | typedef base_checker super_type; 448 | typedef multi_checker self_type; 449 | 450 | public: 451 | typedef typename super_type::iterator iterator; 452 | typedef typename super_type::value_type value_type; 453 | 454 | public: 455 | // Default constructor. 456 | multi_checker() 457 | : super_type() { 458 | } 459 | // Copy constructor. 460 | multi_checker(const self_type &x) 461 | : super_type(x) { 462 | } 463 | // Range constructor. 464 | template 465 | multi_checker(InputIterator b, InputIterator e) 466 | : super_type(b, e) { 467 | } 468 | 469 | // Insertion routines. 470 | iterator insert(const value_type &x) { 471 | int size = this->tree_.size(); 472 | typename CheckerType::iterator checker_res = this->checker_.insert(x); 473 | iterator tree_res = this->tree_.insert(x); 474 | EXPECT_EQ(*tree_res, *checker_res); 475 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); 476 | EXPECT_EQ(this->tree_.size(), size + 1); 477 | return tree_res; 478 | } 479 | iterator insert(iterator position, const value_type &x) { 480 | int size = this->tree_.size(); 481 | typename CheckerType::iterator checker_res = this->checker_.insert(x); 482 | iterator tree_res = this->tree_.insert(position, x); 483 | EXPECT_EQ(*tree_res, *checker_res); 484 | EXPECT_EQ(this->tree_.size(), this->checker_.size()); 485 | EXPECT_EQ(this->tree_.size(), size + 1); 486 | return tree_res; 487 | } 488 | template 489 | void insert(InputIterator b, InputIterator e) { 490 | for (; b != e; ++b) { 491 | insert(*b); 492 | } 493 | } 494 | }; 495 | 496 | char* GenerateDigits(char buf[16], int val, int maxval) { 497 | EXPECT_LE(val, maxval); 498 | int p = 15; 499 | buf[p--] = 0; 500 | while (maxval > 0) { 501 | buf[p--] = '0' + (val % 10); 502 | val /= 10; 503 | maxval /= 10; 504 | } 505 | return buf + p + 1; 506 | } 507 | 508 | template 509 | struct Generator { 510 | int maxval; 511 | Generator(int m) 512 | : maxval(m) { 513 | } 514 | K operator()(int i) const { 515 | EXPECT_LE(i, maxval); 516 | return i; 517 | } 518 | }; 519 | 520 | template <> 521 | struct Generator { 522 | int maxval; 523 | Generator(int m) 524 | : maxval(m) { 525 | } 526 | std::string operator()(int i) const { 527 | char buf[16]; 528 | return GenerateDigits(buf, i, maxval); 529 | } 530 | }; 531 | 532 | template 533 | struct Generator > { 534 | Generator::type> tgen; 535 | Generator::type> ugen; 536 | 537 | Generator(int m) 538 | : tgen(m), 539 | ugen(m) { 540 | } 541 | std::pair operator()(int i) const { 542 | return std::make_pair(tgen(i), ugen(i)); 543 | } 544 | }; 545 | 546 | // Generate values for our tests and benchmarks. Value range is [0, maxval]. 547 | const std::vector& GenerateNumbers(int n, int maxval) { 548 | static std::vector values; 549 | static std::set unique_values; 550 | 551 | if (values.size() < n) { 552 | 553 | for (int i = values.size(); i < n; i++) { 554 | int value; 555 | do { 556 | value = rand() % (maxval + 1); 557 | } while (unique_values.find(value) != unique_values.end()); 558 | 559 | values.push_back(value); 560 | unique_values.insert(value); 561 | } 562 | } 563 | 564 | return values; 565 | } 566 | 567 | // Generates values in the range 568 | // [0, 4 * min(FLAGS_benchmark_values, FLAGS_test_values)] 569 | template 570 | std::vector GenerateValues(int n) { 571 | int two_times_max = 2 * std::max(FLAGS_benchmark_values, FLAGS_test_values); 572 | int four_times_max = 2 * two_times_max; 573 | EXPECT_LE(n, two_times_max); 574 | const std::vector &nums = GenerateNumbers(n, four_times_max); 575 | Generator gen(four_times_max); 576 | std::vector vec; 577 | 578 | for (int i = 0; i < n; i++) { 579 | vec.push_back(gen(nums[i])); 580 | } 581 | 582 | return vec; 583 | } 584 | 585 | template 586 | void DoTest(const char *name, T *b, const std::vector &values) { 587 | typename KeyOfValue::type key_of_value; 588 | 589 | T &mutable_b = *b; 590 | const T &const_b = *b; 591 | 592 | // Test insert. 593 | for (int i = 0; i < values.size(); ++i) { 594 | mutable_b.insert(values[i]); 595 | mutable_b.value_check(values[i]); 596 | } 597 | assert(mutable_b.size() == values.size()); 598 | 599 | const_b.verify(); 600 | printf(" %s fullness=%0.2f overhead=%0.2f bytes-per-value=%0.2f\n", 601 | name, const_b.fullness(), const_b.overhead(), 602 | double(const_b.bytes_used()) / const_b.size()); 603 | 604 | // Test copy constructor. 605 | T b_copy(const_b); 606 | EXPECT_EQ(b_copy.size(), const_b.size()); 607 | EXPECT_LE(b_copy.height(), const_b.height()); 608 | EXPECT_LE(b_copy.internal_nodes(), const_b.internal_nodes()); 609 | EXPECT_LE(b_copy.leaf_nodes(), const_b.leaf_nodes()); 610 | for (int i = 0; i < values.size(); ++i) { 611 | EXPECT_EQ(*b_copy.find(key_of_value(values[i])), values[i]); 612 | } 613 | 614 | // Test range constructor. 615 | T b_range(const_b.begin(), const_b.end()); 616 | EXPECT_EQ(b_range.size(), const_b.size()); 617 | EXPECT_LE(b_range.height(), const_b.height()); 618 | EXPECT_LE(b_range.internal_nodes(), const_b.internal_nodes()); 619 | EXPECT_LE(b_range.leaf_nodes(), const_b.leaf_nodes()); 620 | for (int i = 0; i < values.size(); ++i) { 621 | EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]); 622 | } 623 | 624 | // Test range insertion for values that already exist. 625 | b_range.insert(b_copy.begin(), b_copy.end()); 626 | b_range.verify(); 627 | 628 | // Test range insertion for new values. 629 | b_range.clear(); 630 | b_range.insert(b_copy.begin(), b_copy.end()); 631 | EXPECT_EQ(b_range.size(), b_copy.size()); 632 | EXPECT_EQ(b_range.height(), b_copy.height()); 633 | EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes()); 634 | EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes()); 635 | for (int i = 0; i < values.size(); ++i) { 636 | EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]); 637 | } 638 | 639 | // Test assignment to self. Nothing should change. 640 | b_range.operator=(b_range); 641 | EXPECT_EQ(b_range.size(), b_copy.size()); 642 | EXPECT_EQ(b_range.height(), b_copy.height()); 643 | EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes()); 644 | EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes()); 645 | 646 | // Test assignment of new values. 647 | b_range.clear(); 648 | b_range = b_copy; 649 | EXPECT_EQ(b_range.size(), b_copy.size()); 650 | EXPECT_EQ(b_range.height(), b_copy.height()); 651 | EXPECT_EQ(b_range.internal_nodes(), b_copy.internal_nodes()); 652 | EXPECT_EQ(b_range.leaf_nodes(), b_copy.leaf_nodes()); 653 | 654 | // Test swap. 655 | b_range.clear(); 656 | b_range.swap(b_copy); 657 | EXPECT_EQ(b_copy.size(), 0); 658 | EXPECT_EQ(b_range.size(), const_b.size()); 659 | for (int i = 0; i < values.size(); ++i) { 660 | EXPECT_EQ(*b_range.find(key_of_value(values[i])), values[i]); 661 | } 662 | b_range.swap(b_copy); 663 | 664 | // Test erase via values. 665 | for (int i = 0; i < values.size(); ++i) { 666 | mutable_b.erase(key_of_value(values[i])); 667 | // Erasing a non-existent key should have no effect. 668 | EXPECT_EQ(mutable_b.erase(key_of_value(values[i])), 0); 669 | } 670 | 671 | const_b.verify(); 672 | EXPECT_EQ(const_b.internal_nodes(), 0); 673 | EXPECT_EQ(const_b.leaf_nodes(), 0); 674 | EXPECT_EQ(const_b.size(), 0); 675 | 676 | // Test erase via iterators. 677 | mutable_b = b_copy; 678 | for (int i = 0; i < values.size(); ++i) { 679 | mutable_b.erase(mutable_b.find(key_of_value(values[i]))); 680 | } 681 | 682 | const_b.verify(); 683 | EXPECT_EQ(const_b.internal_nodes(), 0); 684 | EXPECT_EQ(const_b.leaf_nodes(), 0); 685 | EXPECT_EQ(const_b.size(), 0); 686 | 687 | // Test insert with hint. 688 | for (int i = 0; i < values.size(); i++) { 689 | mutable_b.insert(mutable_b.upper_bound(key_of_value(values[i])), values[i]); 690 | } 691 | 692 | const_b.verify(); 693 | 694 | // Test dumping of the btree to an ostream. There should be 1 line for each 695 | // value. 696 | std::stringstream strm; 697 | strm << mutable_b.tree(); 698 | EXPECT_EQ(mutable_b.size(), strcount(strm.str(), '\n')); 699 | 700 | // Test range erase. 701 | mutable_b.erase(mutable_b.begin(), mutable_b.end()); 702 | EXPECT_EQ(mutable_b.size(), 0); 703 | const_b.verify(); 704 | 705 | // First half. 706 | mutable_b = b_copy; 707 | typename T::iterator mutable_iter_end = mutable_b.begin(); 708 | for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_end; 709 | mutable_b.erase(mutable_b.begin(), mutable_iter_end); 710 | EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 2); 711 | const_b.verify(); 712 | 713 | // Second half. 714 | mutable_b = b_copy; 715 | typename T::iterator mutable_iter_begin = mutable_b.begin(); 716 | for (int i = 0; i < values.size() / 2; ++i) ++mutable_iter_begin; 717 | mutable_b.erase(mutable_iter_begin, mutable_b.end()); 718 | EXPECT_EQ(mutable_b.size(), values.size() / 2); 719 | const_b.verify(); 720 | 721 | // Second quarter. 722 | mutable_b = b_copy; 723 | mutable_iter_begin = mutable_b.begin(); 724 | for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_begin; 725 | mutable_iter_end = mutable_iter_begin; 726 | for (int i = 0; i < values.size() / 4; ++i) ++mutable_iter_end; 727 | mutable_b.erase(mutable_iter_begin, mutable_iter_end); 728 | EXPECT_EQ(mutable_b.size(), values.size() - values.size() / 4); 729 | const_b.verify(); 730 | 731 | mutable_b.clear(); 732 | } 733 | 734 | template 735 | void ConstTest() { 736 | typedef typename T::value_type value_type; 737 | typename KeyOfValue::type key_of_value; 738 | 739 | T mutable_b; 740 | const T &const_b = mutable_b; 741 | 742 | // Insert a single value into the container and test looking it up. 743 | value_type value = Generator(2)(2); 744 | mutable_b.insert(value); 745 | EXPECT_TRUE(mutable_b.find(key_of_value(value)) != const_b.end()); 746 | EXPECT_TRUE(const_b.find(key_of_value(value)) != mutable_b.end()); 747 | EXPECT_EQ(*const_b.lower_bound(key_of_value(value)), value); 748 | EXPECT_TRUE(const_b.upper_bound(key_of_value(value)) == const_b.end()); 749 | EXPECT_EQ(*const_b.equal_range(key_of_value(value)).first, value); 750 | 751 | // We can only create a non-const iterator from a non-const container. 752 | typename T::iterator mutable_iter(mutable_b.begin()); 753 | EXPECT_TRUE(mutable_iter == const_b.begin()); 754 | EXPECT_TRUE(mutable_iter != const_b.end()); 755 | EXPECT_TRUE(const_b.begin() == mutable_iter); 756 | EXPECT_TRUE(const_b.end() != mutable_iter); 757 | typename T::reverse_iterator mutable_riter(mutable_b.rbegin()); 758 | EXPECT_TRUE(mutable_riter == const_b.rbegin()); 759 | EXPECT_TRUE(mutable_riter != const_b.rend()); 760 | EXPECT_TRUE(const_b.rbegin() == mutable_riter); 761 | EXPECT_TRUE(const_b.rend() != mutable_riter); 762 | 763 | // We can create a const iterator from a non-const iterator. 764 | typename T::const_iterator const_iter(mutable_iter); 765 | EXPECT_TRUE(const_iter == mutable_b.begin()); 766 | EXPECT_TRUE(const_iter != mutable_b.end()); 767 | EXPECT_TRUE(mutable_b.begin() == const_iter); 768 | EXPECT_TRUE(mutable_b.end() != const_iter); 769 | typename T::const_reverse_iterator const_riter(mutable_riter); 770 | EXPECT_EQ(const_riter, mutable_b.rbegin()); 771 | EXPECT_TRUE(const_riter != mutable_b.rend()); 772 | EXPECT_EQ(mutable_b.rbegin(), const_riter); 773 | EXPECT_TRUE(mutable_b.rend() != const_riter); 774 | 775 | // Make sure various methods can be invoked on a const container. 776 | const_b.verify(); 777 | EXPECT_FALSE(const_b.empty()); 778 | EXPECT_EQ(const_b.size(), 1); 779 | EXPECT_GT(const_b.max_size(), 0); 780 | EXPECT_EQ(const_b.height(), 1); 781 | EXPECT_EQ(const_b.count(key_of_value(value)), 1); 782 | EXPECT_EQ(const_b.internal_nodes(), 0); 783 | EXPECT_EQ(const_b.leaf_nodes(), 1); 784 | EXPECT_EQ(const_b.nodes(), 1); 785 | EXPECT_GT(const_b.bytes_used(), 0); 786 | EXPECT_GT(const_b.fullness(), 0); 787 | EXPECT_GT(const_b.overhead(), 0); 788 | } 789 | 790 | template 791 | void BtreeTest() { 792 | ConstTest(); 793 | 794 | typedef typename std::remove_const::type V; 795 | std::vector random_values = GenerateValues(FLAGS_test_values); 796 | 797 | unique_checker container; 798 | 799 | // Test key insertion/deletion in sorted order. 800 | std::vector sorted_values(random_values); 801 | sort(sorted_values.begin(), sorted_values.end()); 802 | DoTest("sorted: ", &container, sorted_values); 803 | 804 | // Test key insertion/deletion in reverse sorted order. 805 | reverse(sorted_values.begin(), sorted_values.end()); 806 | DoTest("rsorted: ", &container, sorted_values); 807 | 808 | // Test key insertion/deletion in random order. 809 | DoTest("random: ", &container, random_values); 810 | } 811 | 812 | template 813 | void BtreeMultiTest() { 814 | ConstTest(); 815 | 816 | typedef typename std::remove_const::type V; 817 | const std::vector& random_values = GenerateValues(FLAGS_test_values); 818 | 819 | multi_checker container; 820 | 821 | // Test keys in sorted order. 822 | std::vector sorted_values(random_values); 823 | sort(sorted_values.begin(), sorted_values.end()); 824 | DoTest("sorted: ", &container, sorted_values); 825 | 826 | // Test keys in reverse sorted order. 827 | reverse(sorted_values.begin(), sorted_values.end()); 828 | DoTest("rsorted: ", &container, sorted_values); 829 | 830 | // Test keys in random order. 831 | DoTest("random: ", &container, random_values); 832 | 833 | // Test keys in random order w/ duplicates. 834 | std::vector duplicate_values(random_values); 835 | duplicate_values.insert( 836 | duplicate_values.end(), random_values.begin(), random_values.end()); 837 | DoTest("duplicates:", &container, duplicate_values); 838 | 839 | // Test all identical keys. 840 | std::vector identical_values(100); 841 | fill(identical_values.begin(), identical_values.end(), Generator(2)(2)); 842 | DoTest("identical: ", &container, identical_values); 843 | } 844 | 845 | template > 846 | class TestAllocator : public Alloc { 847 | public: 848 | typedef typename Alloc::pointer pointer; 849 | typedef typename Alloc::size_type size_type; 850 | 851 | TestAllocator() : bytes_used_(NULL) { } 852 | TestAllocator(int64_t *bytes_used) : bytes_used_(bytes_used) { } 853 | 854 | // Constructor used for rebinding 855 | template 856 | TestAllocator(const TestAllocator& x) 857 | : Alloc(x), 858 | bytes_used_(x.bytes_used()) { 859 | } 860 | 861 | pointer allocate(size_type n, std::allocator::const_pointer hint = 0) { 862 | EXPECT_TRUE(bytes_used_ != NULL); 863 | *bytes_used_ += n * sizeof(T); 864 | return Alloc::allocate(n, hint); 865 | } 866 | 867 | void deallocate(pointer p, size_type n) { 868 | Alloc::deallocate(p, n); 869 | EXPECT_TRUE(bytes_used_ != NULL); 870 | *bytes_used_ -= n * sizeof(T); 871 | } 872 | 873 | // Rebind allows an allocator to be used for a different type 874 | template struct rebind { 875 | typedef TestAllocator::other> other; 876 | }; 877 | 878 | int64_t* bytes_used() const { return bytes_used_; } 879 | 880 | private: 881 | int64_t *bytes_used_; 882 | }; 883 | 884 | template 885 | void BtreeAllocatorTest() { 886 | typedef typename T::value_type value_type; 887 | 888 | int64_t alloc1 = 0; 889 | int64_t alloc2 = 0; 890 | T b1(typename T::key_compare(), &alloc1); 891 | T b2(typename T::key_compare(), &alloc2); 892 | 893 | // This should swap the allocators! 894 | swap(b1, b2); 895 | 896 | for (int i = 0; i < 1000; i++) { 897 | b1.insert(Generator(1000)(i)); 898 | } 899 | 900 | // We should have allocated out of alloc2! 901 | EXPECT_LE(b1.bytes_used(), alloc2 + sizeof(b1)); 902 | EXPECT_GT(alloc2, alloc1); 903 | } 904 | 905 | template 906 | void BtreeMapTest() { 907 | typedef typename T::value_type value_type; 908 | typedef typename T::mapped_type mapped_type; 909 | 910 | mapped_type m = Generator(0)(0); 911 | (void) m; 912 | 913 | T b; 914 | 915 | // Verify we can insert using operator[]. 916 | for (int i = 0; i < 1000; i++) { 917 | value_type v = Generator(1000)(i); 918 | b[v.first] = v.second; 919 | } 920 | EXPECT_EQ(b.size(), 1000); 921 | 922 | // Test whether we can use the "->" operator on iterators and 923 | // reverse_iterators. This stresses the btree_map_params::pair_pointer 924 | // mechanism. 925 | EXPECT_EQ(b.begin()->first, Generator(1000)(0).first); 926 | EXPECT_EQ(b.begin()->second, Generator(1000)(0).second); 927 | EXPECT_EQ(b.rbegin()->first, Generator(1000)(999).first); 928 | EXPECT_EQ(b.rbegin()->second, Generator(1000)(999).second); 929 | } 930 | 931 | template 932 | void BtreeMultiMapTest() { 933 | typedef typename T::mapped_type mapped_type; 934 | mapped_type m = Generator(0)(0); 935 | (void) m; 936 | } 937 | 938 | } // namespace btree 939 | 940 | #endif // UTIL_BTREE_BTREE_TEST_H__ 941 | -------------------------------------------------------------------------------- /btree_test_flags.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gflags/gflags.h" 16 | 17 | DEFINE_int32(test_values, 10000, 18 | "The number of values to use for tests."); 19 | DEFINE_int32(benchmark_values, 1000000, 20 | "The number of values to use for benchmarks."); 21 | -------------------------------------------------------------------------------- /safe_btree.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // A safe_btree<> wraps around a btree<> and removes the caveat that insertion 16 | // and deletion invalidate iterators. A safe_btree<> maintains a generation 17 | // number that is incremented on every mutation. A safe_btree<>::iterator keeps 18 | // a pointer to the safe_btree<> it came from, the generation of the tree when 19 | // it was last validated and the key the underlying btree<>::iterator points 20 | // to. If an iterator is accessed and its generation differs from the tree 21 | // generation it is revalidated. 22 | // 23 | // References and pointers returned by safe_btree iterators are not safe. 24 | // 25 | // See the incorrect usage examples mentioned in safe_btree_set.h and 26 | // safe_btree_map.h. 27 | 28 | #ifndef UTIL_BTREE_SAFE_BTREE_H__ 29 | #define UTIL_BTREE_SAFE_BTREE_H__ 30 | 31 | #include 32 | #include 33 | #include 34 | 35 | #include "btree.h" 36 | 37 | namespace btree { 38 | 39 | template 40 | class safe_btree_iterator { 41 | public: 42 | typedef typename Iterator::key_type key_type; 43 | typedef typename Iterator::value_type value_type; 44 | typedef typename Iterator::size_type size_type; 45 | typedef typename Iterator::difference_type difference_type; 46 | typedef typename Iterator::pointer pointer; 47 | typedef typename Iterator::reference reference; 48 | typedef typename Iterator::const_pointer const_pointer; 49 | typedef typename Iterator::const_reference const_reference; 50 | typedef typename Iterator::iterator_category iterator_category; 51 | typedef typename Tree::iterator iterator; 52 | typedef typename Tree::const_iterator const_iterator; 53 | typedef safe_btree_iterator self_type; 54 | 55 | void update() const { 56 | if (iter_ != tree_->internal_btree()->end()) { 57 | // A positive generation indicates a valid key. 58 | generation_ = tree_->generation(); 59 | key_ = iter_.key(); 60 | } else { 61 | // Use a negative generation to indicate iter_ points to end(). 62 | generation_ = -tree_->generation(); 63 | } 64 | } 65 | 66 | public: 67 | safe_btree_iterator() 68 | : generation_(0), 69 | key_(), 70 | iter_(), 71 | tree_(NULL) { 72 | } 73 | safe_btree_iterator(const iterator &x) 74 | : generation_(x.generation()), 75 | key_(x.key()), 76 | iter_(x.iter()), 77 | tree_(x.tree()) { 78 | } 79 | safe_btree_iterator(Tree *tree, const Iterator &iter) 80 | : generation_(), 81 | key_(), 82 | iter_(iter), 83 | tree_(tree) { 84 | update(); 85 | } 86 | 87 | Tree* tree() const { return tree_; } 88 | int64_t generation() const { return generation_; } 89 | 90 | Iterator* mutable_iter() const { 91 | if (generation_ != tree_->generation()) { 92 | if (generation_ > 0) { 93 | // This does the wrong thing for a multi{set,map}. If my iter was 94 | // pointing to the 2nd of 2 values with the same key, then this will 95 | // reset it to point to the first. This is why we don't provide a 96 | // safe_btree_multi{set,map}. 97 | iter_ = tree_->internal_btree()->lower_bound(key_); 98 | update(); 99 | } else if (-generation_ != tree_->generation()) { 100 | iter_ = tree_->internal_btree()->end(); 101 | generation_ = -tree_->generation(); 102 | } 103 | } 104 | return &iter_; 105 | } 106 | const Iterator& iter() const { 107 | return *mutable_iter(); 108 | } 109 | 110 | // Equality/inequality operators. 111 | bool operator==(const const_iterator &x) const { 112 | return iter() == x.iter(); 113 | } 114 | bool operator!=(const const_iterator &x) const { 115 | return iter() != x.iter(); 116 | } 117 | 118 | // Accessors for the key/value the iterator is pointing at. 119 | const key_type& key() const { 120 | return key_; 121 | } 122 | // This reference value is potentially invalidated by any non-const 123 | // method on the tree; it is NOT safe. 124 | reference operator*() const { 125 | assert(generation_ > 0); 126 | return iter().operator*(); 127 | } 128 | // This pointer value is potentially invalidated by any non-const 129 | // method on the tree; it is NOT safe. 130 | pointer operator->() const { 131 | assert(generation_ > 0); 132 | return iter().operator->(); 133 | } 134 | 135 | // Increment/decrement operators. 136 | self_type& operator++() { 137 | ++(*mutable_iter()); 138 | update(); 139 | return *this; 140 | } 141 | self_type& operator--() { 142 | --(*mutable_iter()); 143 | update(); 144 | return *this; 145 | } 146 | self_type operator++(int) { 147 | self_type tmp = *this; 148 | ++*this; 149 | return tmp; 150 | } 151 | self_type operator--(int) { 152 | self_type tmp = *this; 153 | --*this; 154 | return tmp; 155 | } 156 | 157 | private: 158 | // The generation of the tree when "iter" was updated. 159 | mutable int64_t generation_; 160 | // The key the iterator points to. 161 | mutable key_type key_; 162 | // The underlying iterator. 163 | mutable Iterator iter_; 164 | // The tree the iterator is associated with. 165 | Tree *tree_; 166 | }; 167 | 168 | template 169 | class safe_btree { 170 | typedef safe_btree self_type; 171 | 172 | typedef btree btree_type; 173 | typedef typename btree_type::iterator tree_iterator; 174 | typedef typename btree_type::const_iterator tree_const_iterator; 175 | 176 | public: 177 | typedef typename btree_type::params_type params_type; 178 | typedef typename btree_type::key_type key_type; 179 | typedef typename btree_type::data_type data_type; 180 | typedef typename btree_type::mapped_type mapped_type; 181 | typedef typename btree_type::value_type value_type; 182 | typedef typename btree_type::key_compare key_compare; 183 | typedef typename btree_type::allocator_type allocator_type; 184 | typedef typename btree_type::pointer pointer; 185 | typedef typename btree_type::const_pointer const_pointer; 186 | typedef typename btree_type::reference reference; 187 | typedef typename btree_type::const_reference const_reference; 188 | typedef typename btree_type::size_type size_type; 189 | typedef typename btree_type::difference_type difference_type; 190 | typedef safe_btree_iterator iterator; 191 | typedef safe_btree_iterator< 192 | const self_type, tree_const_iterator> const_iterator; 193 | typedef std::reverse_iterator const_reverse_iterator; 194 | typedef std::reverse_iterator reverse_iterator; 195 | 196 | public: 197 | // Default constructor. 198 | safe_btree(const key_compare &comp, const allocator_type &alloc) 199 | : tree_(comp, alloc), 200 | generation_(1) { 201 | } 202 | 203 | // Copy constructor. 204 | safe_btree(const self_type &x) 205 | : tree_(x.tree_), 206 | generation_(1) { 207 | } 208 | 209 | iterator begin() { 210 | return iterator(this, tree_.begin()); 211 | } 212 | const_iterator begin() const { 213 | return const_iterator(this, tree_.begin()); 214 | } 215 | iterator end() { 216 | return iterator(this, tree_.end()); 217 | } 218 | const_iterator end() const { 219 | return const_iterator(this, tree_.end()); 220 | } 221 | reverse_iterator rbegin() { 222 | return reverse_iterator(end()); 223 | } 224 | const_reverse_iterator rbegin() const { 225 | return const_reverse_iterator(end()); 226 | } 227 | reverse_iterator rend() { 228 | return reverse_iterator(begin()); 229 | } 230 | const_reverse_iterator rend() const { 231 | return const_reverse_iterator(begin()); 232 | } 233 | 234 | // Lookup routines. 235 | iterator lower_bound(const key_type &key) { 236 | return iterator(this, tree_.lower_bound(key)); 237 | } 238 | const_iterator lower_bound(const key_type &key) const { 239 | return const_iterator(this, tree_.lower_bound(key)); 240 | } 241 | iterator upper_bound(const key_type &key) { 242 | return iterator(this, tree_.upper_bound(key)); 243 | } 244 | const_iterator upper_bound(const key_type &key) const { 245 | return const_iterator(this, tree_.upper_bound(key)); 246 | } 247 | std::pair equal_range(const key_type &key) { 248 | std::pair p = tree_.equal_range(key); 249 | return std::make_pair(iterator(this, p.first), 250 | iterator(this, p.second)); 251 | } 252 | std::pair equal_range(const key_type &key) const { 253 | std::pair p = tree_.equal_range(key); 254 | return std::make_pair(const_iterator(this, p.first), 255 | const_iterator(this, p.second)); 256 | } 257 | iterator find_unique(const key_type &key) { 258 | return iterator(this, tree_.find_unique(key)); 259 | } 260 | const_iterator find_unique(const key_type &key) const { 261 | return const_iterator(this, tree_.find_unique(key)); 262 | } 263 | iterator find_multi(const key_type &key) { 264 | return iterator(this, tree_.find_multi(key)); 265 | } 266 | const_iterator find_multi(const key_type &key) const { 267 | return const_iterator(this, tree_.find_multi(key)); 268 | } 269 | size_type count_unique(const key_type &key) const { 270 | return tree_.count_unique(key); 271 | } 272 | size_type count_multi(const key_type &key) const { 273 | return tree_.count_multi(key); 274 | } 275 | 276 | // Insertion routines. 277 | template 278 | std::pair insert_unique(const key_type &key, ValuePointer value) { 279 | std::pair p = tree_.insert_unique(key, value); 280 | generation_ += p.second; 281 | return std::make_pair(iterator(this, p.first), p.second); 282 | } 283 | std::pair insert_unique(const value_type &v) { 284 | std::pair p = tree_.insert_unique(v); 285 | generation_ += p.second; 286 | return std::make_pair(iterator(this, p.first), p.second); 287 | } 288 | iterator insert_unique(iterator position, const value_type &v) { 289 | tree_iterator tree_pos = position.iter(); 290 | ++generation_; 291 | return iterator(this, tree_.insert_unique(tree_pos, v)); 292 | } 293 | template 294 | void insert_unique(InputIterator b, InputIterator e) { 295 | for (; b != e; ++b) { 296 | insert_unique(*b); 297 | } 298 | } 299 | iterator insert_multi(const value_type &v) { 300 | ++generation_; 301 | return iterator(this, tree_.insert_multi(v)); 302 | } 303 | iterator insert_multi(iterator position, const value_type &v) { 304 | tree_iterator tree_pos = position.iter(); 305 | ++generation_; 306 | return iterator(this, tree_.insert_multi(tree_pos, v)); 307 | } 308 | template 309 | void insert_multi(InputIterator b, InputIterator e) { 310 | for (; b != e; ++b) { 311 | insert_multi(*b); 312 | } 313 | } 314 | self_type& operator=(const self_type &x) { 315 | if (&x == this) { 316 | // Don't copy onto ourselves. 317 | return *this; 318 | } 319 | ++generation_; 320 | tree_ = x.tree_; 321 | return *this; 322 | } 323 | 324 | // Deletion routines. 325 | void erase(const iterator &begin, const iterator &end) { 326 | tree_.erase(begin.iter(), end.iter()); 327 | ++generation_; 328 | } 329 | // Erase the specified iterator from the btree. The iterator must be valid 330 | // (i.e. not equal to end()). Return an iterator pointing to the node after 331 | // the one that was erased (or end() if none exists). 332 | iterator erase(iterator iter) { 333 | tree_iterator res = tree_.erase(iter.iter()); 334 | ++generation_; 335 | return iterator(this, res); 336 | } 337 | int erase_unique(const key_type &key) { 338 | int res = tree_.erase_unique(key); 339 | generation_ += res; 340 | return res; 341 | } 342 | int erase_multi(const key_type &key) { 343 | int res = tree_.erase_multi(key); 344 | generation_ += res; 345 | return res; 346 | } 347 | 348 | // Access to the underlying btree. 349 | btree_type* internal_btree() { return &tree_; } 350 | const btree_type* internal_btree() const { return &tree_; } 351 | 352 | // Utility routines. 353 | void clear() { 354 | ++generation_; 355 | tree_.clear(); 356 | } 357 | void swap(self_type &x) { 358 | ++generation_; 359 | ++x.generation_; 360 | tree_.swap(x.tree_); 361 | } 362 | void dump(std::ostream &os) const { 363 | tree_.dump(os); 364 | } 365 | void verify() const { 366 | tree_.verify(); 367 | } 368 | int64_t generation() const { 369 | return generation_; 370 | } 371 | key_compare key_comp() const { return tree_.key_comp(); } 372 | 373 | // Size routines. 374 | size_type size() const { return tree_.size(); } 375 | size_type max_size() const { return tree_.max_size(); } 376 | bool empty() const { return tree_.empty(); } 377 | size_type height() const { return tree_.height(); } 378 | size_type internal_nodes() const { return tree_.internal_nodes(); } 379 | size_type leaf_nodes() const { return tree_.leaf_nodes(); } 380 | size_type nodes() const { return tree_.nodes(); } 381 | size_type bytes_used() const { return tree_.bytes_used(); } 382 | static double average_bytes_per_value() { 383 | return btree_type::average_bytes_per_value(); 384 | } 385 | double fullness() const { return tree_.fullness(); } 386 | double overhead() const { return tree_.overhead(); } 387 | 388 | private: 389 | btree_type tree_; 390 | int64_t generation_; 391 | }; 392 | 393 | } // namespace btree 394 | 395 | #endif // UTIL_BTREE_SAFE_BTREE_H__ 396 | -------------------------------------------------------------------------------- /safe_btree_map.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // The safe_btree_map<> is like btree_map<> except that it removes the caveat 16 | // about insertion and deletion invalidating existing iterators at a small cost 17 | // in making iterators larger and slower. 18 | // 19 | // Revalidation occurs whenever an iterator is accessed. References 20 | // and pointers returned by safe_btree_map<> iterators are not stable, 21 | // they are potentially invalidated by any non-const method on the map. 22 | // 23 | // BEGIN INCORRECT EXAMPLE 24 | // for (auto i = safe_map->begin(); i != safe_map->end(); ++i) { 25 | // const T *value = &i->second; // DO NOT DO THIS 26 | // [code that modifies safe_map and uses value]; 27 | // } 28 | // END INCORRECT EXAMPLE 29 | #ifndef UTIL_BTREE_SAFE_BTREE_MAP_H__ 30 | #define UTIL_BTREE_SAFE_BTREE_MAP_H__ 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include "btree_container.h" 37 | #include "btree_map.h" 38 | #include "safe_btree.h" 39 | 40 | namespace btree { 41 | 42 | // The safe_btree_map class is needed mainly for its constructors. 43 | template , 45 | typename Alloc = std::allocator >, 46 | int TargetNodeSize = 256> 47 | class safe_btree_map : public btree_map_container< 48 | safe_btree > > { 49 | 50 | typedef safe_btree_map self_type; 51 | typedef btree_map_params< 52 | Key, Value, Compare, Alloc, TargetNodeSize> params_type; 53 | typedef safe_btree btree_type; 54 | typedef btree_map_container super_type; 55 | 56 | public: 57 | typedef typename btree_type::key_compare key_compare; 58 | typedef typename btree_type::allocator_type allocator_type; 59 | 60 | public: 61 | // Default constructor. 62 | safe_btree_map(const key_compare &comp = key_compare(), 63 | const allocator_type &alloc = allocator_type()) 64 | : super_type(comp, alloc) { 65 | } 66 | 67 | // Copy constructor. 68 | safe_btree_map(const self_type &x) 69 | : super_type(x) { 70 | } 71 | 72 | // Range constructor. 73 | template 74 | safe_btree_map(InputIterator b, InputIterator e, 75 | const key_compare &comp = key_compare(), 76 | const allocator_type &alloc = allocator_type()) 77 | : super_type(b, e, comp, alloc) { 78 | } 79 | }; 80 | 81 | template 82 | inline void swap(safe_btree_map &x, 83 | safe_btree_map &y) { 84 | x.swap(y); 85 | } 86 | 87 | } // namespace btree 88 | 89 | #endif // UTIL_BTREE_SAFE_BTREE_MAP_H__ 90 | -------------------------------------------------------------------------------- /safe_btree_set.h: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // The safe_btree_set<> is like btree_set<> except that it removes the caveat 16 | // about insertion and deletion invalidating existing iterators at a small cost 17 | // in making iterators larger and slower. 18 | // 19 | // Revalidation occurs whenever an iterator is accessed. References 20 | // and pointers returned by safe_btree_map<> iterators are not stable, 21 | // they are potentially invalidated by any non-const method on the set. 22 | // 23 | // BEGIN INCORRECT EXAMPLE 24 | // for (auto i = safe_set->begin(); i != safe_set->end(); ++i) { 25 | // const T &value = *i; // DO NOT DO THIS 26 | // [code that modifies safe_set and uses value]; 27 | // } 28 | // END INCORRECT EXAMPLE 29 | 30 | #ifndef UTIL_BTREE_SAFE_BTREE_SET_H__ 31 | #define UTIL_BTREE_SAFE_BTREE_SET_H__ 32 | 33 | #include 34 | #include 35 | 36 | #include "btree_container.h" 37 | #include "btree_set.h" 38 | #include "safe_btree.h" 39 | 40 | namespace btree { 41 | 42 | // The safe_btree_set class is needed mainly for its constructors. 43 | template , 45 | typename Alloc = std::allocator, 46 | int TargetNodeSize = 256> 47 | class safe_btree_set : public btree_unique_container< 48 | safe_btree > > { 49 | 50 | typedef safe_btree_set self_type; 51 | typedef btree_set_params params_type; 52 | typedef safe_btree btree_type; 53 | typedef btree_unique_container super_type; 54 | 55 | public: 56 | typedef typename btree_type::key_compare key_compare; 57 | typedef typename btree_type::allocator_type allocator_type; 58 | 59 | public: 60 | // Default constructor. 61 | safe_btree_set(const key_compare &comp = key_compare(), 62 | const allocator_type &alloc = allocator_type()) 63 | : super_type(comp, alloc) { 64 | } 65 | 66 | // Copy constructor. 67 | safe_btree_set(const self_type &x) 68 | : super_type(x) { 69 | } 70 | 71 | // Range constructor. 72 | template 73 | safe_btree_set(InputIterator b, InputIterator e, 74 | const key_compare &comp = key_compare(), 75 | const allocator_type &alloc = allocator_type()) 76 | : super_type(b, e, comp, alloc) { 77 | } 78 | }; 79 | 80 | template 81 | inline void swap(safe_btree_set &x, 82 | safe_btree_set &y) { 83 | x.swap(y); 84 | } 85 | 86 | } // namespace btree 87 | 88 | #endif // UTIL_BTREE_SAFE_BTREE_SET_H__ 89 | -------------------------------------------------------------------------------- /safe_btree_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // TODO(pmattis): Add some tests that iterators are not invalidated by 16 | // insertion and deletion. 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "gtest/gtest.h" 25 | #include "btree_test.h" 26 | #include "safe_btree_map.h" 27 | #include "safe_btree_set.h" 28 | 29 | class UnsafeArena; 30 | 31 | namespace btree { 32 | namespace { 33 | 34 | template 35 | void SetTest() { 36 | typedef TestAllocator TestAlloc; 37 | BtreeTest, std::allocator, N>, std::set >(); 38 | BtreeAllocatorTest, TestAlloc, N> >(); 39 | } 40 | 41 | template 42 | void MapTest() { 43 | typedef TestAllocator TestAlloc; 44 | BtreeTest, std::allocator, N>, std::map >(); 45 | BtreeAllocatorTest, TestAlloc, N> >(); 46 | BtreeMapTest, std::allocator, N> >(); 47 | } 48 | 49 | TEST(SafeBtree, set_int32_32) { SetTest(); } 50 | TEST(SafeBtree, set_int32_64) { SetTest(); } 51 | TEST(SafeBtree, set_int32_128) { SetTest(); } 52 | TEST(SafeBtree, set_int32_256) { SetTest(); } 53 | TEST(SafeBtree, set_int64_256) { SetTest(); } 54 | TEST(SafeBtree, set_string_256) { SetTest(); } 55 | TEST(SafeBtree, set_pair_256) { SetTest, 256>(); } 56 | TEST(SafeBtree, map_int32_256) { MapTest(); } 57 | TEST(SafeBtree, map_int64_256) { MapTest(); } 58 | TEST(SafeBtree, map_string_256) { MapTest(); } 59 | TEST(SafeBtree, map_pair_256) { MapTest, 256>(); } 60 | 61 | TEST(SafeBtree, Comparison) { 62 | const int kSetSize = 1201; 63 | safe_btree_set my_set; 64 | for (int i = 0; i < kSetSize; ++i) { 65 | my_set.insert(i); 66 | } 67 | safe_btree_set my_set_copy(my_set); 68 | EXPECT_TRUE(my_set_copy == my_set); 69 | EXPECT_TRUE(my_set == my_set_copy); 70 | EXPECT_FALSE(my_set_copy != my_set); 71 | EXPECT_FALSE(my_set != my_set_copy); 72 | 73 | my_set.insert(kSetSize); 74 | EXPECT_FALSE(my_set_copy == my_set); 75 | EXPECT_FALSE(my_set == my_set_copy); 76 | EXPECT_TRUE(my_set_copy != my_set); 77 | EXPECT_TRUE(my_set != my_set_copy); 78 | 79 | my_set.erase(kSetSize - 1); 80 | EXPECT_FALSE(my_set_copy == my_set); 81 | EXPECT_FALSE(my_set == my_set_copy); 82 | EXPECT_TRUE(my_set_copy != my_set); 83 | EXPECT_TRUE(my_set != my_set_copy); 84 | 85 | safe_btree_map my_map; 86 | for (int i = 0; i < kSetSize; ++i) { 87 | my_map[std::string(i, 'a')] = i; 88 | } 89 | safe_btree_map my_map_copy(my_map); 90 | EXPECT_TRUE(my_map_copy == my_map); 91 | EXPECT_TRUE(my_map == my_map_copy); 92 | EXPECT_FALSE(my_map_copy != my_map); 93 | EXPECT_FALSE(my_map != my_map_copy); 94 | 95 | ++my_map_copy[std::string(7, 'a')]; 96 | EXPECT_FALSE(my_map_copy == my_map); 97 | EXPECT_FALSE(my_map == my_map_copy); 98 | EXPECT_TRUE(my_map_copy != my_map); 99 | EXPECT_TRUE(my_map != my_map_copy); 100 | 101 | my_map_copy = my_map; 102 | my_map["hello"] = kSetSize; 103 | EXPECT_FALSE(my_map_copy == my_map); 104 | EXPECT_FALSE(my_map == my_map_copy); 105 | EXPECT_TRUE(my_map_copy != my_map); 106 | EXPECT_TRUE(my_map != my_map_copy); 107 | 108 | my_map.erase(std::string(kSetSize - 1, 'a')); 109 | EXPECT_FALSE(my_map_copy == my_map); 110 | EXPECT_FALSE(my_map == my_map_copy); 111 | EXPECT_TRUE(my_map_copy != my_map); 112 | EXPECT_TRUE(my_map != my_map_copy); 113 | } 114 | 115 | } // namespace 116 | } // namespace btree 117 | --------------------------------------------------------------------------------